最近发现工程项目中一直在用AXI-DMA。这玩意儿搬数据倒是没问题,就是用axi-lite配置起来非常反人类。。。简单的办法其实是用datamover ip核。
这个ip核能干嘛呢。准备写个文章解析一下。由于好多feature没用过,所以仅仅看文档可能理解有误,欢迎指出错误。
首先扫个盲:MM2S指的是Memory map to stream. 读DDR. S2MM指的是steam to memory map. 写DDR.
Datamover能干嘛
- 能把数据以axi_stream的格式从DDR里搬入搬出
- 支持4KB的边界保护以及自动拆解太长的burst
- 可以排队处理多次读写请求
- 支持字节为单位的非对齐传输
- 支持store-and-forward模式。也就是MM2S的时候先把数据缓存下来,再分发出去
- 支持indeterminate BTT mode。也就是说。。S2MM的时候你甚至不需要知道你要写多少数。
简单的使用方法
上图是一个读操作的。写的类似。接口只有4个。
- 把你要搬数据的信息例如起始地址,数据长度等以axi-stream的形式捅到command端口。
- AXI4 Master接到DDR上(实际是接到MIG上)。
- AXI4 Stream Master就是读出来的数。
- AXI-Stream status是状态。拿出来容易debug.
你应该往AXI4-STREAM SLAVE(command)端口里捅什么
这个东西的重中之重显然就是command指令。
指令格式如上面的样子。读写都是一样的。一个一个来讲。
xCACHE: 这个一共4bit. 用于配置axi总线一些cache性质的。感兴趣参考AXI的文档。不关心全给成0. 主要是一个cache相关的东西。
xUSER: 4bit.这个是你自己定义的信号。。也就是说你想用axi总线穿点儿私货。。那就要把数据写到这个地方。到时候axi传输的时候会出现在user端口。
RSVD: Reserved... 干什么的显然。。。
TAG: 这个是给该条指令个一个标签。有这个TAG在出了错debug的时候可以报是哪条指令出错了。当然你要是头铁觉得不用DEBUG. TAG全给0.
SADDR: 读写DDR里的初始地址。要注意的是如果你想非对齐传输,配置Datamover的时候要把非对齐传输点开。(例如ddr指定的是32bit, 对齐传输是指你从0,4,8这些地址开始读,非对齐传输是指你想从1开始读)
DRR: 这个数据就比较绕了。。。这个数据是后面DSA的开关。主要是为了调整Stream端(而不是memory端,memory端直接由SADDR地址就能确定)非对齐操作的位置,也就是说,这个值表示该条指令对应的传输需要对stream端数据做调整。具体怎么调整看后面的DSA. 用在MM2S.
EOF: 这个数据一样比较绕。先说简单的。
在S2MM的过程中,如果INDETERMINATE BTT模式关闭,你想用tlast信号表示你写完了,那么EOF要置高。
在MM2S的过程中,同时存在多条指令。你想让最后一条读出来后再来tlast. 那就只在最后一条置高这个EOF. 如果你开启来非对齐传输。。。最好每条都置高。否则你得注意两条指令之间不会不有废数据。
DSA: 这个是为了调节stream侧的数据非对齐的。。。举个栗子。假如DDR是32bit的。那么它应该有4个byte. (从高到低 m3 m2 m1 m0)。这个DSA如果等于1。表明你会把数据m1放到stream的第一个数据。m0被丢掉了。。。所以如果需要这种操作,就打开DRR, 配置DSA. 否则DRR也不需要打开。
Type: 这个表示你的地址要不要累加。。如果不累加你就是在起始地址疯狂写。所以一般传输要是一整块的话这个要置1.
BTT: 这个简单。你要传输多少个数。。。注意单位是byte. 不是你axi_stream的宽度。
配置IP CORE需要注意的点
Stream端的数据位宽要小于或者等于AXI4端的数据位宽。配置IP核的时候就会提示。
配置界面上Maximum Burst Size这个参数比较绕。指的是AXI总线的burst size. 一般来说设个16什么的就好。你给出的BTT会自动切成这种小的传输。
其他都很简单。。。看上面操作就能实现。
总结
这篇文章解读了一下读DDR的接个IP核。如果不想直接用AXI-FULL来读写DDR,要操作AXI_STREAM数据读写DDR的话,最常用的IP核是DMA和这个datamover。其中DMA更适合用PS来操作。更复杂功能更强大,但是实际使用起来比较复杂,尤其你想从PL写个AXILITE控制DMA的时候。。。所以。
从PL调用DDR直接用datamover才是比较合理的操作。就这这样。。。