一、创建 axi4-full-master 总线接口 IP
创建一个 AXI4-Full 接口总线 IP 设置 IP 的名字为 maxi_full 选择 Full Master 模式 打开快速验证 maxi_full_0就是我们自定义的 IP slave_0 是用来验证 maxi_full_0 正确性 采用默认地址分配即可 
路径 uisrc/03_ip/ maxi_full_1.0/hdl 路径下的 maxi_full_v1_0_M00_AXI.v 就是我们的源码。 另外一个 maxi_full_v1_0.v是软件产生了一个接口文件,如果我们自己定义 IP 可有可无。
二、程序分析
axi 总线信号的关键无非是地址和数据,而写地址的有效取决于 AXI_AWVALID 和AXI_AWREADY,写数据的有效取决于 S_AXI_WVALID 和 S_AXI_WREADY。同理,读地址的有效取决于 AXI_ARVALID 和 AXI_ARREADY,读数据的有效取决于 S_AXI_RVALID 和S_AXI_RREADY。所以以下代码的阅读分析注意也是围绕以上 4 个信号的有效时序。
1:产生初始化信号
同步打拍 + 边沿检测逻辑(核心是把外部的 INIT_AXI_TXN 信号同步到 AXI 时钟域,并生成一个单周期的 init_txn_pulse 启动脉冲),是跨时钟域 / 异步信号同步的典型设计)
- 同步异步信号:通过两级寄存器打拍,将外部异步的
INIT_AXI_TXN同步到 AXI 时钟域,避免亚稳态; - 生成单周期脉冲:配合边沿检测,将持续高电平的启动信号转为单周期的
init_txn_pulse; - 触发状态机:
init_txn_pulse作为状态机从IDLE启动的唯一触发信号,保证事务启动的精准性和唯一性
2:axi-full-master 的 axi_awvalid
当(~axi_awvalid && start_single_burst_write)== 1 条件满足,开始一次写传输,设置 axi_awvalid 有效。
写地址有效信号(axi_awvalid)的控制逻辑,核心遵循 AXI 协议中 “VALID 信号一旦置位就不能主动撤销,必须等待从机 READY 信号响应后才能清零” 的关键规则,专门用于管理写地址通道的握手流程 
- 复位 / 事务初始化(最高优先级) 当 AXI 异步复位信号
M_AXI_ARESETN为低电平,或事务启动脉冲init_txn_pulse有效时,直接将axi_awvalid清零。这是安全兜底逻辑,保证复位 / 新事务启动时,写地址通道处于 “无有效请求” 的初始状态,避免残留的有效信号导致误发起写地址请求。 - 发起写地址请求(次优先级) 仅当 “当前无有效写地址请求(
~axi_awvalid)” 且 “触发了单次突发写(start_single_burst_write有效)” 时,才将axi_awvalid置为高电平。这一条件确保:① 同一时间仅发起一个写地址请求,避免多个请求冲突;② 仅在外部触发写事务时才启动地址通道,符合 “按需发起” 的逻辑。 - 撤销写地址请求(遵循协议规则) 代码内的注释明确了 AXI 协议的核心要求:
VALID信号一旦置位,不能主动撤销(即不能在从机未响应时清零)。因此仅当 “从机已就绪(M_AXI_AWREADY=1)且主机写地址有效(axi_awvalid=1)”—— 也就是写地址握手完成(从机已接收地址)时,才将axi_awvalid清零,这是完全符合 AXI 协议的 “握手完成后撤销” 规则,避免协议违规导致的总线错误。 - 状态保持(兜底逻辑) 若以上条件都不满足(比如
axi_awvalid=1但M_AXI_AWREADY=0),则保持axi_awvalid的当前值不变。这意味着:当主机发起写地址请求(axi_awvalid=1)但从机暂未就绪时,axi_awvalid会持续保持高电平,直到从机响应(M_AXI_AWREADY=1),保证地址请求不会丢失,符合 AXI “VALID 需稳定到握手完成” 的要求。
3:axi-full-slave 的 axi_awaddr
写通道地址每当 M_AXI_AWREADY && axi_awvalid 地址加 1
AXI 主机写地址(axi_awaddr)的递增控制逻辑,核心作用是在每次写地址握手完成后,自动将写地址递增一个突发长度(burst_size_bytes),实现连续向从机 / DDR 的连续地址发起批量写事务,且严格遵循 AXI 协议的地址更新时机要求 
- 复位 / 事务初始化(最高优先级) 当 AXI 异步复位信号
M_AXI_ARESETN为低电平,或事务启动脉冲init_txn_pulse有效时,将写地址axi_awaddr清零('b0表示全 0)。这一逻辑保证:每次复位或新事务启动时,写地址都会回到初始值(通常是你预设的 DDR 起始地址,可在外部将初始值改为C_M_START_ADDR而非全 0),避免残留的旧地址导致数据写入错误位置。 - 地址递增(核心逻辑,对应原注释) 原注释 “Next address after AWREADY indicates previous address acceptance” 直接点明核心规则:只有当从机确认接收了上一个地址(写地址握手完成),才更新下一个地址。具体触发条件是
M_AXI_AWREADY && axi_awvalid(写地址通道握手完成),此时将当前地址加上burst_size_bytes(突发传输的字节数,比如 4 字节、8 字节,需与 AXI 数据位宽匹配),实现地址的连续递增。这一设计的关键优势: ① 地址更新时机严格滞后于 “地址被接收”,符合 AXI 协议 “地址需稳定到握手完成” 的要求,避免地址在传输过程中变化; ② 保证每次写入的地址都是连续的,适配批量写入 DDR 连续地址的场景 (比如从 0x80000000 → 0x80000004 → 0x80000008…)。 - 地址保持(兜底逻辑) 若以上条件都不满足(比如
axi_awvalid=1但M_AXI_AWREADY=0,即主机发起了地址请求但从机暂未就绪),则保持axi_awaddr不变。这意味着:在写地址握手完成前,当前地址会一直稳定,确保从机最终接收的是正确的地址,不会因地址提前递增导致错误。
与整体 AXI 写事务的联动 这段地址递增逻辑是你之前写事务流程的核心配套逻辑,联动关系如下:
- 与
axi_awvalid逻辑联动:axi_awvalid置位发起地址请求,握手完成后axi_awaddr自动递增,为下一次写事务准备好新地址; - 与
burst_size_bytes联动:burst_size_bytes是预设的突发长度(比如 32 位数据对应 4 字节,即burst_size_bytes=4),地址递增步长与数据位宽匹配,保证地址按字节对齐(AXI 协议要求); - 与
write_index联动:地址递增次数与write_index的计数次数一致,最终实现 “写索引每 + 1,地址递增一个突发长度”,精准对应 “每写一次数据,地址往后挪一个数据位宽” 的批量写入需求。
4:axi-full-master 的 axi_wvalid
设置 axi_wvalid <= 1'b1 开始写数据。wnext 信号有效代码 axi_full_master 写数据有效。 AXI 主机写数据通道(W 通道)核心控制逻辑,包含写数据有效信号(axi_wvalid)和写数据握手判定(wnext),严格遵循 AXI 协议中 “WVALID 一旦置位不可主动撤销,需等到突发传输完成(WLAST 置位 + 握手完成)才能清零” 的规则,专门管理批量突发写事务中数据的发送流程 
- 复位 / 事务初始化(最高优先级) 当 AXI 异步复位信号
M_AXI_ARESETN为低电平,或事务启动脉冲init_txn_pulse有效时,直接将axi_wvalid清零。这是安全兜底逻辑:保证复位 / 新事务启动时,写数据通道处于 “无有效数据发送” 的初始状态,避免残留的axi_wvalid=1导致误发送数据,同时与写地址通道(AW 通道)的复位逻辑保持一致,确保读写通道同步初始化。 - 发起写数据请求(次优先级) 仅当 “当前无有效写数据请求(
~axi_wvalid)” 且 “触发单次突发写(start_single_burst_write有效)” 时,才将axi_wvalid置为高电平。这一条件的核心作用:- 保证同一时间仅发起一个写数据请求,避免多个数据帧冲突;
- 与写地址通道的
axi_awvalid触发条件对齐(均由start_single_burst_write触发),确保 “地址请求” 和 “数据请求” 同步发起,符合 AXI 写事务 “地址 + 数据配套传输” 的规则; - 仅在外部触发写事务时才启动数据通道,实现 “按需发送数据”。
- 撤销写数据请求(遵循突发传输协议规则) 代码注释明确了 AXI 突发写的核心要求:
WVALID一旦置位,不能主动撤销,必须等到整个突发传输完成(最后一个数据帧由axi_wlast标识)且该数据帧完成握手(wnext=1,即M_AXI_WREADY && axi_wvalid)后,才能将axi_wvalid清零。wnext是组合逻辑定义的 “写数据握手完成” 标志,标识从机已成功接收当前数据帧;axi_wlast是 AXI 写数据通道的 “突发结束标志”,仅在单次突发传输的最后一个数据帧时置位;- 两者同时满足时清零
axi_wvalid,意味着 “整个突发传输的所有数据帧都已被从机接收”,此时撤销有效信号才符合协议规则,避免突发传输中途中断导致数据丢失。
- 状态保持(兜底逻辑) 若以上条件都不满足(比如
axi_wvalid=1但M_AXI_WREADY=0,或还未到最后一个数据帧),则保持axi_wvalid的当前值不变。这意味着:- 当主机发起写数据请求后,若从机暂未就绪(
M_AXI_WREADY=0),axi_wvalid会持续高电平,直到从机响应,保证数据帧不会丢失; - 在突发传输过程中(未到最后一个数据帧,
axi_wlast=0),即使单帧数据握手完成(wnext=1),axi_wvalid也会保持高电平,继续发送下一个数据帧,直到突发传输结束。
- 当主机发起写数据请求后,若从机暂未就绪(
5:axi-full-master 的 axi_master_last
axi_master_last 信号,当条件满足(((write_index == C_M_AXI_BURST_LEN-2 && C_M_AXI_BURST_LEN >= 2) && wnext) || (C_M_AXI_BURST_LEN == 1 )) == 1 的时候,axi_wlast <= 1'b1。这是 VIVADO 自带的模板,但是这里有个 bug,那就是必须确保 slave 可以连续接收数据,假设发送 last 的时候 wnext == 0,这样就不能把最后一个数据正确写入到 slave 中了。 AXI 主机写数据通道最后一个数据帧标志(axi_wlast)的生成逻辑,核心作用是精准标记单次突发写传输中的 “最后一个数据帧”,适配不同突发长度(C_M_AXI_BURST_LEN)的场景,且严格与写数据握手(wnext)同步,保证 AXI 突发写事务的完整性 
复位 / 事务初始化(最高优先级)
当 AXI 异步复位(
M_AXI_ARESETN=0)或事务启动脉冲(init_txn_pulse=1)有效时,直接清零axi_wlast。这是安全兜底逻辑:保证每次新事务启动时,“最后一个数据帧” 标志处于初始未触发状态,避免残留的axi_wlast=1导致突发传输提前终止。置位 axi_wlast(核心逻辑,适配不同突发长度)
这是代码的核心,分两种场景精准触发
axi_wlast=1,确保 “最后一个数据帧” 标记不提前、不滞后:场景 1:突发长度≥2(批量帧传输)
触发条件:
write_index == C_M_AXI_BURST_LEN-2+C_M_AXI_BURST_LEN >= 2+wnext=1。逻辑本质:写索引(
write_index)计数到 “突发长度 - 2”(倒数第二个数据帧)且该帧完成握手(wnext=1,从机已接收)时,置位axi_wlast—— 提前一拍标记,确保下一个数据帧发送时,axi_wlast=1同步生效,精准标记 “最后一个数据帧”。举例:若突发长度 = 4(需发送 4 帧数据),
write_index=2(4-2=2)且第 2 帧握手完成时,置位axi_wlast,第 3 帧(索引 3)发送时携带axi_wlast=1,标识这是最后一帧。场景 2:突发长度 = 1(单帧传输)
触发条件:
C_M_AXI_BURST_LEN == 1。逻辑本质:单帧传输时无需计数,直接置位
axi_wlast=1,标识这唯一的一帧就是最后一帧,符合 AXI 协议 “单帧突发也需置位 WLAST” 的要求。
清零 axi_wlast(通用场景)
当写数据握手完成(
wnext=1)时,直接清零axi_wlast。这一逻辑的核心作用:无论
axi_wlast是否置位,只要当前数据帧被从机接收,就撤销 “最后一个帧” 标志 —— 保证axi_wlast仅在 “最后一个帧传输期间” 有效,传输完成后立即清零,避免持续高电平导致后续传输误判。单帧突发的特殊清零(兜底)
触发条件:
axi_wlast=1+C_M_AXI_BURST_LEN == 1。逻辑补充:针对单帧突发场景,若因时序问题导致
wnext未及时触发清零,直接通过该条件清零axi_wlast,避免单帧传输后axi_wlast残留高电平。状态保持(兜底逻辑)
若以上条件都不满足(比如
axi_wlast=1但wnext=0,即最后一帧已标记但从机暂未接收),则保持axi_wlast不变,确保 “最后一个帧” 标志稳定到握手完成,符合 AXI 协议 “WLAST 需与对应数据帧的 WVALID 同步稳定” 的要求。
对原有 axi_wlast 生成逻辑的简化 + 时序优化版本,核心意义是通过 “组合逻辑判定 + 单拍延迟 + 边沿检测” 的方式,让 axi_wlast 生成逻辑更简洁、时序更稳定,且严格保证 axi_wlast 仅在 “最后一个数据帧握手完成” 的时刻产生单周期脉冲
逻辑极简:简化判定规则,降低出错概率
- 原有逻辑:需区分
C_M_AXI_BURST_LEN≥2/C_M_AXI_BURST_LEN=1,还要计算 “倒数第二个索引(C_M_AXI_BURST_LEN-2)”,规则复杂且易因突发长度配置错误导致 WLAST 标记错位; - 改写后逻辑:核心判定仅 1 条 ——
write_index==C_M_AXI_BURST_LEN-1(写索引到最后一帧计数)+wnext(数据握手完成),直接标识 “最后一个数据帧已被从机接收”,无需区分单帧 / 多帧,规则直观且不易出错。
- 原有逻辑:需区分
时序稳定:消除组合逻辑毛刺,提升可靠性
原有逻辑:
axi_wlast由时序逻辑直接赋值,若write_index或wnext存在组合逻辑毛刺,会直接导致axi_wlast异常;改写后逻辑:
① 先通过组合逻辑
wlast判定核心条件,再经寄存器wlast_r打拍延迟(同步到 AXI 时钟域),滤除组合逻辑的毛刺;② 最终通过 “上升沿检测(wlast_r=0 且 wlast=1)” 生成
axi_wlast,保证axi_wlast是纯净的单周期脉冲,不会因信号抖动出现多周期高电平,时序稳定性大幅提升。
协议合规:精准生成单周期 WLAST,符合 AXI 时序要求 AXI 协议要求
axi_wlast需与 “最后一个数据帧的axi_wvalid” 同步,且仅需在该帧传输期间有效(单周期即可):- 原有逻辑:
axi_wlast可能因条件分支多,出现 “多周期高电平”(比如从机未及时响应时,WLAST 持续高),虽不违反协议,但易导致后续axi_wvalid撤销逻辑误判; - 改写后逻辑:
axi_wlast是严格的单周期脉冲,仅在 “最后一帧握手完成” 的时钟周期有效,既满足协议 “标记最后一帧” 的要求,又避免持续高电平带来的误判风险。
- 原有逻辑:
可维护性:代码量减少 80%,易调试 / 易扩展
- 原有逻辑:7 + 行时序逻辑 + 多层条件分支,调试时需逐一验证 “单帧 / 多帧 / 复位 / 握手” 等场景;
- 改写后逻辑:仅 3 段核心代码(组合判定 + 单拍延迟 + 边沿检测),逻辑链路清晰,后续修改突发长度、调整判定条件时,仅需修改
C_M_AXI_BURST_LEN一个参数,维护成本大幅降低。
另外需要修改 reg axi_wlast;为 wire axi_wlast;这样就可以确保发送 wlast 的时候数据肯定是有效的。
6:写次数记录 write_index 计数器
AXI 主机突发写事务的帧计数寄存器(write_index)控制逻辑,核心作用是对单次突发写传输中的数据帧进行计数,通过 “初始化清零 + 逐帧递增 + 终端计数停止” 的逻辑,精准控制突发长度(C_M_AXI_BURST_LEN),且注释中提到的 “额外寄存器位简化解码逻辑” 是工业级设计的优化思路, 
- 功能定位
write_index 是 AXI 突发写事务的数据帧计数器,核心作用是:对单次突发传输中的数据帧逐帧计数,严格匹配配置的突发长度 C_M_AXI_BURST_LEN,为 axi_wlast(最后一帧标记)、axi_wvalid(数据有效撤销)提供精准的计数基准。
- 逻辑层级(优先级从高到低)
| 条件类型 | 触发场景 | 操作 | 设计目的 |
|---|---|---|---|
| 清零 | 1. 异步复位(M_AXI_ARESETN=0)2. 全局事务启动( init_txn_pulse=1)3. 单次突发写启动( start_single_burst_write=1) | 计数置 0 | 保证每次新突发写事务启动时,计数从 0 开始,避免旧值干扰 |
| 递增 | 1. 数据帧握手完成(wnext=1,即 M_AXI_WREADY && axi_wvalid)2. 未到最后一帧( write_index != C_M_AXI_BURST_LEN-1) | 计数 + 1 | 仅在 “实际传输完一帧数据” 且 “未到突发长度上限” 时递增,计数与实际传输帧同步 |
| 保持 | 无清零 / 递增触发(如最后一帧握手完成、从机未就绪) | 计数不变 | 避免 “未传输数据却计数” 或 “计数溢出”,保证计数精准 |
- 工业级优化思路(对应注释)
注释中 “Uses extra counter register bit to indicate terminal count” 是关键优化点:
- 常规设计:用
write_index == C_M_AXI_BURST_LEN-1判断最后一帧,需做 “相等比较” 的组合逻辑解码; - 优化设计:将
write_index位宽设计为 “突发长度所需位宽 + 1”(如突发长度 4 用 3 位寄存器),“终端计数(C_M_AXI_BURST_LEN-1)” 可通过寄存器最高位直接标识,减少解码逻辑的延迟,提升时序收敛性(代码中简化为相等比较,核心逻辑一致)。
执行流程示例(C_M_AXI_BURST_LEN=4)
| 阶段 | 触发条件 | write_index 值 | 说明 |
|---|---|---|---|
| 突发写启动 | start_single_burst_write=1 | 0 | 计数初始化 |
| 第 1 帧传输完成 | wnext=1 | 1 | 未到最后一帧,计数 + 1 |
| 第 2 帧传输完成 | wnext=1 | 2 | 未到最后一帧,计数 + 1 |
| 第 3 帧传输完成 | wnext=1 | 3 | 未到最后一帧,计数 + 1 |
| 第 4 帧传输完成 | wnext=1 | 3 | 已到最后一帧(3=4-1),计数停止 |
| 下一次突发启动 | start_single_burst_write=1 | 0 | 计数重新初始化 |
7:axi-full-master 的 axi_wdata
axi_full_master 写数据计数写数据 
- 功能定位
axi_wdata 是 AXI 写数据通道的核心信号,这段代码实现简单递增型写数据生成逻辑:每次突发传输启动后,数据从初始值(1)开始,每成功传输一帧数据(握手完成)就自动 + 1,生成连续递增的数据流,用于 AXI 写事务的基础数据填充(如功能测试、数据校验)。
- 逻辑层级(优先级从高到低)
| 条件类型 | 触发场景 | 操作 | 设计目的 |
|---|---|---|---|
| 初始化 | 1. 异步复位(M_AXI_ARESETN=0)2. 全局事务启动( init_txn_pulse=1) | axi_wdata 置 1 | 保证每次新事务启动时,数据从固定初始值开始,避免旧数据干扰 |
| 数据递增 | 数据帧握手完成(wnext=1,即 M_AXI_WREADY && axi_wvalid) | axi_wdata + 1 | 每成功传输一帧数据,数据值递增,生成连续递增的测试数据流 |
| 保持 | 无初始化 / 递增触发(如从机未就绪、数据未传输) | 数据值不变 | 保证数据在传输期间稳定,符合 AXI “WDATA 需与 WVALID 同步稳定” 的协议要求 |
- 注释掉的逻辑说明
verilog
//else if (wnext && axi_wlast)
// axi_wdata <= 'b0;这是可选的 “最后一帧数据清零” 逻辑,功能为:当最后一帧数据传输完成(wnext && axi_wlast)时,将 axi_wdata 置 0。未启用的原因通常是:
- 测试场景下需连续递增数据流,无需最后一帧清零;
- 若启用,需注意时序对齐(确保
axi_wlast与最后一帧数据同步)。
8:axi-full-master 的 axi_bready
设置 axi_bready 信号
功能定位
axi_bready 是 AXI 写响应通道(B 通道)的主机就绪信号,这段代码实现AXI 写响应握手的极简控制逻辑:主机仅在从机发起写响应(M_AXI_BVALID=1)时置位就绪信号,且仅保持 1 个时钟周期,完成响应接收后立即清零,严格遵循 AXI 写响应通道的握手规则。 
逻辑层级(优先级从高到低)
| 条件类型 | 触发场景 | 操作 | 设计目的 |
|---|---|---|---|
| 初始化 | 1. 异步复位(M_AXI_ARESETN=0)2. 全局事务启动( init_txn_pulse=1) | 置 0 | 保证新事务启动 / 复位时,主机处于 “未就绪” 状态,避免误接收响应 |
| 响应接收准备 | 1. 从机写响应有效(M_AXI_BVALID=1)2. 主机当前未就绪( ~axi_bready) | 置 1 | 仅在从机发起响应且主机未就绪时,置位就绪信号,准备接收写响应(BRESP) |
| 响应接收完成 | 主机就绪信号已置位(axi_bready=1) | 置 0 | 就绪信号仅保持 1 个时钟周期,完成响应握手后立即清零,避免持续就绪导致误响应 |
| 保持 | 无上述触发条件(如从机未发起响应) | 保持当前值 | 保证信号稳定,符合 AXI “BREADY 可异步变化,但需避免毛刺” 的要求 |
9:axi-full-master 的 axi_arvalid
Axi_full_master 读通道的分析非常类似,代码是对称的。当(~axi_arvalid && start_single_burst_read)== 1 条件满足,开始一次写传输,设置 axi_arvalid 有效
axi_arvalid 是 AXI 读地址通道(AR 通道)的主机有效信号,这段代码实现AXI 突发读事务的读地址请求控制逻辑,核心作用是:按 “初始化清零→按需发起请求→握手完成撤销” 的流程,精准管理读地址通道的握手,与写地址通道(axi_awvalid)逻辑完全对称,严格遵循 AXI 协议规则。 
| 条件类型 | 触发场景 | 操作 | 设计目的 |
|---|---|---|---|
| 初始化 | 1. 异步复位(M_AXI_ARESETN=0)2. 全局事务启动( init_txn_pulse=1) | 置 0 | 保证复位 / 新事务启动时,读地址通道处于 “无有效请求” 初始状态,避免误发起读请求 |
| 发起读地址请求 | 1. 当前无有效读地址请求(~axi_arvalid)2. 触发单次突发读( start_single_burst_read=1) | 置 1 | 仅在 “无当前请求 + 外部触发” 时发起读地址请求,避免多个请求冲突 |
| 撤销读地址请求 | 读地址握手完成(M_AXI_ARREADY && axi_arvalid) | 置 0 | 遵循 AXI 协议 “VALID 一旦置位不可主动撤销,需等待 READY 响应后清零” 的规则 |
| 保持 | 无上述触发条件(如 axi_arvalid=1 但 M_AXI_ARREADY=0) | 保持当前值 | 保证读地址请求稳定到握手完成,避免请求丢失 |
10:axi-full-master 的 axi_araddr
读地址计算
axi_araddr 是 AXI 读地址通道(AR 通道)的地址寄存器,这段代码实现突发读事务的连续地址递增逻辑,核心作用是:在每次读地址握手完成后,自动将读地址递增一个突发字节数(burst_size_bytes),实现从连续地址空间(如 DDR、SRAM)批量读取数据,与写地址递增逻辑(axi_awaddr)完全对称。 
11:axi-full-master 的 axi_rready
读数据准备好 
| 条件类型 | 触发场景 | 操作 | 设计目的 |
|---|---|---|---|
| 初始化 | 1. 异步复位(M_AXI_ARESETN=0)2. 全局事务启动( init_txn_pulse=1) | 置 0 | 保证复位 / 新事务启动时,主机处于 “未就绪” 初始状态,避免误接收数据 |
| 读数据传输阶段 | 从机读数据有效(M_AXI_RVALID=1) | - | 分两种子场景控制就绪信号 |
| ├─ 突发传输完成 | M_AXI_RLAST=1(最后一帧)且 axi_rready=1(主机已就绪) | 置 0 | 突发传输的最后一帧数据完成接收后,清零就绪信号,结束本次读数据传输 |
| └─ 正常接收阶段 | 非最后一帧 / 主机未就绪 | 置 1 | 主机置位就绪信号,准备接收从机发送的读数据(包括首帧 / 中间帧) |
| 保持 | 从机无读数据发送(M_AXI_RVALID=0) | 保持当前值 | 保证信号稳定,避免无意义的状态切换 |
12:读次数记录 read_index 计数器
读数据索引计数

| 元素 | 类型 | 功能说明 |
|---|---|---|
rnext | 组合逻辑 | 读数据通道单帧握手完成判定:M_AXI_RVALID(从机发送读数据有效) + axi_rready(主机准备接收) = 单帧数据接收完成 |
read_index | 时序寄存器 | 突发读帧计数器,范围 0 ~ C_M_AXI_BURST_LEN-1,记录当前接收至第几个读数据帧,为 axi_rlast(最后一帧标记)提供计数基准 |
| 条件类型 | 触发场景 | 操作 | 设计目的 |
|---|---|---|---|
| 计数清零 | 1. 异步复位(M_AXI_ARESETN=0)2. 全局事务启动( init_txn_pulse=1)3. 单次突发读启动( start_single_burst_read=1) | 计数置 0 | 保证每次新突发读事务独立计数,从 0 开始,避免旧计数干扰 |
| 计数递增 | 1. 单帧读数据握手完成(rnext=1)2. 未到最后一帧( read_index ≠ C_M_AXI_BURST_LEN-1) | 计数 + 1 | 仅在 “实际接收数据帧” 且 “未到突发长度上限” 时递增,计数与实际接收帧严格同步 |
| 计数保持 | 无清零 / 递增触发(如最后一帧接收完成、从机未发数据、主机未就绪) | 计数不变 | 避免 “未接收数据却计数” 或 “计数溢出”,保证计数精准 |
13:产生对比数据 expected_rdata
数据 expected_rdata 用于和读出的 M_AXI_RDATA 进行对比以此验证数据的正确性 
- 生成与 “写侧发送数据(axi_wdata)” 完全同步的递增序列;
- 作为 “基准值” 与从机返回的实际读数据(
M_AXI_RDATA)对比,快速检测读事务中的数据错误(如丢数、错数、乱序)。
| 条件类型 | 触发场景 | 操作 | 设计目的 |
|---|---|---|---|
| 初始化 | 1. M_AXI_ARESETN=0(异步复位)2. init_txn_pulse=1(全局事务启动) | 置为 1 | 保证每次新事务启动时,预期数据从固定值开始,与写侧 axi_wdata 初始值对齐 |
| 递增 | M_AXI_RVALID && axi_rready(读数据帧握手完成,等价于 rnext) | 自增 1 | 每成功接收一帧读数据,预期数据同步递增,与写侧 axi_wdata 递增逻辑一致 |
| 保持 | 无初始化 / 递增触发(如从机未发数据、主机未就绪) | 保持当前值 | 避免 “未接收数据却递增”,保证校验基准的准确性 |
- 初始值
'b1:与写侧axi_wdata的初始值完全一致,确保 “写发送第 N 帧数据 = 读预期第 N 帧数据”;若需从 0 开始校验,可将'b1改为'b0。 - 注释掉的
|| M_AXI_RLAST:可选优化逻辑,作用是 “读突发最后一帧完成后清零预期数据”,适配多轮突发读的独立校验;未启用是因为init_txn_pulse已覆盖全局事务初始化需求。 - 递增时机:严格同步于 “读数据实际接收完成”,而非 “仅从机发数据”,避免因主机未就绪导致的预期数据超前递增。
14:比对数据正确性
读写数据比较
这段代码是 AXI 读事务数据完整性校验的核心逻辑,通过对比 “从机返回的实际读数据(M_AXI_RDATA)” 和 “本地生成的预期读数据(expected_rdata)”,生成 read_mismatch 错误标志:
- 标志置 1:数据传输出错(丢数、错数、乱序等);
- 标志置 0:数据传输正确或无数据校验动作。
| 元素 | 功能说明 |
|---|---|
read_mismatch | 读数据不匹配错误标志(1 = 出错,0 = 正常),是校验结果的核心输出 |
rnext | 读数据帧握手完成标志(M_AXI_RVALID && axi_rready),仅在此时校验数据 |
M_AXI_RDATA | 从机返回的实际读数据(待校验值) |
expected_rdata | 本地生成的预期读数据(基准值) |
| 条件类型 | 触发场景 | 操作 | 设计目的 |
|---|---|---|---|
| 初始化 | 1. 异步复位(M_AXI_ARESETN=0)2. 全局事务启动( init_txn_pulse=1) | 置 0 | 保证新事务 / 复位时,错误标志处于 “无错误” 初始状态,避免误报 |
| 错误检测 | 1. 读数据帧握手完成(rnext=1)2. 实际数据≠预期数据 | 置 1 | 仅在 “有效数据传输完成” 时校验,避免无意义的空校验(如仅 RVALID 有效但主机未就绪) |
| 错误清零 | 无初始化 / 错误触发条件 | 置 0 | 无校验错误或无数据传输时,错误标志清零,保证标志仅在 “出错周期” 有效 |
15:读写状态机
读写状态机源码




“写→读→校验”
| 状态名 | 核心功能 | 关键输出 / 动作 |
|---|---|---|
| IDLE | 空闲等待,接收事务启动触发(init_txn_pulse) | 清零ERROR/compare_done,触发后跳转到INIT_WRITE |
| INIT_WRITE | 发起突发写事务,控制start_single_burst_write生成单周期脉冲 | 脉冲触发写地址 / 数据逻辑;writes_done=1时跳转到INIT_READ |
| INIT_READ | 发起突发读事务,控制start_single_burst_read生成单周期脉冲 | 脉冲触发读地址 / 数据逻辑;reads_done=1时跳转到INIT_COMPARE |
| INIT_COMPARE | 数据校验结果锁存,输出最终状态 | 锁存error_reg到ERROR,置位compare_done,完成后返回IDLE |
| 信号名 | 功能说明 |
|---|---|
start_single_burst_write | 单周期脉冲,触发单次突发写事务(控制写地址 / 数据逻辑启动) |
start_single_burst_read | 单周期脉冲,触发单次突发读事务(控制读地址 / 数据逻辑启动) |
writes_done/reads_done | 写 / 读事务完成标志(外部逻辑生成,标识所有突发传输完成) |
burst_write_active/burst_read_active | 写 / 读突发活跃标志(标识当前有突发传输在执行) |
error_reg | 数据校验错误寄存器(汇总read_mismatch等错误) |
compare_done | 校验完成标志(1 = 读写校验流程结束) |
ERROR | 最终错误标志(1 = 传输 / 校验出错,0 = 正常) |
16:正在写 burst_write_active
burst_write_active 代表正在写操作

burst_write_active 是 AXI 写突发事务的 “活跃状态标志”,核心作用是:
- 标识当前是否有写突发事务在执行(1 = 活跃,0 = 空闲);
- 作为上层状态机(
INIT_WRITE态)的判断依据,避免重复触发同一写突发事务。
| 条件类型 | 触发场景 | 操作 | 设计目的 |
|---|---|---|---|
| 初始化 | 1. M_AXI_ARESETN=0(异步复位)2. init_txn_pulse=1(全局事务启动) | 置 0 | 保证新事务 / 复位时,写突发处于 “空闲” 初始状态,避免误判 |
| 事务启动 | start_single_burst_write=1(写突发启动脉冲) | 置 1 | 写突发事务被触发后,立即标识 “事务活跃”,阻止状态机重复触发 |
| 事务结束 | M_AXI_BVALID && axi_bready(写响应握手完成) | 置 0 | AXI 写事务的最终收尾(地址 + 数据 + 响应全完成),标识 “事务结束” |
| AXI 写事务闭环关联 |
AXI 写事务的完整流程为:地址通道(AW) → 数据通道(W) → 响应通道(B),该逻辑精准匹配这一流程:
start_single_burst_write触发 → 地址 / 数据通道开始传输 →burst_write_active=1(事务中);- 从机完成地址 + 数据接收后,通过
M_AXI_BVALID发起写响应 → 主机axi_bready应答 → 握手完成 →burst_write_active=0(事务结束)。
17:写完成 writes_done
写数据完成 writes_done 信号

writes_done 是 AXI 多突发写事务的 “全局完成判定标志”,核心作用:
- 判定
C_NO_BURSTS_REQ个预设的写突发事务是否全部执行完毕; - 作为上层状态机(
INIT_WRITE态)的跳转触发信号,当writes_done=1时,状态机从 “写阶段” 切换到 “读阶段”,保证 “写完再读” 的流程闭环。
| 元素 | 含义与作用 |
|---|---|
writes_done | 1bit 标志位(1 = 所有写突发完成,0 = 未完成),是多突发写事务的 “最终收尾信号” |
C_NO_BURSTS_REQ | 配置参数:需要执行的写突发总数(如配置为 3,表示要执行 3 次独立的突发写) |
write_burst_counter | 计数器:记录已完成的写突发数量,write_burst_counter[C_NO_BURSTS_REQ] 是位索引式阈值判定(等价于 计数器 ≥ 2^C_NO_BURSTS_REQ) |
M_AXI_BVALID && axi_bready | AXI B 通道(写响应)握手完成:单次写突发的最终收尾(AXI 写事务 = AW 通道 + W 通道 + B 通道,B 通道完成才代表单次突发真的结束) |
| 优先级 | 条件 | 操作 | 核心目的 |
|---|---|---|---|
| 最高 | 复位 / 全局事务启动 | 置 0 | 保证新事务启动时,标志位回到 “未完成” 初始状态,避免误判 |
| 次高 | 写响应握手 + 计数器达阈值 | 置 1 | 仅当 “所有写突发执行完 + 最后一次写响应完成” 时,才判定全局完成 |
| 最低 | 无触发条件 | 保持原值 | 避免标志位在 “未完成阶段” 频繁翻转,保证状态稳定 |
18:正在读 burst_read_active
读 burst_read_active 代表正在读数据 
burst_read_active 是 AXI 读突发事务的 “活跃状态标志”,核心作用:
- 标识当前是否有读突发事务在执行(1 = 活跃,0 = 空闲);
- 作为上层状态机(
INIT_READ态)的判断依据,避免重复触发同一读突发事务; - 注释存在笔误(将 read 写成 write),实际逻辑完全服务于读事务。
| 条件类型 | 触发场景 | 操作 | 设计目的 |
|---|---|---|---|
| 初始化 | 1. M_AXI_ARESETN=0(异步复位)2. init_txn_pulse=1(全局事务启动) | 置 0 | 保证新事务 / 复位时,读突发处于 “空闲” 初始状态,避免误判 |
| 事务启动 | start_single_burst_read=1(读突发启动脉冲) | 置 1 | 读突发事务被触发后,立即标识 “事务活跃”,阻止状态机重复触发 |
| 事务结束 | M_AXI_RVALID && axi_rready && M_AXI_RLAST(最后一帧读数据握手完成) | 置 0 | AXI 读事务的最终收尾(最后一帧数据接收完成),标识 “事务结束” |
| AXI 读事务闭环关联 |
AXI 读事务的完整流程为:地址通道(AR) → 数据通道(R),该逻辑精准匹配这一流程:
start_single_burst_read触发 → 地址通道开始传输 →burst_read_active=1(事务中);- 从机发送最后一帧读数据(
M_AXI_RLAST=1)→ 主机接收完成(M_AXI_RVALID && axi_rready)→burst_read_active=0(事务结束)。
19:读完成 reads_done
读数据完成 reads_done 信号 
reads_done 是 AXI 多突发读事务的 “全局完成标志”,核心作用:
- 标识配置的
C_NO_BURSTS_REQ个读突发事务全部执行完成,且每个突发的C_M_AXI_BURST_LEN帧数据都接收完毕; - 作为上层状态机(
INIT_READ态)的跳转触发条件,当reads_done=1时,状态机从 “读阶段” 跳转到 “校验阶段”。
| 元素 | 功能说明 |
|---|---|
reads_done | 1bit 标志位(1 = 所有读突发完成,0 = 仍在执行) |
C_M_AXI_BURST_LEN | 单突发帧长度:每个读突发包含的帧数(如 4 表示单次突发读 4 帧数据) |
read_index | 单突发帧计数器:记录当前突发已接收的帧数,read_index == C_M_AXI_BURST_LEN-1 表示单次突发的最后一帧已接收 |
C_NO_BURSTS_REQ | 总突发数:需要执行的读突发总数(如 3 表示执行 3 次独立的突发读) |
read_burst_counter | 总突发数计数器:记录已完成的读突发数量,read_burst_counter[C_NO_BURSTS_REQ] 表示总突发数达到 2^C_NO_BURSTS_REQ(位索引阈值判定) |
M_AXI_RVALID && axi_rready | 读数据握手完成:单帧读数据被主机成功接收(AXI R 通道核心握手逻辑) |
| 条件类型 | 触发场景 | 操作 | 设计目的 |
|---|---|---|---|
| 初始化 | 复位(M_AXI_ARESETN=0)/ 全局事务启动(init_txn_pulse=1) | 置 0 | 保证新事务启动时,标志位处于 “未完成” 初始状态,避免误判 |
| 完成触发 | 1. 最后一帧读数据握手(M_AXI_RVALID && axi_rready)2. 单突发帧计数达标( read_index == C_M_AXI_BURST_LEN-1)3. 总突发数计数达标( read_burst_counter[C_NO_BURSTS_REQ]) | 置 1 | 仅当 “单次突发最后一帧接收 + 所有突发执行完毕” 时,才判定读事务全局完成 |
| 保持 | 无初始化 / 完成触发条件 | 保持 | 避免标志位在 “未完成阶段” 频繁翻转,保证状态稳定 |
20:IP 的更新
由于修改了代码,需要先更新 IP 状态,完成 IP 更新 将axi_master_last代码替换成下列代码 
需要重新更新ip 
三、仿真分析
仿真结果

一次 axi4 写操作 burst lenth=16 如下图所示,由于 WREADY 信号不是连续的,所以可以传输效率不是最高的 


一共进行 64 次 burst 共计写了 1024 个 32bit 数据 
一次读操作的 burst lenth 也是 16 如下图,但是可以看到读数据时连续的,所以效率最高 
一共进行 64 次 burst 共计读了 1024 个 32bit 数据 

可以看到读出的数据 RDATA 和 expected_rdata 一致,所以代码正确。 
