怎么用Verilog語言描述同步FIFO和異步FIFO


感謝

知乎龔大佬

打雜大佬

網上幾個nice的博客(忘了是哪個了。。。。)

前言

雖然FIFO都有IP可以使用,但理解原理還是自己寫一個來得透徹。

什么是FIFO?

Fist in first out。先入先出的數據緩存器,沒有外部讀寫地址線,可同時讀寫。

規則:永遠不要寫一個已經寫滿了的fifo。

          永遠不要讀一個讀空了的fifo。

 

FIFO種類?

同步FIFO和異步FIFO。

同步FIFO只有一個時鍾,也就是說寫端和讀端的時鍾是一毛一樣的。

異步FIFO讀端和寫端兩個時鍾則是不一樣的。包括同頻異相,異頻異相。

 

FIFO用途?

  1. 數據緩沖器。比如你寫端burst一個數據,沒有fifo緩沖的話就炸了。Fifo會把寫端的突發數據吃到肚子里,讀端可以慢慢的一個個讀出來。
  2. 跨時鍾域。異步fifo主要使用在不同時鍾域的邊緣,用來同步數據到另一個時鍾域。

ALTERA FIFO IP 的缺點是什么?

雖然altera貼心的提供了FIFO的IP塊,但是對於可移植性與自定義位寬深度更好的話,還是自己寫的更佳。

 

FIFO深度如何計算?(避免溢出)

對於異步fifo,如果讀時鍾大於寫時鍾且每個周期讀寫,那么一定是會讀空的,反之一定會被寫滿。一般來說,不會設計這么無聊的東西。

假設寫端有突發的數據,而讀端是均勻的讀出,怎么保證fifo不溢出呢?

異步FIFO快轉慢的問題:可能采樣踩不到某些值。

 

同步FIFO:

當緩沖器使用,可以用ram資源搭。

原理圖:

信號定義:

clk:時鍾信號

rst_n:異步復位信號

wr:寫請求

rd:讀請求

data:數據輸入

q:   數據輸出

full:滿信號,表示fifo吃飽了

empty:空信號,表示fifo肚子已經空掉了

usedw:表示fifo中已有的數據個數

 

仿真:

沒有usedw款:

有usedw款:

資源使用量:

 

如何設計一個異步FIFO?

一般用作跨時鍾域,可用ram搭。

判斷讀空與寫滿,讀寫指針要跨時鍾域,所以采用格雷碼減少亞穩態。

 

什么是格雷碼?如何與二進制碼轉換?

格雷碼的基本特點是兩個相鄰的碼只有一位二進制數不同。

二進制轉格雷碼:

簡單來說就是把二進制碼右移一位再與二進制異或。

assign wr_poi_gray = wr_poi ^ (wr_poi>>1); //produce wr pointer gray code;

格雷碼轉二進制:

格雷碼轉二進制是從左邊第二位起,將每位與左邊一位二進制碼的值異或,作為該位二進制碼的值。

比如四位的碼:

bin[3] = gray[3];

bin[2] = gray[2]^bin[3];

bin[1] = gray[1]^bin[2];

bin[0] = gray[0]^bin[1];

原理圖:

信號定義:

wrclk:寫時鍾信號

rdclk: 讀時鍾信號

rst_n:異步復位信號

wr:寫請求

rd:讀請求

data:數據輸入

q: 數據輸出

full:滿信號,表示fifo吃飽了

empty:空信號,表示fifo肚子已經空掉了

 

仿真:寫時鍾是讀時鍾的兩倍。

寫讀測試:由於兩級同步器的存在,判定空滿滯后兩個周期。

 

同時讀寫測試:

資源使用量:

 

注意:

同步FIFO的地址擴展一位作為判斷空滿的狀態位,讀寫指針低位都相同的時候,最高位相同則表示讀空,不同則表示寫滿。

1 assign full = (wr_poi[clogb2(DEPTH)-1:0]== rd_poi[clogb2(DEPTH)-1:0]) && (wr_poi[clogb2(DEPTH)] ^ rd_poi[clogb2(DEPTH)] == 1);  //highest bit is not same but rests bit is same;
2 assign empty = (wr_poi[clogb2(DEPTH)-1:0]== rd_poi[clogb2(DEPTH)-1:0]) && (wr_poi[clogb2(DEPTH)] ^ rd_poi[clogb2(DEPTH)] == 0); //every bit is same;

異步FIFO的地址位也擴展一位作為狀態位,通過格雷碼跨過時鍾域判斷空滿。

在寫時鍾域判斷full:如果本時鍾域的寫地址格雷碼和同步過來的讀地址格雷碼最高位和次高位均不同,其余位相同,則表示寫滿了。

在讀時鍾域判斷empty:如果本時鍾域的讀地址格雷碼和同步過來的寫地址格雷碼最高位和次高位都一樣,其余位也一樣,則表示讀空。

