Menu Close

FIFO IP核在Vivado 2018.2下的使用(四)AXI4- Stream FIFO简单使用

Vivado下FIFO IP核除了文章FIFO IP核使用(一) ,FIFO IP核使用(二),FIFO IP核使用(三)中介绍的标准接口(empty,full,rd_en,wr_en等)之外还可以选择配置集成了AXI4总线的接口。AXI4总线分为三种:AXI4,AXI4-Lite和AXI4-Stream。关于更多AXI总线的知识,参见文章AXI总线基础 。FIFO IP核集成了AXI4-Stream总线,特点是没有地址线,允许无限制的数据突发传输规模。顾名思义,Stream是指数据像水流一样连续不断,用固定的速度发送给接口。

在使用上,标准FIFO和AXI4-Stream FIFO也有区别。举例说明:相对于标准接口FIFO中读使能信号rd_en置位后,还需要一个时钟周期的延迟,数据才会出现在读数据端,AXI4-Stream FIFO在读操作握手后,读数据立马可用。从这点上看,AXI4-Stream FIFO读操作时更简单。在设计实现工程时,设计者可以考虑设计需要,进而选择使用哪种FIFO。本节课将结合使用AXI4-Stream FIFO的实例,带领大家一起学习有AXI4-Stream接口的FIFO使用方法。

1.AXI4-Stream FIFO接口

作为AXI4总线家族的一员,AXI4-Stream肯定有valid/ready/data接口。在AXI4-Stream中,分为主(master),从(slave)两个部分,如下表所示。AXI master接口用来读操作,AXI slave接口用来写操作,如图1所示。

表1:

名称 方向 描述
从: / /
s_axis_tvalid 输入 对应标准FIFO接口中的wr_en
s_axis_tready 输出 对应标准FIFO接口中的~full
s_axis_tdata 输入 对应标准FIFO接口中的din
/ / /
主: / /
m_axis_tvalid 输出 对应标准FIFO接口中的~empty
m_axis_tready 输入 对应标准FIFO接口中的rd_en
m_axis_tdata 输出 对应标准FIFO接口中的dout

 

图1 AXI4-Stream FIFO和 标准FIFO之间的联系

 

注意无论是s_axis_tdata还是m_axis_tdata都是以8-bit/一个字节为基本单位。

读操作和写操作中m_axis_tvalid,m_axis_tready,s_axis_tvalid和s_axis_tready的握手如图2所示:

图2 AXI4-Stream FIFO 握手

 

图1所示的读操作过程:AXI FIFO slave提供information和valid(m_axis_tvalid),一旦检测到ready(m_axis_tready)置位,AXI FIFO slave就会把下一个 准备好的information输出到总线端口上。当FIFO中没有数据(为空)时,valid信号被置低。

图1所示的写操作过程:AXI FIFO master 提供 information和 valid(s_axis_tvalid)信号; AXI FIFO slave通过置位 ready(s_axis_tready)信号来接受 information。 只有当 FIFO 已满时,ready信号才会被置低。

 

可以看出,只有当valid和ready同时有效时,数据传输(读或写)才会发生,广泛的Valid信号和Ready信号握手如图2所示:

图2 Valid和Ready同时为高

除了表1中的信号外,AXI4-Stream FIFO 还有其它的一些信号接口可供选择和配置,这里列出一些常用信号,如表2所示:

表2:

名称 方向 描述
从: / /
s_axis_tstrb 输入 字节使能,高电平为对应数据字节有效。对于 64 位 数据,位 0 对应 DATA 的最低有效字节,位 7 对应最高有效字节。 例如:
• strb[0] = 1b,DATA[7:0] 为 NULL 字节
• strb [7] = 0b,DATA[63:56] 不是 NULL 字节
s_axis_tkeep 输入 字节使能,指示数据的相关字节是否作为数据流的一部分。为低时表示数据相关字节是空字节,可以从数据流中删除。 对于 64 位 数据,位 0 对应 DATA 的最低有效字节,位 7 对应最高有效字节。 例如:
• keep[0] = 1b,DATA[7:0] 为 NULL 字节
• keep[7] = 0b,DATA[63:56] 不是 NULL 字节
s_axis_tlast 输入 指示数据包结束
s_axis_tid 输入 指示不同数据流的数据流标识符
s_axis_tdest 输入 为数据提供路由信息
s_axis_tuser 输入 可以与数据流一起传输的用户自定义信息
/ / /
主: / /
m_axis_tstrb 输出 字节使能,高电平为对应数据字节有效。对于 64 位 数据,位 0 对应 DATA 的最低有效字节,位 7 对应最高有效字节。 例如:
• strb[0] = 1b,DATA[7:0] 为 NULL 字节
• strb [7] = 0b,DATA[63:56] 不是 NULL 字节
m_axis_tkeep 输出 字节使能,指示数据的相关字节是否作为数据流的一部分。为低时表示数据相关字节是空字节,可以从数据流中删除。 对于 64 位 数据,位 0 对应 DATA 的最低有效字节,位 7 对应最高有效字节。 例如:
• keep[0] = 1b,DATA[7:0] 为 NULL 字节
• keep[7] = 0b,DATA[63:56] 不是 NULL 字节
m_axis_tlast 输出 指示数据包结束
m_axis_tid 输出 指示不同数据流的数据流标识符
m_axis_tdest 输出 为数据提供路由信息
m_axis_tuser 输出 可以与数据流一起传输的用户自定义信息

 

