赞
踩
点击上方“蓝字”,学习更多干货!
在数字电路中,跨时钟域处理是个很庞大的问题,因此将会作为一个专题来陆续分享。今天先来从处理单bit跨时钟域信号同步问题来入手。
01
握手(handshake)是用来处理单bit信号的跨时钟域传递的一个有效的方法。在从快时钟向慢时钟传递时,由于输入信号变化较快,输出一侧可能跟不上输入的变化,从而导致“漏采“现象。
图1 “漏采”现象演示
在图1中,由于两个时钟的速度差距,来自快时钟域的脉冲信号还未到达慢时钟的采样边沿便消失了,导致了“漏采”。
在这种情况下,如何让脉冲信号准确无误地传递过去呢?一个方法是将脉冲信号展宽,待输出一侧检测到信号并将其解析为脉冲信号后,再向输入一侧发送应答信号,表明接收到信号并且传输完成。这个过程被称之为“握手”。
02
先来看一个最基本的握手协议,下边是它的电路图。
图2 “握手”电路演示
在上图中 src_clk和dst_clk分别为输入和输出侧的时钟,src_pulse为输入的脉冲信号,dst_pulse为同步到输出端的脉冲信号。可以看到,脉冲信号被同步到输出端后,输出端便立即向输入端发送了应答信号,表示收到信号。而当输出端的应答信号同步到输入端后,输入端才可以同步下一个信号。以下为这个电路的verilog描述。
module Sync_Pulse ( input wire src_clk, input wire dst_clk, input wire rst_n, input wire src_pulse, output wire 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) begin if (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; end always @ (posedge dst_clk or negedge rst_n) begin if (rst_n == 1'b0) begin req_state_dly1 <= 1'b0; req_state_dly2 <= 1'b0; dst_req_state <= 1'b0; end else begin req_state_dly1 <= src_sync_req; req_state_dly2 <= req_state_dly1; dst_req_state <= req_state_dly2; end end assign dst_sync_ack = req_state_dly2; always @ (posedge src_clk or negedge rst_n) begin if (rst_n == 1'b0) begin ack_state_dly1 <= 1'b0; src_sync_ack <= 1'b0; end else begin ack_state_dly1 <= dst_sync_ack; src_sync_ack <= ack_state_dly1; end end assign dst_pulse = dst_req_state & (~req_state_dly2); endmodule
03
上述电路虽然可以完整的同步信号,但是若在同步一个脉冲的过程中,输入端又接收到一个输入进来的脉冲,那么此时刚刚输入进来的脉冲将会同步失败。更糟糕的是该电路没有同步失败的反馈,导致使用者误以为正确同步了信号。鉴于此,将上述电路进行改进,当同步失败后将输出src_sync_fail信号来指示同步失败。以下为该电路的verilog描述(此代码来源于网络):
- module handshake_pulse_sync
- (
- src_clk , //source clock
- src_rst_n , //source clock reset (0: reset)
- src_pulse , //source clock pulse in
- src_sync_fail , //source clock sync state: 1 clock pulse if sync fail.
- dst_clk , //destination clock
- dst_rst_n , //destination clock reset (0:reset)
- dst_pulse //destination pulse out
- );
- //PARA DECLARATION
- //INPUT DECLARATION
- input src_clk ; //source clock
- input src_rst_n ; //source clock reset (0: reset)
- input src_pulse ; //source clock pulse in
- input dst_clk ; //destination clock
- input dst_rst_n ; //destination clock reset (0:reset)
- //OUTPUT DECLARATION
- output src_sync_fail ; //source clock sync state: 1 clock pulse if sync fail.
- 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 ;
- reg ack_state_dly2 ;
- reg req_state_dly1 ;
- reg req_state_dly2 ;
- reg dst_req_state ;
- reg dst_sync_ack ;
-
-
- //--========================MODULE SOURCE CODE==========================--
- //--=========================================--
- // DST Clock :
- // 1. generate src_sync_fail;
- // 2. generate sync req
- // 3. sync 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)
- begin
- if(src_rst_n == 1'b0)
- src_sync_fail <= 1'b0 ;
- else if (src_pulse & (~src_sync_idle))
- src_sync_fail <= 1'b1 ;
- else
- src_sync_fail <= 1'b0 ;
- end
-
-
- //set sync req if src_pulse when sync idle ;
- always @(posedge src_clk or negedge src_rst_n)
- begin
- if(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 ;
- end
-
-
- always @(posedge src_clk or negedge src_rst_n)
- begin
- if(src_rst_n == 1'b0)
- begin
- ack_state_dly1 <= 1'b0 ;
- ack_state_dly2 <= 1'b0 ;
- src_sync_ack <= 1'b0 ;
- end
- else
- begin
- ack_state_dly1 <= dst_sync_ack ;
- ack_state_dly2 <= ack_state_dly1 ;
- src_sync_ack <= ack_state_dly2 ;
- end
- end
-
-
- //--=========================================--
- // DST Clock :
- // 1. sync src sync req
- // 2. generate dst pulse
- // 3. generate sync ack
- //--=========================================--
- always @(posedge dst_clk or negedge dst_rst_n)
- begin
- if(dst_rst_n == 1'b0)
- begin
- req_state_dly1 <= 1'b0 ;
- req_state_dly2 <= 1'b0 ;
- dst_req_state <= 1'b0 ;
- end
- else
- begin
- req_state_dly1 <= src_sync_req ;
- req_state_dly2 <= req_state_dly1 ;
- dst_req_state <= req_state_dly2 ;
- end
- end
-
- //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)
- begin
- if(dst_rst_n == 1'b0)
- dst_sync_ack <= 1'b0;
- else if (req_state_dly2)
- dst_sync_ack <= 1'b1;
- else
- dst_sync_ack <= 1'b0;
- end
- endmodule
从代码可以得知,在同步信号的过程中,src_sync_idle会拉低,此时若再有输入脉冲,则会输出同步失败信号。
仿真结果如下
图3 电路仿真结果
从仿真结果可以看到,该设计达到了同步信号要求。
对该部分有兴趣的,或者有问题想要探讨,欢迎点击“阅读原文”进行留言,也可以直接向公众号发送消息,欢迎大家的来信!
最后,创作不易,如果对你有帮助的话,点个“在看”再走呗!
你点的每个赞,我都认真当成了喜欢
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。