重庆网站建设公司怎么做,最近重大新闻头条,wordpress写的文章代码显示方式,青岛网站优化排名文章目录 一、为什么要做跨时钟域处理二、单bit信号从慢时钟到快时钟处理2.1 使用同步寄存器链(打两拍)2.2 仿真代码编写2.3 仿真结果观察 三、单bit信号从快时钟域到慢时钟域处理3.1 使用脉冲展宽3.2 仿真代码编写3.3 仿真结果观察 四、在任意时钟域跨单bit信号4.1 使用握手协… 文章目录 一、为什么要做跨时钟域处理二、单bit信号从慢时钟到快时钟处理2.1 使用同步寄存器链(打两拍)2.2 仿真代码编写2.3 仿真结果观察 三、单bit信号从快时钟域到慢时钟域处理3.1 使用脉冲展宽3.2 仿真代码编写3.3 仿真结果观察 四、在任意时钟域跨单bit信号4.1 使用握手协议传输单bit脉冲信号4.2 从快到慢仿真代码编写4.3 从快到慢仿真结果观察4.4 从慢到快仿真结果观察 五、多bit数据跨时钟域 一、为什么要做跨时钟域处理 在之前的文章《FPGA静态时序分析与约束一、理解亚稳态》中我知道了什么是亚稳态以及亚稳态对系统的危害。通常我们的系统工程中不止有一个处理时钟当不同时钟域下的信号进行交互的时候就涉及到跨时钟域的问题了。由于不同时钟的频率、相位都可能不同所以就存在目标时钟在采集源时钟域信号时发生亚稳态情况如下图所示 此时源时钟域下的信号变化刚好在目标时钟域的上升沿建立或保持时间范围内因此发生了建立或保持时间违规从而造成亚稳态的输出。因此我们必须对这种情况进行处理处理方式分为三种情况
单bit信号从慢时钟到快时钟单bit信号从快时钟到慢时钟多bit信号跨时钟域
二、单bit信号从慢时钟到快时钟处理
2.1 使用同步寄存器链(打两拍) 在快时钟域频率高于慢时钟域时理论上一个慢时钟域周期的信号可以百分百被快时钟采集到为了防止亚稳态的产生可以通过打两拍的方式处理如下图所示 就算第一级寄存器产生了亚稳态但是经过自身寄存器输出后能够使信号快速回落至稳定状态稳定输出的概率为70%~80%左右第二级寄存器可以稳定输出的概率为99%左右再后面改善就不明显了所以一般情况下进行两级寄存就能消除大多数情况下的亚稳态。代码如下
timescale 1ns / 1ps
module single_bit_slow2fast(input i_signal_a , //慢时钟域的信号input i_clk_b , //快时钟input i_rst_b , //快时钟域复位信号,高电平有效 output o_signal_b , //快时钟域同步后的信号output o_signal_b_pos , //同步后的信号上升沿output o_signal_b_neg //同步后的信号下降沿
);reg r_signal_a_d1 ;
reg r_signal_a_d2 ;
reg r_signal_a_d3 ; //再打一拍是用最稳定的两拍检测边沿信号assign o_signal_b r_signal_a_d2;
assign o_signal_b_pos r_signal_a_d2 (~r_signal_a_d3);
assign o_signal_b_neg (~r_signal_a_d2) r_signal_a_d3;always (posedge i_clk_b or posedge i_rst_b) beginif(i_rst_b 1b1)beginr_signal_a_d1 1b0;r_signal_a_d2 1b0;r_signal_a_d3 1b0;endelse beginr_signal_a_d1 i_signal_a;r_signal_a_d2 r_signal_a_d1;r_signal_a_d3 r_signal_a_d2;end
endendmodule
2.2 仿真代码编写 仿真代码产生两个不同快慢时钟以及慢时钟域的信号代码如下
timescale 1ns / 1ns
module tb_single_bit_slow2fast();reg i_clk_b ;reg clk_a ;reg i_rst_b ;reg i_signal_a ;initial begini_clk_b 0;clk_a 0;i_rst_b 1;i_signal_a 0;#300 (posedge i_clk_b) i_rst_b 0;
endalways #2 i_clk_b ~ i_clk_b;
always #15 clk_a ~clk_a;always (posedge clk_a) beginrepeat(20)begini_signal_a {$random}%2;#30i_signal_a 0;#200;end
endsingle_bit_slow2fast u_single_bit_slow2fast(.i_signal_a ( i_signal_a ),.i_clk_b ( i_clk_b ),.i_rst_b ( i_rst_b ),.o_signal_b ( o_signal_b ),.o_signal_b_pos ( o_signal_b_pos ),.o_signal_b_neg ( o_signal_b_neg )
);endmodule
2.3 仿真结果观察 从仿真来看慢时钟信号无论什么时候发送快时钟依然能采集到。
三、单bit信号从快时钟域到慢时钟域处理
3.1 使用脉冲展宽 对于快时钟域的信号让慢时钟来采集不能使用打两拍来处理因为快时钟信号宽度太小很可能慢时钟采集不到如下图这种情况 在这种情况下我们可以将快时钟下的信号进行展宽至慢时钟能采集到为止然后再用慢时钟打两拍进行同步处理如下所示 具体展宽多长需要看两个时钟频率之间的比值例如快时钟频率是175.5M慢时钟是27M快慢时钟之比6.5所以要将快时钟的脉冲展宽至7个时钟周期宽度才能确保被慢时钟采到。代码如下
timescale 1ns / 1ps
module single_bit_fast2slow#
(parameter CLKA_FPQ 100_000_000,parameter CLKB_FPQ 33_000_000
)
(input i_clk_a , //快时钟input i_rst_a , //快时钟域复位信号高电平有效input i_signal_a , //快时钟脉冲信号input i_clk_b , //慢时钟input i_rst_b , //慢时钟复位信号高电平有效output o_signal_b //慢时钟同步后的信号
);localparam CLK_NUM CLKA_FPQ / CLKB_FPQ;/***********a时钟域*******************/ reg [7:0] clk_cnt ; //快时钟域下的计数器
reg r_i_signal_a ; //需要展宽的信号always (posedge i_clk_a) beginif(i_rst_a)r_i_signal_a 1b0;else if(clk_cnt CLK_NUM)r_i_signal_a 1b0;else if(i_signal_a 1b1)r_i_signal_a 1b1;elser_i_signal_a r_i_signal_a;
endalways (posedge i_clk_a) beginif(i_rst_a)clk_cnt d0;else if(clk_cnt CLK_NUM)clk_cnt d0;else if(r_i_signal_a 1b1)clk_cnt clk_cnt 1b1;elseclk_cnt d0;
end/******************b时钟域**************/
reg r_signal_b1 ;
reg r_signal_b2 ;assign o_signal_b r_signal_b2;always (posedge i_clk_b) beginif(i_rst_b)beginr_signal_b1 1b1;r_signal_b2 1b1;endelse beginr_signal_b1 r_i_signal_a;r_signal_b2 r_signal_b1;endendendmodule
3.2 仿真代码编写
timescale 1ns / 1nsmodule tb_single_bit_fast2slow();reg i_clk_a;
reg i_rst_a;
reg i_signal_a;
reg i_clk_b;
reg i_rst_b;initial begini_clk_a 0;i_rst_a 1;i_clk_b 0;i_rst_b 1;#150i_rst_a 0;#100i_rst_b 0;
endalways#5 i_clk_a ~i_clk_a;
always#15 i_clk_b ~i_clk_b;always (posedge i_clk_a) beginif(i_rst_a 1b1)i_signal_a 1b0;else begini_signal_a {$random}%2;#10;i_signal_a 1b0;#100;endendsingle_bit_fast2slow#(.CLKA_FPQ ( 100_000_000 ),.CLKB_FPQ ( 30_000_000 )
)u_single_bit_fast2slow(.i_clk_a ( i_clk_a ),.i_rst_a ( i_rst_a ),.i_signal_a ( i_signal_a ),.i_clk_b ( i_clk_b ),.i_rst_b ( i_rst_b ),.o_signal_b ( o_signal_b )
);endmodule
3.3 仿真结果观察 仿真设置快时钟频率为100M慢时钟频率为30M因此需要将脉冲宽度展宽四个快时钟周期然后慢时钟再打两拍同步一下由仿真结果观察结果正确我们下面将快时钟设置为500M结果如下 由上面可以看出快时钟为500M慢时钟为30M依然也能正确的采集到快时钟的脉冲信号。
四、在任意时钟域跨单bit信号 前面两种情况我们实现了单bit时钟从快到慢或者从慢到快时钟之间的传输。除了使用以上两种方式外我们还可以通过握手信号来实现任意时钟域之间的单bit信号传输。
4.1 使用握手协议传输单bit脉冲信号 从A时钟域向B时钟域传输脉冲信号可以在A时钟检测脉冲信号然后随即拉高一个valid信号直到B时钟检测到valid信号后拉高一个周期的同步信号同时给出ack信号然后A时钟检测到ack信号后拉低valid信号表示一次传输完成。 代码如下
timescale 1ns / 1ps
module single_bit_handshake#
(parameter CLKA_FPQ 100_000_000,parameter CLKB_FPQ 20_000_000
)
(input i_clk_a , //A时钟input i_rst_a , //A时钟域复位信号高电平有效input i_signal_a , //A时钟脉冲信号input i_clk_b , //B时钟input i_rst_b , //B时钟复位信号高电平有效output o_signal_b //B时钟同步后的信号
);localparam CLK_NUM (CLKA_FPQ CLKB_FPQ) ? 1 : (CLKB_FPQ / CLKA_FPQ);/****************A时钟域*********************/
reg r_signal_a_valid ;
reg r_ack_a1 ;
reg r_ack_a2 ;
/****************B时钟域*********************/
reg r_signal_b1 ;
reg r_signal_b2 ;
reg r_signal_b3 ;
reg r_signal_b_ack ;
reg [7:0] r_clk_cnt_b ;assign o_signal_b r_signal_b3;/****************A时钟域*********************/
always (posedge i_clk_a) beginif(i_rst_a 1b1)r_signal_a_valid 1b0;else if(r_ack_a2 1b1)r_signal_a_valid 1b0;else if(i_signal_a 1b1)r_signal_a_valid 1b1;elser_signal_a_valid r_signal_a_valid;
endalways (posedge i_clk_a) beginif(i_rst_a 1b1)beginr_ack_a1 1b0;r_ack_a2 1b0;endelse beginr_ack_a1 r_signal_b_ack;r_ack_a2 r_ack_a1;endend/****************B时钟域*********************/
always (posedge i_clk_b) beginif(i_rst_b 1b1)beginr_signal_b1 1b0;r_signal_b2 1b0; endelse if(r_signal_a_valid 1b1)beginr_signal_b1 1b1;r_signal_b2 r_signal_b1;endelse beginr_signal_b1 1b0;r_signal_b2 1b0;end
endalways (posedge i_clk_b) beginif(i_rst_b 1b1)r_signal_b3 1b0;else if((r_signal_b1 1b1)(r_signal_b2 1b0))r_signal_b3 1b1;elser_signal_b3 1b0;
endalways (posedge i_clk_b) beginif(i_rst_b 1b1)r_signal_b_ack 1b0;else if(r_clk_cnt_b CLK_NUM)r_signal_b_ack 1b0;else if((r_signal_b1 1b1)(r_signal_b2 1b0))r_signal_b_ack 1b1;elser_signal_b_ack r_signal_b_ack;
endalways (posedge i_clk_b) beginif(i_rst_b 1b1)r_clk_cnt_b d0;else if(r_clk_cnt_b CLK_NUM)r_clk_cnt_b d0;else if(r_signal_b_ack 1b1)r_clk_cnt_b r_clk_cnt_b 1b1;elser_clk_cnt_b d0;
endendmodule
4.2 从快到慢仿真代码编写 先设置从快时钟到慢时钟
timescale 1ns / 1ps
module tb_single_bit_handshake();reg i_clk_a;
reg i_rst_a;
reg i_signal_a;
reg i_clk_b;
reg i_rst_b;initial begini_clk_a 0;i_rst_a 1;i_clk_b 0;i_rst_b 1;#150i_rst_a 0;#100i_rst_b 0;
endalways#1 i_clk_a ~i_clk_a;
always#15 i_clk_b ~i_clk_b;always (posedge i_clk_a) beginif(i_rst_a 1b1)i_signal_a 1b0;else begini_signal_a {$random}%2;#2;i_signal_a 1b0;#100;endendsingle_bit_handshake#(.CLKA_FPQ ( 500_000_000 ),.CLKB_FPQ ( 30_000_000 )
)u_single_bit_handshake(.i_clk_a ( i_clk_a ),.i_rst_a ( i_rst_a ),.i_signal_a ( i_signal_a ),.i_clk_b ( i_clk_b ),.i_rst_b ( i_rst_b ),.o_signal_b ( o_signal_b )
);endmodule
4.3 从快到慢仿真结果观察 由图可看出从500M的快时钟到30M的慢时钟能成功传输。
4.4 从慢到快仿真结果观察 将仿真代码的AB时钟互换一下变成从30M慢时钟传输到500M快时钟仿真代码如下
timescale 1ns / 1ps
module tb_single_bit_handshake();reg i_clk_a;
reg i_rst_a;
reg i_signal_a;
reg i_clk_b;
reg i_rst_b;initial begini_clk_a 0;i_rst_a 1;i_clk_b 0;i_rst_b 1;#150i_rst_a 0;#100i_rst_b 0;
endalways#15 i_clk_a ~i_clk_a;
always#1 i_clk_b ~i_clk_b;always (posedge i_clk_a) beginif(i_rst_a 1b1)i_signal_a 1b0;else begini_signal_a {$random}%2;#30;i_signal_a 1b0;#100;endendsingle_bit_handshake#(.CLKA_FPQ ( 30_000_000 ),.CLKB_FPQ ( 500_000_000 )
)u_single_bit_handshake(.i_clk_a ( i_clk_a ),.i_rst_a ( i_rst_a ),.i_signal_a ( i_signal_a ),.i_clk_b ( i_clk_b ),.i_rst_b ( i_rst_b ),.o_signal_b ( o_signal_b )
);endmodule
仿真结果如下 由图可以看出从慢时钟到快时钟依然能够同步成功。值得注意的是前面这几种单bit跨时钟处理方法不适合连续的触发信号如果需要同步连续的脉冲信号则需要考虑使用异步fifo或者ram。
五、多bit数据跨时钟域 对于多bit情况设计者必须习惯于采用例如双时钟 FIFO 这样的电路DCFIFO来存取数据和进行握手。FIFO 逻辑仅使用同步器传输转换两个时钟域之间的控制信号而数据的读和写则使用双端口的存储器具体FIFO的使用参考《详解Xilinx Native FIFO的使用以及RST复位的注意事项》。