4、AXI总线协议(上):AXI通道介绍与握手规则
各位同学,今天我们来聊聊AXI总线协议。说实话,AXI是我在项目中打交道最多的总线协议之一。从早期的简单SoC到现在的服务器芯片,几乎每个项目都离不开它。我个人习惯把AXI看作是一套精密的"通信协议",它定义了主设备和从设备之间如何高效地传递数据。
嗯,咱们先从最基础的开始——AXI的五个独立通道。
4.1 AXI的五个独立通道
AXI协议最大的特点,就是采用了通道分离的设计。什么意思呢?就是把读操作和写操作完全分开,各自拥有独立的地址通道和数据通道。我刚开始接触时也觉得有点复杂,但用久了你会发现,这种设计对提升总线效率帮助巨大。
具体来说,AXI有五个通道:
- 读地址通道(AR):发送读请求的地址和控制信息
- 读数据通道(R):返回读取的数据和响应信号
- 写地址通道(AW):发送写请求的地址和控制信息
- 写数据通道(W):发送要写入的数据
- 写响应通道(B):返回写操作的完成状态
关键点:读操作只需要两个通道(AR + R),写操作需要三个通道(AW + W + B)。为什么写多一个?因为写操作需要确认数据是否成功写入,这个确认信号就是通过B通道返回的。
你想想看,如果读和写混在一起,总线就得排队等待。现在分开了,读操作和写操作可以同时进行,互不干扰。我在项目中遇到过这样的情况:一个DMA控制器同时进行内存读和写,如果总线不支持分离通道,性能直接砍半。
4.2 读地址通道(AR)详解
读地址通道,说白了就是告诉从设备:"嘿,我想读这个地址的数据。"
AR通道的主要信号包括:
| 信号名 | 位宽 | 描述 |
|---|---|---|
| ARADDR | 32/64位 | 读操作的起始地址 |
| ARLEN | 8位 | 突发传输长度(实际传输次数 = ARLEN + 1) |
| ARSIZE | 3位 | 每次传输的数据字节数(2^ARSIZE) |
| ARBURST | 2位 | 突发类型:FIXED、INCR、WRAP |
| ARID | 可配置 | 读事务ID,用于乱序返回 |
| ARVALID | 1位 | 主设备驱动,表示地址有效 |
| ARREADY | 1位 | 从设备驱动,表示可以接收地址 |
这里有个容易踩坑的地方——ARLEN。我记得刚做第一个AXI项目时,想发4次传输,结果ARLEN设成了4,实际发了5次。后来才反应过来,ARLEN的值是"传输次数减1"。你设成0就是1次传输,设成3就是4次传输。这个细节,我建议你记牢。
4.3 读数据通道(R)详解
读数据通道是从设备返回数据的通道。它和读地址通道是配对的——你发一个读请求,从设备就会通过R通道把数据送回来。
R通道的主要信号:
| 信号名 | 描述 |
|---|---|
| RDATA | 读取的数据,位宽与数据总线一致 |
| RRESP | 读响应状态:OKAY、EXOKAY、SLVERR、DECERR |
| RLAST | 最后一次传输的指示信号 |
| RID | 与ARID匹配,用于识别属于哪个读事务 |
| RVALID | 从设备驱动,表示数据有效 |
| RREADY | 主设备驱动,表示可以接收数据 |
个人经验:RLAST信号非常关键。在突发传输中,RLAST拉高表示这是本次突发的最后一个数据。我曾经在调试一个DDR控制器时,发现读数据总是少一个,最后查出来是从设备没有正确拉高RLAST。嗯,这种问题用逻辑分析仪一抓就能看到。
4.4 写地址通道(AW)与写数据通道(W)
写操作比读操作多了一个通道,因为写数据需要和地址一起发送。但有意思的是,AW和W通道是独立的,它们可以同时发送,也可以先后发送。
AW通道的信号和AR通道几乎一样,只是前缀从AR变成了AW:
- AWADDR:写操作的起始地址
- AWLEN:写突发长度
- AWSIZE:每次写的数据字节数
- AWBURST:突发类型
- AWID:写事务ID
- AWVALID / AWREADY:握手信号
W通道则负责传输实际数据:
| 信号名 | 描述 |
|---|---|
| WDATA | 要写入的数据 |
| WSTRB | 写选通信号,每个bit对应一个字节,1表示该字节有效 |
| WLAST | 最后一次数据传输的指示 |
| WVALID | 主设备驱动,表示数据有效 |
| WREADY | 从设备驱动,表示可以接收数据 |
这里我要特别提一下WSTRB。这个信号很多人一开始不太在意,但它在实际项目中非常有用。比如你想写一个32位数据中的某个字节,WSTRB就可以精确控制哪些字节被写入。我曾经在调试一个PCIe控制器时,发现写数据总是错位,最后查出来是WSTRB的位宽配置错了。你想想看,如果WSTRB搞错了,数据写进去就是乱的。
4.5 写响应通道(B)
写响应通道是AXI写操作的最后一步。当从设备完成写操作后,会通过B通道返回一个响应状态。
B通道的信号很简单:
- BRESP:写响应状态(OKAY、EXOKAY、SLVERR、DECERR)
- BID:与AWID匹配
- BVALID:从设备驱动,表示响应有效
- BREADY:主设备驱动,表示可以接收响应
注意:写响应通道只返回一次,而不是每个数据返回一次。也就是说,一个突发写操作(比如4次传输),只会在最后返回一个B响应。这个和读操作不同,读操作每个数据都带RRESP。
为什么会这样设计?我个人理解是:写操作的数据是主设备主动发送的,从设备只需要在全部接收完后给个总结性的反馈。而读操作的数据是从设备返回的,每个数据都可能出错,所以需要逐个响应。
4.6 通道握手规则
AXI的每个通道都使用VALID-READY握手机制。这个机制说白了就是:发送方说"我有数据要发"(VALID拉高),接收方说"我准备好了"(READY拉高),双方一拍即合,数据就传过去了。
握手有三种情况:
- VALID先有效,READY后有效:发送方先准备好数据,等待接收方。这是最常见的情况。
- READY先有效,VALID后有效:接收方提前准备好,发送方数据就绪后立即传输。
- VALID和READY同时有效:双方同时准备好,一拍即合,效率最高。
这里有个重要的规则:VALID信号一旦拉高,必须保持到握手完成。也就是说,发送方不能随意撤销数据。而READY信号可以随时拉高或拉低,没有这个限制。
避坑指南:我曾经在一个项目中,设计了一个AXI从设备,它的READY信号在VALID到来之前就拉高了,但后来因为内部处理不过来,又把READY拉低了。结果主设备看到READY拉高就认为可以传输,数据发过来后发现READY又没了,导致数据丢失。嗯,从那以后我设计握手逻辑时,都会加一个状态机来保证READY的稳定性。
另外,AXI协议还支持依赖握手。什么意思呢?比如写操作中,W通道的数据必须在AW通道的地址之后发送,但协议允许它们同时发送。读操作中,R通道的数据必须在AR通道的地址之后返回。这些依赖关系是协议层面的约束,设计时一定要遵守。
4.7 通道间的依赖关系
最后,我们总结一下五个通道之间的依赖关系:
| 操作类型 | 依赖关系 |
|---|---|
| 读操作 | R通道必须在AR通道握手完成后才能开始传输数据 |
| 写操作 | W通道可以在AW通道之前或之后发送,但B通道必须在W通道的WLAST之后返回 |
| 跨事务 | 不同ID的事务之间没有依赖关系,可以乱序执行 |
你想想看,这种依赖关系设计得非常巧妙。它既保证了数据的一致性,又给了设计者足够的灵活性。比如写操作中,你可以先发地址再发数据,也可以先发数据再发地址,甚至同时发。这种灵活性在复杂系统中非常有用。
好了,这一章我们介绍了AXI的五个通道和握手规则。下一章我们会深入讲解AXI的突发传输、乱序传输和原子操作,这些都是服务器芯片设计中经常用到的特性。到时候我会结合一个实际的DMA控制器设计案例,带大家一步步实现一个完整的AXI接口。
课后思考:如果你要设计一个AXI从设备,当收到一个读请求时,从设备需要等待几个周期才能返回数据。你会如何设计VALID和READY的时序?是让ARREADY立即拉高,还是等数据准备好再拉高?这两种方式各有什么优缺点?