快时钟域到慢时钟域分两种情况:
1、允许采样丢失:直接采用同步器即可。
2、不允许采样丢失:原理是保证快时钟域的信号宽度满足一定的条件,使得慢时钟域有足够的时间采样到。
对于情况2有两种方法解决:①信号展宽+边沿检测②握手,且①比②要优先被选择。因为握手资源消耗较大,一般不用。
脉冲信号展宽+边沿检测,脉冲信号转换成电平信号再进行边沿检测
module pulse_detect(input clk_fast , input clk_slow , input rst_n ,input data_in ,output dataout
);reg data_in_fast;reg [2:0] data_slow;//将脉冲信号在快时钟域展平为电平信号。即展宽脉冲信号。在两次脉冲信号之间为电平信号。always@(posedge clk_fast or negedge rst_n)beginif(!rst_n)data_in_fast<= 0;elsedata_in_fast<= data_in ? (~data_in_fast) : data_in_fast;end//将展宽的脉冲信号在慢时钟域打两拍,并检测边沿。always@(posedge clk_slow or negedge rst_n)beginif(!rst)data_slow <= 3'b0;elsedata_slow <= {data_slow[1:0],data_in_reg};end assign dataout = data_slow[2] ^ data_slow[1];
endmodule
握手+边沿:
module pulse_detect(input clk_fast , input clk_slow , input rst_n ,input data_in ,output dataout
);//握手方式reg fast_req;//fast时钟域的请求信号reg slow_ack;//slow时钟域的应答信号reg [2:0] slow_req;//slow时钟域的请求信号reg [2:0] fast_ack;//fast时钟域的应答信号//fast时钟域//将slow时钟域的应答信号打三拍,送到fast时钟域always@(posedge clk_fast or negedge rst_n)beginif(!rst_n)fast_ack <= 3'd0;elsefast_ack <= {fast_ack[1:0],slow_ack};end//生成请求信号fast_reqalways@(posedge clk_fast or negedge rst_n)beginif(!rst_n)fast_req <= 0;else if(data_in)fast_req <= 1'b1;else//快时钟域中没有输入数据时//如果慢时钟域应答了,01x,则快时钟域此时不请求,否则,快时钟域的请求信号维持上一时钟的状态fast_req <= ((fast_ack[1]) & (~fast_ack[2])) ? 1'b0 : fast_req; end//slow时钟域//将fast时钟域的请求信号打三拍,送到slow时钟域always@(posedge clk_slow or negedge rst_n)beginif(!rst_n)slow_req <= 0;elseslow_req <= {slow_req[1:0],fast_req};end//生成应答信号slow_ackalways@(posedge clk_slow or negedge rst_n)beginif(!rst_n)slow_ack <= 0;else if(slow_req[1] & (~slow_req[2])) //如果快时钟域的请求信号由0变为1,01x,即发出请求信号,则慢时钟域进行应答slow_ack <= 1'b1;else//如果slow请求信号10x,即慢时钟域请求信号无效时,慢时钟域不应答//否则慢时钟域应答信号不变slow_ack <= (slow_req[2]&(~slow_req[1])) ? 1'b0 : slow_ack;end//当慢时钟域01x,发出请求信号时,输出为1.assign dataout = (~slow_req[2]) & (slow_req[1]);endmodule
module Sync_Pulse (input src_clk,input dst_clk,input rst_n,input src_pulse,output dst_pulse);reg req_state_dly1, req_state_dly2,dst_req_state,src_sync_req;reg ack_state_dly1,src_sync_ack;wire dst_sync_ack;always @ (posedge src_clk or negedge rst_n) beginif (rst_n == 1'b0)src_sync_req <= 1'b0;else if (src_pulse) src_sync_req <= 1'b1;else if (src_sync_ack) src_sync_req <= 1'b0;else;endalways @ (posedge dst_clk or negedge rst_n) beginif (rst_n == 1'b0)beginreq_state_dly1 <= 1'b0;req_state_dly2 <= 1'b0;dst_req_state <= 1'b0;end else beginreq_state_dly1 <= src_sync_req;req_state_dly2 <= req_state_dly1; dst_req_state <= req_state_dly2;endendassign dst_sync_ack = req_state_dly2;always @ (posedge src_clk or negedge rst_n) beginif (rst_n == 1'b0) beginack_state_dly1 <= 1'b0;src_sync_ack <= 1'b0;endelse beginack_state_dly1 <= dst_sync_ack;src_sync_ack <= ack_state_dly1;endendassign dst_pulse = dst_req_state & (~req_state_dly2);endmodule
对上述代码增加同步失败的指示信号
module handshake_pulse_sync
(input src_clk , //source clockinput src_rst_n, //source clock reset (0: reset)input src_pulse , //source clock pulse inoutput src_sync_fail , //source clock sync state: 1 clock pulse if sync fail.input dst_clk , //destination clockinput dst_rst_n , //destination clock reset (0:reset)output dst_pulse //destination pulse out
);//INTER DECLARATION wire dst_pulse ;wire src_sync_idle ;reg src_sync_fail ;reg src_sync_req ;reg src_sync_ack ;reg ack_state_dly1, ack_state_dly2 ;reg req_state_dly1, req_state_dly2 ;reg dst_req_state ;reg dst_sync_ack ;assign src_sync_idle = ~(src_sync_req | src_sync_ack );//report an error if src_pulse when sync busy ;always @(posedge src_clk or negedge src_rst_n) beginif(src_rst_n == 1'b0)src_sync_fail <= 1'b0 ;else if (src_pulse & (~src_sync_idle))src_sync_fail <= 1'b1 ;elsesrc_sync_fail <= 1'b0 ;end//set sync req if src_pulse when sync idle ;always @(posedge src_clk or negedge src_rst_n) beginif(src_rst_n == 1'b0)src_sync_req <= 1'b0 ;else if (src_pulse & src_sync_idle)src_sync_req <= 1'b1 ;else if (src_sync_ack)src_sync_req <= 1'b0 ;endalways @(posedge src_clk or negedge src_rst_n) beginif(src_rst_n == 1'b0) beginack_state_dly1 <= 1'b0 ;ack_state_dly2 <= 1'b0 ;src_sync_ack <= 1'b0 ;endelse beginack_state_dly1 <= dst_sync_ack ;ack_state_dly2 <= ack_state_dly1 ;src_sync_ack <= ack_state_dly2 ;endendalways @(posedge dst_clk or negedge dst_rst_n) beginif(dst_rst_n == 1'b0) beginreq_state_dly1 <= 1'b0 ;req_state_dly2 <= 1'b0 ;dst_req_state <= 1'b0 ;endelse beginreq_state_dly1 <= src_sync_req ;req_state_dly2 <= req_state_dly1 ;dst_req_state <= req_state_dly2 ;endend//Rising Edge of dst_state generate a dst_pulse;assign dst_pulse = (~dst_req_state) & req_state_dly2 ;//set sync ack when src_req = 1 , clear it when src_req = 0 ;always @(posedge dst_clk or negedge dst_rst_n) beginif(dst_rst_n == 1'b0)dst_sync_ack <= 1'b0;else if (req_state_dly2)dst_sync_ack <= 1'b1;elsedst_sync_ack <= 1'b0;end
endmodule
电路分析:
将src时钟域的脉冲信号打一拍之后,在dst时钟域内打三拍进行同步,其中第二拍的结果作为dst时钟域的应答信号,第二拍和第三拍的结果做边沿检测,以保证在dst时钟域输出接收到的脉冲信号。
其中第二拍的应答信号,在src时钟域经过两级同步作为src的应答信号,当输入脉冲信号时,src的请求信号有效。当src的应答信号有效时,请求信号无效。
缺点:上述操作无法检测到脉冲连续输入时产生的错误,即无法检测同步失败。如:在当前脉冲信号同步过程中又发出了新的脉冲信号的情况。
快时钟域至少展宽脉冲宽度到大于慢时钟域的周期长度。