轻松 handle AXIS 总线 tready 信号
在 AXIS 总线数据输入阶段, DataMover 的 tready 信号并不会总处于高电平的接收就绪状态,会在一段时间内为低电平,这就要求主机在 tready 为低电平时,hold 住当前要传输的数据,直到 tready 恢复高电平。
根据仿真在复位之后的第一次传输中会发生这种现象,后续的传输中随着写入数据的增加,DataMover 由于逻辑 AXIS 写入数据和 AXI 存储接口写出速度不均衡(如 DDR/EMMC 等存储介质会出现写 busy 现象),还会产生类似的 tready 为低电平现象。
总而言之,如果不想增加逻辑来 handle tready 信号为低怎么办?
可以在 DataMover AXIS 总线接口之前增加一个 AXIS 接口的 FIFO,用户操作 FIFO 的总线而不是 DataMover 的总线接口。 FIFO 一般在满时才需要处理 tready 为低的情况。
增加AXIS的读写FIFO接口
增加 FIFO 的另一个好处是可以增加 DataMover 的缓冲区空间,并可以按照需求来调整缓冲区的大小。
经过FIFO缓冲和重整的 tready 时序
非对齐传输
在计算机世界中,地址是以字节为单位来组织,每个地址对应一个的就是一个字节(8bit)。好比字节就是地址编码的基础单位。
但是,我们往往会看到在计算机系统中,地址的递增有时不是以 1 为单位,而是以 4/8 为单位,比如上图中上方的箭头指向 Byte0,地址加 4 后指向 Byte4。这里的 4/8 字节对应的是计算机中数据类型的长度,比如 32 位系统中,一个 int 变量的长度为 4Byte ,那么反映到地址上,从当前的 int 变量访问顺序存储的下一个 int 变量,地址递增 4。
但是从计算机组成原理的角度,考虑到访问存储的效率,每次 CPU 存取数据的位宽应该保持一致,并等于每个时钟 CPU 能够处理的最大数据位宽。这个最大数据位宽就是我们通常说的 32/64 位,CPU 的字长。
当读写地址和 CPU 字长对齐时,比如 32 位系统,地址是从 0x0 开始,每隔 32 bit 也就是 4 字节的地址被称为对齐地址。(即 0x0,0x4,0x8....),并且读写字长整数倍字节数的操作被称为地址对齐读写。地址对齐操作的效率最高,总结一下,对齐操作指的是:
- 起始地址是 CPU 字长的整数倍
- 读写数据字节数也为字长整数倍
那回到我们的 DataMover 访问 DDR 的子系统的应用中,这里没有 CPU ,那么对齐指的就是和存储系统的位宽对齐。(PC 中的存储系统为了更高效的访存,位宽一般就等于 CPU 的字长),我们通过 MIG 访问 DDR,所以对齐操作指的是和 MIG 的 AXI 总线位宽对齐。
但在嵌入式系统中,我们往往会有一些非对齐读写需求,比如保存一段长度与存储位宽不一致的数据。DataMover 通过一个重对齐引擎来支持非对齐操作,在 IP 核设置中开启。
在未开启非对齐传输功能的情况下,直接进行非对齐传输可能会导致读写数据错误的情况发生,因为 DataMover 会在未做重对齐的情况直接对数据做截断,导致数据传输错误。
OK!如果只是想通过 DataMover 来进行非对齐传输,勾上这个就完事了,Enjoy it.
如果还想了解一下 DataMover 是如何对非对齐传输进行数据重对齐的同学可以继续往下看 -_-|。
起始地址未对齐的非对齐传输
接下来我们通过一个例子来了解 DataMover 在非对齐传输中的数据重对齐操作。
数据位宽 256b(32B),起始地址为 0x01,显然这是一个非对齐地址,写入 65536 个字节数据(32 * 128B)。
AXIS 写入通道写入对齐的数据。
DataMover 接收来自 AXIS 的数据后,会在 AXI 通道上对数据进行重对齐,我们首先从第一次传输操作来看:
因为起始地址为0x1,原本32字节被重整为31字节,写入数据宽度32B,最低字节通过wstrb屏蔽。比较上二图中可以看到最高位的 0x12 没有在未在此次传输。DataMover 起始地址的非对齐策略是在第一次传输根据起始的未对齐地址进行一次非对齐传输,将第二次的传输的起始地址对齐。此处:
- 第一次传输起始地址为 0x01 ,传输 31 字节;第二次传输开始,地址就对齐了。
- AXIS 输入数据 32 字节宽度,总共传输 32 * 128 = 4096 个字节
- 第一个 32 字节的数据,传输低 31 字节,最高字节放到第二次传输中,以此类推,直到最后一次传输 1 个孤零零的字节。
下图就是第二次传输,可以看到最低字节上是来自前一次传输剩下的最高字节 0x12。其余 31 字节为第二个 32 字节数据的低 31 字节。
直到最后一次传输,通过 wstrb 信号控制,只传输了 1 个字节,这个字节就是最后一个 32 字节数据的最高字节,由于起始地址不对称为 0x1,最后字节的地址顺延到 0x01 + 4096 - 1 = 4096.
下面这张图可以概括上述的内容,AXIS 的数据经过重对齐引擎,得到非对齐传输的 AXI 总线信号。(PS:个人感觉这是笔者画过最漂亮的图了-_-)
起始地址不对齐的读传输可以理解为写传输的反过程。通过读命令去读刚刚写入的数据,读 AXI 总线上得到的数据和 DataMover 在写总线的信号是相同的。 区别在于读总线没有类似 wstrb 的读 strb 信号,需要主机 DataMover 根据传输的信息(传输起始地址,传输字节数)来从非对齐的 AXI 读数据中获得有效的数据。
起始地址对齐,但传输字节数不对齐的传输
此类传输要较前一种简单,因为除了最后一次 AXI 传输,先前的传输都是对齐的。这里不再展开讨论了。至于你说起始地址和传输字节都不对齐的情况,那就优先考虑起始地址不对齐的处理方式吧。
结语
本文作为进阶篇的第二篇内容有点少哈,讨论了如何通过在 DataMover 之前增加 FIFO,简化 tready 信号的用户控制逻辑。并花了一些篇幅讨论了非对齐传输的概念,DataMover 非对齐传输的原理以及机制。在后续的文章中,我们将讨论先前未提及的传输命令字段,尤其是和非对齐传输相关的字段。此外我们将讨论 DataMover AXI burst 长度对读写 DDR 的性能影响以及其他的进阶内容。