異步FIFO設(shè)計,搞清楚這7點就夠了!
掃描二維碼
隨時隨地手機看文章
1、什么是格雷碼(Gray Code)?
格雷碼是美國學(xué)者Frank Gray于1947年提出的一種二進制編碼方式,后面這種編碼方式就以他的名字命名。實際上,格雷碼是有多種編碼形式的。根據(jù)定義,在一組數(shù)的編碼中,若任意兩個相鄰的代碼只有一位二進制數(shù)不同,則稱這種編碼為格雷碼。
下表是不同形式的格雷碼:

表中典型格雷碼具有代表性。若不作特別說明,格雷碼就是指典型格雷碼(后文將簡稱格雷碼),它可從自然二進制碼轉(zhuǎn)換而來。
好了,現(xiàn)在我問你,根據(jù)格雷碼的性質(zhì)你能默寫出16個4bit寬度的格雷碼來嗎?我想一般是比較難的,因為單靠上述性質(zhì)很難推導(dǎo)出來。比如說,0(0000)可以寫出來,1(0001)也可以寫出來,2(0011)也可以寫出來,但是3就不好寫了,因為根據(jù)只能變化一位的性質(zhì),可以是0111,也可以是0010,那么到底是哪個呢?如何不是經(jīng)常使用的話,我想是很難判斷的。
所以接下來就要介紹格雷碼的第二個性質(zhì)了:當(dāng)?shù)贜位從0變到1的時候,之后的數(shù)的N-1位會關(guān)于前半段軸對稱,而比N位高的位是相同的。
我們看一下4bit格雷碼的前四位的例子。示意圖如下:
? 當(dāng)0001跳轉(zhuǎn)到下一位時,毋庸置疑的是,第0位會維持1不變,而第1位會跳轉(zhuǎn)到1,所以可以據(jù)此畫出對稱軸
? 高2位(第3、2位)這保持不變
? 低位(該實例中只有第0位)關(guān)于對稱軸對稱
有了上述三點信息,那么就可以把剩下的2個格雷碼寫出來了。

4bit格雷碼的前8位示意圖如下(這我就不啰嗦了,你們肯定看得懂):

2、異步FIFO為什么要使用格雷碼?
異步FIFO設(shè)計最關(guān)鍵的點是什么?答案是“空”和“滿”的判斷?,F(xiàn)在回想一下,我們是如何進行狀態(tài)判斷的。很簡單,分別構(gòu)建讀指針和寫指針。寫指針總是指向下一個要寫的地址,而讀指針永遠指向當(dāng)前要讀取的地址。再通過對讀、寫指針的比較來判斷空、滿。

