• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

极快入门AXI4总线--AXI4-Stream篇3----XILINX IP AXI4 STREAM DATA FIFO

武飞扬头像
孤独的单刀
帮助1

写在前面

        AXI4系列链接:带你快速入门AXI4总线--汇总篇(直达链接)


1、AXI4 STREAM DATA FIFO是什么?

        IP核----AXI4 STREAM DATA FIFO也是一种先入先出形式的数据缓存队列(FIFO),不过输入输出接口均为AXIS接口。可用在数据缓存,跨时钟域传输等各类场景。搭载的AXIS接口方便了模块移植,比较适合SOC系统。

        在IP catalog搜索,AXI4 STREAM DATA FIFO,再双击出现其配置界面:

学新通

        点击documentation--product guide有XILINX提供的IP手册,需要注意的是这个IP的手册是和其他多个IP构成的一个手册(PG085),所以内容不是特别详尽。 


该IP的参数如下:

        Component Name:自己例化的IP名称,根据自己需求来命名即可

        FIFO Depth:FIFO深度,可选择范围16 and 32768,我们这里设置32

        Memory type:实现FIFO的RAM类型,一般选择自动auto即可

        Independent:是否选择独立时钟,即同步FIFO或者异步FIFO,我们这里不搞复杂了,选择同步FIFO ,选择NO

        CDC sync stages:跨时钟域处理的同步阶数,我们选择的同步时钟,用不到

        Enable Packet Mode: 使能包模式:设置为Yes将使能包模式。此项设定需要TLAST信号被使能。FIFO的操作在包模式下被修改为存储传送的数据,直到TLAST信号被置位。当TLAST信号被置位或者FIFO满了,存储的传送数据将被送至AXI4-Stream master interface。我们这里先不使用。

        ACLKEN Conversion Mode(选择NONE) :ACLKEN转换模式: 这个下拉选项为ACLKEN信号的转换模式。当ACLKEN转换执行时会消耗额外的延迟和逻辑。这个选项有: 

  • None - 这里没有ACLKEN信号关联于IP。 
  • S AXIS Only - 一个S_AXIS_ACLKEN信号关联到S_AXIS_ACLK时钟信号和没M_AXIS_ACLKEN信号。 
  • M AXIS Only - 一个M_AXIS_ACLKEN信号关联到M_AXIS_ACLK时钟信号和没有S_AXIS_ACLKEN信号。 
  • S AXIS & M AXIS - 两边时钟都有 ACLKEN信号关联到他们。

        Enable ECC:Error Correction Checking ,错误纠正检查。不使用

        TDATA Width(bytes): TDATA位宽(字节为最小单位), 该参数指定了所有AXI4-Stream interfaces中的TDATA信号的位宽,以字节为最小单位。该参数为整数,在0到512(IP核设置界面是256)之间。设为0将省略TDATA信号。如果TDATA信号被省略,TKEEP和TSTRB信号也会被省略。接口数据的位宽按bits计算,需要乘以8。我们这里设置1

        Enable TSTRB :使能TSTRB信号 ,如果设定为Yes,这个参数指定是否在所有AXI4-Stream interfaces使用可选的TSTRB信号。这个选项只能在TDATA Width(bytes)参数大于0时才可以使能。这个信号和TKEEP一起构成了对TDATA的描述,表明当前传输的数据是有效、或是占位符或无效。

        Enable TKEEP :使能TSTRB信号 ,如果设定为Yes,这个参数指定是否在所有AXI4-Stream interfaces使用可选的TKEEP信号。这个选项只能在TDATA Width(bytes)参数大于0时才可以使能。这个信号和TKEEP一起构成了对TDATA的描述,表明当前传输的数据是有效、或是占位符或无效。

        Enable TLAST: 使能TLAST。如果设定为Yes,这个参数指定是否在所有AXI4-Stream interfaces使用可选的TLAST信号。对于TLAST信号要重点说明,因为在使用STREAM FIFO时TLAST的作用特别的重要。对于STREAM FIFO来说,TLAST信号的作用是指示一次传输数据流的最后一个数据,也指示着该数据流的结束。其会记录下TLAST信号的位置,及当其SLAVE接口(SFIFO的数据写入接口)的某一个数据写入的同时TLASET信号也为高的话,当MASTER接口(SFIFO的数据读出接口)读出该数据的同时也会将TLAST信号拉高。总结起来就是,进的数据有TLAST,该数据出的时候就会有TLAST。

        TID Width(bits): TID位宽(比特为单位): 如果该参数大于0,这个参数指定是否在所有的AXI4-Stream interfaces中使用TID信号。值大于0省略这个信号。适用于多个AXIS接口构成的系统通信,用于区别源信号。这里不使用

        TDEST Width(bits): TDEST位宽(bits): 如果该参数大于0,这个参数指定是否在所有的AXI4-Stream interfaces中使用TDEST信号。值大于0省略这个信号。适用于多个AXIS接口构成的系统通信,用于区别目标信号。这里不使用

        TUSER Width(bits): TUSER 位宽(bits): 如果该参数大于0,这个参数指定是否在所有的AXI4-Stream interfaces中使用TDEST信号。值大于0省略这个信号。传输用于的定制信息,这里不使用


        FLAG类的信号设置如下:

