1.介紹
FIFO ,F(xiàn)irst In First Out,先入先出隊列,顧名思義,即第一個到達的數(shù)據(jù)也將會是第一個離開。由于同步FIFO的操作速度非常快,并且能 降低系統(tǒng)的復(fù)雜性 ,因此在很多高性能系統(tǒng)中是非常理想的選擇。且同步FIFO相比異步FIFO來說實現(xiàn)起來更簡單。所以在實際項目中用得相對較多。
UART項目中也使用了同步FIFO進行數(shù)據(jù)的緩存,本文主要對此進行講解。
2.FIFO設(shè)計
同步fifo架構(gòu),取自《硬件架構(gòu)的藝術(shù)》
根據(jù)系統(tǒng)時鐘和響應(yīng)速度,需要確定 FIFO深度 。本設(shè)計中深度設(shè)置為15,數(shù)據(jù)寬度8bit。同步FIFO設(shè)計的關(guān)鍵在于空滿信號的產(chǎn)生。
設(shè)計中rptr為 讀指針 ,指向下一個要讀的地址;wptr為 寫指針 ,同樣指向下一個要寫的地址。有效的讀寫使能使讀寫指針遞增。
wfull為 寫滿信號 ,表示FIFO空間已經(jīng)寫滿,不能再寫入數(shù)據(jù);rempty為 讀空信號 ,表示FIFO內(nèi)沒有可供讀寫的有效數(shù)據(jù)。空滿信號的產(chǎn)生是根據(jù)讀寫指針(讀寫地址)產(chǎn)生的。
- FIFO復(fù)位
此FIFO模塊中有兩個復(fù)位,一個是系統(tǒng)復(fù)位rst_,一個是FIFO復(fù)位fifo_rst。
系統(tǒng)復(fù)位為是整系統(tǒng)復(fù)位信號,該系統(tǒng)中所有寄存器會在此復(fù)位信號有效時有一個初始值,避免不定態(tài)的產(chǎn)生。
FIFO復(fù)位信號是同步FIFO的復(fù)位信號,只對此模塊有效,該信號有效時讀寫指針會歸0。
滿足FIFO復(fù)位單獨可控的設(shè)計要求。
- 空滿信號產(chǎn)生
當(dāng)FIFO復(fù)位信號fifo_rst有效時,讀寫指針會歸零,這時rempty信號會拉起,表示FIFO為空狀態(tài),此時往fifo中寫數(shù)據(jù);當(dāng)fifo中沒有空間可以寫時,寫地址是ram的深度即15,寫指針指向下一個寫地址會回到0,此時fifo為滿狀態(tài),wfull信號拉起。
空滿產(chǎn)生
可以發(fā)現(xiàn),在讀寫指針相等時,F(xiàn)IFO要么空要么滿。那么我們怎么對空滿狀態(tài)進行區(qū)分呢?
FIFO深度為15,正常地址應(yīng)該為4bit[3:0],為了區(qū)分空滿狀態(tài),我們將指針設(shè)置為5bit[4:0]。
根據(jù)上述的空滿狀態(tài)產(chǎn)生原理,可以發(fā)現(xiàn):
1) 當(dāng)FIFO為空時,讀寫指針完全相等;
2) 當(dāng)FIFO為滿時,讀寫指針的最高位是相反的,而低4位一定相等。
空滿信號產(chǎn)生
- FIFO數(shù)據(jù)狀態(tài)指示
由于設(shè)計要求FIFO數(shù)據(jù)量需要可查詢,所以增加一個fifo_cnt,它的值為寫指針與讀指針的差值。表示FIFO中剩余的數(shù)據(jù)量,作為輸出傳遞到寄存器配置模塊供系統(tǒng)查詢。
最后附上本項目中所用到的同步FIFO代碼,可將FIFO數(shù)據(jù)位寬和深度參數(shù)化,減少改動方便重復(fù)調(diào)用。另外要養(yǎng)成良好的代碼習(xí)慣,多加注釋。
同步FIFO Verilog代碼:
1`timescale 1ns/1ps
2
3module UART_FIFO(
4 //inputs
5 clk,
6 rst_,
7 fifo_rst,
8 rinc,
9 winc,
10 data_i,
11 //outputs
12 data_o,
13 wfull,
14 rempty,
15 fifo_cnt
16);
17
18input clk; // ARM clock
19input rst_; // ARM reset
20input fifo_rst; // FIFO reset control signal.high active
21input rinc; // FIFO read enable signal
22input winc; // FIFO write enable signal
23input [7:0] data_i; // in data line
24
25output wfull; // write full signal
26output rempty; // read empty signal
27output [7:0] data_o; // FIFO out data
28output [4:0] fifo_cnt; // FIFO statu register
29
30reg [7:0] data_o;
31reg [4:0] fifo_cnt;
32reg [4:0] wptr; // write pointer
33reg [4:0] rptr; // read pointer
34reg [7:0] ram[15:0]; // ram in FIFO
35
36// write data in ram
37always@(posedge clk or negedge rst_) begin
38 if(!rst_) begin
39 data_o <= 8'd0;
40 rptr <= 5'd0;
41 end
42 else begin
43 if(fifo_rst) begin
44 rptr <= 5'd0;
45 end
46 else begin
47 if(rinc && !rempty) begin
48 data_o <= ram[rptr[3:0]];
49 rptr <= rptr + 1'b1;
50 end
51 end
52 end
53end
54
55// read data from ram
56always@(posedge clk or negedge rst_) begin
57 if(!rst_) begin
58 wptr <= 5'd0;
59 end
60 else begin
61 if(fifo_rst) begin
62 wptr <= 5'd0;
63 end