AXI协议基础(一):AXI通道概述与握手协议

各位同学,今天我们来聊聊AXI协议最核心的部分——五个独立通道和那个无处不在的握手协议。说实话,我刚接触AXI时也被这五个通道搞得有点晕,但后来发现,搞懂了它们,整个协议就通了一半。

一、AXI的五个独立通道

AXI协议把一次传输拆成了五个独立的通道。为什么要这么设计?说白了就是为了并行。你想想看,读地址和写地址可以同时发,读数据和写数据也能并行跑,这效率不就上来了吗?

这五个通道分别是:

  • 读地址通道(AR):发送读请求的地址和控制信息
  • 读数据通道(R):返回读到的数据,还带响应信号
  • 写地址通道(AW):发送写请求的地址和控制信息
  • 写数据通道(W):发送要写入的数据
  • 写响应通道(B):返回写操作的完成状态

关键点:每个通道都是单向的,而且读和写是完全独立的。这意味着你可以同时进行读和写操作,互不干扰。

二、读操作的数据流

读操作其实很简单。主机先通过AR通道发个地址过去,从机收到后,通过R通道把数据返回来。我刚开始做验证时,总以为读数据必须等读地址完全处理完才能开始,其实不是这样的。

从机可以在处理读地址的同时,就开始准备数据。只要地址没问题,数据就能很快返回。这里有个细节要注意——读数据通道里除了数据,还有一个RRESP信号,用来告诉主机这次读操作是否成功。

我的经验:在项目中,我习惯把读地址和读数据的时序分开约束。读地址通道的时序通常比较宽松,但读数据通道因为要传大量数据,时序往往更紧张。我曾经在一个DDR控制器项目中,就因为读数据通道的时序没处理好,导致高频下数据采样出错。

三、写操作的数据流

写操作比读操作多了一个通道。主机先通过AW通道发地址,然后通过W通道发数据,最后从机通过B通道返回写响应。

这里有个有意思的地方——写地址和写数据是独立的,所以主机可以先发地址再发数据,也可以先发数据再发地址,甚至可以同时发。我个人习惯是先发地址再发数据,这样从机可以提前准备。

通道 方向 主要信号 说明
AW 主机→从机 AWADDR, AWVALID, AWREADY 写地址和控制信息
W 主机→从机 WDATA, WSTRB, WVALID, WREADY 写数据和字节使能
B 从机→主机 BRESP, BVALID, BREADY 写响应状态
AR 主机→从机 ARADDR, ARVALID, ARREADY 读地址和控制信息
R 从机→主机 RDATA, RRESP, RVALID, RREADY 读数据和响应

四、握手协议:VALID/READY

这是AXI协议的精髓所在。每个通道都使用VALID和READY信号来完成握手。说白了就是:主机说"我有数据要发"(VALID有效),从机说"我准备好了"(READY有效),然后一拍即合,数据就传过去了。

握手有三种情况:

  • VALID先有效,READY后有效:主机先准备好数据,等从机准备好再传
  • READY先有效,VALID后有效:从机先准备好,等主机发数据
  • 同时有效:一拍就完成传输,效率最高

避坑指南:我曾经在一个项目中,从机的READY信号在复位后默认拉高,结果主机一上来就发数据,从机还没初始化完成,数据全丢了。所以我的建议是——READY信号默认拉低,等从机真正准备好了再拉高。

五、握手时序与依赖关系

AXI协议对握手时序有一些基本规则,我总结了几条必须记住的:

  1. VALID信号一旦拉高,必须等到握手完成才能拉低
  2. READY信号可以随时拉高或拉低
  3. 数据必须在VALID和READY同时有效的时钟上升沿被采样
  4. 读数据通道的RLAST信号标记最后一笔数据
  5. 写数据通道的WLAST信号标记最后一笔数据

嗯,这里要注意——读数据通道的RVALID和RREADY握手,必须在读地址通道的ARVALID和ARREADY握手之后才能发生。这是协议规定的依赖关系,不能乱来。

核心要点:五个通道之间虽然有依赖关系,但每个通道内部的握手是完全独立的。这意味着你可以让写地址通道在等待写数据通道的同时,读地址通道已经在处理新的读请求了。

六、AXI通道结构图

下面这张图展示了AXI五个通道之间的数据流和握手关系。我特意把读和写分开画,这样看起来更清楚。

主机 Master 从机 Slave 读地址通道 (AR) ARVALID / ARREADY 读数据通道 (R) RVALID / RREADY 写地址通道 (AW) AWVALID / AWREADY 写数据通道 (W) WVALID / WREADY 写响应通道 (B) BVALID / BREADY 图例: 读地址 读数据 写地址 写数据 写响应

七、握手协议代码示例

下面是一个简单的握手逻辑,用Verilog写的。我习惯把VALID和READY的握手逻辑封装成一个模块,这样复用起来方便。

// 读地址通道握手示例
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        ar_valid <= 1'b0;
        ar_addr  <= 32'b0;
    end else begin
        // 当主机有读请求且握手未完成时
        if (read_req && !ar_valid) begin
            ar_valid <= 1'b1;
            ar_addr  <= read_addr;
        end
        // 握手完成,拉低VALID
        if (ar_valid && ar_ready) begin
            ar_valid <= 1'b0;
        end
    end
end

// 读数据通道握手示例
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        r_ready <= 1'b0;
    end else begin
        // 从机准备好接收读数据
        if (r_valid && !r_ready) begin
            r_ready <= 1'b1;
        end
        // 数据被采样后拉低
        if (r_valid && r_ready) begin
            r_ready <= 1'b0;
        end
    end
end

小技巧:写握手逻辑时,我建议把VALID和READY分开控制。VALID由数据源控制,READY由数据目的地控制。这样逻辑清晰,不容易出错。我曾经见过一个项目把两者混在一起写,调试起来简直要命。

八、实际项目中的注意事项

最后分享几个我在项目中踩过的坑:

  • 死锁问题:如果主机和从机都在等对方先发信号,就会死锁。比如主机等从机的READY,从机等主机的VALID。解决办法是确保至少有一方可以先行动。
  • 数据对齐:AXI协议要求地址必须对齐到传输大小。比如32位传输,地址必须是4的倍数。这个在验证时很容易漏掉。
  • 字节使能:WSTRB信号控制哪些字节有效。我见过有人忘了处理WSTRB,结果写进去的数据全是乱的。

曾经踩过的坑:有一次我在做AXI到APB的桥接,从机的READY信号在复位后有一个时钟周期的毛刺。结果主机检测到READY有效就开始发数据,从机还没准备好,数据全丢了。后来我在READY路径上加了一级寄存器,问题就解决了。

好了,AXI的五个通道和握手协议就讲到这里。这些是AXI协议的基础,后面的内容都会基于这些概念展开。记住一句话——搞懂了握手,就搞懂了AXI的一半。

可可精品资料库