【轉】Verilog學習筆記簡單功能實現(八)...............異步FIFO
基本原理:
1.讀寫指針的工作原理
寫指針:總是指向下一個將要被寫入的單元,復位時,指向第1個單元(編號為0)。
讀指針:總是指向當前要被讀出的數據,復位時,指向第1個單元(編號為0).
2.FIFO的“空”/“滿”檢測
FIFO設計的關鍵:產生可靠的FIFO讀寫指針和生成FIFO“空”/“滿”狀態標誌。
當讀寫指針相等時,表明FIFO為空,這種情況發生在復位操作時,或者當讀指針讀出FIFO中最後一個字後,追趕上了寫指針時,如下圖所示:
當讀寫指針再次相等時,表明FIFO為滿,這種情況發生在,當寫指針轉了一圈,折回來(wrapped around)又追上了讀指針,如下圖:
為了區分到底是滿狀態還是空狀態,可以采用以下方法:
方法1:在指針中添加一個額外的位(extra bit),當寫指針增加並越過最後一個FIFO地址時,就將寫指針這個未用的MSB加1,其它位回零。對讀指針也進行同樣的操作。此時,對於深度為2n的FIFO,需要的讀/寫指針位寬為(n+1)位,如對於深度為8的FIFO,需要采用4bit的計數器,0000~1000、1001~1111,MSB作為折回標誌位,而低3位作為地址指針。
- 如果兩個指針的MSB不同,說明寫指針比讀指針多折回了一次;如r_addr=0000,而w_addr = 1000,為滿。
- 如果兩個指針的MSB相同,則說明兩個指針折回的次數相等。其余位相等,說明FIFO為空;
3. 二進制FIFO指針的考慮
將一個二進制的計數值從一個時鐘域同步到另一個時鐘域的時候很容易出現問題,因為采用二進制計數器時所有位都可能同時變化,在同一個時鐘沿同步多個信號的變化會產生亞穩態問題。而使用格雷碼只有一位變化,因此在兩個時鐘域間同步多個位不會產生問題。所以需要一個二進制到gray碼的轉換電路,將地址值轉換為相應的gray碼,然後將該gray碼同步到另一個時鐘域進行對比,作為空滿狀態的檢測。
使用gray碼解決了一個問題,但同時也帶來另一個問題,即在格雷碼域如何判斷空與滿。
對於“空”的判斷依然依據二者完全相等(包括MSB);
而對於“滿”的判斷,如下圖,由於gray碼除了MSB外,具有鏡像對稱的特點,當讀指針指向7,寫指針指向8時,除了MSB,其余位皆相同,不能說它為滿。因此不能單純的只檢測最高位了,在gray碼上判斷為滿必須同時滿足以下3條:
- wptr和同步過來的rptr的MSB不相等,因為wptr必須比rptr多折回一次。
- wptr與rptr的次高位不相等,如上圖位置7和位置15,轉化為二進制對應的是0111和1111,MSB不同說明多折回一次,111相同代表同一位置。
- 剩下的其余位完全相等。
5.總體實現
以上內容參考http://www.cnblogs.com/BitArt/archive/2013/04/10/3010073.html,非原創。
源碼在原來的基礎上進行改編,如下:
1 module Asyn_FIFO(data_out, full, empty, data_in, wen, wclk, wrst,ren, rclk, rrst); 2 parameter datasize = 8; 3 parameter addrsize = 4; 4 5 input [datasize-1:0]data_in; 6 input wen,ren,wclk,rclk,wrst,rrst; 7 output [datasize-1:0]data_out; 8 output empty,full; 9 10 reg empty,full; 11 wire [datasize-1:0]data_out; 12 13 wire [addrsize-1:0]raddr,waddr; // 14 wire [addrsize:0]rbinnext,wbinnext,rptrnext,wptrnext; 15 wire empty_val,full_val; 16 reg [addrsize:0]rbin,wbin,rptr,wptr,rptr1,rptr2,wptr1,wptr2; 17 reg [addrsize-1:0]memory[0:(addrsize<<1)-1]; 18 19 //雙口RAM 20 assign data_out=memory[raddr]; 21 always @(posedge wclk) 22 begin if(wen&&!full) memory[waddr]<=data_in;end 23 24 //同步wptr指針 25 always @(posedge rclk or negedge rrst) 26 begin if(!rrst) {rptr2,rptr1}<=0; 27 else {rptr2,rptr1}<={rptr1,wptr}; 28 end 29 30 //同步rptr指針 31 always @(posedge wclk or negedge wrst) 32 begin if(!wrst) {wptr2,wptr1}<=0; 33 else {wptr2,wptr1}<={wptr1,rptr}; 34 end 35 36 //產生raddr信號和empty信號 37 always @(posedge rclk or negedge rrst) 38 begin if(!rrst) {rbin,rptr}<=0; 39 else {rbin,rptr}<={rbinnext,rptrnext}; 40 end 41 assign raddr=rbin[addrsize-1:0]; 42 assign rbinnext=rbin+(ren&&~empty); 43 assign rptrnext=(rbinnext>>1)^rbinnext; //生成raddr 44 assign empty_val=(rptrnext==rptr2); 45 always @(posedge rclk or negedge rrst) 46 begin if(!rrst) empty<=1; 47 else empty<=empty_val; 48 end 49 50 //產生waddr信號和full信號 51 always @(posedge wclk or negedge wrst) 52 begin if(!wrst) {wbin,wptr}<=0; 53 else {wbin,wptr}<={wbinnext,wptrnext}; 54 end 55 assign waddr=wbin[addrsize-1:0]; 56 assign wbinnext=wbin+(wen&&~full); 57 assign wptrnext=(wbinnext>>1)^wbinnext; //生成waddr 58 assign full_val=(wptrnext=={~wptr2[addrsize:addrsize-1],wptr2[addrsize-2:0]}); 59 always @(posedge wclk or negedge wrst) 60 begin if(!rrst) full<=0; 61 else full<=full_val; 62 end 63 endmodule
【轉】Verilog學習筆記簡單功能實現(八)...............異步FIFO