格雷碼的一些知識:異步
https://baike.baidu.com/item/%E6%A0%BC%E9%9B%B7%E7%A0%81/6510858?fr=aladdin性能
根據格雷碼判斷fifo寫空或寫滿條件,具體以下:編碼
當最高位和次高位相同,其他位相同認爲是讀空設計
當最高位和次高位不一樣,其他位相同認爲是寫滿指針
因爲是異步FIFO的設計,讀寫時鐘不同,在產生讀空信號和寫滿信號時,會涉及到跨時鐘域的問題,如何解決?blog
跨時鐘域的問題:上面咱們已經提到要經過比較讀寫指針來判斷產生讀空和寫滿信號,可是讀指針是屬於讀時鐘域的,寫指針是屬於寫時鐘域的,而異步FIFO的讀寫時鐘域不一樣,是異步的,要是將讀時鐘域的讀指針與寫時鐘域的寫指針不作任何處理直接比較確定是錯誤的,所以咱們須要進行同步處理之後在進行比較。get
解決方法:兩級寄存器同步 + 格雷碼同步
同步的過程有兩個:it
(1)將寫時鐘域的寫指針同步到讀時鐘域,將同步後的寫指針與讀時鐘域的讀指針進行比較產生讀空信號二進制
(2)將讀時鐘域的讀指針同步到寫時鐘域,將同步後的讀指針與寫時鐘域的寫指針進行比較產生寫滿信號
同步的思想就是用兩級寄存器同步,簡單說就是打兩拍。
咱們若是直接用二進制編碼的讀寫指針去完成上述的兩種同步是不行的,使用格雷碼更合適,爲何呢?
由於二進制編碼的指針在跳變的時候有多是多位數據一塊兒變化,如二進制的7-->8 即 0111 --> 1000 ,在跳變的過程當中 4 位所有發生了改變,這樣很容易產生毛刺,例如
異步FIFO的寫指針和讀指針分屬不一樣時鐘域,這樣指針在進行同步過程當中很容易出錯,好比寫指針在從0111到1000跳變時4位同時改變,這樣讀時鐘在進行寫指針同步後獲得的寫指針多是0000-1111的某個值,一共有2^4個可能的狀況,而這些都是不可控制的,你並不能肯定會出現哪一個值,那出錯的機率很是大,怎麼辦呢?到了格雷碼發揮做用的時候了,而格雷碼的編碼特色是相鄰位每次只有 1 位發生變化, 這樣在進行指針同步的時候,只有兩種可能出現的狀況:1.指針同步正確,正是咱們所要的;2.指針同步出錯,舉例假設格雷碼寫指針從000->001,將寫指針同步到讀時鐘域同步出錯,出錯的結果只多是000->000,由於相鄰位的格雷碼每次只有一位變化,這個出錯結果實際上也就是寫指針沒有跳變保持不變,咱們所關心的就是這個錯誤會不會致使讀空判斷出錯?答案是不會,最可能是讓空標誌在FIFO不是真正空的時候產生,而不會出現空讀的情形。因此格雷碼保證的是同步後的讀寫指針即便在出錯的情形下依然可以保證FIFO功能的正確性。在同步過程當中的亞穩態不可能消除,可是咱們只要保證它不會影響咱們的正常工做便可。
因爲設計的時候讀寫指針用了至少兩級寄存器同步,同步會消耗至少兩個時鐘週期,勢必會使得判斷空或滿有所延遲,這會不會致使設計出錯呢?
異步FIFO經過比較讀寫指針進行滿空判斷,可是讀寫指針屬於不一樣的時鐘域,因此在比較以前須要先將讀寫指針進行同步處理,
將寫指針同步到讀時鐘域再和讀指針比較進行FIFO空狀態判斷,由於在同步寫指針時須要時間,而在這個同步的時間內有可能還會寫入新的數據,所以同步後的寫指針必定是小於或者等於當前實際的寫指針,因此此時判斷FIFO爲空不必定是真空,這樣更加保守,一共不會出現空讀的狀況,雖然會影響FIFO的性能,可是並不會出錯,同理將讀指針同步到寫時鐘域再和寫指針比較進行FIFO滿狀態判斷,同步後的讀指針必定是小於或者等於當前的讀指針,因此此時判斷FIFO爲滿不必定是真滿,這樣更保守,這樣能夠保證FIFO的特性:FIFO空以後不能繼續讀取,FIFO滿以後不能繼續寫入。總結來講異步邏輯轉到同步邏輯不可避免須要額外的時鐘開銷,這會致使滿空趨於保守,可是保守並不等於錯誤,這麼寫會稍微有性能損失,可是不會出錯。
舉個例子:大多數情形下,異步FIFO兩端的時鐘不是同頻的,或者讀快寫慢,或者讀慢寫快,慢的時鐘域同步到快的時鐘域不會出現漏掉指針的狀況,可是將指針從快的時鐘域同步到慢的時鐘域時可能會有指針遺漏,舉個例子以讀慢寫快爲例,進行滿標誌判斷的時候須要將讀指針同步到寫時鐘域,由於讀慢寫快,因此不會有讀指針遺漏,同步消耗時鐘週期,因此同步後的讀指針滯後(小於等於)當前讀地址,因此可能滿標誌會提早產生,滿並不是真滿。進行空標誌判斷的時候須要將寫指針同步到讀指針 ,由於讀慢寫快,因此當讀時鐘同步寫指針 的時候,必然會漏掉一部分寫指針,咱們不用關心那到底會漏掉哪些寫指針,咱們在意的是漏掉的指針會對FIFO的空標誌產生影響嗎?好比寫指針從0寫到10,期間讀時鐘域只同步捕捉到了三、五、8這三個寫指針而漏掉了其餘指針。當同步到8這個寫指針時,真實的寫指針可能已經寫到10 ,至關於在讀時鐘域還沒來得及覺察的狀況下,寫時鐘域可能偷偷寫了數據到FIFO去,這樣在判斷它是否是空的時候會出現不是真正空的狀況,漏掉的指針也沒有對FIFO的邏輯操做產生影響。
二進制碼轉換成二進制格雷碼,其法則是保留二進制碼的最高位做爲格雷碼的最高位,而次高位格雷碼爲二進制碼的高位與次高位相異或,而格雷碼其他各位與次高位的求法相相似。
我再換種更簡單的描述
二進制數 1 0 1 1 0
二進制數右移1位,空位補0 0 1 0 1 1
異或運算 1 1 1 0 1
這樣就能夠實現二進制到格雷碼的轉換了,總結就是移位而且異或,verilog代碼實現就一句:assign wgraynext = (wbinnext>>1) ^ wbinnext;