一、異步FIFO簡介及其原理
FIFO是英文First In First Out 的縮寫,是一種先進(jìn)先出的數(shù)據(jù)緩存器,它與普通存儲(chǔ)器的區(qū)別是沒有外部讀寫地址線,這樣使用起來非常簡單,但缺點(diǎn)就是只能順序?qū)懭霐?shù)據(jù)。異步FIFO 是指讀寫時(shí)鐘不一致,讀寫時(shí)鐘是互相獨(dú)立的。
1.1 用途
用途1:
跨時(shí)鐘域:異步FIFO讀寫分別采用相互異步的不同時(shí)鐘。在現(xiàn)代集成電路芯片中,隨著設(shè)計(jì)規(guī)模的不斷擴(kuò)大,一個(gè)系統(tǒng)中往往含有數(shù)個(gè)時(shí)鐘,多時(shí)鐘域帶來的一個(gè)問題就是,如何設(shè)計(jì)異步時(shí)鐘之間的接口電路。異步FIFO是這個(gè)問題的一種簡便、快捷的解決方案,使用異步FIFO可以在兩個(gè)不同時(shí)鐘系統(tǒng)之間快速而方便地傳輸實(shí)時(shí)數(shù)據(jù)。
用途2:
位寬變換:對于不同寬度的數(shù)據(jù)接口也可以用FIFO,例如單片機(jī)位8位數(shù)據(jù)輸出,而DSP可能是16位數(shù)據(jù)輸入,在單片機(jī)與DSP連接時(shí)就可以使用FIFO來達(dá)到數(shù)據(jù)匹配的目的。
1.2 結(jié)構(gòu)
由圖可見,異步FIFO的核心部件就是一個(gè) Simple Dual Port RAM ;左右兩邊的長條矩形是地址控制器,負(fù)責(zé)控制地址自增、將二進(jìn)制地址轉(zhuǎn)為格雷碼以及解格雷碼;下面的兩對D觸發(fā)器 sync_r2w 和 sync_w2r 是同步器,負(fù)責(zé)將寫地址同步至讀時(shí)鐘域、將讀地址同步至寫時(shí)鐘域。
FIFO的常見參數(shù)
FIFO的寬度:即FIFO一次讀寫操作的數(shù)據(jù)位;
FIFO的深度:指的是FIFO可以存儲(chǔ)多少個(gè)N位的數(shù)據(jù)(如果寬度為N)。
滿標(biāo)志:FIFO已滿或?qū)⒁獫M時(shí)由FIFO的狀態(tài)電路送出的一個(gè)信號,以阻止FIFO的寫操作繼續(xù)向FIFO中寫數(shù)據(jù)而造成溢出(overflow)。
空標(biāo)志:FIFO已空或?qū)⒁諘r(shí)由FIFO的狀態(tài)電路送出的一個(gè)信號,以阻止FIFO的讀操作繼續(xù)從FIFO中讀出數(shù)據(jù)而造成無效數(shù)據(jù)的讀出(underflow)。
讀時(shí)鐘:讀操作所遵循的時(shí)鐘,在每個(gè)時(shí)鐘沿來臨時(shí)讀數(shù)據(jù)。
寫時(shí)鐘:寫操作所遵循的時(shí)鐘,在每個(gè)時(shí)鐘沿來臨時(shí)寫數(shù)據(jù)。
二、 FIFO的“空”/“滿”檢測
FIFO設(shè)計(jì)的關(guān)鍵:產(chǎn)生可靠的FIFO讀寫指針和生成FIFO“空”/“滿”狀態(tài)標(biāo)志。
此處切記判斷讀空和寫滿時(shí)指針的比較方式時(shí)不同的,大華面試時(shí)就問到了這個(gè)問題,一下把我干糊涂了,直接面試涼了。
如上圖所示的同步模塊synchronize to write clk,其作用是把讀時(shí)鐘域的讀指針rd_ptr采集到寫時(shí)鐘(wr_clk)域,然后和寫指針wr_ptr進(jìn)行比較從而產(chǎn)生或撤消寫滿標(biāo)志位wr_full;
同步模塊synchronize to read clk的作用是把寫時(shí)鐘域的寫指針wr_ptr采集到讀時(shí)鐘域,然后和讀指針rd_ptr進(jìn)行比較從而產(chǎn)生或撤消讀空標(biāo)志位rd_empty。
2.1、讀寫指針工作原理
讀指針:總是指向下一個(gè)將要被寫入的單元,復(fù)位時(shí),指向第一個(gè)單元(編號為0)。
寫指針:總是指向當(dāng)前要被讀出的數(shù)據(jù),復(fù)位時(shí),指向第1個(gè)單元(編號為0)
FIFO空標(biāo)志位:
(1)系統(tǒng)復(fù)位,讀寫指針全部清零,讀寫指針相等時(shí);
(2)數(shù)據(jù)讀出速率大于寫入速率,讀指針趕上了寫指針,F(xiàn)IFO為空,如圖所示:
FIFO 寫滿標(biāo)志位的產(chǎn)生
(1)讀寫指針指向了同一地址,但寫指針超前整整一圈,F(xiàn)IFO被寫滿;
2.2、 空滿區(qū)分
為了區(qū)分到底是滿狀態(tài)還是空狀態(tài),可以采用以下方法:
在指針中添加一個(gè)額外的位,當(dāng)寫指針增加并越過最后一個(gè)FIFO地址時(shí),就將未用的最高位(MSB)加1,其他位回0.對讀指針也進(jìn)行同樣的操作。
此時(shí),對于深度為2^n的FIFO,需要的讀寫指針位寬為(n+1)位。如對于深度為8的FIFO,需要采用4bit的計(jì)數(shù)器,0000~1000、1001~1111,MSB作為折回標(biāo)志位,而低3位作為地址指針。
如果兩個(gè)指針的MSB不同,其他位相同,說明寫指針比讀指針多折回了一次;如r_addr=0000,而w_addr = 1000,為滿。如果兩個(gè)指針的MSB相同,其余位相等,則說明兩個(gè)指針折回的次數(shù)相等,說明FIFO為空;
2.3、 二進(jìn)制FIFO指針的考慮
將一個(gè)二進(jìn)制的計(jì)數(shù)值從一個(gè)時(shí)鐘域同步到另一個(gè)時(shí)鐘域的時(shí)候很容易出現(xiàn)問題,因?yàn)椴捎枚M(jìn)制計(jì)數(shù)器時(shí)所有位都可能同時(shí)變化,在同一個(gè)時(shí)鐘沿同步多個(gè)信號的變化會(huì)產(chǎn)生亞穩(wěn)態(tài)問題。而使用格雷碼只有一位變化,因此在兩個(gè)時(shí)鐘域間同步多個(gè)位不會(huì)產(chǎn)生問題。所以需要一個(gè)二進(jìn)制到gray碼的轉(zhuǎn)換電路,將地址值轉(zhuǎn)換為相應(yīng)的gray碼,然后將該gray碼同步到另一個(gè)時(shí)鐘域進(jìn)行對比,作為空滿狀態(tài)的檢測。
(1)二進(jìn)制如何轉(zhuǎn)化為格雷碼
二進(jìn)制數(shù)的最高位保持不變, 后續(xù)位依次與前一位進(jìn)行異或運(yùn)算
assign gray_code = (bin_code>>1) ^ bin_code;
(2) 使用gray碼進(jìn)行對比,如何判斷“空”與“滿”
使用gray碼解決了一個(gè)問題,但同時(shí)也帶來另一個(gè)問題,即在格雷碼域如何判斷空與滿。
對于“空”的判斷依然依據(jù)二者完全相等(包括MSB);
而對于“滿”的判斷,如下圖,由于gray碼除了MSB外,具有鏡像對稱的特點(diǎn),當(dāng)讀指針指向7,寫指針指向8時(shí),除了MSB,其余位皆相同,不能說它為滿。因此不能單純的只檢測最高位了,在gray碼上判斷為滿必須同時(shí)滿足以下3條:
(1)wptr和同步過來的rptr的MSB不相等,因?yàn)閣ptr必須比rptr多折回一次。
(2)wptr與rptr的次高位不相等,如上圖位置7和位置15,轉(zhuǎn)化為二進(jìn)制對應(yīng)的是0111和1111,MSB不同說明多折回一次,111相同代表同一位置。
(3)剩下的其余位完全相等。
這里直接給出結(jié)論:
判斷讀空時(shí) :將寫時(shí)鐘域的寫指針同步到讀時(shí)鐘,然后與讀時(shí)鐘域的讀指針進(jìn)行比較,每一位都完全相同才判斷為讀空;
判斷寫滿時(shí):需要 寫時(shí)鐘域的格雷碼wgray_next 和 被同步到寫時(shí)鐘域的讀指針wr2_rp 高兩位不相同,其余各位完全相同;
1 assign full = (wr_addr_gray == {~(rd_addr_gray_d2[addr_width-:2]),rd_addr_gray_d2[addr_width-2:0]}) ;//高兩位不同
2 assign empty = ( rd_addr_gray == wr_addr_gray_d2 );
三、重要補(bǔ)充
關(guān)于異步FIFO的關(guān)鍵技術(shù),有兩個(gè),一個(gè)是格雷碼減小亞穩(wěn)態(tài),另一個(gè)是指針信號跨異步時(shí)鐘域的傳遞。
我在自己寫異步FIFO的時(shí)候也很疑惑,地址指針在同步化的時(shí)候,肯定會(huì)產(chǎn)生至少兩個(gè)周期的延遲,如果是從快時(shí)鐘域到慢時(shí)鐘域,快時(shí)域的地址指針并不能都被慢時(shí)域的時(shí)鐘捕獲,同步后的指針比起實(shí)際的指針延遲會(huì)更大。如果以此來產(chǎn)生fifo_empty和fifo_full 信號會(huì)非常不準(zhǔn)器。
查找資料和仿真后發(fā)現(xiàn),數(shù)字電路的世界真的很神奇,還有很多的東西需要去學(xué)習(xí)。非常巧妙,FIFO中的一個(gè)潛在的條件是write_ptr總是大于或者等于read_ptr;分為兩種情況,寫快讀慢和寫慢讀快。
·
1.在寫時(shí)鐘大于讀時(shí)鐘時(shí),產(chǎn)生fifo_empty信號,需要將write_ptr同步到讀時(shí)鐘域,寫指針會(huì)有延時(shí),可能比實(shí)際的寫地址要小,如果不滿足fifo_empty的產(chǎn)生條件,沒問題。如果滿足fifo_empty的觸發(fā)條件,說明此時(shí)同步后的write_ptr = read_ptr,即實(shí)際的write_ptr >= read_ptr,最壞的情況就是write_ptr > read_ptr,像這種FIFO非空而產(chǎn)生空標(biāo)志信號的情況稱為“虛空”,但是也并不影響FIFO的功能。
2.在寫時(shí)鐘大于讀時(shí)鐘時(shí),產(chǎn)生fifo_full信號,需要將read_ptr同步到寫時(shí)鐘域,讀指針會(huì)有延時(shí),可能比實(shí)際的讀地址要小,如果不滿足fifo_full的產(chǎn)生條件,沒問題。如果滿足fifo_full的觸發(fā)條件,說明此時(shí)同步后的read_ptr == write_ptr - fifo_depth,即實(shí)際的read_ptr >= read_ptr - fifo_depth,最壞的情況就是read_ptr > read_ptr - fifo_depth,像這種FIFO非滿而產(chǎn)生滿標(biāo)志信號的情況稱為“虛滿”,但是也并不影響FIFO的功能。
寫慢讀快的情況也同上,并沒有大的差異,不再分析。
關(guān)于格雷碼減小亞穩(wěn)態(tài),如果讀寫時(shí)鐘差距過大,從快時(shí)鐘域同步到慢時(shí)鐘域的信號,時(shí)鐘捕獲的相鄰兩個(gè)數(shù)據(jù)變化并不是只有一個(gè)bit位的改變,可能導(dǎo)致格雷碼失去原來的意義。