FIFO使用教程
作者:李西銳校對:陸輝
FIFO的英文全稱叫做First in First out,即先進先出。這也就決定了這個IP核的特殊性,先寫進去的數據優先被讀出,所以,FIFO是不需要地址信號線的,這也是它的一大特點,通常用來做數據的緩存,或者用來解決高速異步數據的交互,即解決了跨時鐘域的問題。此外,FIFO還有一個特點,就是數據被讀出之后就不存在了,不像RAM和ROM一樣,數據被讀出后還存在。所以我們如果想進行多次的讀,那么就需要進行同樣次數的寫。
FIFO分為同步時鐘和異步時鐘,同步FIFO指的是讀寫使用同一個時鐘,在時鐘沿信號來的時候進行讀寫。異步FIFO是指讀寫在不同時鐘下進行,這樣我們可以實現讀寫不同速度。
那么接下來,我們就來實現一下異步FIFO的讀寫過程。
上圖為選擇異步FIFO之后的圖示,在這個圖示中,我們給大家解釋一下每個信號的含義。
FIFO_WRITE:
full:FIFO的滿信號,當FIFO的存儲空間寫滿了之后,此信號拉高,否則為低。此信號為FIFO的輸出信號。
din[17:0]:FIFO的數據輸入,寫進FIFO的數據通過此信號線進入FIFO。
wr_en:FIFO的寫使能,當我們要往FIFO里面寫入數據時,拉高此信號。此信號為FIFO的輸入。
FIFO_READ:
empty:FIFO的空信號,當FIFO的存儲空間空了之后,此信號拉高,否則為低。此信號為FIFO的輸出信號。
dout:FIFO的數據輸出,讀出FIFO的數據通過此信號線輸出。
rd_en:FIFO的讀使能,當我們要從FIFO里面讀出數據時,拉高此信號。此信號為FIFO的輸入。
rst:FIFO復位,默認高電平有效。
wr_clk:寫時鐘
rd_clk: 讀時鐘
wr_rst_busy:寫復位忙信號
rd_rst_busy:讀復位忙信號
在了解了FIFO的端口之后,我們來實現一個應用實例。比如,我們以10MHz的速度往FIFO里面寫數據,寫滿之后,在20MHz的時鐘下將數據讀出,一直讀空。當然,在顯示應用中,FIFO的讀寫是可以同步進行的。
首先,我們先來新建工程。
新建好之后,我們先調用一下IP核:
在IP核管理器界面,搜索FIFO,然后選中圖示所選項雙擊打開。
在FIFO類型選項,我們選擇異步FIFO。剛打開默認的選項為同步FIFO。
在數據端口配置界面,我們將數據位寬改為8bit,深度使用1024。
復位端口在這就不再使用了,所以勾選位置取消掉。
在此界面出現了almost full flag和almost empty flag。這兩個信號是幾乎滿或空的標志信號,在此實驗中,我們不使用。
Datacount是FIFO數據用量計數器,代表了此時FIFO的內部存儲被使用的情況。假設我們寫進去了10個數,那么兩個計數器都為10。
此界面為IP核的信息,在此界面可以看出,我們的讀寫深度發生了變化,我們在前面設置的深度為1024,但是在此處顯示的卻是1023。原因是因為FIFO結構的特殊性,并不是我們設置的有問題。所以,在我們這個異步FIFO中,深度為1023。
點擊OK直接生成。在點擊Generate。
此外,我們還需要兩個不同時鐘,在這里我們使用鎖相環生成。
在管理界面搜索clock。配置過程我們在此前已經講過,就不在過多敘述。
接下來我們寫一下fifo的寫控制器,代碼如下:
1 module fifo_wr( 2 3 input wire clk, 4 input wire rst_n, 5 input wire empty, 6 input wire full, 7 output reg fifo_wr_en, 8 output reg [7:0] fifo_data_in 9 ); 10 11 reg state; 12 13 always @ (posedge clk, negedge rst_n) 14 begin 15 if(rst_n == 1'b0) 16 begin 17 fifo_wr_en <= 1'b0; 18 fifo_data_in <= 8'd0; 19 state <= 1'b0; 20 end 21 else 22 case(state) 23 1'b0 : begin 24 if(empty) 25 state <= 1'b1; 26 else 27 state <= 1'b0; 28 end 29 1'b1 : begin 30 if(full) 31 begin 32 fifo_wr_en <= 1'b0; 33 fifo_data_in <= 8'd0; 34 state <= 1'b0; 35 end 36 else 37 begin 38 fifo_wr_en <= 1'b1; 39 fifo_data_in <= fifo_data_in + 1'b1; 40 state <= 1'b1; 41 end 42 end 43 endcase 44 end 45 46 endmodule
因為我們的實驗是讀空了才寫,所以我們用狀態機來做,先判斷FIFO是否為空。讀控制器代碼如下:
1 module fifo_rd( 2 3 input wire clk, 4 input wire rst_n, 5 input wire empty, 6 input wire full, 7 output reg fifo_rd_en 8 ); 9 10 reg state; 11 12 always @ (posedge clk, negedge rst_n) 13 begin 14 if(rst_n == 1'b0) 15 begin 16 fifo_rd_en <= 1'b0; 17 state <= 1'b0; 18 end 19 else 20 case(state) 21 1'b0 : begin 22 if(full) 23 state <= 1'b1; 24 else 25 state <= 1'b0; 26 end 27 1'b1 : begin 28 if(empty) 29 begin 30 fifo_rd_en <= 1'b0; 31 state <= 1'b0; 32 end 33 else 34 begin 35 fifo_rd_en <= 1'b1; 36 state <= 1'b1; 37 end 38 end 39 endcase 40 end 41 42 endmodule
頂層代碼如下:
1 module fifo( 2 3 input wire clk, 4 input wire rst_n, 5 output wire [7:0] q 6 ); 7 8 wire fifo_wr_clk; 9 wire fifo_rd_clk; 10 wire locked; 11 wire empty; 12 wire full; 13 wire fifo_wr_en; 14 wire [7:0] fifo_data_in; 15 wire fifo_rd_en; 16 17 clk_wiz_0 clk_wiz_0_inst 18 ( 19 // Clock out ports 20 .clk_out1(fifo_wr_clk), // output clk_out1 21 .clk_out2(fifo_rd_clk), // output clk_out2 22 // Status and control signals 23 .reset(~rst_n), // input reset 24 .locked(locked), // output locked 25 // Clock in ports 26 .clk_in1(clk)); // input clk_in1 27 28 fifo_wr fifo_wr_inst( 29 30 .clk (fifo_wr_clk), 31 .rst_n (locked ), 32 .empty (empty ), 33 .full (full ), 34 .fifo_wr_en (fifo_wr_en ), 35 .fifo_data_in (fifo_data_in) 36 ); 37 38 fifo_generator_0 fifo_generator_0_inst ( 39 .wr_clk(fifo_wr_clk), // input wire wr_clk 40 .rd_clk(fifo_rd_clk), // input wire rd_clk 41 .din(fifo_data_in), // input wire [7 : 0] din 42 .wr_en(fifo_wr_en), // input wire wr_en 43 .rd_en(fifo_rd_en), // input wire rd_en 44 .dout(q), // output wire [7 : 0] dout 45 .full(full), // output wire full 46 .empty(empty) // output wire empty 47 ); 48 49 fifo_rd fifo_rd_inst( 50 51 .clk (fifo_rd_clk), 52 .rst_n (locked ), 53 .empty (empty ), 54 .full (full ), 55 .fifo_rd_en (fifo_rd_en) 56 ); 57 58 endmodule
代碼寫完之后,我們寫個仿真驗證一下波形,代碼如下:
1 `timescale 1ns / 1ps 2 3 module fifo_tb; 4 5 reg clk; 6 reg rst_n; 7 wire [7:0] q; 8 9 initial begin 10 clk = 0; 11 rst_n = 0; 12 #105; 13 rst_n = 1; 14 #10000; 15 $stop; 16 end 17 18 always #10 clk = ~clk; 19 20 fifo fifo_inst( 21 22 .clk (clk), 23 .rst_n (rst_n), 24 .q (q) 25 ); 26 27 endmodule
打開波形之后,我們將讀寫控制模塊的信號全部添加到波形窗口:
添加好之后,點擊restart和run-all
由于波形默認運行10us,我們觀察不到全部波形,所以,在此我們繼續點擊run-all,然后點擊break,讓仿真停止。
然后,我們觀察波形:
在波形里面可以清楚的看到我們的fifo_data_in和q的波形,一長一短。這是因為讀的速度快,所以波形維持的時間短。寫數據的時間長度是讀數據時間長度的兩倍。
然后放大波形觀察其他信號:
在黃色光標位置,可以看到滿信號拉高了,然后寫使能就拉低了,狀態開始進入到讀。在讀使能拉高之后,輸出q就有了數據,但是我們的empty信號維持了一段時間才拉低,這是因為fifo的特殊結構導致的,在此我們就不再過多討論。
結論:異步FIFO控制正確,仿真波形輸入和輸出信號正常。
審核編輯:湯梓紅
-
FPGA
+關注
關注
1630文章
21796瀏覽量
605531 -
fifo
+關注
關注
3文章
389瀏覽量
43823 -
時鐘
+關注
關注
11文章
1746瀏覽量
131728 -
IP核
+關注
關注
4文章
331瀏覽量
49601 -
Vivado
+關注
關注
19文章
815瀏覽量
66835
原文標題:FPGA零基礎學習之Vivado-FIFO使用教程
文章出處:【微信號:HXSLH1010101010,微信公眾號:FPGA技術江湖】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論