假如设计有两个输入时钟,如图所示,一个时钟给接口1使用,另一个时钟给接口2使用,因此这里就会存在跨时钟域的问题。
跨时钟域的的处理:
1、单bit:两级D触发器同步
2、多bit:采用异步fifo,异步双口RAM
3、加握手信号
4、格雷码转换
多级寄存器处理:①慢到快②快到慢
①慢到快:输入信号从时钟频率慢同步到时钟频率快
pulse_b是时钟clk_b下的寄存器信号,在时钟clk_a看来,这是一个很宽的电平信号,保持了多个时钟clk_a周期,所以一定能被clk_a采到。采集过程中必须寄存两拍:第一拍将pulse_b同步化,同步化的输出可能带来建立/保持时间的冲突,从而产生亚稳态,因此需要再寄存一拍,以减少亚稳态带来的影响。一般来说两级是最基本要求,如果是高频率设计,则需要增加寄存级数来大幅降低系统的不稳定性。也就是说采用多级寄存器来采样异步时钟域的信号,级数越多,同步过来的信号越稳定。一般代码设计如下:
always @ (posedge clk_a or negedge rst_n) begin if (rst_n == 1'b0) begin pules_a_r1 <= 1'b0; pules_a_r2 <= 1'b0; pules_a_r3 <= 1'b0; end else begin //打3拍 pules_a_r1 <= pulse_b; pules_a_r2 <= pules_a_r1; pules_a_r3 <= pules_a_r2; end end assign pulse_a_pos = pules_a_r2 & (~pules_a_r3); //上升沿检测 assign pulse_a_neg = pules_a_r3 & (~pules_a_r2); //下降沿检测 assign pulse_a = pules_a_r2; //打了两拍,成功把时钟域clk_b的信号同步到时钟域clk_a
②快到慢:输入信号从时钟频率快同步到时钟频率慢
如果输入的单bit信号从快时钟clk_a同步到慢时钟clk_b,那么存在两种不同的情况:输入信号是电平信号level_a、输入信号是脉冲信号pulse_a。
实际上,在一般情况下只有电平信号level_a的宽度才能被clk_b采集到,并保证系统正常工作。同理,脉冲信号pulse_a的宽度不够,因此需要用一个展宽信号来替代pulse_a,实现跨时钟域的握手。主要原理就是先把脉冲信号pulse_a在clk_a下展宽,变成电平信号signal_a,再向clk_b传递,当确认clk_b已经“看见”信号同步过去之后,再清掉signal_a。
//Synchronous module Sync_Pulse( input clka, input clkb, input rst_n, input pulse_ina, output pulse_outb, output signal_outb ); //------------------------------------------------------- reg signal_a; reg signal_b; reg [1:0] signal_b_r; reg [1:0] signal_a_r; //------------------------------------------------------- //在clka下,生成展宽信号signal_a always @(posedge clka or negedge rst_n)begin if(rst_n == 1'b0)begin signal_a <= 1'b0; end else if(pulse_ina == 1'b1)begin signal_a <= 1'b1; end else if(signal_a_r[1] == 1'b1) signal_a <= 1'b0; else signal_a <= signal_a; end //------------------------------------------------------- //在clkb下同步signal_a always @(posedge clkb or negedge rst_n)begin if(rst_n == 1'b0)begin signal_b <= 1'b0; end else begin signal_b <= signal_a; end end //------------------------------------------------------- //在clkb下生成脉冲信号和输出信号 always @(posedge clkb or negedge rst_n)begin if(rst_n == 1'b0)begin signal_b_r <= 2'b00; end else begin signal_b_r <= {signal_b_r[0], signal_b}; end end assign pulse_outb = ~signal_b_r[1] & signal_b_r[0]; assign signal_outb = signal_b_r[1]; //打了两拍,成功把时钟域clk_a的信号同步到时钟域clk_b //------------------------------------------------------- //在clka下采集signal_b[1],生成signal_a_r[1]用于反馈拉低signal_a always @(posedge clka or negedge rst_n)begin if(rst_n == 1'b0)begin signal_a_r <= 2'b00; end else begin signal_a_r <= {signal_a_r[0], signal_b_r[1]}; end end endmodule