FIFO(First In First Out),即先進先出。FPGA 或者 ASIC 中使用到的 FIFO 一般指的是對數據的存儲具有先進先出特性的一個緩存器,常被用於數據的緩存或者高速異步數據的交互。它與普通存儲器的區別是沒有外部讀寫地址線,這樣使用起來相對簡單,但缺點就是只能順序寫入數據,順序的讀出數據,其數據地址由內部讀寫指針自動加 1 完成,不能像普通存儲器那樣可以由地址線決定讀取或寫入某個指定的地址。
FIFO 從讀寫時鍾上來分有兩類結構:單時鍾 FIFO(同步 FIFO)和雙時鍾 FIFO(異步 FIFO)。單時鍾 FIFO 具有一個時鍾(讀寫共用一個時鍾)輸入,因此所有輸入信號的讀取都是在這個時鍾的上升沿進行的,所有輸出信號的變化也是在這個時鍾信號的上升沿的控制下進行的,即單時鍾 FIFO 的所有輸入輸出信號都是同步這個時鍾信號的。而在雙時鍾 FIFO 結構中,寫端口和讀端口分別有獨立的時鍾,所有與寫相關的信號都是同步於寫時鍾 wr_clk 的,所有與讀相關的信號都是同步於讀時鍾 rd_clk 的。下面圖是雙時鍾 FIFO 的整體框圖和內部實現的框圖,有單獨的模塊對讀寫時鍾域進行同步處理。

本文示范一個單時鍾FIFO,數據位寬為8位,數據深度為256,在Vivodo中產生一個FIFO IP核:

將IP核例化到頂層模塊中,並在頂層模塊中完成寫入、讀出的控制(不另外編寫寫入、讀出模塊)。
例化FIFO:
wire full ;//例化FIFO
wire empty ;
reg wr_en ;
reg rd_en ;
reg [ 7:0] din ;
reg [ 1:0] wr_state ;
reg [ 1:0] rd_state ;
fifo u_fifo(
.clk (clk ),
.srst (srst ),
.din (din ),
.wr_en (wr_en ),
.rd_en (rd_en ),
.dout (dout ),
.full (full ),
.empty (empty )
);
寫入控制:
always @(posedge clk ) begin //寫數據
if(srst)begin
wr_en<=0;
din<=0;
wr_state<=0;
end
else begin
case (wr_state)
0:
begin
if(empty)begin
wr_en<=1;
wr_state<=1;
end
else
wr_state<=0;
end
1:
begin
if(full)begin
wr_en<=0;
wr_state<=0;
din<=0;
end
else begin
wr_en<=1;
din<=din+1'b1;
end
end
default:wr_state<=0;
endcase
end
end
讀出控制:
always @(posedge clk ) begin //讀數據
if(srst)begin
rd_en<=0;
rd_state<=0;
end
else begin
case (rd_state)
0:
if(full)begin
rd_en<=1;
rd_state<=1;
end
else begin
rd_en<=0;
rd_state<=0;
end
1:
if(empty)begin
rd_en<=0;
rd_state<=0;
end
else begin
rd_state<=1;
end
default: rd_state<=0;
endcase
end
end
testbench:
`timescale 1ns / 1ps
module fifo_tb();
reg clk;
reg srst;
wire [7:0]dout;
fifo_test u_fifo_test(
.clk (clk ),
.srst (srst ),
.dout (dout )
);
initial clk=1;
always#10 clk=!clk;
initial begin
srst=1;
#201;
srst=0;
#200000;
$stop;
end
endmodule
仿真結果:
時鍾高電平復位,可以發現,當empty脈沖信號出現時,wr_en拉高,開始往FIFO中寫入數據;寫滿之后,full信號脈沖拉高,wr_en拉低,rd_en拉高,開始讀出數據,直至數據全部讀出,empty脈沖信號再次出現,這樣就是一個寫讀周期。