1 assign full =  (wr_poi_gray == {~rd_poi_gray2[clogb2(DEPTH):clogb2(DEPTH)-1],rd_poi_gray2[clogb2(DEPTH)-2:0]});
2 assign empty = (wr_poi_gray2 == rd_poi_gray);

 貼一下同步FIFO的代碼:

已定制ramstyle,如果你的不同請刪掉或者更改。深度必須為2^n,否則更改函數clogb2中的depth為depth>0.
僅供學習交流,請勿用於商業用途,版權所有。異步代碼就不貼了,想研究請聯系我。

 1 //************************************************
 2 //  Filename      : fifo_syn.v                             
 3 //  Author        : kingstacker                  
 4 //  Company       : School                       
 5 //  Email         : kingstacker_work@163.com     
 6 //  Device        : Altera cyclone4 ep4ce6f17c8  
 7 //  Description   : synchronize fifo ;8*8 ;depth shuold be 2^n,otherwise change the clogb2 funtion;                           
 8 //************************************************
 9 module  fifo_syn #(parameter WIDTH = 8,DEPTH = 8)( 
10     //input;
11     input    wire    clk,                //only one clock;
12     input    wire    rst_n,
13     input    wire    wr,                 //wr request;
14     input    wire    rd,                 //rd request;
15     input    wire    [WIDTH-1:0]  data,  //data in;
16     //output;
17     output   wire    [WIDTH-1:0]  q,     //data out;       
18     output   wire    full,               //fifo is full;
19     output   wire    empty,              //fifo is empty;
20     output   wire    [clogb2(DEPTH)-1:0] usedw //data number in fifo;
21 );
22 function integer clogb2 (input integer depth);
23 begin
24     for (clogb2=0; depth>1; clogb2=clogb2+1) //depth>1 when you choose depth 2^n;otherwise change it to depth>0;for example depth is 7;
25         depth = depth >>1;                           
26 end
27 endfunction               
28 (* ramstyle = "M9K" *) reg [WIDTH-1:0]      memory [0:DEPTH-1];
29 reg [clogb2(DEPTH):0] wr_poi;    //wr pointer;
30 reg [clogb2(DEPTH):0] rd_poi;    //rd pointer;
31 reg [WIDTH-1:0] q_r;            //reg q;
32 reg [clogb2(DEPTH)-1:0] usedw_r;   //reg usedw_r;
33 wire wr_flag;                   //real wr request;
34 wire rd_flag;                   //real rd request;
35 assign q = q_r;
36 assign usedw = usedw_r;
37 assign full = (wr_poi[clogb2(DEPTH)-1:0]== rd_poi[clogb2(DEPTH)-1:0]) && (wr_poi[clogb2(DEPTH)] ^ rd_poi[clogb2(DEPTH)] == 1);  //highest bit is not same but rests bit is same;
38 assign empty = (wr_poi[clogb2(DEPTH)-1:0]== rd_poi[clogb2(DEPTH)-1:0]) && (wr_poi[clogb2(DEPTH)] ^ rd_poi[clogb2(DEPTH)] == 0); //every bit is same;
39 assign wr_flag = ((wr == 1'b1) && (full == 1'b0));          //wr enable;
40 assign rd_flag = ((rd == 1'b1) && (empty == 1'b0));         //rd enable;
41 always @(posedge clk or negedge rst_n) begin
42     if (~rst_n) begin
43         wr_poi <= 0;
44     end //if
45     else begin
46         wr_poi <= wr_flag ? wr_poi + 1'b1 : wr_poi;
47         memory[wr_poi[clogb2(DEPTH)-1:0]] <= wr_flag ? data : memory[wr_poi[clogb2(DEPTH)-1:0]];
48     end //else
49 end //always
50 always @(posedge clk or negedge rst_n) begin
51     if (~rst_n) begin
52         rd_poi <= 0;
53         q_r <= 0;
54     end //if
55     else begin
56         rd_poi <= rd_flag ? rd_poi + 1'b1 : rd_poi;
57         q_r <= rd_flag ? memory[rd_poi[clogb2(DEPTH)-1:0]] : q_r;
58     end //else
59 end //always
60 always @(posedge clk or negedge rst_n) begin
61     if (~rst_n) begin
62         usedw_r <= 0;
63     end //if
64     else begin
65         case ({wr_flag,rd_flag})
66                2'b00: begin
67                    usedw_r <= usedw_r;
68                end 
69                2'b10: begin
70                    if (usedw_r == DEPTH-1) begin  // full;
71                        usedw_r <= usedw_r;
72                    end
73                    else begin
74                        usedw_r <= usedw_r + 1'b1;
75                    end
76                end
77                2'b01: begin
78                    if (usedw_r == 0) begin     //empty;
79                        usedw_r <= usedw_r;
80                    end
81                    else begin
82                        usedw_r <= usedw_r - 1'b1;
83                    end
84                end
85                2'b11: begin
86                    usedw_r <= usedw_r;
87                end                                             
88                default:  usedw_r <= 0;
89            endcase //case   
90     end //else
91 end //always
92 
93 endmodule

 

 以上。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM