理論知識(shí)
FIFO(First In First Out, 先入先出 ),是一種數(shù)據(jù)緩沖器,用來實(shí)現(xiàn)數(shù)據(jù)先入先出的讀寫方式。數(shù)據(jù)按順序?qū)懭?FIFO,先被寫入的數(shù)據(jù)同樣在讀取的時(shí)候先被讀出,所以 FIFO存儲(chǔ)器沒有地址線,有一個(gè)寫端口和一個(gè)讀端口。
FIFO 存儲(chǔ)器主要是作為緩存,應(yīng)用在同步時(shí)鐘系統(tǒng)和異步時(shí)鐘系統(tǒng)中,分為 SCFIFO(同步 FIFO)和 DCFIFO(異步 FIFO)。后面實(shí)例中如:多比特?cái)?shù)據(jù)做跨時(shí)鐘域的轉(zhuǎn)換、前后帶寬不同步等都用到了FIFO。
同步FIFO-SCFIFO
SCFIFO IP核配置
full:寫滿標(biāo)志位,有效表示 FIFO 已經(jīng)存儲(chǔ)滿了,此時(shí)禁止再往FIFO中寫入數(shù)據(jù),防止數(shù)據(jù)溢出丟失。當(dāng)寫入數(shù)據(jù)量達(dá)到FIFO設(shè)置的最大空間時(shí),時(shí)鐘上升沿寫入最后一個(gè)數(shù)據(jù)同時(shí)full拉高;讀取數(shù)據(jù)時(shí)隨時(shí)鐘上升沿觸發(fā)同時(shí)拉低。
empty:讀空標(biāo)志位,有效表示 FIFO 中已經(jīng)沒有數(shù)據(jù)了,此時(shí)禁止FIFO繼續(xù)再讀出數(shù)據(jù),否則讀出的將是無效數(shù)據(jù)。寫入數(shù)據(jù)同時(shí)拉低;讀到最后一個(gè)數(shù)據(jù)同時(shí)拉高。
usedw:顯示當(dāng)前FIFO中已存數(shù)據(jù)個(gè)數(shù),寫第一個(gè)數(shù)據(jù)時(shí)就置1,空或滿時(shí)值為0(滿是因?yàn)?a href="http://www.delux-kingway.cn/tags/寄存器/" target="_blank">寄存器溢出)。
almost full:幾乎滿標(biāo)志信號(hào),我們可以控制FIFO快要被寫滿的時(shí)候和full信號(hào)的作用一樣。
almost empty:幾乎空標(biāo)志信號(hào),我們可以控制FIFO快要被讀空的時(shí)候和empty信號(hào)的作用一樣。
Asynchronous clear:異步復(fù)位信號(hào),用于清空FIFO。
Synchronous clear:同步復(fù)位信號(hào),用于清空FIFO。
后面三個(gè)沒有使用
SCFIFO IP核調(diào)用
我們需要寫一個(gè)頂層模塊,并通過testbench定義激勵(lì)來觀察信號(hào)變化,驗(yàn)證SCFIFO IP核。我們可以看到生成的模塊文件中有以下幾個(gè)端口,頂層模塊需要進(jìn)行實(shí)例化
輸入信號(hào)有:sys_clk、輸入256個(gè)8bit的數(shù)據(jù)pi_data(值為十進(jìn)制0~255),輸入數(shù)據(jù)有效的標(biāo)志信號(hào)pi_flag,寫請求信號(hào)rdreq。輸出信號(hào)有:讀取的數(shù)據(jù)po_data、空標(biāo)志信號(hào)empty、滿標(biāo)志信號(hào)full、指示FIFO中存在數(shù)據(jù)個(gè)數(shù)的信號(hào)usedw。
編寫代碼
module fifo(
input wire sys_clk ,
input wire [7:0] pi_data ,
input wire pi_flag ,
input wire rdreq ,
output wire [7:0] po_data ,
output wire empty ,
output wire full ,
output wire [7:0] usedw
);
scfifo_256x8 scfifo_256x8_inst(
.clock (sys_clk ),
.data (pi_data ),
.rdreq (rdreq ),
.wrreq (pi_flag ),
.empty (empty ),
.full (full ),
.q (po_data ),
.usedw (usedw )
);
endmodule
編寫testbench
//reg define
reg sys_clk ;
reg [7:0] pi_data ;
reg pi_flag ;
reg rdreq ;
reg sys_rst_n ;
reg [1:0] cnt_baud ;
//wire define
wire [7:0] po_data ;
wire empty ;
wire full ;
wire [7:0] usedw ;
//初始化系統(tǒng)時(shí)鐘、復(fù)位
initial begin
sys_clk = 1'b1;
sys_rst_n <= 1'b0;
#100;
sys_rst_n <= 1'b1;
end
//sys_clk:模擬系統(tǒng)時(shí)鐘,每10ns電平翻轉(zhuǎn)一次,周期為20ns,頻率為50MHz
always #10 sys_clk = ~sys_clk;
//cnt_baud:計(jì)數(shù)從0到3的計(jì)數(shù)器,用于產(chǎn)生輸入數(shù)據(jù)間的間隔
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_baud <= 2'b0;
else if(&cnt_baud == 1'b1)
cnt_baud <= 2'b0;
else
cnt_baud <= cnt_baud + 1'b1;
//pi_flag:輸入數(shù)據(jù)有效標(biāo)志信號(hào),也作為FIFO的寫請求信號(hào)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
pi_flag <= 1'b0;
else if((cnt_baud == 2'd0) && (rdreq == 1'b0))
pi_flag <= 1'b1;
else
pi_flag <= 1'b0;
//pi_data:輸入頂層模塊的數(shù)據(jù),要寫入到FIFO中的數(shù)據(jù)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
pi_data <= 8'b0;
else if((pi_data == 8'd255) && (pi_flag == 1'b1))
pi_data <= 8'b0;
else if(pi_flag == 1'b1)
pi_data <= pi_data + 1'b1;
//rdreq:FIFO讀請求信號(hào)
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rdreq <= 1'b0;
else if(full == 1'b1)
rdreq <= 1'b1;
else if(empty == 1'b1)
rdreq <= 1'b0;
fifo fifo_inst(
.sys_clk (sys_clk ),
.pi_data (pi_data ),
.pi_flag (pi_flag ),
.rdreq (rdreq ),
.po_data (po_data ),
.empty (empty ),
.full (full ),
.usedw (usedw )
);
endmodule
初始化:初始時(shí)鐘為高電平,復(fù)位有效,延遲100ns后復(fù)位釋放
模擬時(shí)鐘:每隔10ns翻轉(zhuǎn),時(shí)鐘周期20ns,頻率50MHz
輸入間隔計(jì)數(shù)器cnt_baud:從0-3計(jì)數(shù),復(fù)位和溢出歸0,其他情況+1,這里溢出判斷條件(cnt_baud=11)用的是位與為1
輸入有效標(biāo)志信號(hào)pi_flag:也是寫請求信號(hào),變化條件是時(shí)鐘上升沿和復(fù)位下降沿。復(fù)位有效時(shí)歸0;計(jì)數(shù)0且沒有讀請求時(shí)拉高相當(dāng)于四個(gè)時(shí)鐘周期產(chǎn)生一次;其他情況歸0
輸入數(shù)據(jù)pi_data:是要寫到FIFO中的數(shù)據(jù),變化條件是時(shí)鐘上升沿和復(fù)位下降沿。復(fù)位有效時(shí)歸0;輸入255且pi_flag有效時(shí)歸0;其他情況+1,意味著輸入數(shù)據(jù)從0-255循環(huán)
讀請求rdreq:變化條件是時(shí)鐘上升沿和復(fù)位下降沿。復(fù)位有效時(shí)歸0;full信號(hào)拉高時(shí)也拉高說明存滿該讀了;empty拉高時(shí)就歸0說明讀空禁讀了
實(shí)例化
波形變化
我們選擇的是普通模式,讀出數(shù)據(jù)比讀使能晚一拍
對比一下"先出數(shù)據(jù)FIFO模式"的波形,就可以看出延遲不延遲一拍的區(qū)別,這里沒有演示,實(shí)際上只需要在下面這一步時(shí)選擇先出數(shù)據(jù)模式即可
異步FIFO-SCFIFO
DCFIFO IP核配置
命名為"dcfifo_256x8to128x16",我們調(diào)用的dcfifo是輸入256個(gè)深度8位寬、輸出128個(gè)深度16位寬
DSCFIFO IP核調(diào)用
我們需要寫一個(gè)頂層模塊,并通過testbench定義激勵(lì)來觀察信號(hào)變化,驗(yàn)證DCFIFO IP核。我們可以看到生成的模塊文件中有以下幾個(gè)端口,頂層模塊需要進(jìn)行實(shí)例化
輸入信號(hào) :50MHz寫時(shí)鐘wrclk,輸入256個(gè)8bit的數(shù)據(jù)pi_data(值為十進(jìn)制0~255),輸入數(shù)據(jù)有效的標(biāo)志信號(hào)pi_flag,25MHz的讀時(shí)鐘rdclk,寫請求信號(hào)rdreq。 輸出信號(hào) :同步于wrclk的空標(biāo)志信號(hào)wrempty,同步于wrclk的滿標(biāo)志信號(hào)wrfull,同步于wrclk指示FIFO中存在數(shù)據(jù)個(gè)數(shù)的信號(hào)wrusedw,從FIFO中讀取的數(shù)據(jù)po_data,同步于rdclk的FIFO空標(biāo)志信號(hào)rdempty,同步于rdclk 的FIFO滿標(biāo)志信號(hào)rdfull,同步于rdclk指示FIFO中存在數(shù)據(jù)個(gè)數(shù)的信號(hào)rdusedw。
編寫代碼
module fifo
(
//同步于FIFO寫時(shí)鐘
input wire wrclk ,
input wire [7:0] pi_data ,
input wire pi_flag ,
//同步于FIFO讀時(shí)鐘
input wire rdclk ,
input wire rdreq ,
//同步于FIFO寫時(shí)鐘
output wire wrempty ,
output wire wrfull ,
output wire [7:0] wrusedw ,
//同步于FIFO讀時(shí)鐘
output wire [15:0] po_data ,
output wire rdempty ,
output wire rdfull ,
output wire [6:0] rdusedw
);
dcfifo_256x8to128x16 dcfifo_256x8to128x16_inst
(
.data (pi_data), //input [7:0] data
.rdclk (rdclk ), //input rdclk
.rdreq (rdreq ), //input rdreq
.wrclk (wrclk ), //input wrclk
.wrreq (pi_flag), //input wrreq
.q (po_data), //output [15:0] q
.rdempty(rdempty), //output rdempty
.rdfull (rdfull ), //output rdfull
.rdusedw(rdusedw), //output [6:0] rdusedw
.wrempty(wrempty), //output wrempty
.wrfull (wrfull ), //output wrfull
.wrusedw(wrusedw) //output [7:0] wrusedw
);
endmodule
編寫testbench
`timescale 1ns/1ns
module tb_fifo();
//reg define
reg wrclk ;
reg [7:0] pi_data ;
reg pi_flag ;
reg rdclk ;
reg rdreq ;
reg sys_rst_n ;
reg [1:0] cnt_baud ;
reg wrfull_reg0 ;
reg wrfull_reg1 ;
//wire define
wire wrempty ;
wire wrfull ;
wire [7:0] wrusedw ;
wire [15:0] po_data ;
wire rdempty ;
wire rdfull ;
wire [6:0] rdusedw ;
//初始化時(shí)鐘、復(fù)位
initial begin
wrclk = 1'b1;
rdclk = 1'b1;
sys_rst_n <= 1'b0;
#100;
sys_rst_n <= 1'b1;
end
//wrclk:模擬FIFO的寫時(shí)鐘,每10ns電平翻轉(zhuǎn)一次,周期為20ns,頻率為50MHz
always #10 wrclk = ~wrclk;
//rdclk:模擬FIFO的讀時(shí)鐘,每20ns電平翻轉(zhuǎn)一次,周期為40ns,頻率為25MHz
always #20 rdclk = ~rdclk;
//cnt_baud:計(jì)數(shù)從0到3的計(jì)數(shù)器,用于產(chǎn)生輸入數(shù)據(jù)間的間隔
always@(posedge wrclk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_baud <= 2'b0;
else if(&cnt_baud == 1'b1)
cnt_baud <= 2'b0;
else
cnt_baud <= cnt_baud + 1'b1;
//pi_flag:輸入數(shù)據(jù)有效標(biāo)志信號(hào),也作為FIFO的寫請求信號(hào)
always@(posedge wrclk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
pi_flag <= 1'b0;
else if((cnt_baud == 2'd0) && (rdreq == 1'b0))
pi_flag <= 1'b1;
else
pi_flag <= 1'b0;
//pi_data:輸入頂層模塊的數(shù)據(jù),要寫入到FIFO中的數(shù)據(jù)
always@(posedge wrclk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
pi_data <= 8'b0;
else if((pi_data == 8'd255) && (pi_flag == 1'b1))
pi_data <= 8'b0;
else if(pi_flag == 1'b1)
pi_data <= pi_data + 1'b1;
//將同步于rdclk時(shí)鐘的寫滿標(biāo)志信號(hào)wrfull在rdclk時(shí)鐘下打兩拍
always@(posedge rdclk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
begin
wrfull_reg0 <= 1'b0;
wrfull_reg1 <= 1'b0;
end
else
begin
wrfull_reg0 <= wrfull;
wrfull_reg1 <= wrfull_reg0;
end
//rdreq:FIFO讀請求信號(hào)同步于rdclk時(shí)鐘
always@(posedge rdclk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
rdreq <= 1'b0;
//如果wrfull信號(hào)有效就立刻讀,則不會(huì)看到rd_full信號(hào)拉高,
//所以此處使用wrfull在rdclk時(shí)鐘下打兩拍后的信號(hào)
else if(wrfull_reg1 == 1'b1)
rdreq <= 1'b1;
else if(rdempty == 1'b1)//當(dāng)FIFO中的數(shù)據(jù)被讀空時(shí)停止讀取FIFO中的數(shù)據(jù)
rdreq <= 1'b0;
fifo fifo_inst(
.wrclk (wrclk ),
.pi_data(pi_data),
.pi_flag(pi_flag),
.rdclk (rdclk ),
.rdreq (rdreq ),
.wrempty(wrempty),
.wrfull (wrfull ),
.wrusedw(wrusedw),
.po_data(po_data),
.rdempty(rdempty),
.rdfull (rdfull ),
.rdusedw(rdusedw)
);
endmodule
初始化:和同步fifo的區(qū)別在于讀寫時(shí)鐘是異步的,需要初始化兩個(gè)時(shí)鐘
時(shí)鐘模擬:寫時(shí)鐘50MHz每隔10ns翻轉(zhuǎn)一次,讀時(shí)鐘25MHz每隔20ns翻轉(zhuǎn)一次
cnt_baud:計(jì)數(shù)器是基于寫時(shí)鐘的,將變化條件中時(shí)鐘上升沿改為寫時(shí)鐘的上升沿
pi_flag:輸入數(shù)據(jù)有效標(biāo)志信號(hào),基于寫時(shí)鐘,同上
pi_data:輸入數(shù)據(jù),基于寫時(shí)鐘,同上
wrfull:寫滿標(biāo)志信號(hào),基于讀時(shí)鐘,變化條件是讀時(shí)鐘上升沿和復(fù)位下降沿。wrfull在讀時(shí)鐘下打兩拍,(always塊中的語句是順序執(zhí)行的,使用兩個(gè)寄存器b,c,令b=輸入a,c=b,并輸出c,那么c相對于a而言波形不會(huì)產(chǎn)生變化,只是有兩個(gè)時(shí)鐘周期的延遲,這個(gè)就叫打拍,使用幾個(gè)寄存器就是延遲幾個(gè)周期就是打幾拍),這里打兩拍的原因是如果wrfull有效立刻就讀,就看不到rd_full拉高
rdreq:讀請求信號(hào),基于讀時(shí)鐘,變化條件是讀時(shí)鐘上升沿和復(fù)位下降沿。復(fù)位時(shí)歸0;寫滿信號(hào)打兩拍之后的信號(hào)拉高就拉高表示寫滿需要讀,讀空信號(hào)拉高就拉低表示讀空不能讀
波形變化
可以看到當(dāng)pi_flag為高且pi_data為255的同時(shí)wrfull滿標(biāo)志信號(hào)先拉高了,延后一段時(shí)間rdfull滿標(biāo)志信號(hào)也拉高了,說明FIFO的存儲(chǔ)空間已經(jīng)滿了。wrfull滿標(biāo)志信號(hào)和rdfull滿標(biāo)志信號(hào)同步于 不同的時(shí)鐘 ,所以拉高的時(shí)間不同步。
還可以看到wrusedw信號(hào)是8位的計(jì)數(shù)到255,而rdusedw信號(hào)是7位的計(jì)數(shù)到127,因?yàn)檩斎胧?btit的,輸出是16bit的,8256=16128。wrusedw信號(hào)從255變成了0、rdusedw信號(hào)從127變成0的原因和SCFIFO中的情況一樣,都是因?yàn)閿?shù)據(jù)存儲(chǔ)滿了,F(xiàn)IFO內(nèi)部的計(jì)數(shù)器溢出所導(dǎo)致的。
另外可以看出讀出的16bit數(shù)據(jù),是兩次的輸入8bit數(shù)據(jù)拼湊而成,先輸入的在低位,后輸入的在高位,例如輸入00,01,02,03...,兩次輸入的數(shù)據(jù)拼湊為01_00,03_02進(jìn)行輸出。
如果不打兩拍會(huì)發(fā)生什么呢?我們來看波形
-
FPGA
+關(guān)注
關(guān)注
1630文章
21800瀏覽量
606272 -
存儲(chǔ)器
+關(guān)注
關(guān)注
38文章
7529瀏覽量
164383 -
緩沖器
+關(guān)注
關(guān)注
6文章
1943瀏覽量
45669 -
fifo
+關(guān)注
關(guān)注
3文章
390瀏覽量
43882 -
IP核
+關(guān)注
關(guān)注
4文章
331瀏覽量
49658
發(fā)布評論請先 登錄
相關(guān)推薦
關(guān)于FPGA IP核
FPGA的IP軟核使用技巧
![](https://file1.elecfans.com/web2/M00/84/89/wKgZomRmCoeAfRjHAAFaQpF6bbw153.png)
![](https://file1.elecfans.com/web2/M00/85/14/wKgZomRmHzWAG8hpAAAkqDwrZHY228.png)
#硬聲創(chuàng)作季 #FPGA FPGA-27-04 Quartus中fifo IP核介紹與仿真測試-1
![](https://file1.elecfans.com/web2/M00/85/13/wKgaomRmHzWAQi_zAAEIwj46oYE484.png)
#硬聲創(chuàng)作季 #FPGA FPGA-27-04 Quartus中fifo IP核介紹與仿真測試-2
![](https://file1.elecfans.com/web2/M00/85/13/wKgaomRmHzaAA2_WAAEs79POQz0166.png)
#硬聲創(chuàng)作季 #FPGA FPGA-27-04 Quartus中fifo IP核介紹與仿真測試-3
![](https://file1.elecfans.com/web2/M00/85/14/wKgZomRmHzaALjYbAAE5hPUaMq4065.png)
#硬聲創(chuàng)作季 #FPGA FPGA-27-04 Quartus中fifo IP核介紹與仿真測試-4
LabVIEW FPGA CORDIC IP核的arctan使用方法
FPGA零基礎(chǔ)學(xué)習(xí):IP CORE 之 FIFO設(shè)計(jì)
講解幾點(diǎn)關(guān)于FIFO IP核使用時(shí)的注意事項(xiàng)
![講解幾點(diǎn)關(guān)于<b class='flag-5'>FIFO</b> <b class='flag-5'>IP</b><b class='flag-5'>核</b>使用時(shí)的注意事項(xiàng)](https://file1.elecfans.com/web2/M00/8A/73/wKgZomSSltiAMrz6AAAPurV75_o621.jpg)
FPGA學(xué)習(xí)筆記:PLL IP核的使用方法
![<b class='flag-5'>FPGA</b><b class='flag-5'>學(xué)習(xí)</b><b class='flag-5'>筆記</b>:PLL <b class='flag-5'>IP</b><b class='flag-5'>核</b>的<b class='flag-5'>使用方法</b>](https://file1.elecfans.com/web2/M00/94/47/wKgaomTkXFuAEJJkAABDBBcGgk8645.jpg)
FPGA學(xué)習(xí)筆記:ROM IP核的使用方法
![<b class='flag-5'>FPGA</b><b class='flag-5'>學(xué)習(xí)</b><b class='flag-5'>筆記</b>:ROM <b class='flag-5'>IP</b><b class='flag-5'>核</b>的<b class='flag-5'>使用方法</b>](https://file1.elecfans.com/web2/M00/94/43/wKgZomTkXhmAFmybAADGGBhMOZA096.jpg)
FPGA學(xué)習(xí)筆記:RAM IP核的使用方法
![<b class='flag-5'>FPGA</b><b class='flag-5'>學(xué)習(xí)</b><b class='flag-5'>筆記</b>:RAM <b class='flag-5'>IP</b><b class='flag-5'>核</b>的<b class='flag-5'>使用方法</b>](https://file1.elecfans.com/web2/M00/A0/7B/wKgZomTtr9OAZ9IrAABNN01xyDM044.jpg)
評論