什么是FIFO
FIFO (First In First Out) ,也就是先进先出。FPGA或者ASIC中使用到的FIFO一般指的是对数据的存储具有先进先出特性的一个缓存器,常被用于数据的缓存或者高速异步数据的交互。它与普通存储器的区别是没有外部读写地址线,这样使用起来相对简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
FIFO作用:对于存储的数据,先存入FIFO的先被读出,可以确保数据的连续性
1,特征:数据产生速率>数据消耗速率
FIFO写入侧位宽 > FIFO读出侧位宽
2,特征:数据产生速率<数据消耗速率
FIFO写入侧位宽 < FIFO读出侧位宽
标准读模式同步FIFO
利用以下例子来熟悉FIFO使用:
打开vivado 创建工程
点击ok FIFO配置完成
然后编写FIFO测试文件
代码如下
`timescale 1ns / 1ps
module bram_sync_fifo_tb;reg clk; // input wire clkreg srst; // input wire srstreg [7:0]din; // input wire [7 : 0] dinreg wr_en; // input wire wr_enreg rd_en; // input wire rd_enwire [7:0]dout; // output wire [7 : 0] doutwire full; // output wire fullwire almost_full; // output wire almost_fullwire wr_ack; // output wire wr_ackwire overflow; // output wire overflowwire empty; // output wire emptywire almost_empty; // output wire almost_emptywire valid; // output wire validwire underflow; // output wire underflowwire [7:0]data_count; // output wire [7 : 0] data_count bram_sync_fifo your_instance_name (.clk(clk), // input wire clk.srst(srst), // input wire srst.din(din), // input wire [7 : 0] din.wr_en(wr_en), // input wire wr_en.rd_en(rd_en), // input wire rd_en.dout(dout), // output wire [7 : 0] dout.full(full), // output wire full.almost_full(almost_full), // output wire almost_full.wr_ack(wr_ack), // output wire wr_ack.overflow(overflow), // output wire overflow.empty(empty), // output wire empty.almost_empty(almost_empty), // output wire almost_empty.valid(valid), // output wire valid.underflow(underflow), // output wire underflow.data_count(data_count) // output wire [7 : 0] data_count);initial clk = 1;always #10 clk = ~clk;initial beginsrst = 1'b1;wr_en = 1'b0;rd_en = 1'b0;din = 8'hff;#21;srst = 1'b0;//写操作 从0-255 共256数据while(full == 1'b0)begin@(posedge clk);#1;wr_en = 1'b1;din = din + 1'b1;end//再多写1个数据 观察overflow的变化din = 8'hf0;@(posedge clk);#1;wr_en = 1'b0;#2000;//读操作 读256次while(empty == 1'b0)begin@(posedge clk)#1;rd_en = 1'b1;end//再多给一个读使能 看underflow的变化@(posedge clk)#1;rd_en = 1'b0;//复位#200;srst = 1'b1;#21;srst = 1'b0;#2000;$stop;endendmodule
仿真波形
写入时的波形
写满时的波形
读出时的波形
读完时的波形
FWFT读模式异步FIFO
点击ok FIFO配置完成
然后编写FWFT读模式异步FIFO测试文件
代码如下
`timescale 1ns / 1ps
module bram_asynv_fifo_tb;reg rst; // input wire rstreg wr_clk; // input wire wr_clkreg rd_clk; // input wire rd_clkreg [7:0]din; // input wire [7 : 0] dinreg wr_en; // input wire wr_enreg rd_en; // input wire rd_enwire [15:0]dout; // output wire [15 : 0] doutwire full; // output wire fullwire almost_full; // output wire almost_fullwire wr_ack; // output wire wr_ackwire overflow; // output wire overflowwire empty; // output wire emptywire almost_empty; // output wire almost_emptywire valid; // output wire validwire underflow; // output wire underflowwire [7:0]rd_data_count; // output wire [7 : 0] rd_data_countwire [8:0]wr_data_count; // output wire [8 : 0] wr_data_countwire wr_rst_busy; // output wire wr_rst_busywire rd_rst_busy; // output wire rd_rst_busybram_async_fifo your_instance_name (.rst(rst), // input wire rst.wr_clk(wr_clk), // input wire wr_clk.rd_clk(rd_clk), // input wire rd_clk.din(din), // input wire [7 : 0] din.wr_en(wr_en), // input wire wr_en.rd_en(rd_en), // input wire rd_en.dout(dout), // output wire [15 : 0] dout.full(full), // output wire full.almost_full(almost_full), // output wire almost_full.wr_ack(wr_ack), // output wire wr_ack.overflow(overflow), // output wire overflow.empty(empty), // output wire empty.almost_empty(almost_empty), // output wire almost_empty.valid(valid), // output wire valid.underflow(underflow), // output wire underflow.rd_data_count(rd_data_count), // output wire [7 : 0] rd_data_count.wr_data_count(wr_data_count), // output wire [8 : 0] wr_data_count.wr_rst_busy(wr_rst_busy), // output wire wr_rst_busy.rd_rst_busy(rd_rst_busy) // output wire rd_rst_busy);initial wr_clk = 1;always #10 wr_clk = ~wr_clk;initial rd_clk = 1;always #5 rd_clk = ~rd_clk;reg [5:0]cnt;always@(posedge rd_clk or posedge rst)if(rst)#1 cnt <= 1'b0;else if(cnt >= 6'd31)#1 cnt <= 1'b0;else if(rd_en)#1 cnt <= cnt + 1'b1;always@(posedge rd_clk or posedge rst)if(rst)#1 rd_en <= 1'b0;else if(rd_data_count > 9'd31)#1 rd_en <= 1'b1;else if(cnt >= 6'd31)#1 rd_en <= 1'b0;initial beginrst = 1'b1;wr_en = 1'b0;din = 8'hff;#(20*3+1);rst = 1'b0;//写数据@(negedge wr_rst_busy);wait(rd_rst_busy == 1'b0);repeat(257)begin@(posedge wr_clk)#1;wr_en = 1'b1;din = din +1'b1;endwr_en = 1'b0;#1000;$stop;endendmodule
仿真波形
写入时的波形
wr_en拉高 开始写数据
问题1解答:
这一块是由于仿真器设置导致的,在设置中语言选择的是Verilog和VHDL混合模式,所以会导致这个现象,但不建议直接改为Verilog语言模式,因为在一些IP核的底层是由Verilog和VHDL写好的,如果在这里改过来,虽然这一块波形是好的,但有可能在其他地方出现问题。
问题2解答:
看手册可以得知 空FIFO下 wr_data_count的值和 写深度与读深度的比例有关
在前面FIFO设置中,写深度与读深度比例是(256:128)即2:1
看手册可知 wr_data_count的值为4。
问题3解答:
查看手册:
可知:在设置more accurate data counts后,当FIFO为空或几乎空时,写计数会多计数两个读数据量。当empty取消断言后,在almost_empty取消断言后的几个写时钟周期内,写计数会存在一个过渡期,来让自己的值正确。
为此会出现下列情况:
1·虽然没有读操作,但是写计数会出现递减
2.由于写操作的持续,写计数的值并不会按照预期增加
读出时波形
rd_en拉高 开始读数据