4、常见总线协议(三):AMBA AXI4.0总线协议详解、乱序传输与通道机制
AXI4.0,说实话,这是AMBA家族里我最喜欢的一个协议。为什么?因为它够灵活,够快。我在做第一颗AI加速芯片的时候,就是靠AXI4.0把DDR和计算单元之间的带宽吃满的。今天咱们就把它掰开揉碎了讲清楚。
4.1 AXI4.0的整体架构
AXI4.0最大的特点,就是它把读写分开了。不是简单的分开,而是用了五个独立的通道。你想想看,这就像一条双向八车道的高速公路,读和写各走各的道,互不干扰。
这五个通道分别是:
- 读地址通道(AR):发送读请求的地址和控制信息
- 读数据通道(R):返回读到的数据,以及读响应信号
- 写地址通道(AW):发送写请求的地址和控制信息
- 写数据通道(W):发送要写入的数据
- 写响应通道(B):返回写操作的完成状态
每个通道都是独立的,都有自己的握手信号。这意味着什么?意味着你可以同时发读请求、写请求,还能同时收数据。我在项目中遇到过,有些新手把AXI当成APB来用,一个事务做完再做下一个,那带宽利用率简直惨不忍睹。
核心要点:AXI4.0的五个通道是并行工作的。读操作和写操作可以同时进行,互不阻塞。
4.2 通道握手机制
每个通道都用一套简单的握手协议:VALID和READY。发送方拉高VALID表示数据有效,接收方拉高READY表示可以接收。当两者同时为高时,传输发生。
这里有个坑,我踩过。VALID信号不能依赖READY信号。什么意思?就是发送方一旦拉高VALID,就必须保持住,直到握手成功。你不能因为看到READY没拉高,就把VALID拉低。我曾经在一个DMA控制器里犯了这错,结果仿真没问题,上板子就死机。查了两天才发现是VALID被错误地拉低了。
重要规则:VALID一旦拉高,必须保持到握手完成。READY可以等待VALID,但VALID不能等待READY。
4.3 乱序传输——AXI的灵魂
乱序传输,说白了就是允许后发的请求先完成。为什么会这样?你想想看,如果总线连着DDR控制器,读地址0x1000和0x2000。0x1000那行刚好在DDR的Bank冲突,要多等几个周期;而0x2000那行刚好命中,直接就能返回数据。如果非要按顺序来,那就得傻等,多浪费啊。
AXI4.0用ID标签来解决这个问题。每个事务都带一个ID,从设备返回数据时带上相同的ID。主设备根据ID就知道哪个数据对应哪个请求。这样,数据返回的顺序就可以和请求的顺序不一样了。
我个人习惯,在复杂SoC设计中,给每个主设备分配不同的ID高位,低位留给事务编号。这样调试的时候,一看ID就知道是哪个模块发出来的请求。
实战技巧:ID的分配要合理规划。建议高位表示主设备编号,低位表示事务编号。比如主设备0用ID[3:0]=4'b0000~4'b1111,主设备1用ID[3:0]=4'b0001~4'b1111,以此类推。
4.4 乱序深度与顺序保证
乱序不是无限度的。AXI4.0要求:相同ID的事务必须按顺序完成。也就是说,如果你用同一个ID发了两个读请求,那么第一个请求的数据必须在第二个之前返回。
这个约束其实很合理。你想想看,如果同一个ID的事务都乱序了,那软件怎么写?根本没法保证数据的一致性。所以,想要乱序,就得用不同的ID。
我在做视频编解码IP的时候,就用到了这个特性。把帧内预测和帧间预测的请求用不同的ID发出去,帧内预测的数据先回来就先处理,不用等帧间预测。这样流水线就不会因为等待数据而停顿。
4.5 突发传输与地址计算
AXI4.0支持突发传输,一次地址请求可以传输多笔数据。突发类型有三种:
| 突发类型 | 地址变化 | 适用场景 |
|---|---|---|
| FIXED | 地址不变 | FIFO操作、外设寄存器 |
| INCR | 地址递增 | 内存连续读写 |
| WRAP | 地址递增,到边界回绕 | Cache Line填充 |
突发长度从1到256,但要注意:INCR类型最大支持256笔,WRAP类型最大支持16笔。这个限制是因为WRAP需要预知边界,太长的话硬件实现太复杂。
地址对齐也是个容易出错的地方。突发传输的起始地址必须对齐到突发大小的边界。比如你发一个4笔的突发,每笔4字节,那起始地址必须是16字节对齐的。我曾经见过一个同事,地址没对齐,结果仿真跑得好好的,上板子就随机出错。查了三天,最后发现是地址计算逻辑写错了。
4.6 原子操作与锁
AXI4.0支持两种原子操作:独占访问和锁定访问。独占访问用于实现信号量,锁定访问用于实现总线仲裁。
独占访问的流程是这样的:
- 主设备发一个独占读请求
- 从设备返回数据,并记录这个地址被独占监视
- 主设备发一个独占写请求
- 从设备检查这个地址是否被其他主设备修改过
- 如果没有修改,写成功;否则写失败
这个机制在多核系统中特别有用。我记得在做双核CPU系统的时候,就用独占访问来实现自旋锁。两个核同时抢锁,只有一个能成功,另一个就循环重试。简单高效。
注意:独占访问要求从设备支持独占监视。不是所有的从设备都支持,设计时要注意检查。
4.7 低功耗接口
AXI4.0还定义了低功耗接口,通过CACTIVE和CSYSREQ等信号来控制时钟和电源。这个在实际项目中用得不多,但如果你做的是低功耗设计,就绕不开。
低功耗接口的核心思想是:当总线空闲时,可以关闭时钟甚至电源来省电。但要注意,关闭前必须确保所有未完成的事务都处理完了。否则数据就丢了。
我在做IoT芯片的时候用过这个特性。芯片大部分时间都在休眠,只有需要传输数据时才唤醒总线。这样功耗能降低90%以上。但代价是唤醒延迟,大概需要几十个微秒。所以,如果你的系统对延迟敏感,就要权衡一下了。
4.8 实战经验总结
说了这么多,最后分享几个我在项目中总结的经验:
- ID管理要规范:给每个主设备分配独立的ID范围,方便调试
- 地址对齐不能忘:突发传输的地址必须对齐,否则硬件实现会非常复杂
- VALID不能依赖READY:这是AXI协议的基本规则,违反就会出问题
- 乱序要适度:不是乱序深度越大越好,太深了会增加硬件开销和延迟
- 仿真要覆盖边界:地址边界、突发长度边界、ID回绕边界,这些最容易出bug
AXI4.0是个强大的协议,但越强大的东西,用起来越要小心。我建议你在做第一个AXI设计的时候,先画一个时序图,把每个通道的握手过程画清楚。等跑通了,再慢慢优化性能。别一上来就想把带宽吃满,那样很容易翻车。
好了,关于AXI4.0的核心内容就这些。记住,协议是死的,人是活的。理解了背后的设计思想,你就能灵活运用它来解决实际问题。
可可精品资料库