方法1 雙觸發(fā)器(打2拍)
該方法只用于慢到快時(shí)鐘域的1bit信號(hào)傳遞。在Xilinx器件中,可以使用(* ASYNC_REG = "TRUE" *)標(biāo)記,將兩個(gè)寄存器盡量靠近綜合,降低 亞穩(wěn)態(tài)因?qū)Ь€延遲太大而傳播到第二個(gè)寄存器的可能性。
moduleff2( input clk0,//10Minput din, input clk1,//100Moutputdout ); regdin_r=1'd0; (* ASYNC_REG ="TRUE"*) regr0=1'd0; (* ASYNC_REG ="TRUE"*) regr1=1'd0; assigndout = r1; always@(posedgeclk0) din_r <= din;//由于不確定前級(jí)是否有觸發(fā)器,這里默認(rèn)加一級(jí)寄存,防止出現(xiàn)毛刺always@(posedge?clk1)begin? ? ?r0 ? ?<= din_r; ? ? ? ? r1 ? ?<= r0; ? ?endendmodule
方法2 雙向握手 傳遞信號(hào)
雙向握手方法使用了5個(gè)觸發(fā)器,右邊3個(gè)與方法1一致。左邊兩個(gè)用于將確認(rèn)信號(hào)同步到寫(xiě)時(shí)鐘域。用戶必須將信號(hào)保持到確認(rèn)信號(hào)置高。
該方法適用于慢到快、快到慢、1bit信號(hào)傳遞,一般而言,信號(hào)有效值為高電平。
可以用一個(gè)非門(mén)、一個(gè)異或門(mén)、一個(gè)與門(mén),和一個(gè)觸發(fā)器(下圖中的reg-2)實(shí)現(xiàn)信號(hào)保持,輸入低速單脈沖,但是不保證輸出單脈沖,可以在輸出端加一個(gè)寄存器,用于上升沿判斷.
在verilog可以用一些簡(jiǎn)單的判斷來(lái)保持信號(hào)。下面是一個(gè)單向信號(hào)異步橋,支持單脈沖輸入,單脈沖輸出,時(shí)鐘速率無(wú)限制
使用時(shí),確保在active置低時(shí),將s_vld給異步橋。
/* * Name : 單向信號(hào)異步橋 * Origin: 230406 * EE : hel */modulesignalbridge_async( inputwire s_clk , inputwire s_rstn , inputwire s_vld ,// pulse inputinputwire d_clk , inputwire d_rstn , outputreg d_vld ,// pulse outputoutputwire active );reg[1 :0] s_syncer ;reg[1 :0] d_syncer ;wire ack_d2 = s_syncer[1];wire req_d2 = d_syncer[1]; reg req_d3;reg async_req;wire async_ack = req_d2;assign active = async_req | ack_d2 ;// Source clock domainalways@(posedges_clkornegedges_rstn)beginif(!s_rstn)begin s_syncer <=?2'd0; ? ?endelsebegin? ? ? ? ?s_syncer ? <= ?{s_syncer[0],async_ack}; ? ?endendalways?@(posedge?s_clk?ornegedge?s_rstn)?beginif?(!s_rstn)?begin? ? ? ? ?async_req ? <=?1'd0; ? ?endelseif(ack_d2)begin? ? ? ? ?async_req ? <=?1'd0; ? ?endelseif(s_vld)begin? ? ? ? ?async_req ? <=?1'd1; ? ?endend// Destination clock domainalways?@(posedge?d_clk?ornegedge?d_rstn)?beginif?(!d_rstn)?begin? ? ? ? ?d_syncer ? <=?2'd0; ? ?endelsebegin? ? ? ? ?d_syncer ? <= ?{d_syncer[0],async_req}; ? ?endendalways?@(posedge?d_clk?ornegedge?d_rstn)?beginif?(!d_rstn)?begin? ? ? ? ?req_d3 ? ? ?<=?1'd0; ? ? ? ? d_vld ? ? ? <=?1'd0; ? ?endelsebegin? ? ? ? ?req_d3 ? ? ?<= req_d2; ? ? ? ? d_vld ? ? ? <= req_d2 & (~req_d3); ? ?endendendmodule
方法3 雙向握手 傳遞數(shù)據(jù)
可以使用請(qǐng)求信號(hào)采樣跨時(shí)鐘域過(guò)來(lái)的多比特?cái)?shù)據(jù),就可以做到數(shù)據(jù)的跨時(shí)鐘域了(數(shù)據(jù)跨時(shí)鐘域,頻率低到高,高到低)如下圖:
圖里沒(méi)有畫(huà)反饋信號(hào),數(shù)據(jù)需要在目的時(shí)鐘采樣時(shí)保持穩(wěn)定。這種單個(gè)數(shù)據(jù)跨時(shí)鐘域傳輸?shù)木帉?xiě)流程如下:
原時(shí)鐘域置高req,置好data
目的時(shí)鐘域?qū)eq打兩拍變成req_d2
目的時(shí)鐘域檢測(cè)到req_d2置高,將data打到寄存器內(nèi),并將ack置高
原時(shí)鐘域檢測(cè)到ack_d2被置高,拉低req
目的時(shí)鐘域檢測(cè)到req_d2被拉低,將ack拉低
通過(guò)上述流程編寫(xiě)的數(shù)據(jù)異步橋如下:
支持單個(gè)數(shù)據(jù)輸入輸出,時(shí)鐘速率無(wú)限制。使用時(shí),確保在active置低時(shí),將s_din和s_vld給異步橋,s_vld必須為單脈沖。
/* * Name : 單向數(shù)據(jù)異步橋 * Origin: 230404 * EE : hel */moduledatabridge_async #( parameterDW =8)( inputwire s_clk , inputwire s_rstn , inputwire [DW-1:0] s_din , inputwire s_vld ,// pulse inputinputwire d_clk , inputwire d_rstn , outputreg [DW-1:0] d_dout , outputreg d_vld ,// pulse outputoutputwire active );reg[1 :0] s_syncer ;reg[1 :0] d_syncer ;wire ack_d2 = s_syncer[1];wire req_d2 = d_syncer[1]; reg req_d3;reg[DW-1:0] async_dat;reg async_req;wire async_ack = req_d2;assign active = async_req | ack_d2 ;// Source clock domainalways@(posedges_clkornegedges_rstn)beginif(!s_rstn)begin s_syncer <=?2'd0; ? ?endelsebegin? ? ? ? ?s_syncer ? <= ?{s_syncer[0],async_ack}; ? ?endendalways?@(posedge?s_clk?ornegedge?s_rstn)?beginif?(!s_rstn)?begin? ? ? ? ?async_dat ? <= {DW{1'd0}}; ? ?endelseif(s_vld && (!active))begin? ? ? ? ?async_dat ? <= ?s_din; ? ?endendalways?@(posedge?s_clk?ornegedge?s_rstn)?beginif?(!s_rstn)?begin? ? ? ? ?async_req ? <=?1'd0; ? ?endelseif(ack_d2)begin? ? ? ? ?async_req ? <=?1'd0; ? ?endelseif(s_vld)begin? ? ? ? ?async_req ? <=?1'd1; ? ?endend// Destination clock domainalways?@(posedge?d_clk?ornegedge?d_rstn)?beginif?(!d_rstn)?begin? ? ? ? ?d_syncer ? <=?2'd0; ? ?endelsebegin? ? ? ? ?d_syncer ? <= ?{d_syncer[0],async_req}; ? ?endendalways?@(posedge?d_clk?ornegedge?d_rstn)?beginif?(!d_rstn)?begin? ? ? ? ?d_dout ? ? ?<= {DW{1'd0}}; ? ?endelseif(req_d2)begin? ? ? ? ?d_dout ? ? ?<= async_dat; ? ?endendalways?@(posedge?d_clk?ornegedge?d_rstn)?beginif?(!d_rstn)?begin? ? ? ? ?req_d3 ? ? ?<=?1'd0; ? ? ? ? d_vld ? ? ? <=?1'd0; ? ?endelsebegin? ? ? ? ?req_d3 ? ? ?<= req_d2; ? ? ? ? d_vld ? ? ? <= req_d2 & (~req_d3); ? ?endendendmodule
testbench:
`timescale1ns/1psmoduledatabridge_async_tb ();parameterDW =8;regs_clk =0;regs_rstn =0;reg[DW-1:0] s_din =0;regs_vld =0;regd_clk =0;regd_rstn =0;wire[DW-1:0] d_dout;wired_vld;wireactive;reg[DW-1:0]buffer ;realts;realtd;reala;realb;realclkstp;always#(ts) s_clk <= ~s_clk;always#(td)? d_clk <= ~d_clk; databridge_async?#(DW)?databridge_async ( ? ?.s_clk? ?( s_clk ?), ? ?.s_rstn? ( s_rstn ), ? ?.s_din? ?( s_din ?), ? ?.s_vld? ?( s_vld ?), ? ?.d_clk? ?( d_clk ?), ? ?.d_rstn? ( d_rstn ), ? ?.d_dout? ( d_dout ), ? ?.d_vld? ?( d_vld ?), ? ?.active? ( active ) );taskautomatic?gen_trans;input?[DW-1:0]data;begin? ? ?#0? ? ?s_vld ?= ?1; ? ? s_din ?= data; ? ? @(posedge?s_clk); ? ? #0? ? ?s_vld ?= ?0; ? ? s_din ?= ?0;endendtask//automatictaskautomatic?wait_busy;begin? ? ?@(posedge?s_clk);#0; ? ?while?(active)?begin? ? ? ? ?@(posedge?s_clk);#0; ? ?endendendtask//automatictaskautomatic?loop_test;inputinteger?n;integer?i;reg?[63:0]random_dat;beginfor?(i =?0;i
方法4 轉(zhuǎn)為獨(dú)熱碼或格雷碼
如果多bit信號(hào)是簡(jiǎn)單連續(xù)變化(連續(xù)加一或減一),可以將其轉(zhuǎn)為格雷碼,再打2拍到目標(biāo)時(shí)鐘域,最終再解碼為二進(jìn)制編碼。
如果多bit信號(hào)沒(méi)有變化規(guī)律,可以將其轉(zhuǎn)為獨(dú)熱碼,再打2拍到目標(biāo)時(shí)鐘域,最終再解碼為二進(jìn)制編碼。該方法適用于慢到快、多bit信號(hào)傳遞。
為什么data不能直接通過(guò)同步器過(guò)域:
多比特?cái)?shù)據(jù)由于存在傳輸路徑延遲,到達(dá)同步器有先后順序,導(dǎo)致同步器采樣到不同電平,輸出錯(cuò)誤數(shù)據(jù)。
根本原因是源端數(shù)據(jù)有多個(gè)bit發(fā)生跳變。如果每次只有一個(gè)bit跳變(連續(xù)變化格雷碼、獨(dú)熱碼),就一定能采樣到正確的數(shù)據(jù)。
假如目的時(shí)鐘非常慢,比原時(shí)鐘慢很多,在慢時(shí)鐘上升沿時(shí)還是能采到正確數(shù)據(jù),可能采到跳變之前的也可能是之后的,但總之都是source的數(shù)據(jù)。如果采到跳變之前的數(shù)據(jù),就會(huì)產(chǎn)生異步FIFO的虛空虛滿。從這個(gè)角度看,異步FIFO是絕對(duì)安全的(忽略同步器失效),異步FIFO兩邊的時(shí)鐘頻率沒(méi)有任何要求。方法5 深度為2的ASYNC-FIFO
在傳輸信號(hào),不需要較高帶寬時(shí),可以將普通格雷碼異步FIFO特化為2-deep ASYNC-FIFO,該方法適用于慢到快、快到慢、多bit信號(hào)傳遞。一般很少使用2deep-FIFO,而是使用雙向握手來(lái)傳遞單個(gè)多比特?cái)?shù)據(jù)。
方法6 ASYNC-FIFO
該方法適用于慢到快、快到慢、多bit數(shù)據(jù)傳遞。
moduleasync_fifo//(First_Word_Fall_Through FIFO,數(shù)據(jù)提前輸出,可能不利于時(shí)序收斂)#( parameterintegerDATA_WIDTH =16, parameterintegerADDR_WIDTH =8//深度只能是2**ADDR_WIDTH) ( inputwire wr_rst , inputwire wr_clk , inputwire wr_ena , inputwire[DATA_WIDTH-1:0] wr_dat , outputwire wr_full , inputwire rd_rst , inputwire rd_clk , inputwire rd_ena , outputwire[DATA_WIDTH-1:0] rd_dat , outputwire rd_empty );reg [DATA_WIDTH-1:0]mem[0:2**ADDR_WIDTH-1];reg [ADDR_WIDTH :0]wrptr;reg [ADDR_WIDTH :0]rdptr;wire[ADDR_WIDTH-1:0]wraddr = wrptr[ADDR_WIDTH-1:0];wire[ADDR_WIDTH-1:0]rdaddr = rdptr[ADDR_WIDTH-1:0];wire[ADDR_WIDTH :0]wrptr_gray = (wrptr>>1)^wrptr;wire[ADDR_WIDTH :0]rdptr_gray = (rdptr>>1)^rdptr;reg [ADDR_WIDTH :0]wrptr_gray_r0;reg [ADDR_WIDTH :0]wrptr_gray_r1;reg [ADDR_WIDTH :0]rdptr_gray_r0;reg [ADDR_WIDTH :0]rdptr_gray_r1;assignwr_full = (wrptr_gray == {~rdptr_gray_r1[ADDR_WIDTH:ADDR_WIDTH-1],rdptr_gray_r1[ADDR_WIDTH-2:0]});assignrd_empty = (rdptr_gray == wrptr_gray_r1);//在有些設(shè)計(jì)中,full和empty提早一個(gè)時(shí)鐘出現(xiàn),并加了一級(jí)寄存,這有助于收斂always@(posedgewr_clkorposedgewr_rst)beginif(wr_rst)begin rdptr_gray_r0 <=?'d0; ? ? ? ? rdptr_gray_r1 <=?'d0; ? ?endelsebegin? ? ? ? ?rdptr_gray_r0 <= rdptr_gray; ? ? ? ? rdptr_gray_r1 <= rdptr_gray_r0; ? ?endendalways?@(posedge?rd_clk?orposedge?rd_rst)?beginif?(rd_rst)?begin? ? ? ? ?wrptr_gray_r0 <=?'d0; ? ? ? ? wrptr_gray_r1 <=?'d0; ? ?endelsebegin? ? ? ? ?wrptr_gray_r0 <= wrptr_gray; ? ? ? ? wrptr_gray_r1 <= wrptr_gray_r0; ? ?endendalways?@(posedge?wr_clk?orposedge?wr_rst)?beginif?(wr_rst)?begin? ? ? ? ?mem[0] ? ? ?<=?'d0; ? ? ? ? wrptr ? ? ? <=?'d0; ? ?endelseif?(wr_ena&&(!wr_full))?begin? ? ? ? ?mem[wraddr] <= wr_dat; ? ? ? ? wrptr ? ? ? <= wrptr +?1'd1; ? ?endelsebegin? ? ? ? ?mem[wraddr] <= mem[wraddr]; ? ? ? ? wrptr ? ? ? <= wrptr; ? ?endendalways?@(posedge?rd_clk?orposedge?rd_rst)?beginif?(rd_rst)?begin? ? ? ? ?rdptr ? ? ? <=?'d0; ? ?endelseif?(rd_ena&&(!rd_empty))?begin? ? ? ? ?rdptr ? ? ? <= rdptr +?1'd1; ? ?endelsebegin? ? ? ? ?rdptr ? ? ? <= rdptr; ? ?endendassign?rd_dat = mem[rdaddr];endmodule
-
寄存器
+關(guān)注
關(guān)注
31文章
5425瀏覽量
123559 -
Xilinx
+關(guān)注
關(guān)注
73文章
2183瀏覽量
124488 -
觸發(fā)器
+關(guān)注
關(guān)注
14文章
2033瀏覽量
61930 -
時(shí)鐘域
+關(guān)注
關(guān)注
0文章
53瀏覽量
9738
原文標(biāo)題:跨異步時(shí)鐘域的6種方法
文章出處:【微信號(hào):gh_9d70b445f494,微信公眾號(hào):FPGA設(shè)計(jì)論壇】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
評(píng)論