如上圖的FIFO深度為8,則其地址位寬應(yīng)該是3(2的三次方等于8)。當(dāng)寫指針與讀指針都指向同一個位置(即相同)時,可能是空狀態(tài),但也可能是滿狀態(tài)(寫指針超過了讀指針一圈)。(這里說句題外話,不可能是讀指針超過寫指針一圈,因為但讀、寫指針第一次相等時,就應(yīng)該輸出空狀態(tài),然后停止對FIFO進行讀取操作。)所以,究竟如何判斷FIFO是空還是滿呢?答案是無法判斷,只能通過在高位增加一位的方式來判斷,當(dāng)除了最高位MSB外的其他位都相同,最高位不同時則表明此時寫指針超過了讀指針一圈,F(xiàn)IFO被寫滿了;當(dāng)除了最高位MSB外的其他位都相同,最高位相同時則表明此時寫指針等于讀指針,F(xiàn)IFO被讀空了。
這種方法用來對同步FIFO進行判斷是沒有問題的,因為同步FIFO的讀、寫指針是同一時鐘域下的信號,可以直接對比。但是異步FIFO的讀、寫指針是不同時鐘域下的信號,如果直接對比則會有亞穩(wěn)態(tài)的問題。為了對異步FIFO的讀、寫指針進行判斷,我們首先需要將其同步到統(tǒng)一的時鐘域下,而這就引發(fā)出了新的問題----讀、寫指針在大多數(shù)情況下都不是個單bit信號,而是個多bit信號。如果讀、寫指針直接使用2進制的形式進行同步,則難以避免同步過程中會出現(xiàn)的多個bit信號同時變化的問題。如7(0111)跳轉(zhuǎn)到8(1000),此時有4個bit信號都發(fā)生了變化,如果直接同步,則由于不同信號之間的延遲(skew),可能導(dǎo)致亞穩(wěn)態(tài)、錯采、漏采等等問題。
此時不妨回想下格雷碼的性質(zhì):每相鄰位之間只有一個bit的變化。FIFO的指針是遞增的,這使得在傳輸遞增的多bit信號時,格雷碼具有天然的優(yōu)勢。還是從7到8的例子,若使用格雷碼,則應(yīng)該是7(0100)--8(1100),這樣就只有1個bit的變化了(最高位),這樣就將多bit信號的跨時鐘域轉(zhuǎn)變成了單bit信號的跨時鐘域,而單個bit的跨時鐘域同步是很好實現(xiàn)的。
3、讀指針、寫指針應(yīng)該被同步到哪個時鐘域?
異步FIFO的讀、寫指針是不同時鐘域的信號,那么就不能直接對比,而是需要將其同步到同一時鐘域才能進行對比?,F(xiàn)在問題來了?指針應(yīng)該被同步到哪個時鐘域?可選項有第三方時鐘域、讀時鐘域和寫時鐘域。接下來不妨逐個分析。
首先需要說明的是,這說的同步都是指使用2個(或者3個,但此類情況不多)FF(觸發(fā)器)來進行同步(俗稱“打兩拍”),這種同步方式是有延遲的(時序開銷,可以看做是兩個目同步時鐘周期)。
第三方時鐘域:不難知道一個信號從一個時鐘域同步到另一個時鐘域(被同步時鐘域)是需要時間的(這里僅考慮從滿到快,也就是暫時不考慮漏采的問題),需要的時間取決于被同步時鐘域的周期以及需要同步的個數(shù)。假設(shè)這個時間是T,那么經(jīng)過T時間后,由于讀寫時鐘不一致,原來的讀寫時針增加(也可能不變)的量是不一致。比如說實際上讀寫時針都指向4(且最高位相同),那么這種情況實際上是出現(xiàn)了讀空的情況。但是同步到第三方時鐘域后,可能寫指針成了6,而讀指針變成了8(讀時鐘比寫時鐘快),那么在這種情況下FIFO就不會報“讀空”,從而造成功能錯亂。所以該種方法不可取。
同步到寫時鐘域:讀指針同步到寫時鐘域需要時間T,在經(jīng)過T時間后,可能原來的讀指針會增加或者不變,也就是說同步后的讀指針一定是小于等于原來的讀指針的。寫指針也可能發(fā)生變化,但是寫指針本來就在這個時鐘域,所以是不需要同步的,也就意味著進行對比的寫指針就是真實的寫指針。
現(xiàn)在來進行寫滿的判斷:也就是寫指針超過了同步后的讀指針一圈。但是原來的讀指針是大于等于同步后的讀指針的,所以實際上這個時候?qū)懼羔樒鋵嵤菦]有超過讀指針一圈的,也就是說這種情況是“假寫滿”。那么“假寫滿”是一種錯誤的設(shè)計嗎?答案是NO。前面我們說過異步FIFO設(shè)計的關(guān)鍵點是產(chǎn)生合適的“寫滿”和“讀空”信號,那么何謂“合適”?該報的時候沒報算合適嗎?當(dāng)然不算合適。不該報的時候報了算不算合適?答案是算??梢韵胂笠幌拢僭O(shè)一個深度為100的FIFO,在寫到第98個數(shù)據(jù)的時候就報了“寫滿”,會引起什么后果?答案是不會造成功能錯誤,只會造成性能損失(2%),大不了FIFO的深度我少用一點點就是的。事實上這還可以算是某種程度上的保守設(shè)計(安全)。
接著進行讀空的判斷:也就是同步后的讀指針追上了寫指針。但是原來的讀指針是大于等于同步后的讀指針的,所以實際上這個時候讀指針實際上是超過了寫指針。這種情況意味著已經(jīng)發(fā)生了“讀空”,卻仍然有錯誤數(shù)據(jù)讀出。所以這種情況就造成了FIFO的功能錯誤。
同步到讀時鐘域:寫指針同步到讀時鐘域需要時間T,在經(jīng)過T時間后,可能原來的讀指針會增加或者不變,也就是說同步后的寫指針一定是小于等于原來的寫指針的。讀指針也可能發(fā)生變化,但是讀指針本來就在這個時鐘域,所以是不需要同步的,也就意味著進行對比的讀指針就是真實的讀指針。
現(xiàn)在來進行寫滿的判斷:也就是同步后的寫指針超過了讀指針一圈。但是原來的寫指針是大于等于同步后的寫指針的,所以實際上這個時候?qū)懼羔樢呀?jīng)超過了讀指針不止一圈,這種情況意味著已經(jīng)發(fā)生了“寫滿”,卻仍然數(shù)據(jù)被覆蓋寫入。所以這種情況就造成了FIFO的功能錯誤。
接著進行讀空的判斷:也就是讀指針追上了同步后的指針。但是原來的寫指針是大于等于同步后的寫指針的,所以實際上這個時候讀指針其實還沒有追上寫指針,也就是說這種情況是“假讀空”。那么“假讀空”是一種錯誤的設(shè)計嗎?答案是NO。前面我們說過異步FIFO設(shè)計的關(guān)鍵點是產(chǎn)生合適的“寫滿”和“讀空”信號,那么何謂“合適”?該報的時候沒報算合適嗎?當(dāng)然不算合適。不該報的時候報了算不算合適?答案是算。可以想象一下,假設(shè)某個FIFO,在讀到還剩2個數(shù)據(jù)的時候就報了“讀空”,會引起什么后果?答案是不會造成功能錯誤,只會造成性能損失(2%),大不了我先不讀了,等數(shù)據(jù)多了再讀就是的。事實上這還可以算是某種程度上的保守設(shè)計(安全)。
現(xiàn)在可以總結(jié)一下:
? “寫滿”的判斷:需要將讀指針同步到寫時鐘域,再與寫指針判斷
? “讀空”的判斷:需要將寫指針同步到讀時鐘域,再與讀指針判斷
假讀空示意如下:

