一、AXI通道详解:读地址通道、读数据通道、写地址通道、写数据通道、写响应通道的信号定义与握手协议
各位同学,咱们今天来聊聊AXI总线最核心的东西——五个独立通道。说实话,我刚接触AXI时也被这五个通道搞得有点晕,但后来发现,只要搞懂了它们各自的分工和握手方式,整个AXI互连的骨架就清晰了。
AXI协议把一次传输拆成了五个独立的通道,就像五条并行的流水线。这样做的好处很明显:读和写可以同时进行,地址和数据也能分开处理,效率自然就上去了。我当年在做一个多核处理器项目时,就是因为没处理好通道间的依赖关系,导致死锁,折腾了好几天才找到原因。嗯,咱们今天就把这些坑提前填上。
1.1 读地址通道(AR通道)
读地址通道,说白了就是主设备告诉从设备:「我要读数据,地址在这,你看着办。」这个通道的信号不多,但每个都很关键。
| 信号 | 方向 | 描述 |
|---|---|---|
| ARID | 主→从 | 读地址ID,用于标识一次传输事务 |
| ARADDR | 主→从 | 读起始地址 |
| ARLEN | 主→从 | 突发长度,表示一次突发传输包含多少笔数据 |
| ARSIZE | 主→从 | 每笔数据的字节数(2^ARSIZE字节) |
| ARBURST | 主→从 | 突发类型:FIXED、INCR、WRAP |
| ARVALID | 主→从 | 主设备指示地址有效 |
| ARREADY | 从→主 | 从设备准备好接收地址 |
这里有个细节我特别想强调:ARLEN表示的是「额外」的数据笔数。比如ARLEN=0表示一笔数据,ARLEN=3表示四笔数据。这个坑我踩过,当时仿真死活不对,查了半天才发现是ARLEN少加了1。
1.2 读数据通道(R通道)
读数据通道是从设备把数据返回给主设备的通道。它和读地址通道是配对的——你发一个地址,我回一堆数据。
| 信号 | 方向 | 描述 |
|---|---|---|
| RID | 从→主 | 读数据ID,必须与ARID匹配 |
| RDATA | 从→主 | 读回来的数据 |
| RRESP | 从→主 | 读响应状态:OKAY、EXOKAY、SLVERR、DECERR |
| RLAST | 从→主 | 指示最后一笔数据 |
| RVALID | 从→主 | 从设备指示数据有效 |
| RREADY | 主→从 | 主设备准备好接收数据 |
注意看,R通道里有个RLAST信号,它告诉主设备:「这是最后一笔了,别再等了。」我见过不少新手设计时忘了检查RLAST,导致读操作永远停不下来。嗯,这个信号在突发传输中特别重要。
1.3 写地址通道(AW通道)
写地址通道和读地址通道几乎一模一样,只是方向不同。主设备通过它告诉从设备:「我要往这个地址写数据。」
| 信号 | 方向 | 描述 |
|---|---|---|
| AWID | 主→从 | 写地址ID |
| AWADDR | 主→从 | 写起始地址 |
| AWLEN | 主→从 | 突发长度 |
| AWSIZE | 主→从 | 每笔数据字节数 |
| AWBURST | 主→从 | 突发类型 |
| AWVALID | 主→从 | 地址有效 |
| AWREADY | 从→主 | 从设备准备好 |
我个人习惯把AW通道和AR通道放在一起设计,因为它们本质上就是一对镜像。你想想看,地址通道的握手协议完全一样,只是数据流方向不同而已。
1.4 写数据通道(W通道)
写数据通道是主设备把要写的数据发送给从设备。这里有个有意思的地方——写地址和写数据是分开的通道,这意味着地址可以先发,数据后到,或者反过来也行。
| 信号 | 方向 | 描述 |
|---|---|---|
| WID | 主→从 | 写数据ID(注意:AXI4中已废弃) |
| WDATA | 主→从 | 写数据 |
| WSTRB | 主→从 | 字节选通信号,指示哪些字节有效 |
| WLAST | 主→从 | 最后一笔数据指示 |
| WVALID | 主→从 | 数据有效 |
| WREADY | 从→主 | 从设备准备好接收数据 |
WSTRB这个信号我得重点说说。它是个位宽等于数据总线字节数的掩码信号。比如64位数据总线,WSTRB就是8位。哪一位为1,对应的字节就有效。我曾经遇到一个bug,就是WSTRB没处理好,导致写进去的数据全是乱的。后来发现是字节对齐没做对。
1.5 写响应通道(B通道)
写响应通道是从设备给主设备的反馈:「你写的数据我收到了,结果如何?」这个通道只有一笔响应,对应一次完整的写突发传输。
| 信号 | 方向 | 描述 |
|---|---|---|
| BID | 从→主 | 响应ID,必须与AWID匹配 |
| BRESP | 从→主 | 写响应状态 |
| BVALID | 从→主 | 响应有效 |
| BREADY | 主→从 | 主设备准备好接收响应 |
注意,写响应只有在所有数据都传输完成后才会发出。也就是说,从设备必须收到WLAST为高的那笔数据后,才能给出B通道的响应。这个顺序关系在设计中很容易被忽略。
1.6 握手协议:VALID与READY的舞蹈
AXI的握手协议其实就三个字:握手。发送方拉高VALID,接收方拉高READY,当两者都为高时,数据就在时钟上升沿被采样。
这里有三种握手场景:
- VALID先到,READY后到:最常见的情况。发送方先准备好数据,接收方忙完后再接收。
- READY先到,VALID后到:接收方提前告诉发送方「我准备好了」,发送方再发数据。
- 同时到达:一拍搞定,效率最高。
我个人建议在设计中尽量让VALID和READY同时到达,这样可以减少延迟。但实际项目中,从设备往往需要几个周期才能准备好,所以VALID先到的情况更常见。
核心原则:VALID一旦拉高,必须保持到握手成功。READY可以随时拉高或拉低,但建议在握手成功后立即拉低,避免重复采样。
1.7 通道间的依赖关系
五个通道不是完全独立的,它们之间有明确的依赖关系。我画了一张图,帮你理清这些关系:
从图上可以看得很清楚:
- 读操作:必须先有AR通道的地址,才能有R通道的数据返回。
- 写操作:AW通道和W通道没有严格的先后顺序,可以地址先发,也可以数据先发,甚至可以同时发。但B通道的响应必须在W通道的最后一笔数据(WLAST)之后才能发出。
避坑指南:我曾经在一个项目中,写地址和写数据通道的握手顺序没处理好,导致从设备收到了地址但数据迟迟没到,结果从设备超时返回了SLVERR。后来我加了一个FIFO来缓存地址,等数据到了再一起处理,问题就解决了。
1.8 实际设计中的注意事项
说了这么多理论,咱们来点实际的。在设计AXI互连时,有几个点我建议你特别注意:
- ID信号必须匹配:RID必须等于ARID,BID必须等于AWID。如果ID不匹配,主设备会认为数据是别人的,直接丢弃。这个错误在仿真中很难发现,因为数据可能看起来是对的,只是顺序乱了。
- WLAST不能漏:写数据通道的最后一笔必须拉高WLAST,否则从设备会一直等下去。我见过一个案例,因为WLAST没拉高,整个系统卡死了。
- RRESP和BRESP的处理:响应状态有四种:OKAY(正常)、EXOKAY(独占访问成功)、SLVERR(从设备错误)、DECERR(地址解码错误)。设计时一定要检查响应状态,不能默认都是OKAY。
- 字节选通WSTRB:写数据时,WSTRB决定了哪些字节被写入。如果WSTRB全为0,那这次写操作实际上什么都没做。这个特性可以用来实现「部分写」操作。
警告:AXI协议要求,在一次突发传输中,地址必须对齐到突发大小的边界。比如ARSIZE=3(8字节),那么ARADDR必须是8字节对齐的。如果不满足,从设备可能会返回DECERR。这个约束在设计中一定要检查。
好了,关于AXI五个通道的信号定义和握手协议,咱们就聊到这里。记住,理解这些通道的独立性和依赖关系,是设计AXI互连的基础。下一节我们会深入讨论如何把这些通道组合起来,构建一个完整的AXI互连架构。