2. AXI通道与握手:读地址、读数据、写地址、写数据、写响应五个独立通道,以及VALID-READY握手协议详解
AXI总线最让我欣赏的设计,就是它的五个独立通道。说实话,我第一次接触时也觉得通道数有点多。但用久了你会发现,这恰恰是AXI高性能的基石。
每个通道都是单向的,数据流方向固定。读通道有三个,写通道有两个。我习惯把它们拆成「读事务」和「写事务」两套来理解。
2.1 五个独立通道概览
先看一张我画的通道结构图,这样你脑子里能有个整体印象:
你看,读事务需要两个通道配合:先发地址,再收数据。写事务需要三个通道:发地址、发数据、收响应。为什么写比读多一个通道?因为写操作需要从设备告诉你「写完了,结果如何」。
关键点:五个通道彼此独立,各自有独立的VALID-READY握手。这意味着地址和数据可以同时发送,也可以错开发送。AXI不要求它们之间有任何固定的时序关系。
2.2 读事务通道详解
读地址通道(AR通道)
主控通过AR通道告诉从设备:「我要读哪个地址,读多少数据」。我见过不少新手把ARADDR和AWADDR搞混,其实记住「AR = Address Read」就行了。
AR通道的关键信号:
- ARADDR:读起始地址。注意,对于突发传输,这是第一个数据的地址。
- ARLEN:突发长度。表示一次突发传输中要读多少个数据。值为0表示读1个,值为7表示读8个。
- ARSIZE:每次传输的字节数。3'b011表示8字节,3'b010表示4字节。
- ARBURST:突发类型。00=FIXED,01=INCR,10=WRAP。
- ARVALID:主控发出的握手信号,表示地址和控制信息有效。
- ARREADY:从设备发出的握手信号,表示可以接收地址。
我的经验:设计AR通道时,我习惯把地址对齐检查放在最前面。比如ARSIZE=3(8字节),地址必须8字节对齐。曾经有个项目,因为地址没对齐,仿真跑得好好的,上板就出问题。查了两天才发现是地址位[2:0]没清零。
读数据通道(R通道)
从设备通过R通道把数据返回给主控。这个通道有个特殊信号——RLAST,它告诉主控「这是最后一个数据了」。
R通道的关键信号:
- RDATA:读回来的数据。总线宽度可以是32、64、128、256、512、1024位。
- RRESP:读响应。00=OKAY,01=EXOKAY,10=SLVERR,11=DECERR。
- RLAST:当前传输的最后一个数据。这个信号很重要,主控靠它判断一次突发是否结束。
- RVALID:从设备发出的握手信号,表示数据有效。
- RREADY:主控发出的握手信号,表示可以接收数据。
读事务的流程很简单:主控发地址 → 从设备返回数据。但要注意,从设备不一定马上返回数据,它可能需要几个时钟周期来准备。这就是为什么要有VALID-READY握手。
2.3 写事务通道详解
写地址通道(AW通道)
AW通道和AR通道几乎一模一样,只是方向不同。AWADDR、AWLEN、AWSIZE、AWBURST这些信号的含义和读通道完全对应。
我刚开始做AXI设计时,总觉得AW和AR可以合并成一个通道。后来才明白,独立的地址通道让读写可以并行进行。主控可以在等待读数据的同时,发送写地址。这就是AXI高性能的秘密之一。
写数据通道(W通道)
W通道负责把要写的数据发送给从设备。它也有一个WLAST信号,表示最后一个数据。
W通道的关键信号:
- WDATA:要写入的数据。
- WSTRB:写选通信号。每个bit对应一个字节,1表示该字节有效。比如32位总线,WSTRB[3:0]分别对应byte3~byte0。
- WLAST:当前传输的最后一个数据。
- WVALID:主控发出的握手信号,表示数据有效。
- WREADY:从设备发出的握手信号,表示可以接收数据。
注意:写数据通道和写地址通道是独立的。主控可以先发地址再发数据,也可以先发数据再发地址,甚至可以同时发。但从设备通常需要先收到地址才知道数据要写到哪里去。所以设计从设备时,我建议把地址和数据都收齐了再开始写操作。
写响应通道(B通道)
写响应通道是AXI独有的。每次写突发传输结束后,从设备必须通过B通道返回一个响应。主控收到响应后,才知道这次写操作是否成功。
B通道的关键信号:
- BRESP:写响应。00=OKAY,01=EXOKAY,10=SLVERR,11=DECERR。
- BVALID:从设备发出的握手信号,表示响应有效。
- BREADY:主控发出的握手信号,表示可以接收响应。
为什么需要写响应?你想想看,如果写操作失败了,主控怎么知道?没有响应通道的话,主控只能靠超时来判断,那效率太低了。AXI的设计思路是:每个事务都要有明确的完成状态。
2.4 VALID-READY握手协议详解
这是AXI最核心的机制。说白了,就是发送方和接收方之间的一种「确认收到」的协议。
握手的基本规则:
- VALID:发送方把数据准备好后,拉高VALID,表示「数据有效,你可以取了」。
- READY:接收方准备好接收时,拉高READY,表示「我准备好了,你可以发了」。
- 传输发生:当VALID和READY同时为高时,数据被成功传输。
这里有三种握手场景:
| 场景 | 描述 | 时序特点 |
|---|---|---|
| VALID先有效 | 发送方先准备好数据,等待接收方 | VALID先拉高,READY后拉高 |
| READY先有效 | 接收方先准备好,等待发送方 | READY先拉高,VALID后拉高 |
| 同时有效 | 双方同时准备好 | VALID和READY在同一周期拉高 |
我个人最喜欢第三种场景,零等待传输,效率最高。但实际设计中,第一种场景更常见——从设备通常需要几个周期才能准备好接收数据。
重要规则:一旦VALID被拉高,发送方不能将其拉低,直到握手成功。也就是说,数据必须保持稳定,直到被接收方取走。这个规则保证了协议的可靠性。
看一个简单的读地址握手例子:
// 主控发送读地址
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
arvalid <= 1'b0;
araddr <= 32'b0;
end else if (arready && arvalid) begin
// 握手成功,可以发下一个地址
arvalid <= 1'b0;
end else if (has_read_request) begin
arvalid <= 1'b1;
araddr <= read_addr;
end
end
// 从设备接收读地址
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
arready <= 1'b0;
end else begin
arready <= can_accept_address;
end
end
这段代码展示了最基本的握手逻辑。注意看,主控在arready和arvalid同时为高时,才知道地址被成功接收了。然后它才能去处理下一个请求。
2.5 握手协议中的依赖关系
五个通道之间有一些依赖关系,我总结了几条:
- 读数据依赖读地址:从设备必须先收到读地址,才能返回读数据。这是最明显的依赖。
- 写响应依赖写数据和写地址:从设备必须收到地址和数据后,才能返回写响应。但地址和数据谁先到无所谓。
- 读数据可以提前准备好:从设备可以在收到地址后的任意时刻返回数据。主控必须准备好接收。
- 写响应必须在最后一个数据之后:B通道的响应必须在WLAST被接收之后才能发出。这是协议明确要求的。
避坑指南:我曾经设计过一个从设备,写响应逻辑写错了,在收到WLAST之前就返回了BRESP。结果主控收到响应后以为写完了,又开始发新的写请求。两个写事务的数据混在一起,调试了整整一天。记住:写响应必须在WLAST握手成功之后才能发出。
2.6 握手机制的性能影响
VALID-READY握手虽然增加了控制逻辑,但它带来的好处是巨大的:
- 解耦:发送方和接收方不需要知道对方的状态,各自独立工作。
- 流水线:主控可以连续发送多个地址,从设备逐个处理。这就是AXI支持乱序传输的基础。
- 背压:接收方可以通过拉低READY来告诉发送方「慢一点,我跟不上了」。这是流控的核心机制。
说白了,VALID-READY就是一套优雅的流控协议。它让高速设备和低速设备可以无缝对接,谁也不用等谁。
嗯,通道和握手这部分就讲到这里。记住五个通道的名字和方向,理解VALID-READY的握手规则,你就掌握了AXI通信的基础。剩下的就是多写代码,多仿真,慢慢积累经验。