3、AXI握手协议:VALID/READY握手机制、通道间依赖关系、传输顺序与乱序传输
大家好,欢迎来到第三章。今天我们来聊聊AXI总线最核心的机制——握手协议。说实话,我见过不少工程师,写AXI代码时总觉得只要把信号拉出来就行,结果一上板就出问题。嗯,问题多半出在握手没搞明白。
3.1 VALID/READY握手机制
AXI的五个独立通道(读地址、读数据、写地址、写数据、写响应),每个通道都靠VALID和READY这一对信号来握手。说白了,就是发送方说“我有数据了”,接收方说“我准备好了”,两人一拍即合,传输就完成了。
握手有三种基本场景,我画了个图帮大家理解:
三种情况都成立,但有个关键规则:VALID一旦拉高,就不能再变低,直到握手成功。READY可以随时变,但VALID不行。为什么?我当年第一次写AXI从机时,就踩过这个坑——VALID拉高后又撤回了,结果主机直接挂死。
核心规则:
- VALID可以等READY,READY也可以等VALID
- 但VALID一旦拉高,必须保持到握手完成
- READY可以提前拉高,也可以握手前拉低
3.2 通道间依赖关系
AXI有五个通道,它们不是各玩各的。通道之间有严格的依赖关系。你想想看,如果写数据还没准备好,写地址先过去了,从机收到地址却等不到数据,那不就卡住了?
我整理了一个依赖关系表,大家对照着看:
| 依赖关系 | 说明 | 实际影响 |
|---|---|---|
| 写地址 → 写数据 | 写地址通道和写数据通道相互独立,但都必须在写响应之前完成 | 地址和数据可以乱序到达,但响应必须等两者都到 |
| 写数据/写地址 → 写响应 | 从机必须收到地址和数据后,才能返回写响应 | 响应通道依赖前两个通道的完成 |
| 读地址 → 读数据 | 主机发送读地址后,从机才能返回读数据 | 读数据必须等读地址握手完成后才能出现 |
| 读数据 ↔ 写数据 | 两者之间没有直接依赖 | 读和写可以完全并行 |
这里有个容易忽略的点:写响应必须等写地址和写数据都握手完成后才能发出。我在一个项目中,从机设计成了收到地址就回响应,结果数据还没到,主机以为写完了,又开始发新请求——数据全乱套了。
避坑指南:
我曾经在一个DMA控制器设计中,把写响应逻辑写成了“收到地址即响应”。结果仿真没问题,上板后数据一致性校验全挂。查了三天才发现,从机在数据还没到达时就回了BVALID。记住:写响应必须等WLAST也握手完成!
3.3 传输顺序与乱序传输
AXI支持乱序传输,这是它比AHB强的地方之一。但乱序不是随便乱,有规则约束。
先说说顺序传输。在AXI3中,同一ID的传输必须保序。什么意思?就是你先发了地址A,再发地址B,那么数据A必须在数据B之前回来。这很好理解,就像排队买票,先来后到。
但AXI4引入了乱序能力。不同ID的事务可以乱序完成。举个例子:
- ID=0 发起了读请求A
- ID=1 发起了读请求B
- 即使请求A先发出,请求B的数据也可能先回来
为什么会这样?因为从机可能对不同ID的请求有不同的处理速度。比如ID=0访问的是慢速外设,ID=1访问的是快速SRAM,那ID=1的数据先回来完全合理。
个人经验:
我建议大家在设计互连结构时,尽量利用乱序特性。比如CPU发起的读请求用ID=0,DMA用ID=1,外设用ID=2。这样不同主机的请求可以乱序处理,总线利用率能提升30%以上。但要注意:同一ID内部必须保序,否则逻辑会非常复杂。
乱序传输的实现依赖ID标签。每个事务都带一个ID,从机返回数据时带上相同的ID。主机根据ID来区分数据属于哪个请求。这就像快递包裹上的订单号,不管包裹到的顺序如何,你都能知道它对应哪个订单。
这里有个关键点:同一ID的事务必须保序,不同ID的事务可以乱序。我见过有人把不同主机的请求都赋成同一个ID,结果乱序回来时主机完全无法区分,数据全乱了。
最后说一个实际设计中的小技巧。如果你不确定自己的设计是否需要支持乱序,最简单的做法是:每个主机分配独立的ID,并且保证同一主机内部按顺序发送。这样既利用了乱序的灵活性,又避免了复杂的ID管理逻辑。我早期的几个项目都是这么干的,效果很好。
本章要点回顾:
- VALID/READY握手:VALID必须保持到握手成功,READY可以随时变化
- 通道依赖:写响应依赖写地址和写数据,读数据依赖读地址
- 乱序传输:不同ID可乱序,同一ID必须保序
- ID管理:合理分配ID是乱序设计的关键
好了,这一章就到这里。握手协议是AXI的基石,搞懂了它,后面的内容会顺畅很多。下一章我们聊聊地址映射和地址译码,那是另一个容易踩坑的地方。