2025-12-12studying

AXI-Lite 协议总结

博主

AXI-Lite 协议总结

1. AXI-Lite 背景介绍

1.1 什么是 AXI-Lite

AXI-Lite(Advanced eXtensible Interface Lite)是 ARM AMBA(Advanced Microcontroller Bus Architecture)协议族中的一种简化版 AXI 协议。它是 AXI4 协议的精简版本,专为简单的外设寄存器访问而设计。

1.2 适用场景

  • 寄存器映射外设:控制寄存器、状态寄存器的读写
  • 低速、小数据量通信:不适合大块数据传输
  • 简单的 Master-Slave 通信:一次只能传输一个数据字(32 位或 64 位)
  • PS-PL 交互:Zynq 中 PS 端通过 AXI-Lite 访问 PL 端的寄存器接口

1.3 与 AXI4 的主要区别

特性 AXI-Lite AXI4
数据宽度 32 位或 64 位 32/64/128/256/512/1024 位
突发传输 ❌ 不支持(每次只传输 1 个数据) ✅ 支持(最多 256 次)
事务 ID ❌ 不支持 ✅ 支持(用于乱序传输)
复杂度 简单 复杂
资源消耗

1.4 项目中的应用

在本项目中,我们使用 AXI-Lite 协议实现 Zynq PS 端(ARM 处理器)与 PL 端(FPGA 逻辑)之间的寄存器通信:

  • PS 端通过 M_AXI_GP0 接口作为 Master
  • PL 端实现 AXI-Lite Slave 接口
  • 实现 1024-bit 数据寄存器和标志位握手机制

2. AXI-Lite 信号说明

AXI-Lite 协议包含 5 个独立的通道,每个通道都有独立的握手机制:

2.1 全局信号

信号名 方向 说明
ACLK 输入 全局时钟信号
ARESETN 输入 全局复位信号(低电平有效,异步复位,同步释放)

2.2 写地址通道(AW Channel)

信号名 方向(相对于 Slave) 位宽 说明
S_AXI_AWADDR 输入 32/64 写地址,指向要写入的寄存器地址
S_AXI_AWPROT 输入 3 保护类型(访问权限,通常为 0)
S_AXI_AWVALID 输入 1 Master 发出的写地址有效信号
S_AXI_AWREADY 输出 1 Slave 发出的写地址就绪信号

2.3 写数据通道(W Channel)

信号名 方向(相对于 Slave) 位宽 说明
S_AXI_WDATA 输入 32/64 写数据,要写入寄存器的数据
S_AXI_WSTRB 输入 4/8 写数据选通信号(字节使能),指示哪些字节有效
S_AXI_WVALID 输入 1 Master 发出的写数据有效信号
S_AXI_WREADY 输出 1 Slave 发出的写数据就绪信号

2.4 写响应通道(B Channel)

信号名 方向(相对于 Slave) 位宽 说明
S_AXI_BRESP 输出 2 写响应状态: 00 = OKAY(正常) 01 = EXOKAY(独占访问) 10 = SLVERR(从设备错误) 11 = DECERR(解码错误)
S_AXI_BVALID 输出 1 Slave 发出的写响应有效信号
S_AXI_BREADY 输入 1 Master 发出的写响应就绪信号

2.5 读地址通道(AR Channel)

信号名 方向(相对于 Slave) 位宽 说明
S_AXI_ARADDR 输入 32/64 读地址,指向要读取的寄存器地址
S_AXI_ARPROT 输入 3 保护类型(访问权限,通常为 0)
S_AXI_ARVALID 输入 1 Master 发出的读地址有效信号
S_AXI_ARREADY 输出 1 Slave 发出的读地址就绪信号

2.6 读数据通道(R Channel)

信号名 方向(相对于 Slave) 位宽 说明
S_AXI_RDATA 输出 32/64 读数据,从寄存器读取的数据
S_AXI_RRESP 输出 2 读响应状态(与 BRESP 编码相同)
S_AXI_RVALID 输出 1 Slave 发出的读数据有效信号
S_AXI_RREADY 输入 1 Master 发出的读数据就绪信号

3. AXI-Lite 握手规则

AXI-Lite 采用双向握手机制(VALID/READY 握手),每个通道都是独立的。

3.1 基本握手规则

对于每个通道,传输发生需要满足:

VALID && READY == 1 (在时钟上升沿采样)

重要规则:

  1. VALID 信号:由发送方(Master 或 Slave)控制,一旦置高,必须保持高直到握手完成
  2. READY 信号:由接收方控制,可以随时置高或置低(但建议保持稳定)
  3. 握手完成:当 VALID == 1READY == 1 时,在时钟上升沿完成传输
  4. 独立性:各通道之间可以独立握手,但写操作需要 AW、W、B 三个通道都完成

3.2 重要约束和规则

