LJgibbs · 2020年05月14日

从 IP 开始,学习数字逻辑:DataMover 基础篇

作者:李凡
来源:https://zhuanlan.zhihu.com/p/82129170

何为 DataMover

DataMover 很有趣的名字,他是谁,数据搬运工?那可得跟我们代码搬运工好生亲近下。-\_-

DataMover 是 DMA 的一种形式。Direct Memory Access 对我们来说是一个更熟悉的名字。在不需要 CPU 干预的情况下,DMA 可以进行数据的搬运,包括但不仅限于将数据从外部存储,比如 DDR,搬运到内部寄存器,或者搬运到外部存储的另一个位置。这些都只需要 CPU 一句话的事:

CPU:DMA, 帮我搬个数据!
DMA:BOSS,你只需要告诉我从哪搬(起始地址),搬多少(字节长度),搬到哪!

然后 CPU 就可以爱干嘛干嘛,数据的搬运,和 DDR 打交道就全权由 DMA 负责了。

我们今天讨论的 DataMover 和上述典型的 DMA 的区别就在于,他不是由 CPU 来分配任务,而是由 FPGA 逻辑通过命令总线给出任务:从哪搬,搬到哪。

DataMover 的接口

那么 DataMover 是如何进行他的工作呢,我们可以从他的端口来了解。这里以 DM 的读通道为例。DataMover 共有三路接口(status 一般在调试中用于观察状态),一路 AXI 总线,两路 AXIS 总线。


                                                                            AXI DataMover 读通道

读通道,将数据从如 DDR 这样的外部存储,搬运到 FPGA 的逻辑模块中。DDR 在 FPGA 上通过 MIG IP 访问,即 Memory 访问接口。MIG 提供了一个 AXI4 Slave 接口。DataMover 的 Master 接口连接到 MIG 的 Slave 接口,AXI4 协议提供了一种基于地址的访问 DDR 能力。关于 AXI4 对存储介质的地址访问,可以参考以下的文章,该文章中访问的是 BRAM ,但总线操作和访问 DDR 类似。
https://zhuanlan.zhihu.com/p/46672113


                                                              连接DDR示意图

如何创建 DDR MIG 在各个开发板的教程中都有提及,Step by Step 设置自己的开发板上搭载的 DDR 芯片信息和引脚即可。如果你有钱....有幸能用 Xilinx 的评估板,那么 MIG 还可以一键建立,自动导入硬件和 DDR 信息。

(我们实验室就是这么有钱...有幸有很多板子,包括 Xilinx ZCU102/VCU709/ KCU116 等等,如果对 FPGA 开发有兴趣,欢迎在今年以及未来的考/保研中加入我们实验室,我们有不错的硬件条件和项目。PS:坐标东部沿海211,省部共建国家重点实验室 )

无论是哪款开发板,都可以通过包含在 vivado 中的 MIG 中的示例工程对 MIG 进行仿真以及上板调试。
514.jpg
                                                                                              盗图自 xilinx PPT

从 MIG 中读取的 DDR 数据会以 AXI-Stream 总线的方式提供给逻辑部分。 AXI-S 总线相比 上述的 AXI4-Full 协议,信号更少,逻辑也比较简单。你可以从以下的文章中了解 AXI-S 的定义:https://zhuanlan.zhihu.com/p/49834243

应用 AXI 协议没有定义说的那么复杂,以下是读取一段数据的示例。


                                                         简单的AXIS时序

tvalid 为高表示数据有效,tlast 置起表示当前是当次传输的最后一个数据,比如表示一次 DDR 读操作的结束。tkeep 表示数据中的有效字节,作用和 AXI4-Full 中的 strb 作用相同。

前文提到 DataMover 有两路 AXI-S 总线,一路总线是数据输出总线,将从 DDR 读取的数据输出。另一路为命令输入总线。

DataMover 命令

前文提到 DataMover 是由逻辑控制,控制的方式是通过命令输入 AXIS 总线输入 DataMover 命令。

DataMover 命令控制的就是读写操作的起始地址传输字节长度。命令有如下的格式,根据地址宽度的不同,命令长度不同,一般地址宽度,N,取 32 比特,命令长度 72 比特。


                                                                              命令格式

