4、AXI4总线协议详解:AXI4通道与握手机制、地址/数据/控制信号、突发传输与乱序传输、AXI4-Lite与AXI4-Stream
AXI4,全称Advanced eXtensible Interface,是ARM公司推出的AMBA总线家族中的核心成员。说实话,在FPGA和SoC设计领域,你要是没跟AXI4打过交道,那都不好意思说自己做过高速设计。我个人习惯把AXI4看作是一套“交通规则”——它规定了数据怎么在路上跑、什么时候该停、什么时候该让。
这一章,咱们就把它彻底讲透。我会从最基础的通道结构开始,一步步深入到握手机制、突发传输,最后再聊聊AXI4的两个变种:Lite和Stream。
4.1 AXI4的五个独立通道
AXI4最核心的设计思想,就是“通道分离”。它把一次总线事务拆成了五个独立的通道。你想想看,这就像一条高速公路,把入口、出口、快车道、慢车道全部分开,车流自然就顺畅了。
这五个通道分别是:
- 读地址通道(AR):Master告诉Slave“我要读哪个地址”
- 读数据通道(R):Slave把读到的数据返回给Master
- 写地址通道(AW):Master告诉Slave“我要往哪个地址写”
- 写数据通道(W):Master把要写的数据发给Slave
- 写响应通道(B):Slave告诉Master“写操作完成了,结果如何”
每个通道都是单向的,数据流方向固定。这样做的好处很明显——读和写可以同时进行,互不干扰。我在项目中遇到过一种情况,DMA同时做内存搬运,读和写完全重叠,如果没有这种分离设计,性能直接腰斩。
4.2 握手机制:VALID和READY
每个通道都有一套独立的握手机制,核心就是两个信号:VALID和READY。
说白了,这就是一个“你准备好了吗?我准备好了!”的对话过程。
- VALID:发送方拉高,表示“我这边数据/地址已经准备好了”
- READY:接收方拉高,表示“我可以接收了”
传输发生的条件只有一个:VALID和READY同时为高,在时钟上升沿采样,数据就传过去了。
关键点:VALID不能依赖READY。发送方一旦准备好,就必须拉高VALID,不能等READY来了再拉。这是AXI协议的死规定,违反的话时序会出大问题。
我曾经踩过一个坑:在设计一个AXI Slave时,为了省逻辑,我让VALID等READY来了再拉高。结果仿真没问题,上板子就死机。查了两天才发现,Master那边等VALID等了半天,以为Slave死了,直接超时复位。从那以后,我再也不敢在VALID上做手脚。
4.3 地址、数据与控制信号
每个通道除了VALID和READY,还有一组核心信号。咱们挑几个重点说说。
读地址通道(AR)
- ARADDR:读起始地址
- ARLEN:突发长度,表示这次读多少个数据
- ARSIZE:每个数据的字节数
- ARBURST:突发类型,固定地址/增量地址/回绕地址
读数据通道(R)
- RDATA:读回来的数据
- RRESP:读响应状态,OKAY/EXOKAY/SLVERR/DECERR
- RLAST:最后一个数据时拉高,告诉Master“这次突发结束了”
写地址通道(AW)
- AWADDR、AWLEN、AWSIZE、AWBURST:和读通道类似
写数据通道(W)
- WDATA:要写的数据
- WSTRB:字节选通信号,每个bit对应一个字节,1表示该字节有效
- WLAST:最后一个数据时拉高
写响应通道(B)
- BRESP:写响应状态
小技巧:WSTRB这个信号很多人容易忽略。比如你要写一个32位总线中的第2个字节,WSTRB就设成4'b0010。如果不设对,Slave可能会把不该写的数据也写进去。我调试DDR控制器时就遇到过这种问题,数据总是对不上,最后发现是WSTRB没处理好。
4.4 突发传输与乱序传输
突发传输是AXI4的杀手锏。说白了,就是一次地址握手,后面连续传多个数据,不用每个数据都重新发地址。
举个例子:你要从地址0x1000开始连续读8个32位数据。如果没有突发,你得发8次地址、收8次数据。有了突发,你只需要发一次地址,Slave就会连续返回8个数据。
突发类型有三种:
| ARBURST/AWBURST | 类型 | 说明 |
|---|---|---|
| 2'b00 | FIXED | 固定地址,所有数据访问同一个地址 |
| 2'b01 | INCR | 增量地址,地址依次递增 |
| 2'b10 | WRAP | 回绕地址,地址递增到边界后回到起始 |
乱序传输呢?这个更高级。AXI4允许Master同时发出多个地址请求,Slave可以按任意顺序返回数据。你想想看,如果Slave内部有多个存储体,有的快有的慢,乱序传输就能让快的先返回,不用等慢的。
乱序靠两个东西实现:ID信号和事务ID。每个事务都有一个唯一的ID,返回数据时带上同样的ID,Master就知道这个数据属于哪个事务了。
注意:乱序传输虽然能提高效率,但实现复杂度也上去了。如果你的设计不需要乱序,可以把ID设成固定值,强制顺序返回。我一般建议初学者先做顺序传输,跑通了再考虑乱序优化。
4.5 AXI4-Lite与AXI4-Stream
AXI4有两个简化版本,专门针对不同场景。
AXI4-Lite
AXI4-Lite是AXI4的轻量版。它去掉了突发传输,每次只能传一个数据。信号也简化了,没有ID、没有突发长度、没有WSTRB(其实有,但固定全有效)。
什么时候用AXI4-Lite?
- 配置寄存器:比如设置DMA的源地址、目的地址
- 控制状态寄存器:比如启动、停止、查询状态
- 低速外设:比如GPIO、UART的控制接口
我个人习惯把所有控制类接口都用AXI4-Lite。原因很简单——逻辑少、时序好、不容易出错。你想想看,配置寄存器又不需要高带宽,用全功能AXI4纯属浪费。
AXI4-Stream
AXI4-Stream就更极端了,它连地址都去掉了。只有数据通道,没有地址通道,也没有写响应通道。数据像流水一样从Master流到Slave。
信号也简化到极致:
- TDATA:数据
- TVALID:数据有效
- TREADY:接收方准备好
- TLAST:最后一个数据
- TKEEP:字节有效指示(可选)
- TUSER:用户自定义信号(可选)
AXI4-Stream最适合什么场景?
- 高速数据流:比如ADC采样数据、视频像素流
- DMA数据传输:数据从一个外设搬到另一个外设
- FIFO接口:本质上就是带握手的FIFO读写
经验之谈:AXI4-Stream的握手机制和AXI4完全一样,也是VALID+READY。所以如果你已经理解了AXI4的握手,Stream就是小菜一碟。区别只在于Stream没有地址,数据怎么解释完全由用户自己定义。
嗯,到这里AXI4的核心内容就讲完了。从五个通道到握手机制,从突发传输到乱序,再到Lite和Stream两个变种,这些东西你吃透了,后面做FPGA内存控制器和RISC-V总线接口就会轻松很多。