[FPGA基础] AXI4篇

Xilinx FPGA AXI4 使用文档

1. 概述

AXI4(Advanced eXtensible Interface 4)是ARM公司AMBA协议中的高性能互连协议,广泛应用于Xilinx FPGA,用于处理器、IP核和自定义逻辑间的高带宽数据通信。本文档聚焦于AXI4(全AXI4)协议的使用,涵盖协议概述、信号描述、设计流程、Vivado相关IP核及示例代码,不涉及AXI4-Lite和AXI4-Stream。

2. AXI4 协议简介

AXI4是面向存储器映射的点对点通信协议,支持高带宽、低延迟的突发传输,适用于DMA、存储器接口等场景。

2.1 AXI4 关键特性

  • 独立通道:读地址、读数据、写地址、写数据、写响应五个通道独立操作,提升并发性。
  • 突发传输:支持固定(FIXED)、增量(INCR)和回绕(WRAP)突发,最大突发长度256次。
  • 灵活数据宽度:支持32位、64位、128位等,需与硬件匹配。
  • 对齐与非对齐传输:支持多种数据对齐方式。
  • 响应机制:支持OKAY、EXOKAY、SLVERR、DECERR等多种响应状态。

3. AXI4 接口信号描述

以下为AXI4协议的主要信号描述:

信号名方向描述
ACLK输入全局时钟信号,所有信号同步于此。
ARESETN输入全局复位信号,低电平有效。
写地址通道
AWADDR主->从写地址,指定写操作的目标地址。
AWLEN主->从突发长度,0表示1次传输,255表示256次传输。
AWSIZE主->从每次传输的字节数(2^n,n=0到7,如2表示4字节)。
AWBURST主->从突发类型:0(FIXED)、1(INCR)、2(WRAP)。
AWVALID主->从写地址有效信号。
AWREADY从->主写地址就绪信号。
写数据通道
WDATA主->从写数据。
WSTRB主->从写数据选通信号,指示哪些字节有效(每位对应一个字节)。
WLAST主->从写数据最后一个传输的标志。
WVALID主->从写数据有效信号。
WREADY从->主写数据就绪信号。
写响应通道
BRESP从->主写响应状态:0(OKAY)、1(EXOKAY)、2(SLVERR)、3(DECERR)。
BVALID从->主写响应有效信号。
BREADY主->从写响应就绪信号。
读地址通道
ARADDR主->从读地址,指定读操作的目标地址。
ARLEN主->从读突发长度,0表示1次传输,255表示256次传输。
ARSIZE主->从每次传输的字节数(2^n,n=0到7)。
ARBURST主->从读突发类型:0(FIXED)、1(INCR)、2(WRAP)。
ARVALID主->从读地址有效信号。
ARREADY从->主读地址就绪信号。
读数据通道
RDATA从->主读数据。
RRESP从->主读响应状态:0(OKAY)、1(EXOKAY)、2(SLVERR)、3(DECERR)。
RLAST从->主读数据最后一个传输的标志。
RVALID从->主读数据有效信号。
RREADY主->从读数据就绪信号。

4. Xilinx FPGA 中的 AXI4 设计流程

在Xilinx FPGA中使用AXI4协议通常包括以下步骤:

4.1 需求分析

  • 确定数据带宽需求(如32位、64位、128位)。
  • 选择突发类型(INCR最常用,WRAP用于缓存,FIXED用于固定地址)。
  • 确定主从设备角色(处理器为Master,存储器为Slave)。

4.2 使用 Vivado IP 核

Vivado提供多个AXI4相关IP核,简化设计流程。以下为常用IP核:

  • AXI Interconnect (PG059)

    • 功能:连接多个AXI4主从设备,支持时钟域转换、数据宽度转换和协议转换。
    • 配置:支持1到16个主/从接口,数据宽度32/64/128/256/512位。
    • 用途:构建复杂的多主多从系统,如Zynq SoC中的PS到PL通信。
  • AXI DMA (PG021)

    • 功能:实现高效的数据搬运,支持AXI4存储器映射接口。
    • 配置:支持Scatter-Gather模式、数据宽度32/64/128位、突发长度最大256。
    • 用途:处理器与PL间的高速数据传输,如图像处理或网络数据包处理。
  • AXI BRAM Controller (PG078)

    • 功能:将AXI4接口连接到片上Block RAM。
    • 配置:支持32/64位数据宽度,突发传输优化。
    • 用途:实现高速片上存储器访问。
  • AXI Memory Mapped to Stream Mapper (PG102)

    • 功能:将AXI4存储器映射接口转换为AXI4-Stream(本文不深入讨论,但常与AXI4配合)。
    • 配置:支持多种数据宽度和突发长度。
    • 用途:存储器数据到流式处理的桥接。
  • AXI Verification IP (PG267)

    • 功能:提供AXI4协议仿真验证工具,支持主/从/监控模式。
    • 配置:可模拟AXI4主从设备,检查协议合规性。
    • 用途:验证自定义AXI4 IP的正确性。

