最近在學習FPGA的FIFO,現在將最近的FIFO學習情況做一個小結:
首先從幾個問題來引入FIFO的概念吧
1) FIFO是什么?
答:FIFO的英文是First in First out,也就是先進先出,即先進入FIFO的資料也最先被讀出,一般作為資料傳輸的緩沖器,他與普通的RAM和ROM的區別在于FIFO不用給定讀寫的地址,在進行讀寫操作的程序當中是順序進行的,不需要給定地址線,
2) FIFO的作用是?
a)FIFO的作用主要是在進行資料傳輸的程序當中,作為緩沖器對資料進行緩沖,
b)FIFO可以處理跨時鐘域的資料互動,主要是異步FIFO,可以處理不同時鐘域的資料傳輸,因為來自不同時鐘域的資料傳輸速率不一樣,如果沒有FIFO的話,很可能產生接收資料不是傳輸資料的現象,同時也能避免亞穩態的現象,
3)同步FIFO和異步FIFO的區別是?
FIFO分為同步FIFO和異步FIFO,當配置為同步FIFO的時候,只使用wr_clk,即所有的輸入輸出的信號都同步于寫時鐘;當被配置為異步FIFO的時候,寫埠和讀埠分別由獨立的時鐘,即wr_clk和rd_clk,
到這里想必大家對FIFO有了一個大致的了解,那么FIFO大致是什么樣子的呢?那就請看下圖:

其中左側Write Agent是寫資料側,右側為讀資料側,對FIFO操作時要注意各個信號的方向,其中almost_full于almost_empty是FIFO的將滿和將空標志,也就是full和empty信號的前一拍,這兩個信號的作用是在于避免使FIFO寫滿和讀空,所以這兩個信號出現表示不能往FIFO里面寫資料了,以及不能從FIFO里面讀資料了,
同時要注意almost_full信號是在Write_Agent模塊產生的,如果在Read Agent模塊使用的話,建議將這個先進行同步處理,也就是我們俗稱的打拍處理,同時如果在Write Agent模塊中使用almost_empty信號也是這樣,
那么說到這兒,我們怎么設計FIFO呢?我們可以呼叫Vivado當中的IP核,打開IP Catalog搜索FIFO,點擊FIFO Generate就可以對FIFO進行配置,
另外附上fifo的設計思路如下:

大致FIFO的基礎知識了解的差不多了,那我們就上代碼吧
1) 頂層模塊,完成對讀FIFO模塊、寫FIFO模塊以及FIFO IP核進行例化
頂層模塊代碼如下:(該例程是異步FIFO,但是寫時鐘和讀時鐘都是采用的同一個時鐘)
module FIFO_IP(
input sys_clk ,
input sys_rst_n ,
);
wire fifo_wr_en;
wire fifo_rd_en;
wire [7:0] fifo_din;
wire [7:0] fifo_dout;
wire full;
wire empty;
wire almost_full;
wire almost_empty;
wire [7:0] rd_data_count ;
wire [7:0] wr_data_count ;
//例化FIFO IP核
fifo_generator_0 your_instance_name (
.wr_clk(sys_clk), // input wire wr_clk
.rd_clk(sys_clk), // input wire rd_clk
.din(fifo_din), // input wire [31 : 0] din
.wr_en(fifo_wr_en), // input wire wr_en
.rd_en(fifo_rd_en), // input wire rd_en
.dout(fifo_out), // output wire [31 : 0] dout
.full(full), // output wire full
.almost_full(almost_full), // output wire almost_full
.empty(empty), // output wire empty
.almost_empty(almost_empty), // output wire almost_empty
.rd_data_count(rd_data_count), // output wire [7 : 0] rd_data_count
.wr_data_count(wr_data_count) // output wire [7 : 0] wr_data_count
);
//例化fifo寫模塊
fifo_wr u_fifo_wr(
.clk (sys_clk ),
.rst_n (sys_rst_n ),
.almost_empty (almost_empty),
.almost_full (almost_full ),
.fifo_wr_data (fifo_wr_data),
.fifo_wr_en (fifo_wr_en )
);
//例化fifo讀模塊
fifo_rd u_fifo_rd(
.clk (s’y’s_clk ),
.rst_n (sys_rst_n ),
.fifo_rd_en (fifo_rd_en ),
.almost_empty (almost_empty ),
.almost_full (almost_full ),
.fifo_rd_data (fifo_dout )
);
endmodule
讀寫控制模塊如下:
module fifo_wr(
input clk ,
input rst_n ,
input almost_empty ,
input almost_full ,
output reg [7:0] fifo_wr_data ,
output reg fifo_wr_en
);
reg [1:0] state ;
reg almost_empty_d0;//因為empty是讀時鐘域過來的,所以要做同步處理
reg almost_empty_d1;
reg [3:0] dly_cnt ;//延時計數器
always@(posedge clk )begin//上升沿有效
if(!rst_n) begin //打拍處理
almost_empty_d0 <= 1’b0;
almost_empty_d1 <= 1’b1;
end
else begin
almost_empty_d0 <= almost_empty;
almost_empty_d1 <= almost_empty_d0;
end
end
//像fifo寫資料(上升沿寫資料的哈,所以沒有復位的下降沿)
always@(posedge clk)begin
if(!rst_n)begin
state <= 2’d0;
fifo_wr_en<=1’b0;
fifo_wr_data<=32’d0;
dly_cnt<=4’d0 ;
end
else begin
case(state)
2’d0:begin
if(almost_empty_d1)begin
state<=2’d1;
end
else
state <= state;
end
2’d1:begin
if(dly_cnt == 4’d10)begin
dly_cnt <= 4’d0;
state <= 2’d2;
fifo_wr_en<=1’b1;
end
else
dly_cnt <=dly_cnt ;
end
2’d2:begin
if(almost_empty)begin
state<=2’d0;//回到1狀態
fifo_wr_en<=1’b0;
fifo_wr_data<=32’d0;
end
else begin
fifo_wr_en <=1’b1;
fifo_wr_data<=fifo_wr_data+1’b1;
end
end
default:state<=2’d0;
endcase
end
end
endmodule
3) 讀資料模塊如下:(與寫模塊很相似)
module fifo_rd(
input clk ,
input rst_n ,
output reg fifo_rd_en ,
input almost_empty ,
input almost_full ,
input [7:0] fifo_rd_data
);
reg almost_full_d0;
reg almost_full_d1;
reg [3:0] dly_cnt;
reg [1:0] state;
always@(posedge clk)begin
if(!rst_n)begin
almost_full_d0<=1’b0;
almost_full_d1<=1’b0;
end
else begin
almost_full_d0 <= almost_full ;
almost_full_d1 <= almost_full_d0 ;
end
end
always@(posedge clk)begin
if(!rst_n)begin
fifo_rd_en<=1’d0;
state <=2’d0;
dly_cnt<=4’d0;
end
else begin
case(state)
2’d0:begin
if(almost_full_d1)
state<=2’d1;
else
state <= state;
end
2’d1:begin
if(dly_cnt==4’d10)begin
dly_cnt<=4’d0;
state<=2’d2;
end
else
dly_cnt<=dly_cnt;
end
2’d2:begin
if(almost_empty)begin
fifo_rd_en <= 1’b0;
state <= 2’d0;
end
else
fifo_rd_en<=1’b1;
end
default:state<=2’d0;
endcase
end
end
endmodule
至此整個FIFO的大致講解到此結束,如果大家有什么問題可以一起探討哦,并且一起學習FPGA,后面也會持續更新一些FPGA相關知識
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/226979.html
標籤:其他
上一篇:關于心跳包的實作手法
