本文所研究的FIFO,從硬體的觀點來看,就是一塊數據記憶體。它有兩個連線埠,一個用來寫數據,就是將數據存入FIFO;另一個用來讀數據,也就是將數據從FIFO當中取出。與FIFO操作相關的有兩個指針,寫指針指向要寫的記憶體部分,讀指針指向要讀的記憶體部分。FIFO控制器通過外部的讀寫信號控制這兩個指針移動,並由此產生FIFO空信號或滿信號。
對於異步FIFO而言,數據是由某一個時鐘域的控制信號寫入FIFO,而由另一個時鐘域的控制信號將數據讀出FIFO。也就是說,讀寫指針的變化動作是由不同的時鐘產生的。因此,對FIFO空或滿的判斷是跨時鐘域的。如何根據異步的指針信號對FIFO的滿狀態或空狀態進行正確的判斷是本文研究的重點。此外,設計過程中的一些細節問題也將在文中涉及到。
1 指針以及滿空信號的產生
為了更好地說明問題,先探討一下同步FIFO指針移動以及滿空信號的產生過程。對於同步FIFO,讀寫指針都指向一個記憶體的初始位置,每進行一次讀寫操作,相應的指針就遞增一次,指向下一個記憶體位置。當指針移動到了記憶體的最後一個位置時,它又重新跳回初始位置。在FIFO非滿或非空的情況下,這個過程將隨著讀寫控制信號的變化一直進行下去。如果FIFO處於空的狀態,下一個讀動作將會導致向下溢出(underflow),一個無效的數據被讀人;同樣,對於一個滿了的FIFO,進行寫動作將會導致向上溢出(overflow),一個有用的數據被新寫入的數據覆蓋。這兩種情況都屬於誤動作,因此需要設定滿和空兩個信號,對滿信號置位表示FIFO處於滿狀態,對滿信號復位表示FIFO非滿,還有空間可以寫入數據;對空信號置位表示FIFO處於空狀態,對空信號復位表示FIFO非空,還有有效的數據可以讀出。
當讀指針和寫指針相等也就是指向同一個記憶體位置的時候,FIFO可能處於滿或空兩種狀態。可以通過不同的方法判斷或區分FIFO究竟是處於滿狀態還是空狀態,也就是究竟是寫指針從後趕上了讀指針,還是讀指針從後趕上了寫指針。本文所套用的方法是設定一個額外的狀態位,指針由它的地址位以及狀態位組成。地址位隨著相應的操作遞增,指針由記憶體的最後位置返回到初始位置的時候狀態位取反。因此,當讀寫指針的地址位和狀態位全部吻合的時候,讀寫指針經歷了相同次數的循環移動,也就是說,FIFO處於空狀態(圖1(a));如果讀寫指針的地址位相同而狀態位相反,寫指針比讀指針多循環一次,標誌FIFO處於滿狀態(圖1(b))。 (2)二進制指針可以用於任意大小的FIFO;格雷碼指針只能用於大小為2的冪的FIFO。
2 二進制指針和格雷碼指針的同步
二進制指針是由一位狀態位和若干位二進制編碼的地址位組成的(例如由三位地址和一位狀態位構成的指針的變化:0000→0001→0010→0011→0100→0101→0110→0111→1000→1001→1010→1011→1100→1101→1110→1111)。如果在不同的時鐘域內直接同步二進制指針,有可能產生問題。例如,當讀指針從0111向1000變化的時侯,指針所有的位都要變化,如果寫時鐘恰好在讀指針的變化時刻採樣,寫者得到的讀指針值有可能是從0000到1111中的任何一個。所以二進制指針不宜被直接同步,但可以通過一對握手信號同步二進制指針。
例如,讀指針被讀者存人一個暫存器時,讀者就發出一個就緒信號。當寫者看到就緒信號時,讀取讀指針,發出一個收到數據的確認信號。當讀者看到確認信號時,就收回就緒信號,然後用當前的讀指針值刷新暫存器(圖2)。在收到確認信號前,存放讀指針的暫存器內容保持不變,確保了被讀取的指針的正確性。
為了能夠在不同的時鐘域內直接同步指針,可以對指針使用格雷碼的編碼方式,也就是指針每次移動只變化一位,這樣就避免了由於指針多位同時變化而無法直接同步的問題。圖3表示了一個三位地址的記憶體用於格雷碼編碼的FIFO。n位地址的記憶體需要n+1位的格雷碼。使用最高位(也就是第n-1位)作為狀態位,從第n—2到第0位作為地址的第n-2位到第0位;對狀態位(也就是第n-1位)和第n-2位進行位異或運算產生地址的第n-2位(也就是地址的最高位)。通過對圖3的觀察可以得知,四位格雷碼編碼的指針和三位二進制加狀態位編碼的指針具有同樣的功能:指針產生的地址循環遍歷8個記憶體地址,每一次遍歷後狀態位取反。值得注意的一點,是當指針從0100變化到1100的時候,相應的地址由100變為000,狀態位和一位地址同時發生了變化,所以不能同步由另一個時鐘域格雷碼指針產生的狀態位和地址位,此時應該直接由另一個時鐘域同步指針來完成,由同步後的指針產生相應的狀態位和地址位。
3 保守的滿空判斷
對於異步FIFO設計,無論是採用握手還是直接同步的方法來獲取對方時鐘域的指針,對滿空信號的判斷總是“保守”的。
(1)滿空信號的復位(滿信號復位表示FIFO非滿,空信號復位表示FIFO非空)和實際FIFO的情況相比有一定的延遲。例如,空信號是由讀者用讀指針與同步或握手後得到的寫指針進行比較產生的。由於同步或握手需要一定的時間,在這段時間,寫者可能向FIFO寫入新的數據,寫指針發生了變化,此時FIFO已經非空,但此刻空信號仍然沒有復位。對於寫者而言,滿信號的復位也會遇到相同的問題。不過,在通常情況下,FIFO只要確保不會向下溢出或向上溢出,復位的延遲就不會導致向下溢出或向上溢出,是可以接受的。
(2)滿空信號的置位(滿信號置位表示FIFO滿,空信號置位表示FIFO空)和FIFO的實際情況相比沒有延遲。例如,同樣考慮FIFO為空的情況,讀者使用讀指針和同步或握手後的寫指針進行比較,由於FIFO為空,寫動作不會發生,相應的寫指針也保持不變,因此讀者獲得的就是當時的寫指針值。這樣就能馬上對空信號置位。同樣地,在FIFO滿的情況下,由於讀指針不發生變化,寫者得到的是當前的讀指針值,能夠馬上判斷FIFO為滿。
從以上兩點的討論可以得出結論,FIFO滿空判斷是保守的,寫者可能在FIFO還有一定空間時停止寫數據,但不會在FIFO已經滿了的情況下繼續寫數據;讀者可能在FIFO還有一些有效的數據時停止讀數據,但是不會在FIFO已經空的情況下繼續讀數據。保守的滿空判斷能夠滿足FIFO的功能要求。
4 二進制指針和格雷碼指針的比較
二進制指針和格雷碼指針兩者各有優缺點:?
(1)由於通過握手同步,指針可以有多位同時變化,二進制指針每次移動可以跳躍過任意的長度,這樣給FIFO的某些功能的實現帶來了方便(例如,硬體直接控制FIFO從快取的數據流中丟棄一個出錯的包);而格雷碼指針一般只能做遞增或遞減的移動。
(3) 與直接同步相比,通過握手同步需要多時鐘周期,因此二進制指針的滿空判斷比格雷碼指針的滿空判斷更“保守”;對於設計一個容量很大且由記憶體構成的FIFO來說,由於保守判斷而損失的空間可以忽略;但對於一個容量較小的FIFO而言,這種“保守”可能是無法接受的。例如,一個由8個暫存器組成的FIFO,對於格雷碼編碼的指針,最壞情況下,FIFO被寫者判斷為滿時,裡面實際只存有五個數據(使用兩級同步器,可能需要三個周期同步,而在這三個周期內都有讀動作發生);而對與二進制編碼的指針,FIFO被判為滿時,FIFO里可能只有三個數據或更少(使用兩級同步器,最好的情況下,需要五個周期握手,而在這五個周期里都有讀動作發生)。
設計者在兩種方法的比較選擇上應該考慮到以上的幾點。
本文介紹的異步FIFO的設計方法的兩種不同盡路都能夠實現功能正確的異步FIFO。對這兩種方法設計的FIFO的優缺點所做的簡要分析,對FIFO的設計具有指導意義。