00回顧
前面的文章我們講了亞穩(wěn)態(tài)的產(chǎn)生,是由于觸發(fā)器在工作過(guò)程中存在數(shù)據(jù)的建立時(shí)間和保持時(shí)間。在上升沿觸發(fā)電路中,建立時(shí)間就是在時(shí)鐘上升沿到來(lái)之前,觸發(fā)器數(shù)據(jù)保持穩(wěn)定的最小時(shí)間;而保持時(shí)間就是在時(shí)鐘上升沿到來(lái)之后,觸發(fā)器數(shù)據(jù)端數(shù)據(jù)還應(yīng)該保持的最小時(shí)間。如果數(shù)據(jù)在時(shí)鐘上升沿前后的這個(gè)窗口內(nèi)發(fā)生改變,即違反了建立保持時(shí)間,會(huì)使觸發(fā)器工作在一個(gè)不穩(wěn)定的狀態(tài),影響下一級(jí)觸發(fā)器,發(fā)生連鎖反應(yīng)使整個(gè)系統(tǒng)工作失常。
異步FIFO是一種重要的異步時(shí)鐘域的數(shù)據(jù)同步手段,在實(shí)際應(yīng)用中非常常見(jiàn),面試時(shí)也作為常考題型出現(xiàn)在視野中。但是如何設(shè)計(jì)一個(gè)高可靠性、高速的異步FIFO也是一個(gè)難點(diǎn)。
UART項(xiàng)目?jī)?nèi)部雖然只使用了同步FIFO實(shí)現(xiàn)數(shù)據(jù)的緩存,但咱們趁熱打鐵,將異步FIFO的原理和設(shè)計(jì)中需要關(guān)注的地方一并講透,可以說(shuō)干貨滿滿,建議收藏~
01異步FIFO結(jié)構(gòu)
異步FIFO架構(gòu)
異步FIFO主要是由 雙端口存儲(chǔ)器 、 寫指針產(chǎn)生邏輯 、讀指針產(chǎn)生邏輯及空滿標(biāo)志產(chǎn)生邏輯4部分組成。讀寫操作是由兩個(gè)完全不同時(shí)鐘域的時(shí)鐘所控制。在寫時(shí)鐘域部分,由寫指針產(chǎn)生邏輯生成寫端口所需要的寫地址和寫控制信號(hào);在讀時(shí)鐘域部分,由讀指針產(chǎn)生邏輯生成讀端口所需要的讀地址和讀控制信號(hào);在空滿標(biāo)志產(chǎn)生部分,通常是把寫指針與讀指針相互比較產(chǎn)生空滿標(biāo)志。讀寫時(shí)鐘屬于不同的時(shí)鐘域,如何同步異步信號(hào),使觸發(fā)器不產(chǎn)生亞穩(wěn)態(tài)及如何正確地設(shè)計(jì)空、滿信號(hào)的控制電路,使FIFO不會(huì)溢出,造成數(shù)據(jù)丟失是異步FIFO設(shè)計(jì)的兩個(gè)難點(diǎn)。
指針實(shí)現(xiàn)方式
- 使用二進(jìn)制方式實(shí)現(xiàn)指針
以寫指針為例。在寫請(qǐng)求有效時(shí),寫指針在時(shí)鐘上升沿來(lái)時(shí)遞增。同樣在讀請(qǐng)求有效時(shí),讀指針在讀時(shí)鐘沿來(lái)時(shí)遞增。在產(chǎn)生空滿信號(hào)時(shí),需要比較讀寫指針,由于兩個(gè)指針?lè)謱儆诓煌臅r(shí)鐘域,彼此之間異步,在使用二進(jìn)制計(jì)數(shù)器實(shí)現(xiàn)指針時(shí), 可能會(huì)導(dǎo)致用于比較的指針采樣錯(cuò)誤 。
比如,二進(jìn)制的值會(huì)從1111變?yōu)?000,這時(shí)所有位都會(huì)發(fā)生改變。雖然同步以后可以有效避免亞穩(wěn)態(tài),但是仍然可能得到錯(cuò)誤的采樣值。
從1111到0000轉(zhuǎn)換可能的中間值:
1111 —> 0000
1111 —> 0001
1111 —> 0010
1111 —> 0011
1111 —> 0100
1111 —> 0101
1111 —> 0110
1111 —> 0111
1111 —> 1000
1111 —> 1001
1111 —> 1010
1111 —> 1011
1111 —> 1100
1111 —> 1101
1111 —> 1110
1111 —> 1111
如果同步時(shí)鐘沿在1111向0000轉(zhuǎn)換的中間某個(gè)位置到來(lái),就可能將四位2進(jìn)制的任何值采樣同步到新的時(shí)鐘域中。而FIFO空滿信號(hào)產(chǎn)生使用錯(cuò)誤的指針將產(chǎn)生誤標(biāo)志,從而使FIFO滿時(shí)沒(méi)有正確產(chǎn)生滿標(biāo)志,導(dǎo)致數(shù)據(jù)丟失;FIFO空時(shí)沒(méi)有正確產(chǎn)生空標(biāo)志,導(dǎo)致讀出垃圾數(shù)據(jù)。
所以采用二進(jìn)制方式實(shí)現(xiàn)指針不是最終的方案,建議盡量避免使用二進(jìn)制計(jì)數(shù)產(chǎn)生指針。
** 使用格雷碼方式實(shí)現(xiàn)指針
格雷碼(gray)相對(duì)于二進(jìn)制的優(yōu)勢(shì)在于:格雷碼 從一個(gè)數(shù)變?yōu)橄乱粋€(gè)數(shù)時(shí)只有一位發(fā)生變化 。
所以格雷碼在轉(zhuǎn)換時(shí)最多只會(huì)出現(xiàn)一位錯(cuò)誤。比如從1000變?yōu)?000時(shí),兩級(jí)同步器采樣要么為1000(舊值),要么為0000(新值),而不會(huì)出現(xiàn)其他的值。這樣就可以避免產(chǎn)生錯(cuò)誤的空滿標(biāo)志。
在格雷碼實(shí)現(xiàn)FIFO指針時(shí)需要注意, 對(duì)于寫邏輯部分,產(chǎn)生寫滿信號(hào)需要對(duì)讀指針(格雷碼)進(jìn)行同步;對(duì)于讀邏輯部分,產(chǎn)生讀空信號(hào)需要對(duì)寫指針(格雷碼)進(jìn)行同步 。
有人要問(wèn)了,使用兩級(jí)同步器對(duì)指針同步時(shí),不可避免的會(huì)產(chǎn)生兩個(gè)時(shí)鐘的延遲,這個(gè)延遲會(huì)不會(huì)對(duì)讀寫數(shù)據(jù)產(chǎn)生?別急,我會(huì)掰開來(lái)講清楚的。我們先講講二進(jìn)制和格雷碼的相互轉(zhuǎn)換。
- 兩種格雷碼計(jì)數(shù)器
上面我們已經(jīng)講了格雷碼這種編碼方式可以有效的避免絕大部分錯(cuò)誤。那怎么產(chǎn)生格雷碼編碼方式的讀寫指針呢?別看格雷碼計(jì)數(shù)器看起來(lái)復(fù)雜,實(shí)現(xiàn)起來(lái)其實(shí)很簡(jiǎn)單。這里有兩種方案產(chǎn)生讀寫指針。
方案A:
方案A
步驟1:將格雷碼轉(zhuǎn)換為二進(jìn)制值;
步驟2:根據(jù)條件遞增二進(jìn)制值;
步驟3:將二進(jìn)制值轉(zhuǎn)換為格雷碼;
步驟4:將計(jì)數(shù)器的最終格雷碼值保存到寄存器中。方案B:
方案B
步驟1:根據(jù)條件遞增二進(jìn)制值;
步驟2:將二進(jìn)制值保存到寄存器中,同時(shí)將二進(jìn)制值轉(zhuǎn)換為格雷碼;
步驟3:將計(jì)數(shù)器的最終格雷碼值保存到寄存器中。這兩種方案有什么區(qū)別?
可以發(fā)現(xiàn),方案A的讀寫指針產(chǎn)生必須經(jīng)過(guò)相對(duì)復(fù)雜的二進(jìn)制和格雷碼的相互轉(zhuǎn)換邏輯和遞增邏輯,這條組合邏輯極有可能 限制FIFO的最高工作頻率 ,成為關(guān)鍵路徑。
而方案B將二進(jìn)制值的結(jié)果保存在一組額外的寄存器中,雖然增加了電路的面積(這點(diǎn)面積基本沒(méi)有影響),但避免了復(fù)雜的組合邏輯,可以 提高系統(tǒng)工作頻率 。
格雷碼和二進(jìn)制相互轉(zhuǎn)換
- 格雷碼到二進(jìn)制的轉(zhuǎn)換
格雷碼轉(zhuǎn)換為二進(jìn)制的公式為:
對(duì)于n位計(jì)數(shù)器來(lái)說(shuō),i
例如當(dāng)n=4時(shí),對(duì)應(yīng)的格雷碼到二進(jìn)制的轉(zhuǎn)換為:
bin[0] = gray[0] ^ gray[1] ^ gray[2] ^ gray[3]
bin[1] = gray[1] ^ gray[2] ^ gray[3]
bin[2] = gray[2] ^ gray[3]
bin[3] = gray[3]
可以看出,bin[3]是通過(guò)將格雷值右移3位得到;bin[2]是通過(guò)將格雷值右移2位得到;bin[1]是將格雷值右移1位得到;bin[0]是將格雷值右移0位得到。(右移后需按位異或)
下面是格雷碼到二進(jìn)制轉(zhuǎn)換的Verilog代碼。
module gray_to_bin(bin,gray);
parameter SIZE=4;
input [SIZE-1:0] gray;
output [SIZE-1:0] bin;
reg [SIZE-1:0] bin;
integer i;
always @(*) begin
for(i=0;i<=SIZE;i=i+1)
bin = ^(gray >>i);
end
endmodule
- 二進(jìn)制到格雷碼的轉(zhuǎn)換
二進(jìn)制到格雷碼的轉(zhuǎn)換公式為:
同樣,對(duì)于n位計(jì)數(shù)器來(lái)說(shuō),i
例如當(dāng)n=4時(shí),對(duì)應(yīng)的二進(jìn)制到格雷碼的轉(zhuǎn)換為:
gray[0] = bin[0] ^ bin[1]
gray[1] = bin[1] ^ bin[2]
gray[2] = bin[2] ^ bin[3]
gray[3] = bin[3]
可以看出,可以通過(guò)逐位異或,或者將二進(jìn)制碼右移后與自身異或的操作,計(jì)算出對(duì)應(yīng)的格雷碼。
下面是二進(jìn)制到格雷碼轉(zhuǎn)換的Verilog代碼:
module bin_to_gray(bin,gray);
parameter SIZE=4;
input [SIZE-1:0] bin;
output [SIZE-1:0] gray;
assign gray = (bin >>1) ^ bin;
endmodule
格雷碼計(jì)數(shù)器實(shí)現(xiàn)
本格雷碼計(jì)數(shù)器采用方案B實(shí)現(xiàn),可有效提高FIFO的最大操作頻率。所以不會(huì)涉及到格雷碼到二進(jìn)制的轉(zhuǎn)換。
根據(jù)上文中格雷碼和二進(jìn)制碼的特點(diǎn),細(xì)心的同學(xué)可以發(fā)現(xiàn),格雷碼和二進(jìn)制碼的最高位是相同的,所以只需對(duì)低三位進(jìn)行格雷碼的轉(zhuǎn)換。以寫指針為例,具體實(shí)現(xiàn)方式如下:
parameter SIZE=4;
reg [SIZE:0] wbin,wbnext;
reg [SIZE:0] wptr,wgnext;
always @(posedge wclk ornegedge rst_n) begin
if(!rst_n) begin
wbin <= 'h0;
wptr[SIZE-1:0] <= 'h0;
end
elsebegin
wbin <= wbnext;
wptr[SIZE-1:0] <= wgnext[SIZE-1:0];
end
end
always @(*) wptr[SIZE] = wbin[SIZE];
assign wbnext = !wfull ? wbin+winc : wbin;
assign wgnext[SIZE-1:0] = (wbnext[SIZE-1:0] >>1) ^ wbnext[SIZE-1:0];
指針同步后的影響
在FIFO中,F(xiàn)IFO寫滿時(shí)不應(yīng)該再向FIFO中寫數(shù)據(jù),避免造成FIFO溢出,導(dǎo)致數(shù)據(jù)丟失。所以在寫時(shí)鐘域,需要將寫指針和同步后的讀指針進(jìn)行比較,產(chǎn)生寫滿標(biāo)志。下面我將舉例說(shuō)明將讀指針同步到寫時(shí)鐘域后對(duì)寫滿標(biāo)志和寫數(shù)據(jù)的影響。
在最初的t0時(shí)刻,讀寫指針都為0。隨著后續(xù)數(shù)據(jù)寫入FIFO,寫指針遞增。當(dāng)?shù)竭_(dá)t5時(shí)刻時(shí),F(xiàn)IFO寫滿,讀寫指針相等,寫滿信號(hào)wfull由0變?yōu)?。
如果在t6時(shí)刻發(fā)生了讀操作,由于兩級(jí)同步器包含兩個(gè)觸發(fā)器,將讀指針同步到寫時(shí)鐘域會(huì)導(dǎo)致讀指針在兩個(gè)寫時(shí)鐘后出現(xiàn),寫滿信號(hào)wfull在t6和t7時(shí)刻都為1,t7時(shí)刻后變?yōu)?。這雖然增加了阻止數(shù)據(jù)寫入的周期(2 wclk cycle),但是對(duì)數(shù)據(jù)的準(zhǔn)確性無(wú)任何影響。
空滿邏輯同步后效果
類似的,在FIFO空時(shí)也會(huì)阻止FIFO的讀操作。
FIFO的讀空信號(hào)產(chǎn)生是把寫指針同步到讀時(shí)鐘域和讀指針進(jìn)行比較。
在t10時(shí)刻,寫指針等于讀指針,此時(shí)FIFO為空。若t11時(shí)刻時(shí)開始向FIFO寫入數(shù)據(jù),t11,t12時(shí)刻雖然FIFO不為空,但是由于兩級(jí)同步器的延時(shí),此時(shí)讀空信號(hào)rempty仍然為1,這會(huì)阻止FIFO的讀操作,但這是無(wú)害的。在t12時(shí)刻后,rempty釋放,此時(shí)FIFO可以開始讀操作。
在將滿時(shí)通知寫的一邊FIFO已滿,在將空時(shí)通知讀的一邊FIFO已空都是可以的,即使同步后的指針存在延時(shí),阻止寫/讀的影響會(huì)使FIFO掛起一段時(shí)間,但不會(huì)導(dǎo)致任何錯(cuò)誤。
空滿信號(hào)產(chǎn)生
空滿標(biāo)志的產(chǎn)生是異步FIFO設(shè)計(jì)的核心。如何正確設(shè)計(jì)此部分的邏輯,會(huì)直接影響到FIFO的性能??諠M標(biāo)志的產(chǎn)生原則是: 寫滿不溢出,讀空不多讀 。
最直接的做法是采用讀寫指針相比較來(lái)產(chǎn)生空滿標(biāo)志。當(dāng)讀寫指針的差值等于一個(gè)預(yù)設(shè)值時(shí),空滿信號(hào)被置位。這種實(shí)現(xiàn)方式邏輯簡(jiǎn)單,但是它的減法器形成了一個(gè)比較大的組合邏輯。限制了FIFO的速度。
所以一般采用相等或是不相等的比較邏輯,避免使用減法器。采用直接比較的方法必須區(qū)分當(dāng)讀寫地址相等的時(shí)候是空還是滿,所以必須增加額外的1位控制信號(hào)來(lái)區(qū)分空滿標(biāo)志。
以16x16異步FIFO為例,寫指針wptr[4:0],讀指針rptr[4:0],其中低三位為真正的讀寫地址,最高位用來(lái)區(qū)分空滿。
若讀寫指針完全相等,表示讀地址追上了寫地址,此時(shí)FIFO為空;若最高位相反但其余位相同,表示寫地址領(lǐng)先讀地址一個(gè)周期,此時(shí)FIFO為滿。
讀寫指針比較產(chǎn)生空滿標(biāo)志rempty和wfull,將寫指針同步到讀時(shí)鐘域,產(chǎn)生讀空信號(hào)rempty控制異步FIFO的讀操作;將讀指針同步到寫時(shí)鐘域,產(chǎn)生寫滿信號(hào)wfull控制異步FIFO的寫操作。
空滿信號(hào)的Verilog實(shí)現(xiàn)如下:
wire wfull;
wire rempty;
reg [SIZE:0] wptr_reg1;
reg [SIZE:0] wptr_reg2;
reg [SIZE:0] rptr_reg1;
reg [SIZE:0] rptr_reg2;
// 寫指針在讀時(shí)鐘域的兩級(jí)同步
always @(posedge rclk ornegedge rst_n) begin
if(!rst_n) begin
wptr_reg1 <= 'h0;
wptr_reg2 <= 'h0;
end
elsebegin
wptr_reg1 <= wptr;
wptr_reg2 <= wptr_reg1;
end
end
// 讀指針在寫時(shí)鐘域的兩級(jí)同步
always @(posedge wclk ornegedge rst_n) begin
if(!rst_n) begin
rptr_reg1 <= 'h0;
rptr_reg2 <= 'h0;
end
elsebegin
rptr_reg1 <= rptr;
rptr_reg2 <= rptr_reg1;
end
end
//空滿標(biāo)志產(chǎn)生
assign wfull = ({!wptr[SIZE],wptr[SIZE-1:0]}==rptr_reg2)? 1'b1 : 1'b0;
assign rempty = (wptr_reg2==rptr)? 1'b1:1'b0;
好了,異步FIFO到這里講完了,大家可以試試自己寫一個(gè)異步FIFO,調(diào)整讀寫時(shí)鐘的頻率和比例,進(jìn)行前后仿真看看性能怎樣呢~
-
存儲(chǔ)器
+關(guān)注
關(guān)注
38文章
7649瀏覽量
167355 -
控制電路
+關(guān)注
關(guān)注
83文章
1734瀏覽量
137234 -
觸發(fā)器
+關(guān)注
關(guān)注
14文章
2039瀏覽量
62139 -
FIFO存儲(chǔ)
+關(guān)注
關(guān)注
0文章
103瀏覽量
6188 -
異步時(shí)鐘
+關(guān)注
關(guān)注
0文章
17瀏覽量
9510
發(fā)布評(píng)論請(qǐng)先 登錄
同步FIFO設(shè)計(jì)詳解及代碼分享

握手型接口的同步FIFO實(shí)現(xiàn)

關(guān)于同步fifo做緩存的問(wèn)題
異步FIFO的設(shè)計(jì)分析及詳細(xì)代碼

FPGA之FIFO練習(xí)3:設(shè)計(jì)思路
同步FIFO之Verilog實(shí)現(xiàn)
FIFO設(shè)計(jì)—同步FIFO

FIFO設(shè)計(jì)—異步FIFO

一個(gè)簡(jiǎn)單的RTL同步FIFO設(shè)計(jì)
基于寄存器的同步FIFO
基于Verilog的同步FIFO的設(shè)計(jì)方法
同步FIFO設(shè)計(jì)分析

同步FIFO和異步FIFO的區(qū)別 同步FIFO和異步FIFO各在什么情況下應(yīng)用
同步FIFO和異步FIFO區(qū)別介紹

評(píng)論