在Vivado中:

  1. 打开IP Catalog,搜索“AXI”。
  2. 选择所需IP核,配置参数(如数据宽度、突发长度、时钟域)。
  3. 生成IP核并集成到Block Design中。

4.3 自定义 AXI4 IP 设计

若现有IP核无法满足需求,可通过以下方式开发自定义AXI4 IP:

  1. Vivado IP Packager

    • 创建新IP,定义AXI4主或从接口。
    • 配置接口参数(如地址宽度、数据宽度)。
    • 打包为可复用IP核。
  2. Verilog/VHDL 实现

    • 编写AXI4主或从设备逻辑,遵循VALID/READY握手协议。
    • 实现突发传输逻辑,处理AWLEN、ARLEN、WLAST、RLAST等信号。
  3. 验证

    • 使用AXI Verification IP(AXI VIP)进行仿真。
    • 检查协议时序、响应状态和数据完整性。

4.4 时序设计

  • 所有信号需与ACLK同步。
  • 使用ARESETN进行复位初始化,确保复位后信号处于已知状态。
  • 遵循VALID/READY握手规则:VALID信号置位后需保持,直到READY置位完成握手。

4.5 调试

  • 使用Vivado ILA(Integrated Logic Analyzer)捕获AXI4信号。
  • 检查AWVALID/AWREADY、WVALID/WREADY等握手信号。
  • 验证突发长度(AWLEN/ARLEN)、地址对齐和响应状态(BRESP/RRESP)。

5. 示例:AXI4 从设备设计

以下为一个简单的AXI4从设备Verilog代码,支持突发写和读操作。

module axi4_slave #(
    parameter C_S_AXI_ADDR_WIDTH = 32,
    parameter C_S_AXI_DATA_WIDTH = 32
) (
    // AXI4 接口信号
    input  wire                          s_axi_aclk,
    input  wire                          s_axi_aresetn,
    // 写地址通道
    input  wire [C_S_AXI_ADDR_WIDTH-1:0] s_axi_awaddr,
    input  wire [7:0]                    s_axi_awlen,
    input  wire [2:0]                    s_axi_awsize,
    input  wire [1:0]                    s_axi_awburst,
    input  wire                          s_axi_awvalid,
    output wire                          s_axi_awready,
    // 写数据通道
    input  wire [C_S_AXI_DATA_WIDTH-1:0] s_axi_wdata,
    input  wire [C_S_AXI_DATA_WIDTH/8-1:0] s_axi_wstrb,
    input  wire                          s_axi_wlast,
    input  wire                          s_axi_wvalid,
    output wire                          s_axi_wready,
    // 写响应通道
    output wire [1:0]                    s_axi_bresp,
    output wire                          s_axi_bvalid,
    input  wire                          s_axi_bready,
    // 读地址通道
    input  wire [C_S_AXI_ADDR_WIDTH-1:0] s_axi_araddr,
    input  wire [7:0]                    s_axi_arlen,
    input  wire [2:0]                    s_axi_arsize,
    input  wire [1:0]                    s_axi_arburst,
    input  wire                          s_axi_arvalid,
    output wire                          s_axi_arready,
    // 读数据通道
    output wire [C_S_AXI_DATA_WIDTH-1:0] s_axi_rdata,
    output wire [1:0]                    s_axi_rresp,
    output wire                          s_axi_rlast,
    output wire                          s_axi_rvalid,
    input  wire                          s_axi_rready
);

// 内部存储器(模拟存储器)
reg [C_S_AXI_DATA_WIDTH-1:0] mem [0:1023];
reg                         awready;
reg                         wready;
reg [1:0]                   bresp;
reg                         bvalid;
reg                         arready;
reg [C_S_AXI_DATA_WIDTH-1:0] rdata;
reg [1:0]                   rresp;
reg                         rvalid;
reg                         rlast;

// 写地址通道
assign s_axi_awready = awready;
always @(posedge s_axi_aclk or negedge s_axi_aresetn) begin
    if (!s_axi_aresetn) begin
        awready <= 1'b0;
    end else begin
        if (s_axi_awvalid && !awready) begin
            awready <= 1'b1;
        end else begin
            awready <= 1'b0;
        end
    end
end

// 写数据通道
assign s_axi_wready = wready;
always @(posedge s_axi_aclk or negedge s_axi_aresetn) begin
    if (!s_axi_aresetn) begin
        wready <= 1'b0;
    end else begin
        if (s_axi_wvalid && !wready) begin
            wready <= 1'b1;
        end else begin
            wready <= 1'b0;
        end
    end
end