2. AXI4-Stream FIFO实例

  • AXI4-Stream FIFO IP核设置

在Vivado的IP Catalog的搜索栏中输入 FIFO ,在结果中选择 FIFO Generator ,如图3所示。

图3 搜索 FIFO Generator

 

双击打开FIFO Generator IP核,在Interface Type中选择 AXI Stream。Clocl Type AXI选择Common Clock(同步时钟)。

 

图4 Interface Type

 

在AXI4 Stream Ports中选择TDATA NUM BYTES为1,表示数据都是以1字节(8-bit)读/写。数据中携带的其它信息设置为0,不使用TSTRB和TKEEP两个字节使能,可以看到最后计算出来的总数据宽度是8-bit,如图5所示。

图5 设置端口数据宽度

 

在配置选项中选择Configuration Options为FIFO,设置FIFO Depth,这里深度设置为1024。

图6 Config设置

 

对于Status Flags这里选择不设置。

图7 状态标志

 

在最后的Summary页面中可以看出前面步骤的总结。对比设置的参数,如果和图8有差异,可以返回去修改设置。在全部设置完后,点击OK结束AXI4-Stream FIFO IP核设置。

图8 AXI4-Stream FIFO设置总结

 

  • 读写AXI4-Stream FIFO 工程

本文使用了一个简单的例子来写FIFO和读FIFO。因为在实体程序中已经把FIFO的数据写进去了,所以在仿真程序中只是例化了模块,以及生成了一个时钟,用来调度模块中读写FIFO的状态机。

实体程序如下:

`timescale 1ns / 1ps



module top(
    input clk,
    input s_aresetn,
    output [7:0] m_axis_tdata
    );
    
wire s_axis_tready;
reg s_axis_tvalid = 0;
    
wire m_axis_tvalid;
reg m_axis_tready=0;

reg [7:0] s_axis_tdata;

//wire  wr_rst_busy;
//wire rd_rst_busy;

reg [1:0] st;
reg [4:0] count;
reg [7:0] data;

wire [10:0]axis_data_count;
    
always @ (posedge clk or negedge s_aresetn)
begin
    if(~s_aresetn)
    begin
        s_axis_tdata <= 0;
        st <= 0;
        count <= 0;
        data <= 0;
    end
    else
    begin
        case(st)
        0://write
        begin
            if(s_axis_tready)  
            begin
                if( count > 20 )
                    st <= 3;
                else st <= 1;
            end
        end
        1:
        begin
            s_axis_tdata <= data;
            s_axis_tvalid <= 1;
            count <= count + 1;
            data <= data + 1;
            st <= 2;
        end
        2:
        begin
            s_axis_tvalid <= 0;
            st <= 0;
        end
        3://read
        begin
            count <= 0;
            if(m_axis_tvalid)
            begin
                m_axis_tready <= 1;
            end
            else
                st <= 0;
        end
        endcase
    end
end
    
    
    
fifo_generator_0 fifo_axi (

      .s_aclk(clk),                // input wire s_aclk
      .s_aresetn(s_aresetn),          // input wire s_aresetn
      .s_axis_tvalid(s_axis_tvalid),  // input wire s_axis_tvalid
      .s_axis_tready(s_axis_tready),  // output wire s_axis_tready
      .s_axis_tdata(s_axis_tdata),    // input wire [7 : 0] s_axis_tdata
      .m_axis_tvalid(m_axis_tvalid),  // output wire m_axis_tvalid
      .m_axis_tready(m_axis_tready),  // input wire m_axis_tready
      .m_axis_tdata(m_axis_tdata)  // output wire [7 : 0] m_axis_tdata
    );
    

    
endmodule

 

仿真代码如下:

`timescale 1ns / 1ps


module tb(

    );
    wire [7:0] m_axis_tdata;
    reg s_aresetn = 0;
    reg clk = 0;
    
always #5 clk = ~clk;

initial begin
    s_aresetn = 0;
    #200
    s_aresetn = 1;
end    

top top_inst(
    .clk(clk),
    .s_aresetn(s_aresetn),
    .m_axis_tdata(m_axis_tdata)
);
endmodule

 

 

  • 仿真波形

图9 写操作

 

从图9中可以看出在s_axis_tready和s_axis_tvalid同时为高时,数据被写入了FIFO。在写入一个数据之后,m_axis_tvalid为高表示FIFO里已经有一个数据可以进行读操作了。

 

图10 读操作

 

一旦FIFO里有数据,m_axis_tvalid被置位,但是一直到m_axis_tready为高时,读操作才有效,可以看到数据依次出现在m_axis_tdata端口。

 

图11 边写边读

 

因为m_axis_tready一直为高,所以一旦有数据被写入FIFO,立即被读出来,即图11所示的边写边读。

 

3. 扩展

在上述创建的AXI4-Stream FIFO IP核基础上,增加字节使能s_axis_tstrb(m_axis_tstrb)和指示数据包结束的s_axis_tlast(m_axis_tlast)来控制FIFO的读写操作。

Posted in FPGA, FPGA 教材教案, FPGA开发板, FPGA硬件资源, Verilog, Verilog, Vivado, Vivado, 开发工具, 开发工具, 开发板, 开发语言, 教材与教案, 文章, 编程语言

发表回复

相关链接