4. 突发传输:AXI突发传输的基本概念
突发传输,说白了就是一次握手,传一堆数据。我刚开始接触AXI时,总觉得这玩意儿有点绕。后来做项目多了,才发现它其实是总线效率的灵魂。
你想想看,如果没有突发传输,每次读写都要单独发地址、等握手,那效率得多低?AXI的突发机制,就是让你发一次地址,然后连续传多个数据。嗯,这里要注意,地址通道和数据通道是分开的,所以可以流水线操作。
4.1 什么是突发传输?
突发传输的核心思想很简单:一次地址请求,多次数据传输。
举个例子,你想从地址0x1000开始读4个32位的数据。如果没有突发,你得发4次读地址、等4次读数据。有了突发,你只需要发一次地址(0x1000),然后连续收4个数据回来。
我个人习惯把突发长度(Burst Length)和突发大小(Burst Size)放在一起看。突发长度就是一次传多少笔数据,突发大小就是每笔数据有多少字节。两者相乘,就是一次突发传输的总数据量。
关键参数:
- ARLEN/AWLEN:突发长度,实际传输笔数 = ARLEN + 1
- ARSIZE/AWSIZE:突发大小,每笔数据的字节数(1、2、4、8字节等)
- ARBURST/AWBURST:突发类型,决定地址如何变化
我在项目中遇到过一个问题:有人把ARLEN设成了3,以为传3笔数据。结果只传了3笔,少了一笔。为什么?因为ARLEN=3表示传4笔(0、1、2、3)。这个坑我踩过,所以现在每次配置都会加1再检查一遍。
4.2 三种突发类型
AXI定义了三种突发类型,分别是FIXED、INCR和WRAP。它们决定了每次传输后地址怎么变。
| 突发类型 | 编码 | 地址变化方式 | 典型应用场景 |
|---|---|---|---|
| FIXED | 00 | 地址不变 | FIFO、状态寄存器 |
| INCR | 01 | 地址递增 | 内存连续读写、DMA |
| WRAP | 10 | 地址递增,到边界回绕 | Cache line fill、缓存行操作 |
4.3 FIXED:固定地址突发
FIXED突发,地址从头到尾都不变。每次传输都访问同一个地址。
这玩意儿什么时候用?我告诉你,最典型的就是访问FIFO。FIFO的读端口只有一个地址,你读一次,数据出来,地址还是那个地址。再读一次,数据又出来,地址还是不变。
还有状态寄存器。比如你想连续读某个状态寄存器的值,用FIXED突发就很合适。每次读的都是同一个寄存器,但数据可能因为硬件状态变化而不同。
小技巧:FIXED突发时,数据顺序很重要。比如你写FIFO,第一笔数据是第一个字,第二笔是第二个字。如果顺序搞反了,数据就乱了。我一般会在RTL里加个计数器,确保数据顺序和预期一致。
4.4 INCR:增量地址突发
INCR突发是最常用的类型。每次传输后,地址增加一个突发大小(ARSIZE)。
比如你从0x1000开始,ARSIZE=4(4字节),突发长度=4。那么地址变化是:
第1笔:0x1000
第2笔:0x1004
第3笔:0x1008
第4笔:0x100C
说白了,就是连续的内存地址。DMA传数据、CPU读内存、写帧缓冲,基本都是INCR。我做过一个视频处理的项目,从DDR读图像数据,用的就是INCR突发。一次读64字节,效率比单次读写高了好几倍。
这里要注意,INCR突发的地址可以跨4KB边界吗?嗯,AXI协议允许,但很多从设备不支持。我建议你设计时尽量让突发不跨4KB边界,否则可能会触发从设备的地址对齐错误。
避坑指南:我曾经遇到一个bug,INCR突发的起始地址没有对齐到突发大小。比如ARSIZE=8(8字节),但起始地址是0x1004。结果从设备返回的数据全是乱的。后来查协议才发现,INCR突发的起始地址必须对齐到ARSIZE。这个坑,我劝你别踩。
4.5 WRAP:回绕地址突发
WRAP突发,名字就说明了它的特点:地址递增,但到了边界就绕回来。
这个边界怎么算?边界 = 突发长度 × 突发大小。比如突发长度=4,突发大小=4字节,那么边界就是16字节。地址从起始地址开始,递增到边界-1,然后绕回起始地址。
举个例子,起始地址0x100C,突发长度=4,突发大小=4字节:
第1笔:0x100C
第2笔:0x1010 (注意,这里到了边界?不,边界是0x100C + 16 = 0x101C)
第3笔:0x1014
第4笔:0x1018
等等,不对。让我重新算一下。
正确示例:
起始地址:0x100C
突发长度:4(传4笔)
突发大小:4字节
边界 = 4 × 4 = 16字节
地址范围:0x100C ~ 0x101B(共16字节)
第1笔:0x100C
第2笔:0x1010
第3笔:0x1014
第4笔:0x1018
没有回绕?嗯,因为起始地址0x100C + 16 = 0x101C,而0x1018还没到边界。
再换个例子:
起始地址:0x101C
突发长度:4
突发大小:4字节
边界 = 16字节
地址范围:0x101C ~ 0x102B
第1笔:0x101C
第2笔:0x1020
第3笔:0x1024
第4笔:0x1028
还是没有回绕?哦,我明白了。WRAP的回绕发生在地址达到边界时,但边界是起始地址对齐到突发总大小的结果。
让我重新说清楚:
WRAP的边界 = 起始地址对齐到(突发长度 × 突发大小)的地址。
比如起始地址0x101C,突发长度=4,突发大小=4,那么对齐到16字节边界就是0x1010。
地址范围:0x1010 ~ 0x101F(共16字节)
第1笔:0x101C
第2笔:0x1020 → 超过0x101F,回绕到0x1010
第3笔:0x1014
第4笔:0x1018
WRAP突发最常见的应用场景是Cache line fill。CPU从内存读一个缓存行,比如64字节。如果缓存行起始地址是0x1000,但CPU只想要0x101C开始的16字节,那就用WRAP突发,从0x101C开始读,绕回0x1000,正好读完整个缓存行。
核心区别总结:
- FIXED:地址不变,适合FIFO、寄存器
- INCR:地址递增,适合连续内存
- WRAP:地址递增后回绕,适合缓存操作
4.6 如何选择突发类型?
我个人的经验是:
- 如果访问的是FIFO或状态寄存器,用FIXED。别用INCR,否则地址会跑飞。
- 如果访问的是连续内存(DDR、SRAM),用INCR。这是最通用的选择。
- 如果做Cache控制器,用WRAP。但要注意,WRAP的突发长度只能是2、4、8、16,不能是其他值。
还有一个细节:INCR和WRAP的地址变化步长都是突发大小(ARSIZE),但WRAP多了边界回绕的逻辑。设计从设备时,WRAP的处理比INCR复杂一些,因为你要判断地址是否到了回绕点。
4.7 知识体系图
下面这张图展示了突发传输的核心概念和三种类型的区别:
这张图把突发传输的核心参数和三种类型的关系画清楚了。你设计时,先确定用哪种类型,再配好长度和大小,基本就稳了。
最后说一句:突发传输是AXI的精髓。我见过很多新手,一上来就只用INCR,遇到FIFO也硬上INCR,结果地址乱飞。其实FIXED和WRAP各有各的用处,选对了,性能能翻倍。选错了,debug能让你怀疑人生。