一文快速掌握DataMover IP的使用教程

作者: FPGA入门到精通

AXI DataMover IP是Xilinx提供的一种高性能数据传输模块,它能够实现在AXI4内存映射域和AXI4-Stream域之间的高效数据移动。

DataMover IP的使用可以大大简化数据传输的复杂性,提高设计的性能,这个IP在Xilinx中各种复杂DMA IP中都有应用,比如VDMA、XDMA等等。

本文将从基础概念入手,逐步深入到AXI DataMover IP的配置和使用,帮助读者快速掌握这一强大的IP核。

一、AXI DataMover IP概述

1、DataMover 是什么?

AXI DataMover是一个高度可配置的IP核,它支持在AXI4和AXI4-Stream两种不同的接口之间进行数据传输。

简单理解就是上层程序告诉DataMover,从哪里(起始地址)开始,搬数据(读数据或写数据),搬多少数据(数据长度)!

1.png

DataMover有两个数据传输通道:

(1)MM2S(Memory to Stream):从AXI4内存映射域读取数据到AXI4-Stream域。

2.png

(2)S2MM(Stream to Memory):从AXI4-Stream域写入数据到AXI4内存映射域。

3.png

不管是MM2S还是S2MM的通道,都包含:

  • 命令逻辑FIFO,存储一系列的命令参数,可以排队;

  • 状态逻辑FIFO,存储每个命令执行的结果,可报错;

  • 读写引擎,读写引擎负责执行命令、协议转换。

这两个通道以类似全双工的方式独立运行。AXI DataMover IP 核是一个关键构建块,具有 4 KB 地址边界保护、自动突发分区功能,并且能够使用 AXI4-Stream 协议的几乎全部带宽功能,可以对多个传输请求进行排队。

2、DataMover 命令

这个命令主要参数是读写起始地址、数据长度。

实际的地址宽度与DDR MIG IP有关,用N表示,一般默认取32bit,同时地址宽度也决定了命令长度。

命令格式如下:

4.png

具体的内容含义:

5.JPG

命令时序示例:

6.png

DataMover 元素的命令接口可以允许命令FIFO 中排队。

3、Status Interface 状态接口与接口时序

状态接口,用于反馈命令执行的结果。

状态接口格式如下:

7.png

状态字节描述:

  • OKAY:值为1表示执行命令成功,值为0表示执行命令失败。

  • SLVERR:从机错误,值为1表示错误,值为0表示正常。

  • DECERR:解码错误,一般是地址错误,值为1表示错误,值为0表示正常。

  • INTERR:内部错误,要求DMA发0个数据,tlast信号到来的时间不对等均会引发内部错误,值为1表示错误,值为0表示正常。

  • TAG:对应命令中的TAG。

命令时序示例:

8.png

除了状态接口可查询执行状态外,另外提供s2mm_err/mm2s_err信号,出现错误时,就会拉高。

需要注意的是,如果DataMover出现报错的话会停止工作,只有将DataMover复位后,才能继续执行新的命令。

二、AXI DataMover IP 使用

1、调用DataMover IP

在vivado中打开IP Catalog,输入DataMover,双击打开DataMover IP。

9.png

2、基本参数设置界面

10.png

Enable MM2S :此框允许您配置 MM2S 通道选项。


Enable S2MM :此框允许您配置 S2MM 通道选项

Channel Type:通道类型 – 选择“完整”或“基本”。选择“完整”允许为所有可能的组合和高级功能配置 MM2S 通道。基本模式限制了某些功能,并允许 MM2S 仅用于 32 位或 64 位宽的数据。

Memory Mapped Data Width:内存映射数据宽度 — 指定 AXI4 读取总线的数据宽度(以位为单位)。有效值为 32、64、128、256、512 和 1,024。根据频道类型,这些选项会有所不同。

Stream Data Width:流数据宽度 – 指定 MM2S 流总线的数据宽度(以位为单位)。有效值为 8、16、32、64、128、256、512 和 1,024。此值不能大于内存映射数据宽度。

Maximum Burst Size:最大突发大小

Bytes To Transfer (BTT) Bit Used:要传输的字节数 (BTT) 已用位数 – 指定 MM2S 命令的 BTT 数字段中的有效位数。有效选项为 8 到 23。