假寫滿示意如下:

4、如何判斷異步FIFO的空和滿?
在同步FIFO的設(shè)計中,我們把讀、寫指針的位寬拓寬了1bit,目的是區(qū)分原來的讀、寫指針相等時判斷空、滿的問題。同步FIFO的指針使用的是2進制碼的形式,而異步FIFO為了減少多bit信號跨時鐘域傳輸?shù)膩喎€(wěn)態(tài)問題,采用的是格雷碼形式的指針,那么格雷碼形式的指針應(yīng)該如何對比來判斷空和滿?
首先要說明的是,將格雷碼轉(zhuǎn)換成2進制再進行對比是一種很好的辦法,但是會消耗多的組合邏輯資源,所以我們暫時不討論。

先觀察上圖,假定我們要設(shè)計的FIFO深度為8,那么指針寬度是4,因為寬度為3時無法區(qū)分空、滿。
空的判斷很好判斷,只要讀寫指針?biāo)形蝗恳恢?,則說明此時是空狀態(tài)。
滿的判斷復(fù)雜一點,假設(shè)采用同步FIFO的判斷方法----最高位不同,其他位一致。我們用實際的數(shù)值來看看是什么情況:當(dāng)讀指針的值為0100,則說明此時讀指針指向最高的空間7,那么若是FIFO滿了,則寫指針應(yīng)該是1100,那么1100對應(yīng)的二進制是多少呢?是8。那么讀寫指針、一個指向7,另一個卻指向8,這是滿?顯然不是。
如果真的是滿的話,寫指針應(yīng)該是多少?應(yīng)該是15,也就是1000,此時寫指針是超過讀指針8,也就是一圈的。那么0100和1000有什么聯(lián)系?很顯然,高兩位相反,低位相同。這種規(guī)律的形成原因是我們之前提到的,格雷碼的變化都關(guān)于某個對稱軸對稱。
總結(jié):
? 當(dāng)最高位和次高位相同,其余位相同認為是讀空
? 當(dāng)最高位和次高位不同,其余位相同認為是寫滿
5、空和滿的判斷是準(zhǔn)確的嗎?
在第4點我們知道了----將讀指針同步到寫時鐘域來判斷滿;將寫指針同步到讀時鐘域來判斷空。既然是異步FIFO,那么讀寫時鐘域的信號是不一致的,其中一個的頻率快,另一個的頻率這慢。那么在兩次同步過程中,一定是一次慢時鐘采快時鐘和一次快時鐘采慢時鐘??鞎r鐘采慢時鐘是不會有問題的,因為這符合采樣定理。但是慢時鐘采快時鐘則會有問題,因為采樣過程不符合采樣定理。
那么會造成什么問題?答案是漏采。某些數(shù)值可能會被漏掉。例如原本是連續(xù)的0--1--2---3的信號,從快時鐘同步到慢時鐘后,就變成了離散的0--3,其中的1、2被漏掉了。那么這樣一種現(xiàn)象會導(dǎo)致空、滿的判斷是準(zhǔn)確的嗎?答案是不準(zhǔn)確,但沒關(guān)系。
設(shè)想讀慢寫快與讀快寫慢兩種情況:
讀慢寫快:
進行寫滿判斷的時候需要將讀指針同步到寫時鐘域,因為讀慢寫快,所以不會有讀指針遺漏,同步消耗時鐘周期,所以同步后的讀指針滯后(小于等于)當(dāng)前讀地址,所以可能寫滿會提前產(chǎn)生,并非真寫滿。
進行讀空判斷的時候需要將寫指針同步到讀指針 ,因為讀慢寫快,所以當(dāng)讀時鐘同步寫指針的時候,必然會漏掉一部分寫指針,我們不用關(guān)心那到底會漏掉哪些寫指針,我們在乎的是漏掉的指針會對FIFO的讀空產(chǎn)生影響嗎?比如寫指針從0寫到10,期間讀時鐘域只同步捕捉到了3、5、8這三個寫指針而漏掉了其他指針。當(dāng)同步到8這個寫指針時,真實的寫指針可能已經(jīng)寫到10 ,相當(dāng)于在讀時鐘域還沒來得及覺察的情況下,寫時鐘域可能寫了數(shù)據(jù)到FIFO去,這樣在判斷它是不是空的時候會出現(xiàn)不是真正空的情況,漏掉的指針也沒有對FIFO的邏輯操作產(chǎn)生影響。
讀快寫慢:
進行讀空判斷的時候需要將寫指針同步到讀指針 ,因為讀快寫慢,所以不會有寫指針遺漏,同步消耗時鐘周期,所以同步后的寫指針滯后(小于等于)當(dāng)前寫地址,所以可能讀空會提前產(chǎn)生,并非真讀空。
進行寫滿判斷的時候需要將讀指針同步到寫時鐘域,因為讀快寫慢,所以當(dāng)寫時鐘同步讀指針的時候,必然會漏掉一部分讀指針,我們不用關(guān)心那到底會漏掉哪些讀指針,我們在乎的是漏掉的指針會對FIFO的寫滿產(chǎn)生影響嗎?比如讀指針從0讀到10,期間寫時鐘域只同步捕捉到了3、5、8這三個讀指針而漏掉了其他指針。當(dāng)同步到8這個讀指針時,真實的讀指針可能已經(jīng)讀到10 ,相當(dāng)于在寫時鐘域還沒來得及覺察的情況下,讀時鐘域可能從FIFO讀了數(shù)據(jù)出來,這樣在判斷它是不是滿的時候會出現(xiàn)不是真正滿的情況,漏掉的指針也沒有對FIFO的邏輯操作產(chǎn)生影響。
現(xiàn)在我們會發(fā)現(xiàn),所謂的空滿信號實際上是不準(zhǔn)確的,在還沒有空、滿的時鐘就已經(jīng)輸出了空滿信號,這樣的空滿信號一般稱為假空、假滿。假空、假滿信號本質(zhì)上是一種保守設(shè)計,想象一下,一個深度為16的異步FIFO,在其寫入14個數(shù)據(jù)時,即輸出了寫滿(假滿)標(biāo)志,這會對我們的設(shè)計造成影響嗎?會,會削弱我們的效率,我們實際使用的FIFO深度成了14,但是會使得我們的設(shè)計產(chǎn)生錯誤嗎?顯然不會。同樣的,在FIFO深度仍有2時即輸出了讀空(假空)標(biāo)志,也不會使得我們的設(shè)計出錯,但是會降低效率,因為我們使用的FIFO深度又少了2。
6、既然有假滿、假空,那么有沒有真滿、真空?
還真有,但是沒意義。既然我們可以將讀指針同步到寫時鐘域來判斷假滿;將寫指針同步到讀時鐘域來判斷假空。那么對應(yīng)地,可以讀指針同步到寫時鐘域來判斷空;將寫指針同步到讀時鐘域來判斷滿。
在寫時鐘域判斷空:
讀指針被同步過來的信號(同步后讀指針)是滯后于真實讀指針的信號,當(dāng)同步后讀指針等于寫指針時,真實讀指針實際上早就等于寫指針了,也就是說此時的空一定是空,甚至已經(jīng)空了一段時間了。這樣的空標(biāo)志顯然是沒有使用意義的,因為會造成對FIFO的過讀操作,你來來回回讀個空FIFO有什么意義呢?也就是說真空能實現(xiàn),但是沒實際使用意義。
在讀時鐘域判斷滿:
寫指針被同步過來的信號(同步后寫指針)是滯后于真實寫指針的信號,但同步后寫指針超過讀指針一圈時,真實寫指針實際上早就超過讀指針一圈了,也就是說此時的滿一定是滿,甚至已經(jīng)滿了一段時間了。這樣的滿標(biāo)志顯然是沒有使用意義的,因為會造成對FIFO的過寫操作,你來來回回寫個滿FIFO有什么意義呢?也就是說真滿也能實現(xiàn),但是同樣沒實際使用意義。
7、非2次冪深度的FIFO如何設(shè)計?
在第1點關(guān)于格雷碼的性質(zhì)中,我們闡述了:
? 在一組數(shù)的編碼中,若任意兩個相鄰的代碼只有一位二進制數(shù)不同,則稱這種編碼為格雷碼
? 當(dāng)?shù)贜位從0變到1的時候,之后的數(shù)的N-1位會關(guān)于前半段軸對稱,而比N位高的位是相同的。
由這兩點,我們發(fā)現(xiàn)格雷碼都可以關(guān)于某條對稱軸對稱。所以只有當(dāng)FIFO深度為2的冪次方時,才能做到格雷碼繞一圈后,回到初始位置仍然只有1bit變化,如15(1000)----0(0000)。當(dāng)FIFO深度不為2的冪次方時,顯然從最尾端跳轉(zhuǎn)到開頭端,變化的就不止一個bit了。比如FIFO深度為7,顯然,從13(1011)----0(0000),變化了可不止1bit。這樣的話在這一次跳變就失去了格雷碼存在的意義了,所以得想點其他辦法解決。
前面說過,格雷碼相鄰每位只變化1bit,而且關(guān)于中軸對稱的。那么我們可以這樣編碼:針對深度為7的FIFO,從1(0001)開始,一直到(14個數(shù)表示7深度,高位區(qū)分狀態(tài))14(1001),1(0001)與14(1001)是關(guān)于中軸對稱的(高位為變化位),所以也只有1bit的跳變。同樣的如果深度為6的FIFO,就從2(0011)開始,到13(1011),同樣只跳變1bit。

空標(biāo)志只用判斷讀、寫指針是否全部相等即可。但是滿標(biāo)志就不能用“高兩位相反,其他位相同來判斷了”,需要找其他規(guī)律了。從這里可以看出,格雷碼作為一種無權(quán)碼,在比較和運算等方面不如有權(quán)碼二進制靈活。所以,咱要不還是轉(zhuǎn)回二進制再比較吧。
不管你設(shè)計FIFO用RAM還是直接調(diào)用IP也好,最終實現(xiàn)都是用的Block RAM資源,其生成的位寬肯定是2的冪次。所以啊,不用也是浪費啊。