// 写操作
reg [C_S_AXI_ADDR_WIDTH-1:0] write_addr;
reg [7:0]                   burst_count;
always @(posedge s_axi_aclk or negedge s_axi_aresetn) begin
    if (!s_axi_aresetn) begin
        write_addr <= 0;
        burst_count <= 0;
    end else begin
        if (awready && s_axi_awvalid) begin
            write_addr <= s_axi_awaddr;
            burst_count <= s_axi_awlen;
        end
        if (wready && s_axi_wvalid) begin
            mem[write_addr[9:2]] <= s_axi_wdata;
            if (s_axi_wlast) begin
                write_addr <= 0;
                burst_count <= 0;
            end else begin
                write_addr <= write_addr + (1 << s_axi_awsize);
                burst_count <= burst_count - 1;
            end
        end
    end
end

// 写响应通道
assign s_axi_bresp = bresp;
assign s_axi_bvalid = bvalid;
always @(posedge s_axi_aclk or negedge s_axi_aresetn) begin
    if (!s_axi_aresetn) begin
        bvalid <= 1'b0;
        bresp  <= 2'b00; // OKAY
    end else begin
        if (wready && s_axi_wvalid && s_axi_wlast && !bvalid) begin
            bvalid <= 1'b1;
            bresp  <= 2'b00;
        end else if (s_axi_bready && bvalid) begin
            bvalid <= 1'b0;
        end
    end
end

// 读地址通道
assign s_axi_arready = arready;
always @(posedge s_axi_aclk or negedge s_axi_aresetn) begin
    if (!s_axi_aresetn) begin
        arready <= 1'b0;
    end else begin
        if (s_axi_arvalid && !arready) begin
            arready <= 1'b1;
        end else begin
            arready <= 1'b0;
        end
    end
end

// 读数据通道
assign s_axi_rdata = rdata;
assign s_axi_rresp = rresp;
assign s_axi_rvalid = rvalid;
assign s_axi_rlast = rlast;
reg [C_S_AXI_ADDR_WIDTH-1:0] read_addr;
reg [7:0]                   read_burst_count;
always @(posedge s_axi_aclk or negedge s_axi_aresetn) begin
    if (!s_axi_aresetn) begin
        rvalid <= 1'b0;
        rresp  <= 2'b00; // OKAY
        rdata  <= 0;
        rlast  <= 1'b0;
        read_addr <= 0;
        read_burst_count <= 0;
    end else begin
        if (arready && s_axi_arvalid && !rvalid) begin
            read_addr <= s_axi_araddr;
            read_burst_count <= s_axi_arlen;
            rvalid <= 1'b1;
            rresp  <= 2'b00;
            rdata  <= mem[s_axi_araddr[9:2]];
            rlast  <= (s_axi_arlen == 0);
        end else if (rvalid && s_axi_rready) begin
            if (read_burst_count == 0) begin
                rvalid <= 1'b0;
                rlast  <= 1'b0;
            end else begin
                read_addr <= read_addr + (1 << s_axi_arsize);
                read_burst_count <= read_burst_count - 1;
                rdata <= mem[read_addr[9:2] + 1];
                rlast <= (read_burst_count == 1);
            end
        end
    end
end
endmodule

5.1 示例说明

  • 该模块实现了一个AXI4从设备,支持突发读写操作。
  • 地址宽度32位,数据宽度32位,支持INCR突发(未实现WRAP和FIXED)。
  • 使用1024个32位存储单元模拟存储器。
  • 支持VALID/READY握手,响应状态为OKAY。
  • 可通过Vivado IP Packager打包为IP核。

6. 注意事项

  1. 时钟与复位

    • 确保所有信号与ACLK同步。
    • 使用ARESETN初始化信号状态。
  2. 握手协议

    • VALID信号需在READY之前或同时置位,且保持直到握手完成。
    • 避免死锁,确保READY信号及时响应。
  3. 突发传输

    • 正确处理AWLEN/ARLEN,确保突发长度不超过256。
    • 使用WLAST/RLAST标记最后一个传输。
  4. 数据对齐

    • 确保WSTRB信号正确指示有效字节。
    • 检查AWADDR/ARADDR对齐,防止越界访问。
  5. 性能优化

    • 优化突发长度,减少地址通道开销。
    • 使用AXI Interconnect处理多主多从场景。
  6. 调试与验证

    • 使用AXI VIP验证协议合规性。
    • 通过ILA检查握手时序、突发计数和响应状态。

7. 设计工具推荐

  • SZ901
    SZ901 是一款基于XVC协议的FPGA网络下载器。
    • 最高支持53M
    • 支持4路JTAG独立使用
    • 支持端口合并
    • 支持国产FLASH烧写
    • 下载器无限扩展
    • 配备专属程序固化软件,一键烧写,能大大减小程序固化时间!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值