当前位置: 首页 > news >正文

【电路笔记 通信】AXI4-Lite协议 FPGA实现 Valid-Ready Handshake 握手协议

在这里插入图片描述

AXI4-Lite Top 模块

  • 本文的分析基于项目:https://github.com/arhamhashmi01/Axi4-lite/tree/main/Axi4-lite-vivado

  • 寄存器转换级略图 RTL SCHEMATIC:
    在这里插入图片描述
            

  • 重新涂色与标注的效果:

在这里插入图片描述

  • 注:常见一种做法是 Master 直接常拉高 BREADY,参考代码未使用,这样只要 Slave 提供写响应,握手就能立即完成,不会卡住,这样可以大幅简化逻辑:

    • Master 的 RREADY、BREADY → 可以常高(随时能接收)。
    • Slave 的 AWREADY、WREADY、ARREADY → 也可以常高(随时能接收)。
  • 注:上图Slave侧只标注了 Read Channel (Slave -> Master)

`timescale 1ns / 1ps
module axi4_lite_top#(// 参数定义parameter DATA_WIDTH = 32,    // 数据宽度parameter ADDRESS    = 32     // 地址宽度)(input                           ACLK,       // AXI 时钟信号input                           ARESETN,    // AXI 复位信号(低有效)input                           read_s,     // 顶层控制信号:触发读事务input                           write_s,    // 顶层控制信号:触发写事务input    [ADDRESS-1:0]          address,    // 顶层输入地址input    [DATA_WIDTH-1:0]       W_data      // 顶层输入写数据);// AXI Master-Slave 之间交互的信号线定义logic  M_ARREADY, S_RVALID, M_ARVALID, M_RREADY;logic  S_AWREADY, S_BVALID, M_AWVALID, M_BREADY;logic  M_WVALID,  S_WREADY;logic [ADDRESS-1 : 0]  M_ARADDR;  // Master -> Slave 读地址logic [ADDRESS-1 : 0]  M_AWADDR;  // Master -> Slave 写地址logic [DATA_WIDTH-1:0] M_WDATA;   // Master -> Slave 写数据logic [DATA_WIDTH-1:0] S_RDATA;   // Slave -> Master 读数据logic [3:0]            M_WSTRB;   // 写数据字节使能(32bit=4字节,所以 4bit),写数据掩码logic [1:0]            S_RRESP;   // Slave -> Master 读响应logic [1:0]            S_BRESP;   // Slave -> Master 写响应// 实例化 AXI4-Lite Masteraxi4_lite_master u_axi4_lite_master0(.ACLK       (ACLK),.ARESETN    (ARESETN),// 控制信号.START_READ (read_s),      // 触发读.START_WRITE(write_s),     // 触发写.address    (address),     // 读写地址.W_data     (W_data),      // 写入数据// Read Channel (Master -> Slave).M_ARADDR   (M_ARADDR),    // 读地址.M_ARVALID  (M_ARVALID),   // 地址有效.M_ARREADY  (M_ARREADY),   // 从机就绪.M_RDATA    (S_RDATA),     // 从机返回的数据.M_RRESP    (S_RRESP),     // 读响应(OKAY/SLVERR).M_RVALID   (S_RVALID),    // 从机返回数据有效.M_RREADY   (M_RREADY),    // 主机准备好接收数据// Write Channel (Master -> Slave).M_AWADDR   (M_AWADDR),    // 写地址.M_AWVALID  (M_AWVALID),   // 地址有效.M_AWREADY  (S_AWREADY),   // 从机就绪.M_WDATA    (M_WDATA),     // 写数据.M_WSTRB    (M_WSTRB),     // 写数据掩码.M_WVALID   (M_WVALID),    // 写数据有效.M_WREADY   (S_WREADY),    // 从机准备好接收数据.M_BRESP    (S_BRESP),     // 从机写响应.M_BVALID   (S_BVALID),    // 响应有效.M_BREADY   (M_BREADY)     // 主机准备好接收响应);// 实例化 AXI4-Lite Slaveaxi4_lite_slave u_axi4_lite_slave0(.ACLK       (ACLK),.ARESETN    (ARESETN),// Read Channel (Slave -> Master).S_ARADDR   (M_ARADDR),    // 主机发来的读地址.S_ARVALID  (M_ARVALID),   // 地址有效.S_ARREADY  (M_ARREADY),   // 从机就绪.S_RDATA    (S_RDATA),     // 返回的数据.S_RRESP    (S_RRESP),     // 读响应.S_RVALID   (S_RVALID),    // 数据有效.S_RREADY   (M_RREADY),    // 主机就绪// Write Channel (Slave -> Master).S_AWADDR   (M_AWADDR),    // 主机发来的写地址.S_AWVALID  (M_AWVALID),   // 地址有效.S_AWREADY  (S_AWREADY),   // 从机就绪.S_WDATA    (M_WDATA),     // 写数据.S_WSTRB    (M_WSTRB),     // 写数据掩码.S_WVALID   (M_WVALID),    // 数据有效.S_WREADY   (S_WREADY),    // 从机就绪.S_BRESP    (S_BRESP),     // 写响应.S_BVALID   (S_BVALID),    // 响应有效.S_BREADY   (M_BREADY)     // 主机准备接收响应);
endmodule

axi4_lite_top描述

这个 axi4_lite_top 模块就是一个 AXI4-Lite 主从对接的顶层封装

  • axi4_lite_master 接收顶层输入的 read_s / write_s 信号,发起 AXI 读写事务;
  • axi4_lite_slave 响应 Master 的请求,返回读写数据与响应;
  • 两者通过 AXI4-Lite 信号互联,形成一个完整的读写通路。

激励文件

`timescale 1ns / 1ps
module axi4_lite_top_tb();logic           ACLK_tb;logic           ARESETN_tb;//logic           read_s_tb;     // 注释掉读信号logic           write_s_tb;logic [31:0]    address_tb;logic [31:0]    W_data_tb;axi4_lite_top u_axi4_lite_top0(.ACLK(ACLK_tb),.ARESETN(ARESETN_tb),//.read_s(read_s_tb),   // 注释掉读接口.write_s(write_s_tb),.address(address_tb), // 顶层输入地址.W_data(W_data_tb)    // 顶层输入写数据);initial begin#5;ACLK_tb=0;ARESETN_tb=0;//read_s_tb=0;    // 注释掉读操作write_s_tb=0;                           #5;ACLK_tb=1;ARESETN_tb=1;write_s_tb=0;#15;// -------- 写测试开始 --------write_s_tb=1;address_tb = 5;W_data_tb = 4;#10;write_s_tb=0;#20;// -------- 写测试结束 --------// -------- 以下是读测试,注释掉 --------//write_s_tb=0;//read_s_tb=0;//#30;//read_s_tb=1;//address_tb = 5;//#10;//read_s_tb=0;// -----------------------------------#40;$finish;            endalways begin#5 ACLK_tb = ~ACLK_tb;end
endmodule

AXI4-Lite 主设备(Master)

时序分析

  • 仿真的写时序

在这里插入图片描述

VALID & READY 握手基本规则
  • VALID:由 发送方 发出,表示“数据/地址/响应已经准备好,可以被接收”。

  • READY:由 接收方 发出,表示“我已经准备好接收”。

  • 握手成功条件: 当 VALID = 1 且 READY = 1 时,数据才算真正传输成功。

  • 握手特点

    • VALID 不能依赖 READY 才拉高(发送方必须主动把数据放出来)。
    • READY 可以提前为高,也可以等到看到 VALID 才拉高。
    • 只有 VALID 和 READY 同时为高的那个时钟周期,传输的数据才被“采纳”。例如:

assign write_addr = M_AWVALID && M_AWREADY; // 地址握手完成条件
         // 写地址和写数据握手都完成 → 等待写响应
         WRITE_CHANNEL : if (write_addr && write_data)
                 next_state = WRESP__CHANNEL;

握手条件是 M_ARVALID && M_ARREADY,FSM 中体现为:
        RADDR_CHANNEL : if (M_ARVALID && M_ARREADY)
                  next_state = RDATA__CHANNEL; // 读地址握手成功,进入等待读数据状态。

  • 官方写时序 :https://docs.amd.com/r/en-US/pg202-mipi-dphy/AXI4-Lite-Interface
    在这里插入图片描述

状态机

  • AXI4-Lite Master 状态机,能发起 一次读事务一次写事务,并根据握手机制自动切换状态。状态机流程:
  1. IDLE → 等待外部触发
  2. WRITE_CHANNEL → 发送地址和数据
  3. WRESP__CHANNEL → 等待写响应
  4. RADDR_CHANNEL → 发送读地址
  5. RDATA__CHANNEL → 等待读数据

代码实现

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 05/04/2024 05:52:55 PM
// Design Name: 
// Module Name: axi4_lite_master
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: AXI4-Lite Master 实现,包含读写通道握手逻辑和有限状态机
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////module axi4_lite_master #(parameter ADDRESS = 32,       // 地址总线宽度parameter DATA_WIDTH = 32     // 数据总线宽度)(// ================= 全局信号 ==================input                           ACLK,       // AXI 时钟input                           ARESETN,    // AXI 低电平复位 (active low)input                           START_READ,   // 触发一次读事务input                           START_WRITE,  // 触发一次写事务input          [ADDRESS-1 : 0]  address,     // 读/写地址,来自TOPinput          [DATA_WIDTH-1:0] W_data,      // 要写入的数据,来自TOP// =============== AXI4-Lite 输入信号(从 Slave 来) ===============// Read Address Channelinput                           M_ARREADY,   // 从机准备好接收读地址// Read Data Channelinput          [DATA_WIDTH-1:0] M_RDATA,     // 从机返回的数据input               [1:0]       M_RRESP,     // 从机返回的响应input                           M_RVALID,    // 从机提供的数据有效// Write Address Channelinput                           M_AWREADY,   // 从机准备好接收写地址// Write Data Channelinput                           M_WREADY,    // 从机准备好接收写数据// Write Response Channelinput             [1:0]         M_BRESP,     // 从机返回的写响应input                           M_BVALID,    // 从机写响应有效// =============== AXI4-Lite 输出信号(Master 发出) ===============// Read Address Channeloutput logic    [ADDRESS-1 : 0] M_ARADDR,    // 读地址output logic                    M_ARVALID,   // 读地址有效// Read Data Channeloutput logic                    M_RREADY,    // Master 准备好接收数据// Write Address Channeloutput logic    [ADDRESS-1 : 0] M_AWADDR,    // 写地址output logic                    M_AWVALID,   // 写地址有效// Write Data  Channeloutput logic   [DATA_WIDTH-1:0] M_WDATA,     // 写数据output logic   [3:0]            M_WSTRB,     // 写掩码(字节选通)output logic                    M_WVALID,    // 写数据有效// Write Response Channeloutput logic                    M_BREADY     // Master 准备好接收写响应);// ============== 内部寄存器与信号 ==============logic read_start;     // 记录一次读事务开始logic write_addr;     // 写地址握手完成标志logic write_data;     // 写数据握手完成标志logic write_start;    // 记录一次写事务开始// 状态机定义:AXI4-Lite 事务状态typedef enum logic [2 : 0] {IDLE,            // 空闲状态WRITE_CHANNEL,   // 发送写地址和写数据WRESP__CHANNEL,  // 等待写响应RADDR_CHANNEL,   // 发送读地址RDATA__CHANNEL   // 等待读数据返回} state_type;state_type state , next_state;// ============== AXI4-Lite 接口输出逻辑 ==============// --- Read Address Channel ---assign M_ARADDR  = (state == RADDR_CHANNEL) ? address : 32'h0;  // 只有在发读地址时有效assign M_ARVALID = (state == RADDR_CHANNEL) ? 1 : 0;            // 发出读地址握手信号// --- Read Data Channel ---assign M_RREADY  = (state == RDATA__CHANNEL || state == RADDR_CHANNEL) ? 1 : 0; // 进入读阶段时,准备接收数据// --- Write Address Channel ---assign M_AWVALID = (state == WRITE_CHANNEL) ? 1 : 0;            // 发出写地址握手信号assign M_AWADDR  = (state == WRITE_CHANNEL) ? address : 32'h0;  // 写地址assign write_addr = M_AWVALID && M_AWREADY;                     // 地址握手完成条件assign write_data = M_WVALID  && M_WREADY;                      // 数据握手完成条件// --- Write Data Channel ---assign M_WVALID  = (state == WRITE_CHANNEL) ? 1 : 0;            // 写数据有效assign M_WDATA   = (state == WRITE_CHANNEL) ? W_data : 32'h0;   // 写数据assign M_WSTRB   = (state == WRITE_CHANNEL) ? 4'b1111 : 0;      // 默认写全字节// --- Write Response Channel ---assign M_BREADY  = ((state == WRITE_CHANNEL)||(state == WRESP__CHANNEL)) ? 1 : 0; // Master 随时准备接收写响应// ============== 状态机寄存器(时序逻辑) ==============always_ff @(posedge ACLK) beginif (~ARESETN) beginstate <= IDLE;   // 复位回到空闲态end else beginstate <= next_state; // 状态跳转endend// 捕捉输入控制信号,打一拍always_ff @(posedge ACLK) beginif (~ARESETN) beginread_start  <= 0;write_start <= 0;end else beginread_start  <= START_READ;   // 外部触发读write_start <= START_WRITE;  // 外部触发写endend// ============== 状态机组合逻辑 ==============always_comb begincase (state)// 空闲态:等待开始信号IDLE : beginif (write_start) beginnext_state = WRITE_CHANNEL;   // 进入写地址/数据阶段end else if (read_start) beginnext_state = RADDR_CHANNEL;   // 进入读地址阶段end else beginnext_state = IDLE;endend// 发读地址 → 等待读数据RADDR_CHANNEL  : if (M_ARVALID && M_ARREADY) next_state = RDATA__CHANNEL;// 读数据握手成功 → 回到空闲RDATA__CHANNEL : if (M_RVALID && M_RREADY) next_state = IDLE;// 写地址和写数据握手都完成 → 等待写响应WRITE_CHANNEL  : if (write_addr && write_data) next_state = WRESP__CHANNEL;// 写响应握手成功 → 回到空闲WRESP__CHANNEL : if (M_BVALID && M_BREADY) next_state = IDLE;// 默认兜底default : next_state = IDLE;endcaseend
endmodule

AXI4-Lite 从设备(Slave)

  • IDLE → AW (写地址握手) → W (写数据握手) → B (写应答) → IDLE
  • IDLE → AR (读地址握手) → R (读数据握手) → IDLE
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 05/04/2024 05:52:55 PM
// Design Name: 
// Module Name: axi4_lite_slave
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: AXI4-Lite 从设备,内部包含一个寄存器阵列,用于存储和返回数据。
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////

模块定义

module axi4_lite_slave #(parameter ADDRESS = 32,      // 地址宽度(通常为 32 bit)parameter DATA_WIDTH = 32    // 数据总线宽度(通常为 32 bit))(// 全局信号input                           ACLK,      // 时钟信号input                           ARESETN,   // 复位信号,低有效//// Read Address Channel (读地址通道) 输入input           [ADDRESS-1:0]   S_ARADDR,  // 读地址input                           S_ARVALID, // 读地址有效// Read Data Channel (读数据通道) 输入input                           S_RREADY,  // 主设备准备好接收数据// Write Address Channel (写地址通道) 输入input           [ADDRESS-1:0]   S_AWADDR,  // 写地址input                           S_AWVALID, // 写地址有效// Write Data Channel (写数据通道) 输入input          [DATA_WIDTH-1:0] S_WDATA,   // 写数据input          [3:0]            S_WSTRB,   // 写字节使能(通常忽略,写全字)input                           S_WVALID,  // 写数据有效// Write Response Channel (写响应通道) 输入input                           S_BREADY,  // 主设备准备好接收写响应	// Read Address Channel 输出output logic                    S_ARREADY, // 从设备准备好接收读地址// Read Data Channel 输出output logic    [DATA_WIDTH-1:0]S_RDATA,   // 从设备返回的数据output logic         [1:0]      S_RRESP,   // 读响应(OKAY=00)output logic                    S_RVALID,  // 读数据有效// Write Address Channel 输出output logic                    S_AWREADY, // 从设备准备好接收写地址output logic                    S_WREADY,  // 从设备准备好接收写数据// Write Response Channel 输出output logic         [1:0]      S_BRESP,   // 写响应(OKAY=00)output logic                    S_BVALID   // 写响应有效);

内部变量和寄存器定义

    localparam no_of_registers = 32;               // 定义 32 个寄存器(寄存器阵列)logic [DATA_WIDTH-1 : 0] register [no_of_registers-1 : 0]; // 从设备内部存储器logic [ADDRESS-1 : 0]    addr;                 // 保存当前访问地址logic  write_addr;                             // 写地址握手成功标志logic  write_data;                             // 写数据握手成功标志

FSM(有限状态机)状态定义

    typedef enum logic [2 : 0] {IDLE,           // 空闲WRITE_CHANNEL,  // 等待写地址 + 写数据WRESP__CHANNEL, // 写响应RADDR_CHANNEL,  // 接收读地址RDATA__CHANNEL  // 返回读数据} state_type;state_type state , next_state;

信号分配

    // 读地址握手assign S_ARREADY = (state == RADDR_CHANNEL) ? 1 : 0;// 读数据返回assign S_RVALID = (state == RDATA__CHANNEL) ? 1 : 0;assign S_RDATA  = (state == RDATA__CHANNEL) ? register[addr] : 0; // 从寄存器阵列读数据assign S_RRESP  = (state == RDATA__CHANNEL) ? 2'b00 : 0;          // OKAY// 写地址握手assign S_AWREADY = (state == WRITE_CHANNEL) ? 1 : 0;// 写数据握手assign S_WREADY = (state == WRITE_CHANNEL) ? 1 : 0;assign write_addr = S_AWVALID && S_AWREADY;   // 地址握手成功assign write_data = S_WREADY && S_WVALID;     // 数据握手成功// 写响应assign S_BVALID = (state == WRESP__CHANNEL) ? 1 : 0;assign S_BRESP  = (state == WRESP__CHANNEL) ? 2'b00 : 0;          // OKAY

寄存器读写逻辑

    integer i;always_ff @(posedge ACLK) begin// 异步复位:清零寄存器if (~ARESETN) beginfor (i = 0; i < 32; i++) beginregister[i] <= 32'b0;endendelse begin// 写操作if (state == WRITE_CHANNEL) beginregister[S_AWADDR] <= S_WDATA;  // 将写数据存入地址对应寄存器end// 读操作else if (state == RADDR_CHANNEL) beginaddr <= S_ARADDR;               // 保存读地址endendend

状态机转换

    // 状态寄存器always_ff @(posedge ACLK) beginif (!ARESETN) beginstate <= IDLE;endelse beginstate <= next_state;endend// 下一个状态逻辑always_comb begincase (state)IDLE : beginif (S_AWVALID) beginnext_state = WRITE_CHANNEL;   // 有写请求end else if (S_ARVALID) beginnext_state = RADDR_CHANNEL;   // 有读请求end else beginnext_state = IDLE;endendRADDR_CHANNEL   : if (S_ARVALID && S_ARREADY ) next_state = RDATA__CHANNEL;RDATA__CHANNEL  : if (S_RVALID  && S_RREADY  ) next_state = IDLE;WRITE_CHANNEL   : if (write_addr && write_data) next_state = WRESP__CHANNEL;WRESP__CHANNEL  : if (S_BVALID  && S_BREADY  ) next_state = IDLE;default : next_state = IDLE;endcaseend
endmodule
http://www.dtcms.com/a/335457.html

相关文章:

  • 【计算机网络面试】键入网址到网页显示期间,发生了什么?
  • Tomcat Connector连接器原理
  • Bee1.17.25更新Bug,完善功能.不支持NOSQL,分库分表Sharding(2.X版有)
  • Rust Async 异步编程(一):入门
  • AI评测的科学之道:当Benchmark遇上统计学
  • uniapp中uni.showToast和 uni.showLoading同时使用时出现提示中断冲突问题。
  • Maven 开发实践
  • Java ConcurrentHashMap 深度解析
  • Mitt 事件发射器完全指南:200字节的轻量级解决方案
  • Git 命令指南:从 0 到熟练、从常用到“几乎全集”(含常见报错与解决)建议收藏!!!
  • Leetcode 深度优先搜索 (2)
  • Java多线程进阶-JUC之ReentrantLock与Callable
  • Oracle algorithm的含义
  • 【牛客刷题】01字符串按递增长度截取并转换为十进制数值
  • 26. 值传递和引用传递的区别的什么?为什么说Java中只有值传递
  • 告别“测试滞后”:AI实时测试工具在敏捷开发中的落地经验
  • 【JavaEE】多线程 -- 单例模式
  • 基于Python的情感分析与情绪识别技术深度解析
  • 锂电池SOH预测 | Matlab基于KPCA-PLO-Transformer-LSTM的的锂电池健康状态估计(锂电池SOH预测),附锂电池最新文章汇集
  • CVPR2 2025丨大模型创新技巧:文档+语音+视频“大模型三件套”
  • 音频分类标注工具
  • 91.解码方法
  • GaussDB 数据库架构师修炼(十三)安全管理(5)-全密态数据库
  • 17.5 展示购物车缩略信息
  • JMeter(进阶篇)
  • 3D打印——给开发板做外壳
  • 蓝凌EKP产品:JSP 性能优化和 JSTL/EL要点检查列表
  • Trae 辅助下的 uni-app 跨端小程序工程化开发实践分享
  • Docker之自定义jkd镜像上传阿里云
  • Spring AI 集成阿里云百炼平台