MUX 同步器这种方式,要求被同步的数据,跟随一个使能信号,如下图类型:
这在特定的场景下是不难实现的,下面具体讲它的实现方式。
一、实现原理
想要将 data bus 从 clkA 转到 clkB(不论谁的频率快慢都一样),我们通过 data bus 的 valid 信号(属于 clkA),也就是图中的 data enable A,将 data enable A 使用 two flip-flop synchronizer 跨到 clkB,也就是 data enable B,并且使用 data enable B 当作最右边 DFF 的 flip-flop enable 信号(在图中使用 mux 来示意),由于 data enable A 的时序等同于 data bus,跨到 data enable B 时也就保证了 data bus 穿过 DFF 的信号已经稳定,即可拿来锁入最后一级 DFF,最后一级的 DFF 的 Q 即是 data bus 存在于 clk B domain 的稳定信号。
我们将中间信号标注一下,以便于波形图分析使用:
如上图,我们假设时钟 A 是慢时钟,我们的数据仅持续一个时钟即可被同步到 B 时钟域。根据电路,得到的波形图如下:
根据电路框图,我们使用 Verilog 语言进行描述,然后仿真,看其效果:
module mux_synchronizer( input wire clka , input wire clkb , input wire rst , input wire [3:0] data_bus , input wire data_enable_a , output reg data_bus_b ); reg reg_data_enable_a ; reg data_enable_b_mid ; reg data_enable_b ; reg [3:0] reg1_data_bus_a ; wire [3:0] data_bus_mux ; //时钟域 a 下同步本地数据及其有效标志信号,改善时序 always@(posedge clka or posedge rst) begin if(rst) begin reg_data_enable_a <= 1'b0 ; reg1_data_bus_a <= 4'd0 ; end else begin reg_data_enable_a <= data_enable_a ; reg1_data_bus_a <= data_bus ; end end //将数据有效标志信号同步到 b 时钟域,两级同步器 always@(posedge clkb or posedge rst) begin if(rst) begin data_enable_b_mid <= 1'b0 ; data_enable_b <= 1'b0; end else begin data_enable_b_mid <= reg_data_enable_a; data_enable_b <= data_enable_b_mid; end end //写法 1: assign data_bus_mux = data_enable_b ? reg1_data_bus_a : data_bus_b; always@(posedge clkb or posedge rst) begin if(rst) begin data_bus_b <= 4'b0; end else begin data_bus_b <= data_bus_mux; end end // //写法 2: // always@(posedge clkb or posedge rst) begin // if(rst) begin // data_bus_b <= 4'b0; // end // else if(data_enable_b) begin // data_bus_b <= reg1_data_bus_a; // end // else begin // data_bus_b <= data_bus_b; // end // end endmodule
注意到,我们的注释处,有写法 2,这种描述,和电路图中的 MUX 写法是一致的。
其实 MUX 充当的作用就是触发器的一个使能信号,如果有带有使能的触发器,那就直接使用无疑了。 而 Xilinx 的 FPGA 中,就有这样的触发器呀,如下为上述电路的 RTL 图:
综合后的原理图:
实现后的原理图:
下面对其功能进行仿真。
二、功能仿真
首先我们仿真从慢时钟到快时钟的情况,仿真平台如下:
module sim_mux_synchronizer( ); reg clka ; reg clkb ; reg rst ; reg [3:0] data_bus ; reg data_enable_a ; wire [3:0] data_bus_b ; initial begin clka = 1'b0; forever begin #5 clka = ~clka; end end initial begin clkb = 1'b0; forever begin #2 clkb = ~clkb; end end initial begin rst = 1'b1; data_bus = 4'b0; data_enable_a = 1'b0; #15 rst = 1'b0; #20 @(posedge clka) begin data_bus = #0.5 4'b1101; data_enable_a = #0.5 1'b1; end @(posedge clka) begin data_bus = #0.5 4'b0; data_enable_a = #0.5 1'b0; end end mux_synchronizer u_mux_synchronizer( .clka ( clka ), .clkb ( clkb ), .rst ( rst ), .data_bus ( data_bus ), .data_enable_a ( data_enable_a ), .data_bus_b ( data_bus_b ) ); endmodule
由此得到仿真波形:
可见,实现了我们想要的功能。
下面提一个问题:如果是从快时钟跨时钟域到慢时钟域呢?我们不妨简单仿真一下:
假设数据在快时钟域内持续时间大概是慢时钟域的三个时钟那么长,如下稍微修改即可得到仿真平台:
module sim_mux_synchronizer( ); reg clka ; reg clkb ; reg rst ; reg [3:0] data_bus ; reg data_enable_a ; wire [3:0] data_bus_b ; initial begin clka = 1'b0; forever begin #2 clka = ~clka; end end initial begin clkb = 1'b0; forever begin #5 clkb = ~clkb; end end initial begin rst = 1'b1; data_bus = 4'b0; data_enable_a = 1'b0; #15 rst = 1'b0; #20 @(posedge clka) begin data_bus = #0.5 4'b1101; data_enable_a = #0.5 1'b1; end repeat(7) begin @(posedge clka); end @(posedge clka) begin data_bus = #0.5 4'b0; data_enable_a = #0.5 1'b0; end end mux_synchronizer u_mux_synchronizer( .clka ( clka ), .clkb ( clkb ), .rst ( rst ), .data_bus ( data_bus ), .data_enable_a ( data_enable_a ), .data_bus_b ( data_bus_b ) ); endmodule
得到仿真图:
可见也是没问题的。但是这个方法也有局限性,如果是快时钟到慢时钟,且快时钟的数据使能脉冲很短,那么慢时钟那两个 DFF 都可能采不到快时钟的数据使能脉冲。
三、参考资料
- What is a FIFO in an FPGA
- Synchronizer techniques for multi-clock domain SoCs & FPGAs
- Verifying Clock Domain Crossing
- Crossing Clock Domains in an FPGA
- Crossing clock domains
- Clock-Domain Crossing (CDC)
- Get those clock domains in sync
- Introduction to Clock Domain Crossing: Double Flopping
- 使用 Mux synchronizer (Qualifier)解決 bus 跨 clock domain crossing(CDC)的問題
- Understanding clock domain crossing issues
- Clock Domain Crossing (CDC) : Asynchronous communications across boundaries
- Clock Domain Crossing
- FPGA 逻辑设计回顾(5)多比特信号的 CDC 处理方式之 MUX 同步器
扫码关注尚为网微信公众号
原创文章,作者:sunev,如若转载,请注明出处:https://www.sunev.cn/embedded/1276.html