赞
踩
握手又称结绳法,适用场景为数据有效信号在数据信号前一个周期或数据有效信号在数据的第一个周期,且在握手期间,数据需要保持不变,直到源时钟域收到了解绳的有效信号。
源码如下:
- module toggle(
- input wire clka,
- input wire clkb,
- input wire rst_n,
- input wire a_en,
- input wire [7:0] data_a_in,
-
- output reg [7:0] data_b_out,
- output wire b_en,
- output wire ack_a
- );
-
- reg a_en_d1;
- reg a_en_d2;
- wire a_en_neg;
-
- reg a_req;
-
- reg req_d1;
- reg req_d2;
-
- reg ack_d1;
- reg ack_d2;
-
- wire ack_pos;
-
- always@(posedge clka or negedge rst_n)begin
- if(!rst_n)begin
- a_en_d1 <= 1'b0;
- a_en_d2 <= 1'b0;
- end
- else begin
- a_en_d1 <= a_en;
- a_en_d2 <= a_en_d1;
- end
- end
-
- assign a_en_neg = a_en_d2 && (~a_en_d1);
-
- always@(posedge clka or negedge rst_n)begin
- if(!rst_n)
- a_req <= 1'b0;
- else if(a_en_neg)
- a_req <= 1'b1;
- else if(ack_pos)
- a_req <= 1'b0;
- end
- always@(posedge clkb or negedge rst_n)begin
- if(!rst_n)begin
- req_d1 <= 1'b0;
- req_d2 <= 1'b0;
- end
- else begin
- req_d1 <= a_req;
- req_d2 <= req_d1;
- end
- end
- always@(posedge clka or negedge rst_n)begin
- if(!rst_n)begin
- ack_d1 <= 1'b0;
- ack_d2 <= 1'b0;
- end
- else begin
- ack_d1 <= req_d2;
- ack_d2 <= ack_d1;
- end
- end
- assign b_en = (~req_d2) && (req_d1);
-
- assign ack_pos = (~ack_d2) && ack_d1;
- assign ack_a = ack_d2;
- always@(posedge clkb or negedge rst_n)begin
- if(!rst_n)
- data_b_out <= 8'd0;
- else if(b_en)
- data_b_out <= data_a_in;
- end
-
-
- endmodule

testbench如下:
- `timescale 1ns/1ns
- module toggle_tb();
- reg clka;
- reg clkb;
- reg rst_n;
- reg a_en;
- reg [7:0] data_a_in;
-
- wire [7:0] data_b_out;
- wire b_en;
- wire ack_a;
-
- always #5 clka = ~clka;
- always #10 clkb = ~clkb;
-
- initial begin
- rst_n = 1'b0;
- clka = 1'b0;
- clkb = 1'b0;
- #11;
- rst_n = 1'b1;
- #10000;
- $finish;
- end
-
- reg ack_a_d1;
-
- always@(posedge clka or negedge rst_n)begin
- if(!rst_n)begin
- a_en <= 1'b1;
- ack_a_d1 <= 1'b0;
- end
- else begin
- ack_a_d1 <= ack_a;
- a_en <= (~ack_a_d1) && ack_a;
- end
- end
-
- always@(posedge clka or negedge rst_n)begin
- if(!rst_n)
- data_a_in <= 8'd0;
- else if(a_en)
- data_a_in <= {$random}%256;
- end
- toggle toggle_inst(
- .clka (clka),
- .clkb (clkb),
- .rst_n (rst_n),
- .a_en (a_en),
- .data_a_in (data_a_in),
- .data_b_out (data_b_out),
- .b_en (b_en),
- .ack_a (ack_a)
- );
- initial begin
- $fsdbDumpfile("tb.fsdb");
- $fsdbDumpvars;
- end
- endmodule

仿真结果如下:
其中G1中为源时钟域信号,G2为目的时钟域信号
原理图如下:
DMUX适用于慢时钟域向快时钟域传递(因为两级同步器),且数据有效信号在数据信号的前一个周期或者数据有效信号在数据信号的第一个周期。数据信号要保证在有效信号同步期间保持不变。
源代码如下:
- module dmux(
- input wire clka,
- input wire clkb,
- input wire a_en,
- input wire rst_n,
- input wire [7:0] data_in,
-
- output reg [7:0] data_out
- );
-
- reg a_en_d1;
- reg a_en_d2;
-
- always@(posedge clkb or negedge rst_n)begin
- if(!rst_n)begin
- a_en_d1 <= 1'b0;
- a_en_d2 <= 1'b0;
- end
- else begin
- a_en_d1 <= a_en;
- a_en_d2 <= a_en_d1;
- end
- end
-
- always@(posedge clkb or negedge rst_n)begin
- if(!rst_n)
- data_out <= 8'd0;
- else if(a_en_d2)
- data_out <= data_in;
- end
- endmodule

testbench如下:
- `timescale 1ns/1ns;
- module dmux_tb();
- reg clka;
- reg clkb;
- reg rst_n;
- reg a_en;
- reg [7:0] data_in;
-
- wire [7:0] data_out;
-
- always #10 clka = ~clka;
- always #5 clkb = ~clkb;
-
- initial begin
- clka = 1'b0;
- clkb = 1'b0;
- rst_n = 1'b0;
- a_en = 1'b0;
- data_in = 8'd0;
- #11;
- rst_n = 1'b1;
- @(posedge clka)
- a_en = 1'b1;
- data_in = {$random} %256;
- @(posedge clka)
- a_en = 1'b0;
- #33;
- @(posedge clka)
- a_en = 1'b1;
- @(posedge clka)
- a_en = 1'b0;
- data_in = ($random)%256;
- #100;
- $finish;
- end
-
- dmux dmux_inst(
- .clka (clka),
- .clkb (clkb),
- .rst_n (rst_n),
- .a_en (a_en),
- .data_in (data_in),
- .data_out (data_out)
- );
-
- initial begin
- $fsdbDumpfile("tb.fsdb");
- $fsdbDumpvars;
- end
-
- endmodule

仿真结果如下:
可以清晰看到两种情况。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。