Bootstrap

【AXIS】AXI-Stream FIFO设计实现

AXI-Stream FIFO

  在FPGA中,遇到数据流传输时经常会用到AXI-Stream协议,它主要包含tdata,tvalid,tready三个信号。
在这里插入图片描述

信号名称功能
tdata由发送数据端(主机端master)发送,为需要传输的数据
tvalid由发送数据端(主机端master)发送,代表数据有效
tready由接收数据端(从机端slave)发送,代表可接收数据
tkeep / tstrb / tuser …由发送数据端(主机端master)发送,一般可等同于额外需要传输的数据

  当遇到从机端可能无法响应主机端发来请求的情况时,需要使用FIFO进行数据同步。对于FIFO的实现可以采用如下方式:

  • 深度为1的FIFO

  下述代码通过位拓展的方式实现了一个深度为1的FWFT FIFO,这种方式使用存储及触发器资源的数量最少。

module axis_fifo #(
    parameter TDATA_WIDTH = 1,
    parameter FIFO_DEPTH = 1
) (
    input   logic clk,

    input   logic   [TDATA_WIDTH - 1 : 0]   m_axis_tdata,
    input   logic                           m_axis_tvalid, 
    output  logic                           m_axis_tready, 
    
    output  logic   [TDATA_WIDTH - 1 : 0]   s_axis_tdata,  
    output  logic                           s_axis_tvalid, 
    input   logic                           s_axis_tready  
);


    logic fifo_rd_cnt_r = 1'b0, fifo_wr_cnt_r = 1'b0;

    always_ff @(posedge clk) begin
        if (m_axis_tvalid & m_axis_tready) begin
            fifo_wr_cnt_r <= ~fifo_wr_cnt_r;
        end
    end

    always_ff @(posedge clk) begin
        if (s_axis_tvalid & s_axis_tready) begin
            fifo_rd_cnt_r <= ~fifo_rd_cnt_r;
        end
    end

    assign m_axis_tready = fifo_wr_cnt_r == fifo_rd_cnt_r;
    assign s_axis_tvalid = fifo_wr_cnt_r != fifo_rd_cnt_r;

    logic [TDATA_WIDTH - 1 : 0] ram;

    always_ff @(posedge clk) begin
        if (m_axis_tvalid & m_axis_tready) begin
            ram <= m_axis_tdata;
        end
    end

   always_comb begin
       s_axis_tdata = ram;
   end

endmodule

通过仿真可以看到,数据能够进行缓存输出。

在这里插入图片描述

   上述代码的问题在于无法满足连续数据流的读写需求。
在这里插入图片描述
   为了解决上述问题,通常需要使用深度大于1的fifo。

  • 深度大于1的FIFO

这里以深度为2为例,fifo的实现方式如下

module axis_fifo_3 #(
    parameter TDATA_WIDTH = 1,
    parameter FIFO_DEPTH = 2 // 2 ** n
) (
    input   logic clk,

    input   logic   [TDATA_WIDTH - 1 : 0]   m_axis_tdata,
    input   logic                           m_axis_tvalid, 
    output  logic                           m_axis_tready, 
    
    output  logic   [TDATA_WIDTH - 1 : 0]   s_axis_tdata,  
    output  logic                           s_axis_tvalid, 
    input   logic                           s_axis_tready  
);
    localparam FIFO_DEPTH_WIDTH = $clog2(FIFO_DEPTH);

    logic [FIFO_DEPTH_WIDTH : 0] fifo_rd_cnt_r = 'b0, fifo_wr_cnt_r = 'b0;

    always_ff @(posedge clk) begin
        if (m_axis_tvalid & m_axis_tready) begin
            fifo_wr_cnt_r <= fifo_wr_cnt_r + 'd1;
        end
    end

    always_ff @(posedge clk) begin
        if (s_axis_tvalid & s_axis_tready) begin
            fifo_rd_cnt_r <= fifo_rd_cnt_r + 'd1;
        end
    end

    assign m_axis_tready = ~((fifo_wr_cnt_r[FIFO_DEPTH_WIDTH] != fifo_rd_cnt_r[FIFO_DEPTH_WIDTH]) && (fifo_wr_cnt_r[FIFO_DEPTH_WIDTH - 1 : 0] == fifo_rd_cnt_r[FIFO_DEPTH_WIDTH - 1 : 0]));
    assign s_axis_tvalid = ~(fifo_wr_cnt_r == fifo_rd_cnt_r);

    logic [TDATA_WIDTH - 1 : 0] ram[FIFO_DEPTH - 1:0];

    always_ff @(posedge clk) begin
        if (m_axis_tvalid & m_axis_tready) begin
            ram[fifo_wr_cnt_r[FIFO_DEPTH_WIDTH - 1 : 0]] <= m_axis_tdata;
        end
    end

    always_comb begin
        s_axis_tdata = ram[fifo_rd_cnt_r[FIFO_DEPTH_WIDTH - 1 : 0]];
    end

endmodule

   通过仿真可以看到,在连续数据流情况下,数据能够进行缓存输出。
在这里插入图片描述

完整代码

  完整工程可于公众号回复AXIS_FIFO下载。

;