关于这一点,可以参考 Arm 的 AMBA 总线协议手册:AMBA AXI Protocol Specification ,里面提供了一个经典的依赖关系图(Dependencies between channel handshake signals):

信号都是高位有效,单头箭头指向的信号可以在箭头开头的信号之前或之后置位,双头箭头指向的信号必须在箭头开头的信号断言之后才置位

image-20251221135957526

  1. VALID 不能依赖 READY:发送方不能等待 READY 才置高 VALID,但可以等待 READY 才撤销 VALID
  2. READY 可以先于 VALID 置高:接收方可以提前置高 READY,等待 VALID
  3. 死锁避免:Slave 必须能够响应任意有效的地址和数据,即使返回错误响应。
  4. 地址对齐:32 位数据必须 4 字节对齐(地址低 2 位为 0),64 位数据必须 8 字节对齐(地址低 3 位为 0)

3.3 本项目中遇到的问题

错误现象

  • 写地址通道和写数据通道独立握手,导致可能只有其中一个通道完成握手
  • bvalid 只检查了 wready && wvalid,没有检查写地址通道是否完成
  • 如果 AW 通道未完成但 W 通道完成,bvalid 会错误地置高
  • 导致 AXI 协议违反,Master 端卡死

正确做法

  • awreadywready 都应该等待对方通道也有效时才置高(或者都独立响应,但 B 通道必须等两者都完成)
  • bvalid 必须同时检查 awready && awvalidwready && wvalid 都完成

4. 问题分析和解决

4.1 波形分析

抓取的波形都放在文件夹 doc/ila波形/20251221波形 里面。

错误波形如下,握手不正确,很明显 bvalid 只针对 wreadywvalid 做了回应,但是没有对 awreadyawvalid 做回应。

image-20251221000626938

正确的波形(经过修改)

image-20251221010826705

read 读取波形正常(因为read相对简单,没有回复,所以后续说了,只放出波形)

image-20251221002102341

之前的代码:

// write AXI Addr
always @(posedge ps_axi_clk or negedge ps_axi_rst_n  ) begin
        if (!ps_axi_rst_n) begin
            ps_axi_awready <= 1'b0;
        end else begin
            if (~ps_axi_awready && ps_axi_awvalid) begin
                ps_axi_awready <= 1'b1;
            end else begin
                ps_axi_awready <= 1'b0;
            end
        end
    end
// write AXI data 
always @(posedge ps_axi_clk or negedge ps_axi_rst_n) begin
        if (!ps_axi_rst_n) begin
            ps_axi_wready <= 1'b0;
        end else begin
            if (~ps_axi_wready && ps_axi_wvalid ) begin
                ps_axi_wready <= 1'b1;
            end 
            else begin
                ps_axi_wready <= 1'b0;
            end
        end
    end
// AXI write respone
always @(posedge ps_axi_clk or negedge ps_axi_rst_n) begin
        if (!ps_axi_rst_n) begin
            ps_axi_bvalid <= 1'b0;
            ps_axi_bresp  <= 2'b0;
        end else begin
            if ( ps_axi_wready && ps_axi_wvalid && ~ps_axi_bvalid ) begin// 写地址,写数据都正确传输
                ps_axi_bvalid <= 1'b1;
                ps_axi_bresp  <= 2'b0;  // OKAY
            end 
            
            if (ps_axi_bready && ps_axi_bvalid ) begin
                ps_axi_bvalid <= 1'b0;
            end
        end
    end

更新的代码:

// write AXI Addr
always @(posedge ps_axi_clk or negedge ps_axi_rst_n  ) begin
        if (!ps_axi_rst_n) begin
            ps_axi_awready <= 1'b0;
        end else begin
            if (~ps_axi_awready && ps_axi_awvalid && ps_axi_wvalid) begin // modify!!!
                ps_axi_awready <= 1'b1;
            end else begin
                ps_axi_awready <= 1'b0;
            end
        end
    end
// write AXI data 
always @(posedge ps_axi_clk or negedge ps_axi_rst_n) begin
        if (!ps_axi_rst_n) begin
            ps_axi_wready <= 1'b0;
        end else begin
            if (~ps_axi_wready && ps_axi_wvalid && ps_axi_awvalid ) begin // modify!!!
                ps_axi_wready <= 1'b1;
            end 
            else begin
                ps_axi_wready <= 1'b0;
            end
        end
    end

