FPGA(四)FIFO

4.1 IP核使用

4.1.1 Basic配置

主要是FIFO Implementation选项,总体上分为同步FIFO异步FIFO,下面的表格列出了使用的资源以及支持的特性。

Non-symmetric aspect ratios:支持读写宽度不同。

如果选择异步FIFO还会有Synchronization Stages配置项,表示写时钟域的数据经过多少(读时钟)周期同步到读时钟域。

4.1.2 Port配置

  • Read Mode

    • Standard FIFO:默认需要读使能才有输出数据。
    • First Word Fall Through:只要FIFO不为空,第一个写入的数据会自动(无需读使能)出现在输出端口,后续的数据才需要读使能,如下图所示。

  • WidthDepth:按需填写。注意异步FIFO的实际深度会比配置的少。

  • Output Registers:同RAM IP核。Embedded Registers表示使用BRAM资源自带的寄存器;Fabric Registers表示使用通用逻辑资源。

  • Initailization

    • Synchronous Reset:同步复位。
    • Asynchronous Reset:异步复位。会多出rd_rst_busywr_rst_busy 信号,表示读/写复位忙(FIFO内部还在处理复位过程),为高电平时应当禁止读/写操作。异步FIFO只能异步复位。
    • Full Flags Reset Value:控制复位后full信号的初始状态。同步复位只能为0;异步复位可以为0或1,为1表示复位后FIFO满,需要先读才能写。
    • Dout Reset Value:复位时默认的读端口输出。

4.1.3 Status Flags配置

  • Almost Full Flag:再写一个数据就满了。

  • Almost Empty Flag:再读一个数据就空了。

  • Write Acknowledge:写应答。写入操作成功完成的下一个周期(即wr_en的下一个周期)拉高。

  • Overflow:写溢出。向已满FIFO写入数据时拉高。

  • Valid Flag:读有效。读端口dout有效时拉高。

  • Underflow Flag:读下溢出。从空的FIFO中读数据时拉高。

  • Programmable Flags:可以自定义设置full或empty的阈值。可以是单一阈值(Single)或一个阈值区间(Multiple)。也可以选择该阈值由外部传入。

    Full Threshold Assert Value表示数据个数达到该值时自定义full信号拉高;Full Threshold Negate Value表示个数小于该值时才拉低,使用该信号需要选择Multiple,起到防止边界抖动的作用。

4.1.4 Data Counts配置

  • Data Count:指示FIFO中有多少数据。

上面的图片是同步FIFO,只能设置Data Count Width。下面的读写计数异步FIFO才支持。

4.2 同步FIFO测试

设置FIFO的深度为16,先写入18个数据,会有2个数据overflow,然后一直读取FIFO。

`timescale 1ns / 1ps

module syn_tb();
    logic       clk;
    logic       rst_n;
    logic [7:0] din;
    logic       wr_en;
    logic       rd_en;
 
    wire  [7:0] dout;
    wire        full;
    wire        almost_full;
    wire        wr_ack;
    wire        overflow;
    wire        empty;
    wire        almost_empty;
    wire        valid;
    wire        underflow;
    wire  [3:0] data_count;

    always #5 clk = ~clk;
 
    initial begin
        clk = 1;
        rst_n = 0;
        
        #30
        rst_n = 1;
    end
 
    logic [4:0] cnt;
    
    always_ff @(posedge clk, negedge rst_n) begin
        if (!rst_n) begin
            cnt <= 0;
            din <= 0;
            wr_en <= 0;
        end
        else if (cnt < 18) begin
            cnt <= cnt + 1;
            wr_en <= 1;
            din <= din + 1;
        end
        else begin
            wr_en <= 0;
        end
    end
 
    always_ff @(posedge clk, negedge rst_n) begin
        if (!rst_n) begin
            rd_en <= 0;
        end
        else if (cnt == 18) begin
            rd_en <= 1;
        end
    end

    fifo_generator_0 fifo_u (
      .clk(clk),                    // input wire clk
      .srst(!rst_n),                // 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 [3 : 0] data_count
    );
 
endmodule

4.3 异步FIFO测试

写位宽16,深度15;读位宽8,深度30。写频率50MHz,读频率100MHz。

Synchronization Stages = 2时波形如下:

  • 两个标记(读写count)之间隔了Synchronization Stages + 2 = 4个读时钟周期。(为什么+2,网上说是因为Empty Threshold Assert Value设置的2)
  • 写深度为15,所以有1周期的overflow。

Synchronization Stages = 3时波形如下,两个标记之间间隔3 + 2 = 5个读时钟周期。

`timescale 1ns / 1ps

module asyn_tb();
    logic       rst_n;
    logic       wr_clk;
    logic       rd_clk;
    logic [15:0]din;
    logic       wr_en;
    logic       rd_en;
 
    wire  [7:0] dout;
    wire        full;
    wire        almost_full;
    wire        wr_ack;
    wire        overflow;
    wire        empty;
    wire        almost_empty;
    wire        valid;
    wire        underflow;
    wire  [4:0] rd_data_count;
    wire  [3:0] wr_data_count;
    wire        wr_rst_busy;
    wire        rd_rst_busy;
    
    always #10 wr_clk = ~wr_clk;
    always #5  rd_clk = ~rd_clk;
    
    initial begin
        wr_clk = 1;
        rd_clk = 1;
        rst_n = 0;
        
        #30 rst_n = 1;
    end
    
    logic       flag;   // control when to write
    logic [4:0] cnt;
    
    initial begin
        flag = 0;
        #350 flag = 1;
        #20 flag = 0;
    end

    always_ff @(posedge wr_clk, negedge rst_n) begin
        if (!rst_n) begin
            cnt <= 0;
            din <= 0;
            wr_en <= 0;
        end
        else if(flag == 1 || (1 <= cnt && cnt < 16)) begin
            cnt <= cnt + 1;
            wr_en <= 1;
            din <= din + 1;
        end
        else begin
            wr_en <= 0;
        end
    end
 
    always_ff @(posedge rd_clk, negedge rst_n) begin
        if(!rst_n) begin
            rd_en <= 0;
        end
        else if(cnt == 16) begin
            rd_en <= 1;
        end
    end
 
    fifo_generator_1 fifo_u (
      .rst(!rst_n),                   // input wire rst
      .wr_clk(wr_clk),                // input wire wr_clk
      .rd_clk(rd_clk),                // input wire rd_clk
      .din(din),                      // input wire [15 : 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
      .rd_data_count(rd_data_count),  // output wire [4 : 0] rd_data_count
      .wr_data_count(wr_data_count),  // output wire [3 : 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
    );
 
endmodule

FPGA(四)FIFO
https://shuusui.site/blog/2025/12/09/fpga-4/
作者
Shuusui
发布于
2025年12月9日
更新于
2025年12月11日
许可协议