信號(hào)從快時(shí)鐘域傳輸?shù)铰龝r(shí)鐘域來時(shí),需要根據(jù)信號(hào)的特點(diǎn)來進(jìn)行同步處理。對(duì)于單 bit 信號(hào),一般可按電平信號(hào)和脈沖信號(hào)來區(qū)分。
同步邏輯設(shè)計(jì)中,電平信號(hào)是指長時(shí)間保持不變的信號(hào)。保持不變的時(shí)間限定是相對(duì)于慢時(shí)鐘而言的。只要快時(shí)鐘的信號(hào)保持高電平或低電平的時(shí)間足夠長,以至于能被慢時(shí)鐘在滿足時(shí)序約束的條件下采集到,就可以認(rèn)為該信號(hào)為電平信號(hào)。
既然電平信號(hào)能夠被安全的采集到,所以從快時(shí)鐘域到慢時(shí)鐘域的電平信號(hào)也采用延遲打拍的方法做同步。
同步邏輯設(shè)計(jì)中,脈沖信號(hào)是指從快時(shí)鐘域輸出的有效寬度小于慢時(shí)鐘周期的信號(hào)。如果慢時(shí)鐘域直接去采集這種窄脈沖信號(hào),有可能會(huì)漏掉。
假如這種脈沖信號(hào)脈寬都是一致的,在知道兩個(gè)時(shí)鐘頻率比的情況下,可以采用"快時(shí)鐘域脈寬擴(kuò)展+慢時(shí)鐘域延遲打拍"的方法進(jìn)行同步。
如果有時(shí)窄脈沖信號(hào)又表現(xiàn)出電平信號(hào)的特點(diǎn),即有時(shí)信號(hào)的有效寬度大于慢時(shí)鐘周期而能被慢時(shí)鐘采集到,那么對(duì)此類信號(hào)再進(jìn)行脈沖擴(kuò)展顯然是不經(jīng)濟(jì)的。此時(shí),可通過"握手傳輸"的方法進(jìn)行同步。
假設(shè)脈沖信號(hào)的高電平期間為有效信號(hào)期間,其基本原理如下。
pulse_fast_r
??;蛘呖鞎r(shí)鐘域輸出高電平信號(hào)時(shí),不要急于將信號(hào)拉低,先保持輸出信號(hào)為高電平狀態(tài)。
pulse_fast_r
?進(jìn)行延遲打拍采樣。因?yàn)榇藭r(shí)的脈沖信號(hào)被快時(shí)鐘域保持拉高狀態(tài),延遲打拍肯定會(huì)采集到該信號(hào)。
pulse_fast2s_r
?后,再反饋給快時(shí)鐘域。
pulse_fast2s_r
?進(jìn)行延遲打拍采樣。如果檢測到反饋信號(hào)為高電平,證明慢時(shí)鐘域已經(jīng)接收到有效的高電平信號(hào)。如果此時(shí)快時(shí)鐘域自身邏輯不再要求脈沖信號(hào)為高電平狀態(tài),拉低快時(shí)鐘域的脈沖信號(hào)即可。此方法實(shí)質(zhì)是通過相互握手的方式對(duì)窄脈沖信號(hào)進(jìn)行脈寬擴(kuò)展。
利用握手信號(hào)進(jìn)行同步處理的 Verilog 模型描述如下。
//同步模塊工作時(shí)鐘大約為 25MHz 的模塊
//異步數(shù)據(jù)對(duì)來自工作時(shí)鐘為 100MHz 的模塊
module pulse_syn_fast2s
#( parameter PULSE_INIT = 1'b0
)
(
input rstn,
input clk_fast,
input pulse_fast,
input clk_slow,
output pulse_slow);
wire clear_n ;
reg pulse_fast_r ;
/**************** fast clk ***************/
//(1) 快時(shí)鐘域檢測到脈沖信號(hào)時(shí),不急于將脈沖信號(hào)拉低
always@(posedge clk_fast or negedge rstn) begin
if (!rstn)
pulse_fast_r <= PULSE_INIT ;
else if (!clear_n)
pulse_fast_r <= 1'b0 ;
else if (pulse_fast)
pulse_fast_r <= 1'b1 ;
end
reg [1:0] pulse_fast2s_r ;
/************ slow clk *************/
//(2) 慢時(shí)鐘域?qū)π盘?hào)進(jìn)行延遲打拍采樣
always@(posedge clk_slow or negedge rstn) begin
if (!rstn)
pulse_fast2s_r <= 3'b0 ;
else
pulse_fast2s_r <= {pulse_fast2s_r[0], pulse_fast_r} ;
end
assign pulse_slow = pulse_fast2s_r[1] ;
reg [1:0] pulse_slow2f_r ;
/********* feedback for slow clk to fast clk *******/
//(3) 對(duì)反饋信號(hào)進(jìn)行延遲打拍采樣
always@(posedge clk_fast or negedge rstn) begin
if (!rstn)
pulse_slow2f_r <= 1'b0 ;
else
pulse_slow2f_r <= {pulse_slow2f_r[0], pulse_slow} ;
end
//控制快時(shí)鐘域脈沖信號(hào)拉低
assign clear_n = ~(!pulse_fast && pulse_slow2f_r[1]) ;
endmodule
testbench 描述如下:
`timescale 1ns/1ps
module test ;
reg clk_100mhz, clk_25mhz ;
reg rstn ;
initial begin
clk_100mhz = 0 ;
clk_25mhz = 0 ;
rstn = 0 ;
#11 rstn = 1 ;
end
always #(10/2) clk_100mhz = ~clk_100mhz ;
always #(45/2) clk_25mhz = ~clk_25mhz ;
reg [7:0] cnt ;
reg pulse_sig ;
always @(posedge clk_100mhz or negedge rstn) begin
if (!rstn) begin
cnt <= 'b0 ;
end
else begin
cnt <= cnt + 1'b1 ;
end
end
//窄脈沖生成部分
always @(posedge clk_100mhz or negedge rstn) begin
if (!rstn) begin
pulse_sig <= 1'b0 ;
end
else if (cnt == 5 ||
cnt == 40 || cnt == 42 ||
cnt >= 75 && cnt <= 81 || cnt == 85 || cnt == 87 )
begin
pulse_sig <= 1'b1 ;
end
else begin
pulse_sig <= 1'b0 ;
end
end
pulse_syn_fast2s u_fast2s_pulse(
.rstn (rstn),
.clk_fast (clk_100mhz),
.pulse_fast (pulse_sig),
.clk_slow (clk_25mhz),
.pulse_slow ());
initial begin
forever begin
#100;
if ($time >= 10000) $finish ;
end
end
endmodule // test
仿真結(jié)果如下,由圖可知:
當(dāng)多位寬數(shù)據(jù)進(jìn)行同步時(shí),如果該數(shù)據(jù)各 bit 位都可以看作電平信號(hào),即相對(duì)一段時(shí)間內(nèi)各 bit 位數(shù)據(jù)均可以保持不變以至于能被慢時(shí)鐘采集到,可以消耗一些觸發(fā)器資源對(duì)多位寬數(shù)據(jù)進(jìn)行簡單的延遲打拍同步。
但如果數(shù)據(jù)變化速率過快,就不能再使用延遲打拍采樣的方法。因?yàn)榇藭r(shí)數(shù)據(jù)各 bit 位不再是電平信號(hào),變化的時(shí)間也參差不齊,用異步時(shí)鐘進(jìn)行打拍采樣,可能會(huì)采集到因路徑延遲不同而導(dǎo)致的錯(cuò)誤數(shù)據(jù)。
解決此類異步問題的常用方法是采用異步 FIFO (First In First Out)。具體請(qǐng)參考下一節(jié):《Verilog FIFO 設(shè)計(jì)》。
點(diǎn)擊這里下載源碼
更多建議: