FPGA教程系列-Vivado AXI4-Lite slave 测试

FPGA教程系列-Vivado AXI4-Lite slave 测试

新知识:

可以创建ip的时候,直接使用AXI4 VIP来验证IP

自动生成了一个BD的验证模块,这个功能在纯verilog里用的比较少,但是比较直观

代码解读:

  1. 模块声明与参数 (Parameters)
verilog 复制代码
module myip_axi_lite_slave_slave_lite_v1_0_S00_AXI #
(
    // ...
    parameter integer C_S_AXI_DATA_WIDTH = 32, // 数据总线宽度,通常为 32 位
    parameter integer C_S_AXI_ADDR_WIDTH = 4   // 地址总线宽度,4 位可以寻址 16 个字节(即4个32位寄存器)
)

定义了模块名称和可配置参数。通过参数化设计,使得该模块可以在不同位宽的系统中使用。这里默认是标准的 32 位数据宽和 4 位地址宽。

  1. 端口定义 (Ports) - AXI4-Lite 接口
verilog 复制代码
(
    input wire  S_AXI_ACLK,    // 全局时钟
    input wire  S_AXI_ARESETN, // 全局复位(低电平有效)
    // 写地址通道 (Write Address Channel)
    input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
    input wire [2 : 0] S_AXI_AWPROT, // 保护类型(通常不使用,保留)
    input wire  S_AXI_AWVALID,       // 主机发送:写地址有效
    output wire  S_AXI_AWREADY,      // 从机回复:准备好接收写地址
    // 写数据通道 (Write Data Channel)
    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_WVALID,        // 主机发送:写数据有效
    output wire  S_AXI_WREADY,       // 从机回复:准备好接收写数据
    // 写响应通道 (Write Response Channel)
    output wire [1 : 0] S_AXI_BRESP, // 从机回复:写操作状态(成功/失败)
    output wire  S_AXI_BVALID,       // 从机回复:写响应有效
    input wire  S_AXI_BREADY,        // 主机发送:准备好接收响应
    // 读地址通道 (Read Address Channel)
    input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
    input wire [2 : 0] S_AXI_ARPROT,
    input wire  S_AXI_ARVALID,
    output wire  S_AXI_ARREADY,
    // 读数据通道 (Read Data Channel)
    output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
    output wire [1 : 0] S_AXI_RRESP,
    output wire  S_AXI_RVALID,
    input wire  S_AXI_RREADY
);

定义了 AXI4-Lite 协议所需的 5 个通道(写地址、写数据、写响应、读地址、读数据)的所有信号。

关键点 :所有以 VALID​ 结尾的信号都是发送方发出的,所有以 READY 结尾的信号都是接收方发出的。只有当 VALID 和 READY 同时为高时,数据传输才算完成(握手成功)。

  1. 内部信号与地址解码参数
verilog 复制代码
// AXI4LITE 内部寄存器定义,用于驱动输出端口
reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr;
reg  axi_awready;
// ... (其他 axi_ 前缀的寄存器)

// 地址解码参数
localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1;
localparam integer OPT_MEM_ADDR_BITS = 1;

ADDR_LSB:这是地址最低有效位。在 32 位系统中,数据是 4 字节对齐的(地址 0x0, 0x4, 0x8...)。因此地址的最低 2 位(bit 0 和 bit 1)不用于选择寄存器,我们从 bit 2 开始看。如果数据宽是 64 位,则从 bit 3 开始看。

OPT_MEM_ADDR_BITS :用于决定需要几位地址线来区分寄存器。这里设为 1,意味着利用 2 位地址线(bit 2 和 bit 3)可以区分 2(1+1)=42^{(1+1)} = 42(1+1)=4 个寄存器。

  1. 用户寄存器定义 (User Registers)
verilog 复制代码
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg0;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg1;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg2;
reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg3;

这是该 IP 核的"心脏"。这 4 个寄存器就是主机通过 AXI 总线读写的目标。可以将逻辑控制信号连接到这些寄存器上。

  1. IO 连接与状态机定义
verilog 复制代码
assign S_AXI_AWREADY = axi_awready;
// ... (将内部寄存器连接到输出端口)

reg [1:0] state_write;
reg [1:0] state_read;
localparam Idle = 2'b00, Raddr = 2'b10, Rdata = 2'b11, Waddr = 2'b10, Wdata = 2'b11;

将内部逻辑信号输出,并定义读写状态机的状态(空闲、地址阶段、数据阶段)。

  1. 写状态机 (Write State Machine)
verilog 复制代码
always @(posedge S_AXI_ACLK)
begin
    // 复位逻辑 ...
    // case(state_write)
    // Idle: 等待复位结束,准备好接收地址 (axi_awready <= 1)
    // Waddr: 
    //    等待主机的写地址有效 (AWVALID) 和自身的准备好 (AWREADY)。
    //    如果写数据 (WVALID) 也同时也有效,说明地址和数据一起来了,直接完成握手,跳回 Waddr。
    //    如果只有地址来了但数据没来,进入 Wdata 状态等待数据。
    // Wdata:
    //    等待主机的写数据有效 (WVALID),握手完成后回到 Waddr 状态,并发出写响应 (BVALID)。
end

处理写操作的握手协议。它控制何时接收地址,何时接收数据,以及何时发送"写完成"信号。这个状态机主要负责控制信号(Ready/Valid)的流转,而不是数据的实际存储。

  1. 寄存器写入逻辑 (Memory Mapped Register Write Logic)
verilog 复制代码
always @( posedge S_AXI_ACLK )
begin
  // ... 复位清零 ...
  else begin
    if (S_AXI_WVALID) // 当写数据有效时
      begin
        // 根据地址选择写入哪个寄存器 (slv_reg0 ~ 3)
        case ( ... )
          2'h0: // 写 slv_reg0
            for ( byte_index = 0; ... ) // 循环处理字节选通
              if ( S_AXI_WSTRB[byte_index] == 1 ) 
                slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];
          // ... 处理 reg1, reg2, reg3
        endcase
      end
  end
end

这是实际保存数据的地方。

关键机制 (WSTRB) :AXI 支持字节写入。WSTRB​ 的每一位对应数据的一个字节。例如,如果 WSTRB​ 是 4'b0001​,则只写入最低的 8 位,高 24 位保持不变。for 循环就是为了实现这个功能。

  1. 读状态机 (Read State Machine)
verilog 复制代码
always @(posedge S_AXI_ACLK)
begin
    // ...
    // Idle: 复位后进入 Raddr,准备接收读地址 (axi_arready <= 1)
    // Raddr: 
    //    当主机发送有效的读地址 (ARVALID) 且从机准备好 (ARREADY) 时:
    //    锁存地址,拉高 axi_rvalid (告诉主机数据准备好了),进入 Rdata 状态。
    // Rdata:
    //    等待主机接收数据 (RREADY)。当主机读走数据后,拉低 rvalid,回到 Raddr 状态等待下一次读取。
end

处理读操作的握手协议。AXI-Lite 的读操作相对简单,收到地址后,下一周期通常就能给出数据。

  1. 读数据输出逻辑 (Read Data Generation)
verilog 复制代码
assign S_AXI_RDATA = (axi_araddr[...] == 2'h0) ? slv_reg0 : 
                     (axi_araddr[...] == 2'h1) ? slv_reg1 : 
                     (axi_araddr[...] == 2'h2) ? slv_reg2 : 
                     (axi_araddr[...] == 2'h3) ? slv_reg3 : 0;

这是一个多路选择器(MUX)。根据当前读状态机锁存的地址 (axi_araddr​),决定将 slv_reg0​ 到 slv_reg3​ 中的哪一个的值放到 S_AXI_RDATA 线上发回给主机。

仿真:

炫酷的AXI VIP IP效果。

还可以显示事务流程,虽然但是吧,可能也会有助于理解。

查看仿真的波形:

观察波形,对比状态机的图,应该是先进入了WADDR状态将地址写入,然后,由于WVALID为0,进入了WDATA状态,之后写数据。

可以参考状态机的跳转:

再看读数据:

其实主要就是看握手。

相关推荐
Wishell20151 天前
FPGA教程系列-Vivado AXI4-Lite接口
仿真
民乐团扒谱机4 天前
【微实验】仿AU音频编辑器开发实践:从零构建音频可视化工具
算法·c#·仿真·audio·fft·频谱
Wishell20154 天前
FPGA教程系列-Vivado AXI4-Stream Data FIFO核解读测试
仿真
Wishell20157 天前
FPGA教程系列-Vivado AXI4-Stream接口解读
仿真
民乐团扒谱机8 天前
十字路口交通信号灯控制器设计(Multisim 电路 + Vivado 仿真)
单片机·fpga开发·verilog·状态机·仿真·时序逻辑·multism
Wishell20158 天前
FPGA教程系列-Vivado AXI4-Stream自定义IP核
仿真
智行众维10 天前
【用户心得】SCANeR™Studio学习笔记(六):人因工程Pack——一站式搞定驾驶模拟的多模态数据同步
笔记·学习·自动驾驶·汽车·仿真·scaner·人因工程
世冠科技10 天前
建模仿真技术成为汽车产教融合新引擎,世冠科技董事长李京燕发表主题报告
仿真·国产软件
Wishell201511 天前
FPGA教程系列-Vivado Aurora 8B/10B 例程解读
仿真