学新通

        Enable write data count:使能写入数据计数,同步于写时钟

        Enable almost full:使能写入几乎满,同步于写时钟

        Enable programmable full:使能可编程满,同步于写时钟。可以自己设置阈值来提醒当前FIFO的写入状态

        Programmable full threshold:可编程满阈值

        Enable read data count:使能读取数据计数,同步于读时钟

        Enable almost empty:使能读取几乎空,同步于读时钟

        Enable programmable empty:使能可编程空,同步于读时钟。可以自己设置阈值来提醒当前FIFO的读取状态

        Programmable empty threshold:可编程空阈值


再来看一下此时的FIFO框图:

学新通

        其中除了标志信号、时钟、复位信号外,就是两个接口M_AXIS、S_AXIS。我们知道AXIS是一种半双工的总线,数据传输永远是从MASTER发送给SLAVE,所以可以判断出M_AXIS是发送接口来发送FIFO中的数据,即FIFO读取端;S_AXIS是接收接口来将数据写入FIFO中,即FIFO写入端。


2、自己编写的仿真验证

        接下来我们例化一个FIFO,并依照AXIS的握手协议来对其进行仿真验证,预期实现以下功能:

  • FIFO深度32,AXIS的数据位宽32位,读写时钟50M
  • 先将FIFO写满,等待几个周期,将其读空

        编写的Testbench如下:

  1.  
    `timescale 1ns/1ns //时间单位/精度
  2.  
    //------------<模块及端口声明>----------------------------------------
  3.  
    module tb_fifo();
  4.  
     
  5.  
    reg s_axis_aresetn;
  6.  
    reg s_axis_aclk;
  7.  
    //写FIFO端口
  8.  
    reg s_axis_tvalid;
  9.  
    reg [31 : 0] s_axis_tdata;
  10.  
    reg s_axis_tlast;
  11.  
    wire [31 : 0] axis_wr_data_count;
  12.  
    wire s_axis_tready;
  13.  
    wire almost_full;
  14.  
    //读FIFO端口
  15.  
    reg m_axis_tready;
  16.  
    wire m_axis_tvalid;
  17.  
    wire [31 : 0] m_axis_tdata;
  18.  
    wire m_axis_tlast;
  19.  
    wire [31 : 0] axis_rd_data_count;
  20.  
    wire almost_empty;
  21.  
    //------------<设置初始测试条件>----------------------------------------
  22.  
    initial begin
  23.  
    s_axis_aclk = 1'b0; //初始时钟为0
  24.  
    s_axis_aresetn <= 1'b0; //初始复位
  25.  
    s_axis_tvalid <= 1'b0;
  26.  
    s_axis_tdata <= 32'd0;
  27.  
    s_axis_tlast <= 1'b0;
  28.  
    m_axis_tready <= 1'b0;
  29.  
    #60 //60个时钟周期后
  30.  
    s_axis_aresetn <= 1'b1; //拉高复位,系统进入工作状装
  31.  
    #70
  32.  
    s_axis_tvalid <= 1'b1; //拉高tvalid,准备发送信好
  33.  
    wait(s_axis_tready); //等待从机响应
  34.  
    repeat(35)begin //重复35个时钟周期
  35.  
    @(posedge s_axis_aclk)
  36.  
    s_axis_tdata <= s_axis_tdata 1; //发数据从1开始累加1
  37.  
    end
  38.  
    s_axis_tvalid <= 1'b0; //结束发送
  39.  
    m_axis_tready <= 1'b1; //拉高tready,准备接收
  40.  
    @(posedge almost_empty)
  41.  
    #20 m_axis_tready <= 1'b0; //接收完所有数据后拉低m_axis_tready
  42.  
    #40 $finish;
  43.  
    end
  44.  
    //------------<设置时钟>----------------------------------------------
  45.  
    always #10 s_axis_aclk = ~s_axis_aclk; //系统时钟周期20ns
  46.  
     
  47.  
    //tlast
  48.  
    always@(posedge s_axis_aclk or negedge s_axis_aresetn ) begin
  49.  
    if(!s_axis_aresetn)
  50.  
    s_axis_tlast <= 1'b0;
  51.  
    //发送33个数据(最后一个数据)拉高
  52.  
    else if(axis_data_fifo_0_inst.s_axis_tdata == 'd33)
  53.  
    s_axis_tlast <= 1'b1;
  54.  
    else
  55.  
    s_axis_tlast <= 1'b0;
  56.  
    end
  57.  
     
  58.  
    //------------<例化被测试模块>----------------------------------------
  59.  
    axis_data_fifo_0 axis_data_fifo_0_inst (
  60.  
    //系统端口
  61.  
    .s_axis_aresetn (s_axis_aresetn ), // input wire s_axis_aresetn
  62.  
    .s_axis_aclk (s_axis_aclk ), // input wire s_axis_aclk
  63.  
    //写FIFO端口
  64.  
    .s_axis_tvalid (s_axis_tvalid ), // input wire s_axis_tvalid
  65.  
    .s_axis_tready (s_axis_tready ), // output wire s_axis_tready
  66.  
    .s_axis_tdata (s_axis_tdata ), // input wire [7 : 0] s_axis_tdata
  67.  
    .s_axis_tlast (s_axis_tlast ), // input wire s_axis_tlast
  68.  
    .axis_wr_data_count (axis_wr_data_count ), // output wire [31 : 0] axis_wr_data_count
  69.  
    .almost_empty (almost_empty ), // output wire almost_empty
  70.  
    //读FIFO端口
  71.  
    .m_axis_tvalid (m_axis_tvalid ), // output wire m_axis_tvalid
  72.  
    .m_axis_tready (m_axis_tready ), // input wire m_axis_tready
  73.  
    .m_axis_tdata (m_axis_tdata ), // output wire [7 : 0] m_axis_tdata
  74.  
    .m_axis_tlast (m_axis_tlast ), // output wire m_axis_tlast
  75.  
    .axis_rd_data_count (axis_rd_data_count ), // output wire [31 : 0] axis_rd_data_count
  76.  
    .almost_full (almost_full ) // output wire almost_full
  77.  
    );
  78.  
     
  79.  
    endmodule
学新通

        仿真结果如下:

学新通

        局部放大,写数据部分仿真图:

学新通

        读数据部分仿真图:

学新通

        这里对时序图不做讲解(图上的注释已经非常详尽了),只说一下FIFO的深度问题。从图中我们发现两点:

  • FIFO设置的深度为32,仿真实际深度为34
  • 读取FIFO时,数据并没有落后1个时钟周期 

        关于XILINX的FIFO IP核,有两种读取模式:standard FIFO,first word fall through。这两种模式的时序如下:

学新通

学新通

         不难发现,standard FIFO模式读取数据会有一个周期的延迟;而first word fall through模式下,读取数据没有延迟。所以在本文中的FIFO都是first word fall through模式。

        而这两种模式的actual depth而会有一点点区别。依然打开FIFO generator,分别选择两种模式看看实际深度的区别,如下:

学新通

学新通

         可以看到standard FIFO模式的实际深度是32,而first word fall through模式的实际深度是34。这就解释了为什么我们的仿真FIFO深度是34了。

3、XILINX官方例程仿真

        同其他许多IP一样,这个IP Xilinx也会我们提供example design。右击IP,选择open IP example design

学新通

        点击OK

学新通

        此时会新生成一个工程,该工程目录如下: 

        的学新通

         点击run simulation进行行为仿真,添加波形如下:

学新通

         仿真结果如下所示:

学新通

        过程较长,我们截取一些局部图。

        下图中,FIFO复位未完成时,存在不稳定的现象 ;FIFO的写入和读取均需要等待一定的时间。

学新通

         下图中:

                每1个时钟周期写入1个数据 ;每2个时钟周期读取1个数据

                tlast一直被拉高,代表每包数据只有一个

                写入数据累加1(32‘d16843 == 32'b0000_0001_0000_0001_0000_0001_0000_0001;32‘d33686 == 32'b0000_0002_0000_0002_0000_0002_0000_0002)         

学新通

         下图中:

                由于写时钟是读时钟的2倍,所以FIFO很快会被写满,被写满后只有等待读出数据后才能继续写入,由于写使能一直拉高,就会形成一种读写平衡状态

学新通

         下图中:

                一次写入一包数据,个数16个,s_axis_tlast表示写入一包数据的最后一个

学新通

         下图中:

                一次读出一包数据,个数16个,m_axis_tlast表示读取一包数据的最后一个

学新通

         下图中:

                用户拉低s_axis_tvalid信号,停止写入FIFO;继续读取FIFO;待FIFO中的数据全部被读出来后,FIFO拉低m_axis_tvalid信号,表示FIFO被读空

学新通

4、其他

  • 需要整个工程的朋友可以私信或者评论留下邮箱
  • 创作不易,希望各位大佬多多三连支持!一家之言,如有错误还请指正!


 

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgfahic
系列文章
更多 icon
同类精品
更多 icon
继续加载