Enable xCache and xUser:启用 xCache 和 xUser - 如果要更改 AXI4 接口的 *cache 和 *user 信号,请选择此选项。

Enable MM2S Control Signals, Enable S2MM Control Signals:启用 MM2S 控制信号,启用 S2MM 控制信号 - 启用此功能会暴露 MM2S、S2MM 接口的所有控制和状态信号。启用后,您需要小心连接信号。默认情况下,它们不会公开并绑定到默认状态。

Address Width (32 -64):地址宽度 (32 -64) - 指定地址空间的宽度。它可以是介于 32 和 64 之间的任何值。

3、Advanced Options 高级选项

11.png

这是配置MM2S 和 S2MM 通道的高级选项。

Enable Asynchronous Clocks:启用异步时钟 – 此设置允许使用 MM2S 内存映射接口异步操作 MM2S 命令和状态流接口。

Allow Unaligned Transfers:允许未对齐传输 – 此设置启用或禁用 MM2S 数据重新对齐引擎 (DRE)。选中后,DRE 被启用,并允许数据重新对齐到 MM2S 内存映射数据路径上的字节(8 位)级别。对于 MM2S 通道,数据从存储器中读取。如果启用了 DRE,则数据读取可以从任何缓冲区地址偏移量开始,并且读取数据将对齐,以便读取的第一个字节是 AXI4-Stream 上的第一个有效字节输出。对齐或未对齐的内容基于内存映射数据宽度。

Enable Store and Forward:启用存储和转发 – 此设置提供 MM2S 存储和转发功能的包含/省略。此选项仅在“完整”模式下可用。此外,当内存映射数据宽度与流数据宽度不同时,此选项始终处于启用状态。

ID width:ID宽度 — 此值设置ID端口的宽度。将此值设置为 0 将禁用 ID 端口。

ID Value:ID值 — 这是放在ID端口上的值。

4、DataMover的接口


