3、AXI握手协议:VALID/READY握手机制、通道依赖关系、传输顺序与乱序传输
大家好,我是老周。今天咱们聊聊AXI总线里最核心、也最容易被忽视的部分——握手协议。
说实话,我见过不少工程师,能把AXI的五个通道背得滚瓜烂熟,但一遇到时序收敛问题就抓瞎。为什么?因为没吃透握手协议的本质。你想想看,整个AXI总线就像一条高速公路,而VALID和READY就是每个路口的红绿灯。灯怎么亮、什么时候亮,直接决定了这条路上会不会堵车、会不会撞车。
3.1 VALID/READY握手机制
AXI的每个通道都独立使用一套VALID/READY握手信号。说白了,就是发送方说“我有数据了”(VALID拉高),接收方说“我准备好了”(READY拉高),两者同时为高时,传输发生。
这里有个关键点:VALID不能依赖READY。什么意思?发送方一旦把VALID拉高,就必须保持到握手完成,不能因为接收方没准备好就撤回去。我当年刚做AXI控制器时,就犯过这个错——看到READY没拉高,就把VALID又拉低了,结果仿真直接报协议违例。
握手有三种基本场景:
- VALID先有效,READY后有效:最常见的情况。发送方准备好数据,等待接收方就绪。
- READY先有效,VALID后有效:接收方提前告知“我随时可以收”,发送方准备好后立即传输。
- 同时有效:一拍完成传输,效率最高。
重要原则:VALID可以等待READY,但READY不能等待VALID。这是协议的死规定,目的是防止死锁。
嗯,这里要注意:虽然协议允许READY先有效,但实际设计中,我建议尽量让VALID先有效。为什么?因为这样更容易控制时序,尤其是高频设计时,READY信号往往来自复杂的仲裁逻辑,提前拉高反而会增加组合路径。
3.2 通道依赖关系
AXI有五个通道:读地址(AR)、读数据(R)、写地址(AW)、写数据(W)、写响应(B)。它们之间不是独立的,存在严格的依赖关系。
我画了一张图,帮你理清这些关系:
依赖关系其实很简单:
- 读事务:必须先发AR,再收R。R通道的数据必须与AR通道的地址对应。
- 写事务:AW和W可以同时发,但B响应必须在AW和W都完成后才能返回。
我个人习惯在设计验证环境时,专门写一个断言来检查这些依赖关系。曾经有一次,我发现从设备在W数据还没收完时就返回了B响应,结果导致主设备误以为写操作已完成,后续读到了错误的数据。这种bug在仿真里很难复现,但一旦出现,定位起来非常痛苦。
3.3 传输顺序与乱序传输
AXI支持乱序传输,这是它相比AHB的一大优势。但乱序不是随便乱,而是有规则的乱。
每个事务都有一个ID标签(ARID/AWID)。从设备在处理事务时,可以按任意顺序完成,但必须保证:相同ID的事务必须按顺序完成。
举个例子:
主设备发出:
事务A:ARID=0,地址0x1000
事务B:ARID=1,地址0x2000
事务C:ARID=0,地址0x3000
从设备可以这样返回:
先返回B的数据(ID=1)
再返回A的数据(ID=0)
最后返回C的数据(ID=0)
注意:A和C的ID相同,所以C必须在A之后返回。
设计技巧:如果你想让多个事务完全乱序,给每个事务分配不同的ID。如果希望严格保序,所有事务用同一个ID。
我在做多端口DDR控制器时,就充分利用了乱序特性。CPU发起的读请求优先级高,我用ID=0;DMA发起的请求带宽大,我用ID=1。这样DDR控制器可以优先处理CPU的请求,同时DMA的请求也不会被完全阻塞。
但乱序也带来了麻烦。我曾经遇到一个bug:从设备返回数据时,把两个不同ID的数据顺序搞反了。仿真时一切正常,因为数据内容恰好一样。但实际芯片跑起来,偶尔会出现数据错乱。后来我加了一个ID检查逻辑,才彻底解决。
避坑指南:乱序传输时,主设备必须有能力重新排序接收到的数据。如果你用的是现成的AXI互联IP,通常已经处理好了。但如果是自己写的主设备接口,一定要实现一个重排序缓冲区(Reorder Buffer),按发出顺序把数据整理好。
最后说一个我踩过的坑:写事务的乱序。很多人以为写事务不能乱序,其实是可以的。从设备可以按任意顺序处理写请求,但B响应必须按AW的顺序返回。换句话说,写地址的顺序决定了写响应的顺序,但写数据可以乱序到达。
嗯,这个知识点有点绕。你只要记住一句话:ID相同的事务,响应必须保序;ID不同的事务,可以乱序。这就够了。
好了,握手协议就讲到这里。下一节我们聊聊地址映射和跨时钟域处理,那又是另一番天地了。
可可精品资料库