always @(posedge ps_axi_clk or negedge ps_axi_rst_n) begin
        if (!ps_axi_rst_n) begin
            ps_axi_bvalid <= 1'b0;
            ps_axi_bresp  <= 2'b0;
        end else begin
            if ( ps_axi_awready && ps_axi_awvalid && ps_axi_wready && ps_axi_wvalid && ~ps_axi_bvalid ) begin// 写地址,写数据都正确传输
                ps_axi_bvalid <= 1'b1;
                ps_axi_bresp  <= 2'b00;  // OKAY
            end
            else if( ps_axi_wready && ps_axi_wvalid && ~ps_axi_bvalid ) begin
                ps_axi_bvalid <= 1'b1;
                ps_axi_bresp  <= 2'b10;  // SLVERR, in case of deadlock
            end
            else if( ps_axi_awready && ps_axi_awvalid && ~ps_axi_bvalid ) begin
                ps_axi_bvalid <= 1'b1;
                ps_axi_bresp  <= 2'b10;  // SLVERR, in case of deadlock
            end
            
            if (ps_axi_bready && ps_axi_bvalid ) begin
                ps_axi_bvalid <= 1'b0;
                ps_axi_bresp  <= 2'b00; 
            end
        end
    end

4.2 代码对比

错误代码的关键问题

  1. 写地址通道(AW)和写数据通道(W)独立握手

    // AW 通道只检查 awvalid
    if (~ps_axi_awready && ps_axi_awvalid) begin
        ps_axi_awready <= 1'b1;
    end
    
    // W 通道只检查 wvalid
    if (~ps_axi_wready && ps_axi_wvalid) begin
        ps_axi_wready <= 1'b1;
    end
    

    问题:两个通道可能不同时完成握手,导致后续逻辑错误

  2. 写响应通道(B)只检查写数据通道

    // 只检查 wready && wvalid,没有检查 awready && awvalid
    if (ps_axi_wready && ps_axi_wvalid && ~ps_axi_bvalid) begin
        ps_axi_bvalid <= 1'b1;
    end
    

    问题:如果 AW 通道未完成但 W 通道完成,会错误地发送写响应

正确代码的关键修改

  1. AW 和 W 通道等待对方也有效

    // AW 通道等待 W 通道也有效
    if (~ps_axi_awready && ps_axi_awvalid && ps_axi_wvalid) begin
        ps_axi_awready <= 1'b1;
    end
    
    // W 通道等待 AW 通道也有效
    if (~ps_axi_wready && ps_axi_wvalid && ps_axi_awvalid) begin
        ps_axi_wready <= 1'b1;
    end
    

    效果:确保两个通道基本同时完成握手

  2. B 通道检查两个通道都完成

    // 必须两个通道都完成才发送响应
    if (ps_axi_awready && ps_axi_awvalid && 
        ps_axi_wready && ps_axi_wvalid && 
        ~ps_axi_bvalid) begin
        ps_axi_bvalid <= 1'b1;
        ps_axi_bresp  <= 2'b00;  // OKAY
    end
    

    效果:确保写事务完整完成后才响应

  3. 添加错误处理(防止死锁)

    // 如果只有一个通道完成,返回错误响应(防止死锁)
    else if(ps_axi_wready && ps_axi_wvalid && ~ps_axi_bvalid) begin
        ps_axi_bvalid <= 1'b1;
        ps_axi_bresp  <= 2'b10;  // SLVERR
    end
    

    效果:即使出现异常情况也能响应,避免 Master 永久等待


5. 总结

5.1 实现成果

今天实现了 PS 端和 PL 端基于寄存器的交互,基于 PS-PL 使用了 AXI-Lite 协议。

5.2 遇到的问题及解决过程

  1. 问题发现

    • 程序在 Xil_Out 函数调用时崩溃
    • 经过调试发现不是立即崩溃,而是循环几次之后才崩溃
    • 怀疑是握手交互不对导致程序卡死
  2. 问题分析

    • 通过查看 AXI AMBA 总线协议手册,了解握手规则
    • 初步检查代码逻辑,看似没有问题
    • 使用 ILA 抓包,发现了错误的波形
    • 发现对 AXI-Lite 握手规则理解不够深入
  3. 问题根源

    • 写地址通道(AW)和写数据通道(W)独立握手,没有同步
    • 写响应通道(B)只检查了写数据通道,没有检查写地址通道
    • 导致协议违反,Master 端等待超时
  4. 解决方案

    • 修改 AW 和 W 通道的握手逻辑,要求对方通道也有效
    • 修改 B 通道响应逻辑,确保两个通道都完成
    • 添加错误处理机制,防止死锁

5.3 关键经验教训

  1. 理解协议细节很重要:AXI-Lite 的握手规则看似简单,但实现时容易忽略细节
  2. 调试工具很重要:ILA 抓包是发现时序问题的关键工具
  3. 错误处理很重要:即使出现异常情况,也应该能够响应,避免死锁
  4. 代码审查很重要:看似合理的代码可能违反协议规范

5.4 参考资料

  • ARM AMBA AXI Protocol Specification (ARM IHI 0022)
  • Xilinx AXI Reference Guide (UG761)
  • Vivado Design Suite User Guide (UG910)