axi_datamover_0 u_axi_datamover_0 (


   ///////////////mm2s////////////////////

  .m_axi_mm2s_aclk(m_axi_mm2s_aclk),                        // input wire m_axi_mm2s_aclk

  .m_axi_mm2s_aresetn(m_axi_mm2s_aresetn),                  // input wire m_axi_mm2s_aresetn


  .mm2s_err(mm2s_err),                                      // output wire mm2s_err


  //cmd

  .m_axis_mm2s_cmdsts_aclk(m_axis_mm2s_cmdsts_aclk),        // input wire m_axis_mm2s_cmdsts_aclk

  .m_axis_mm2s_cmdsts_aresetn(m_axis_mm2s_cmdsts_aresetn),  // input wire m_axis_mm2s_cmdsts_aresetn

  .s_axis_mm2s_cmd_tvalid(s_axis_mm2s_cmd_tvalid),          // input wire s_axis_mm2s_cmd_tvalid

  .s_axis_mm2s_cmd_tready(s_axis_mm2s_cmd_tready),          // output wire s_axis_mm2s_cmd_tready

  .s_axis_mm2s_cmd_tdata(s_axis_mm2s_cmd_tdata),            // input wire [71 : 0] s_axis_mm2s_cmd_tdata


  //sts status

  .m_axis_mm2s_sts_tvalid(m_axis_mm2s_sts_tvalid),          // output wire m_axis_mm2s_sts_tvalid

  .m_axis_mm2s_sts_tready(m_axis_mm2s_sts_tready),          // input wire m_axis_mm2s_sts_tready

  .m_axis_mm2s_sts_tdata(m_axis_mm2s_sts_tdata),            // output wire [7 : 0] m_axis_mm2s_sts_tdata

  .m_axis_mm2s_sts_tkeep(m_axis_mm2s_sts_tkeep),            // output wire [0 : 0] m_axis_mm2s_sts_tkeep

  .m_axis_mm2s_sts_tlast(m_axis_mm2s_sts_tlast),            // output wire m_axis_mm2s_sts_tlast


  //AXI4-FULL

  .m_axi_mm2s_arid(m_axi_mm2s_arid),                        // output wire [3 : 0] m_axi_mm2s_arid

  .m_axi_mm2s_araddr(m_axi_mm2s_araddr),                    // output wire [31 : 0] m_axi_mm2s_araddr

  .m_axi_mm2s_arlen(m_axi_mm2s_arlen),                      // output wire [7 : 0] m_axi_mm2s_arlen

  .m_axi_mm2s_arsize(m_axi_mm2s_arsize),                    // output wire [2 : 0] m_axi_mm2s_arsize

  .m_axi_mm2s_arburst(m_axi_mm2s_arburst),                  // output wire [1 : 0] m_axi_mm2s_arburst

  .m_axi_mm2s_arprot(m_axi_mm2s_arprot),                    // output wire [2 : 0] m_axi_mm2s_arprot

  .m_axi_mm2s_arcache(m_axi_mm2s_arcache),                  // output wire [3 : 0] m_axi_mm2s_arcache

  .m_axi_mm2s_aruser(m_axi_mm2s_aruser),                    // output wire [3 : 0] m_axi_mm2s_aruser

  .m_axi_mm2s_arvalid(m_axi_mm2s_arvalid),                  // output wire m_axi_mm2s_arvalid

  .m_axi_mm2s_arready(m_axi_mm2s_arready),                  // input wire m_axi_mm2s_arready

  .m_axi_mm2s_rdata(m_axi_mm2s_rdata),                      // input wire [511 : 0] m_axi_mm2s_rdata

  .m_axi_mm2s_rresp(m_axi_mm2s_rresp),                      // input wire [1 : 0] m_axi_mm2s_rresp

  .m_axi_mm2s_rlast(m_axi_mm2s_rlast),                      // input wire m_axi_mm2s_rlast

  .m_axi_mm2s_rvalid(m_axi_mm2s_rvalid),                    // input wire m_axi_mm2s_rvalid

  .m_axi_mm2s_rready(m_axi_mm2s_rready),                    // output wire m_axi_mm2s_rready


  //AXI4-Stream

  .m_axis_mm2s_tdata(m_axis_mm2s_tdata),                    // output wire [31 : 0] m_axis_mm2s_tdata

  .m_axis_mm2s_tkeep(m_axis_mm2s_tkeep),                    // output wire [3 : 0] m_axis_mm2s_tkeep

  .m_axis_mm2s_tlast(m_axis_mm2s_tlast),                    // output wire m_axis_mm2s_tlast

  .m_axis_mm2s_tvalid(m_axis_mm2s_tvalid),                  // output wire m_axis_mm2s_tvalid

  .m_axis_mm2s_tready(m_axis_mm2s_tready),                  // input wire m_axis_mm2s_tready


  //////////////S2MM/////////////////////

  .m_axi_s2mm_aclk(m_axi_s2mm_aclk),                        // input wire m_axi_s2mm_aclk

  .m_axi_s2mm_aresetn(m_axi_s2mm_aresetn),                  // input wire m_axi_s2mm_aresetn

  .s2mm_err(s2mm_err),                                      // output wire s2mm_err


  //cmd

  .m_axis_s2mm_cmdsts_awclk(m_axis_s2mm_cmdsts_awclk),      // input wire m_axis_s2mm_cmdsts_awclk

  .m_axis_s2mm_cmdsts_aresetn(m_axis_s2mm_cmdsts_aresetn),  // input wire m_axis_s2mm_cmdsts_aresetn

  .s_axis_s2mm_cmd_tvalid(s_axis_s2mm_cmd_tvalid),          // input wire s_axis_s2mm_cmd_tvalid

  .s_axis_s2mm_cmd_tready(s_axis_s2mm_cmd_tready),          // output wire s_axis_s2mm_cmd_tready

  .s_axis_s2mm_cmd_tdata(s_axis_s2mm_cmd_tdata),            // input wire [71 : 0] s_axis_s2mm_cmd_tdata


  //sts

  .m_axis_s2mm_sts_tvalid(m_axis_s2mm_sts_tvalid),          // output wire m_axis_s2mm_sts_tvalid

  .m_axis_s2mm_sts_tready(m_axis_s2mm_sts_tready),          // input wire m_axis_s2mm_sts_tready

  .m_axis_s2mm_sts_tdata(m_axis_s2mm_sts_tdata),            // output wire [7 : 0] m_axis_s2mm_sts_tdata

  .m_axis_s2mm_sts_tkeep(m_axis_s2mm_sts_tkeep),            // output wire [0 : 0] m_axis_s2mm_sts_tkeep

  .m_axis_s2mm_sts_tlast(m_axis_s2mm_sts_tlast),            // output wire m_axis_s2mm_sts_tlast


  //AXI4-FULL

  .m_axi_s2mm_awid(m_axi_s2mm_awid),                        // output wire [3 : 0] m_axi_s2mm_awid

  .m_axi_s2mm_awaddr(m_axi_s2mm_awaddr),                    // output wire [31 : 0] m_axi_s2mm_awaddr

  .m_axi_s2mm_awlen(m_axi_s2mm_awlen),                      // output wire [7 : 0] m_axi_s2mm_awlen

  .m_axi_s2mm_awsize(m_axi_s2mm_awsize),                    // output wire [2 : 0] m_axi_s2mm_awsize

  .m_axi_s2mm_awburst(m_axi_s2mm_awburst),                  // output wire [1 : 0] m_axi_s2mm_awburst

  .m_axi_s2mm_awprot(m_axi_s2mm_awprot),                    // output wire [2 : 0] m_axi_s2mm_awprot

  .m_axi_s2mm_awcache(m_axi_s2mm_awcache),                  // output wire [3 : 0] m_axi_s2mm_awcache

  .m_axi_s2mm_awuser(m_axi_s2mm_awuser),                    // output wire [3 : 0] m_axi_s2mm_awuser

  .m_axi_s2mm_awvalid(m_axi_s2mm_awvalid),                  // output wire m_axi_s2mm_awvalid

  .m_axi_s2mm_awready(m_axi_s2mm_awready),                  // input wire m_axi_s2mm_awready

  .m_axi_s2mm_wdata(m_axi_s2mm_wdata),                      // output wire [511 : 0] m_axi_s2mm_wdata

  .m_axi_s2mm_wstrb(m_axi_s2mm_wstrb),                      // output wire [63 : 0] m_axi_s2mm_wstrb

  .m_axi_s2mm_wlast(m_axi_s2mm_wlast),                      // output wire m_axi_s2mm_wlast

  .m_axi_s2mm_wvalid(m_axi_s2mm_wvalid),                    // output wire m_axi_s2mm_wvalid

  .m_axi_s2mm_wready(m_axi_s2mm_wready),                    // input wire m_axi_s2mm_wready

  .m_axi_s2mm_bresp(m_axi_s2mm_bresp),                      // input wire [1 : 0] m_axi_s2mm_bresp

  .m_axi_s2mm_bvalid(m_axi_s2mm_bvalid),                    // input wire m_axi_s2mm_bvalid

  .m_axi_s2mm_bready(m_axi_s2mm_bready),                    // output wire m_axi_s2mm_bready


  //AXI4-Stream

  .s_axis_s2mm_tdata(s_axis_s2mm_tdata),                    // input wire [31 : 0] s_axis_s2mm_tdata

  .s_axis_s2mm_tkeep(s_axis_s2mm_tkeep),                    // input wire [3 : 0] s_axis_s2mm_tkeep

  .s_axis_s2mm_tlast(s_axis_s2mm_tlast),                    // input wire s_axis_s2mm_tlast

  .s_axis_s2mm_tvalid(s_axis_s2mm_tvalid),                  // input wire s_axis_s2mm_tvalid

  .s_axis_s2mm_tready(s_axis_s2mm_tready)                  // output wire s_axis_s2mm_tready

);

三、代码使用示例

写命令代码示例


always@(posedge clk or posedge reset) begin

    if(reset) begin

        s_axis_s2mm_cmd_tvalid <= 0;

        burst_addr <= 0;

    end else begin

        if(s_axis_s2mm_cmd_tready&&s_axis_s2mm_cmd_tvalid)

            s_axis_s2mm_cmd_tvalid <= 1'b0;

        else if(fifo_in_wr_req) //输入fifo已缓存一定数据

            s_axis_s2mm_cmd_tvalid <= 1'b1;

    end

end


assign s_axis_s2mm_cmd_tdata = s_axis_s2mm_cmd_tvalid ? {9'd0,burst_addr,2'b01,6'd0,1'b1,BTT[22:0]} : 72'b0;

参考上面的代码编写读写命令代码。

最新文章

最新文章