FPGA-FIF0模型与应用场景(IP核)

什么是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 clk
     reg srst;                  // input wire srst
     reg [7:0]din;                   // input wire [7 : 0] din
     reg wr_en;               // input wire wr_en
     reg rd_en;               // input wire rd_en
     wire [7:0]dout;                  // output wire [7 : 0] dout
     wire full;               // output wire full
     wire almost_full;    // output wire almost_full
     wire wr_ack;            // output wire wr_ack
     wire overflow;        // output wire overflow
     wire empty;              // output wire empty
     wire almost_empty;  // output wire almost_empty
     wire valid;               // output wire valid
     wire underflow;        // output wire underflow
     wire [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 begin
        srst = 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;
        
    end

endmodule

仿真波形

写入时的波形

写满时的波形

读出时的波形

读完时的波形

FWFT读模式异步FIFO

点击ok FIFO配置完成

然后编写FWFT读模式异步FIFO测试文件

代码如下

`timescale 1ns / 1ps
module bram_asynv_fifo_tb;
      reg rst;                     // input wire rst
      reg wr_clk;                // input wire wr_clk
      reg rd_clk;                // input wire rd_clk
      reg [7:0]din;                     // input wire [7 : 0] din
      reg wr_en;                 // input wire wr_en
      reg rd_en;                // input wire rd_en
      wire [15:0]dout;                  // output wire [15 : 0] dout
      wire full;                   // output wire full
      wire almost_full;     // output wire almost_full
      wire wr_ack;               // output wire wr_ack
      wire overflow;           // output wire overflow
      wire empty;                // output wire empty
      wire almost_empty;   // output wire almost_empty
      wire valid;                // output wire valid
      wire underflow;          // output wire underflow
      wire [7:0]rd_data_count; // output wire [7 : 0] rd_data_count
      wire [8:0]wr_data_count;  // output wire [8 : 0] wr_data_count
      wire wr_rst_busy;     // output wire wr_rst_busy
      wire rd_rst_busy;      // output wire rd_rst_busy

bram_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 begin
        rst = 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;
            end
        wr_en = 1'b0;
        #1000;
        $stop;
        
    end
    
endmodule

仿真波形

写入时的波形

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拉高  开始读数据

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值