相比於同步FIFO,異步主要區別在與讀寫時鍾的不同,其中異步FIFO的full信號將在寫時鍾域內確定,empty信號將在讀時鍾域內確定。針對跨時鍾域信號傳輸需要對信號進行編碼格式轉換及進行兩級同步處理,編碼格式轉換即將二進制數轉換成格雷碼表示,這是因為相鄰兩個格雷碼只有一位數據發生變化:
十進制 | 二進制 | 格雷碼 |
0 | 000 | 000 |
1 | 001 | 001 |
2 | 010 | 011 |
3 | 011 | 010 |
4 | 100 | 110 |
5 | 101 | 111 |
6 | 110 | 101 |
即二進制碼轉換成格雷碼:從最低位開始,相鄰兩位異或結果為格雷碼最低位
其對應的程序代碼
always @(*)
for(i=0;i<WIDTH_D;i=i+1)//此時WIDTH_D=3
gray_c_d[i]<=bin_c[i]^bin_c[i+1];
assign gray_c={h_b,gray_c_d};
反之格雷碼轉換成二進制碼:格雷碼中所有位異或結果為二進制碼最低位,格雷碼中除最低位之外的所有異或為二進制次低位,以此類推
其對應程序代碼:
bin[0] = gray[3]^gray[2]^gray[1]^gray[0];
bin[1] = gray[3]^gray[2]^gray[1];
bin[2] = gray[3]^gray[2];
bin[3] = gray[3];
將二進制碼轉換成格雷碼的目的:二進制碼不適合做FIFO的空滿判斷,二進制碼在增減時,多bit位發生變化,如011-100,三個bit位全部發生變化。又因為讀寫時鍾的不同步,異步的寫時鍾很可能在狀態不穩定的中間某個狀態進行采樣,這就會得到錯誤的數據,進而產生錯誤的判斷。其次也是為了減少亞穩態對電路的影響。
異步FIFO中,不同時鍾域之間的信號傳遞需要進行兩級同步處理,盡可能的防止亞穩態的傳播。
為什么會產生亞穩態?---因為讀寫時鍾的不同,在讀,寫時鍾采樣有效沿到來時,數據仍處於不穩定狀態,不滿足建立保持時間要求,就會產生亞穩態。且只要電路中有異步,亞穩態是無法避免的,只能減少它對電路產生的影響。
常見消除亞穩態的方法:進行兩級同步,即打兩拍。
always @(posedge w_r_clk or negedge rst_n)
begin
if(!rst_n)
begin
syn_1<='h0;
syn_2<='h0;
end
else
begin
syn_1<=w_r_gaddr; //進行兩級同步操作
syn_2<=_syn_1;
end
end
assign w_r_gaddr_syn=syn_2;
補充:為什么多bit數據,例如地址位用格雷碼表示可以進行兩級同步操作?
因為當多bit數據為二進制表示時,在同一時鍾有效沿可能會有多位發生翻轉,則在另一時鍾域采到的時候由於寄存器需要1到2個周期,所以可能會出現錯誤的值。但是如果使用格雷碼進行兩級同步,在同一時鍾有效沿只有一bit位發生翻轉,其他位皆保持穩定,這樣通過兩級同步后,輸出的數據其他位皆保持,翻轉的bit位要么保持,要么更新為翻轉后的值,不會出現其他不該出現的值。
慢時鍾域的格雷碼同步到快時鍾域時,如果慢時鍾域的一個周期內,快時鍾出現2個及以上時鍾周期,為什么不會產生多bit同步問題?
因為格雷碼的翻轉是出現在慢時鍾域,且每次只發生一bit位翻轉,其余皆保持穩定。那么當快時鍾域進行同步采樣時,最多可以采到1bit位發生翻轉,這個翻轉可能會給快時鍾域的第一級輸出帶來亞穩態問題,但是最終的同步輸出要么保持要么更新1bit的數據,不會出現不該出現的問題。即雖然慢時鍾域同步過來的多bit位跟之前的多bit位相比發生變化,但是這些不同bit位的翻轉不是同時進行的。