一般只需要关注三个字段,EOF 字段设为 1 ,其他字段可以暂时填 0,这些填充固定值的字段将在后续的文章中进行分析。

  • BTT:Byte to Transfer
  • 传输字节数
  • SADDR: start address
  • 起始地址
  • Type:
  • 突发传输类型,这个字段在过去的 IP 核版本中没有启用(ISE 时代),默认为 incr
  • 字段为 1 时:突发传输类型为 incr ,数据会保存在以起始地址开始递增的地址中
  • 字段为 0 时:突发传输类型为 fixed, 数据均保存在起始地址中,覆盖旧值

当地址为32bit宽时,cmd 为32(低32位)+32(地址)+4(TAG)+4(RSVD)=72 bit


                                                                            AXI DataMover 写通道
写通道的逻辑与读通道相同,只是数据的方向相反。

仿真

这部分中将演示 DataMover 基本的读写方式,输入由 testbench 产生。后续的文章中会讨论一些更加实用的逻辑,应用于板级调试中。

读操作

通过 testbench 写入命令,这里定义了一个写入命令的 task,将起始地址和字节长度组装成一个命令。这里 #UI\_CLK\_PERIOD; 代表延时一个周期

//task: read channel
task mm2s_cmd;
    input logic[22:0] btt;
    input logic[31:0] saddr;
    logic [71:0] cmd = {
                            4'b0000,
                            4'b0000,
                            saddr,
                            1'b0,//DRR
                            1'b1,//EOF
                            6'b000000,//DSA
                            1'b1,//type 1:incr 0:fixed
                            btt
        };
    begin
    S_AXIS_MM2S_CMD_0_tdata=cmd;
    S_AXIS_MM2S_CMD_0_tvalid=1;
    #UI_CLK_PERIOD;
    S_AXIS_MM2S_CMD_0_tdata=0;
    S_AXIS_MM2S_CMD_0_tvalid=0;
    end 
endtask

调用 task,指定传输的长度以及起始地址。

mm2s\_cmd(23'd64,32'h00000000);

514.png
                                                                                                  读数据时序

读取到 64 字节数据,因为数据位宽 32 字节,所以读到两个有效信号脉冲。

写操作

写入命令和读命令类似,写命令可以在写数据之前或者之后,没有严格的对应关系。通过 AXIS 总线写入数据, DataMover 内部有一定缓存空间,相当于向一个 FIFO 写入数据。定义了一个写入指定长度的 task ,写入 data\_num*32 bit 数据

//task:write data
 task s2mm_data;
 input logic [31:0] data_num;
 begin
        S_AXIS_S2MM_1_tvalid=1;
        S_AXIS_S2MM_1_tdata=256'h12345678123456781234567812345678;
        S_AXIS_S2MM_1_tkeep=32'hfffffffff;
        S_AXIS_S2MM_1_tlast=0;
        repeat(data_num-1)begin
        #UI_CLK_PERIOD;
        end
        S_AXIS_S2MM_1_tlast=1;
        #UI_CLK_PERIOD;
        S_AXIS_S2MM_1_tdata=0;
        S_AXIS_S2MM_1_tkeep=0;
        S_AXIS_S2MM_1_tlast=0;
        S_AXIS_S2MM_1_tvalid=0;
 end
endtask


                                                                          写命令与写数据时序

这里写入了两个32位宽的数据,在第二个数据处, tlast 信号置起,表示传输的最后一个有效数据,tlast 清除表示此次传输结束。

结语

本文是 DataMover 的基础篇,初步介绍了 IP 核的用途和用法,并通过 testbench 调用 IP 实现了读写操作。但没有涉及比较复杂的部分,比如未对齐传输等。如何使用这些更复杂的应用,以及如何将 DataMover 使用在实际项目中,我们将在后续的文章中进行讨论。

参考资料

https://www.xilinx.com/support/documentation/ip\_documentation/axi\_datamover/v5\_1/pg022\_axi\_datamover.pdfwww.xilinx.com

推荐阅读

关注此系列,请关注专栏FPGA的逻辑
推荐阅读
关注数
10614
内容数
577
FPGA Logic 二三事
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息