AXI4-Full突发传输掉数据——突发长度算错、WRAP边界、窄传输字节错位,调试一周才发现是协议理解错了

AXI4-Full是AXI协议族里最复杂的一种------支持突发传输、支持乱序、支持多机并行。

很多人以为AXI4-Full就是"AXI4-Lite + BURST",结果一写代码就踩坑:数据丢了、顺序乱了、WRAP传输直接卡死。

这篇把AXI4-Full最常见的4个致命坑全部拆开,配上核心代码片段。完整工程代码(DMA控制器、WRAP地址生成、窄传输处理、突发错误处理)可"私信"获取。


痛苦点一:突发长度算错,传输一半就断了

问题描述

你用AXI4-Full做DMA,从DDR读4KB数据到FPGA内部BRAM,结果只读了一半。

C

// 读4KB数据,32bit接口,1024次传输

AXI_DMA_Read(src_addr=0x10000000, length=4096);

仿真时发现:只读了512个数据(2KB),剩下的一半不见了。

根本原因

AXI4-Full的突发长度(AxLEN)编码规则:

AxLEN7:0 实际突发长度 说明
0x00 1次 AxLEN=0表示1次传输
0x01 2次
0x0F 16次
0xFF 256次 AXI4最大值

AxLEN = 实际传输次数 - 1

如果你要读1024次,必须设置AxLEN = 1023(0x3FF),但AXI4单突发最大256次(AxLEN=255),所以不能一次发完,必须拆成多个突发。

错误做法

verilog

// ❌ 错误:AxLEN直接填传输次数

assign arlen = 16'd1024; // ❌ 这表示1025次传输!AXI4会截断

assign arlen = 16'd256; // ❌ 这表示257次传输!

// ❌ 错误的突发拆分:

// 想读1024次,拆成4个突发:

assign arlen_0 = 16'd256; // 257次

assign arlen_1 = 16'd256; // 257次

assign arlen_2 = 16'd256; // 257次

assign arlen_3 = 16'd255; // 256次

// 总计:257+257+257+256 = 1027次 ← 多了3次!

正确做法(关键公式)

复制代码
verilog

// ✅ 核心公式:AxLEN = beats - 1

// 4KB数据,32bit接口 → 1024 beats

// AXI4单突发最多256 beats → 拆成4个突发,每个arlen=255

// 最后一次不足256 beat时,arlen = (剩余beats) - 1

📌 完整DMA读控制器代码(包含突发拆分、地址累加、状态机)点击"阅读原文"获取。

💡 注意:AxLEN最大取值为0xFF(255),硬件IP/Interconnect会直接截断超长突发,不能一次下发1023。

关键计算公式

参数 公式
总传输次数 ceil(字节数 / (数据位宽/8))
突发次数 ceil(总传输次数 / 最大突发长度)
AxLEN 实际传输次数 - 1

痛苦点二:WRAP突发传输出错,地址跳回起点后数据乱了

问题描述

用WRAP模式读环形缓冲区,地址回绕后数据顺序全乱。

verilog

// 从地址0x100开始,突发长度16,WRAP边界256字节

assign araddr = 32'h00000100;

assign arlen = 8'd15; // 16次传输

assign arburst = 2'b10; // WRAP模式

仿真时发现:第12次传输后,地址不是0x110而是跳回了0x100!数据顺序全乱了。

根本原因

WRAP突发的地址计算规则和INCR完全不同:

突发模式 地址变化 适用场景
FIXED (00) 地址不变 FIFO读写
INCR (01) 地址递增 普通内存访问
WRAP (10) 到达边界后回绕 Cache行填充

WRAP边界 = 突发长度 × 传输字节数,且边界必须是2的幂。

错误做法

verilog

// ❌ 起始地址不在边界上

assign araddr = 32'h00000110; // 0x110,边界64字节,预期会回绕到0x100

正确做法(核心计算)

verilog

// ✅ WRAP边界 = (arlen+1) × (1 << arsize)

// 低位掩码 = 边界 - 1

// 当前地址 = 高位(起始地址 & ~掩码) + 低位((起始偏移 + 累加步长) & 掩码)

💡 工程建议 :实际项目中90%的场景用INCR即可,WRAP主要用于Cache行填充。如果不需要WRAP,直接用arburst = 2'b01(INCR)。

WRAP使用场景总结

场景 是否用WRAP 原因
普通内存读写 ❌ 用INCR 简单可靠
FIFO读写 ❌ 用FIXED 地址不变
Cache行填充 ✅ 用WRAP 提升Cache性能
循环缓冲区 可选 INCR+地址回绕更直观

痛苦点三:窄传输(Narrow Transfer)字节错位

问题描述

64bit AXI接口连接32bit外设,写入数据后读回错位。

verilog

// 64bit AXI接口

// 但外设寄存器是32bit

// 地址0x00: reg0 (32bit)

// 地址0x04: reg1 (32bit)

// 地址0x08: reg2 (32bit)

// 地址0x0C: reg3 (32bit)

你写入64bit数据到地址0x00,期望写到reg0和reg1,但读回来发现数据全错了。

根本原因

AXI的WSTRB(写选通)信号决定了哪些字节有效。窄传输是指:数据位宽大于实际传输大小,需要用WSTRB选择有效字节。

AXI读无RSTRB,读窄传输靠地址区分数据位置,地址bit2用来选择64bit接口中的高低32bit,这是窄读错位最高发的坑点。

错误做法

verilog

// ❌ 错误:忽略WSTRB,直接写整个64bit

assign reg0 = wdata31:0; // 忽略了WSTRB

assign reg1 = wdata63:32;

// 如果Master只想写reg0:

// wdata = 64'hXXXX_XXXX_1234_5678

// wstrb = 8'h0F (只有低4字节有效)

// 错误实现会把高32bit的垃圾数据也写入reg1

正确做法(核心逻辑)

verilog

// ✅ 写:根据WSTRB逐字节写入

if (wstrb0) reg07:0 <= wdata7:0;

if (wstrb1) reg015:8 <= wdata15:8;

// ... 类似处理其他字节

// ✅ 读:用地址bit2区分64bit中的高低32bit

assign rdata = (araddr2 == 1'b0) ? {regs1, regs0} : {regs3, regs2};

💡 关键点

  • 写操作:WSTRB决定哪些字节有效,无效字节不写入

  • 读操作:没有RSTRB,用地址选择返回数据

  • 地址对齐:64bit接口地址必须是8字节对齐

  • 推荐做法:32bit外设直接用32bit AXI接口,避免窄传输


痛苦点四:突发传输中间出错,数据残缺怎么办

问题描述

你用AXI4-Full读取256次突发数据,读到一半RRESP返回了SLVERR:

verilog

// 读突发过程中

// Beat 0-127: RRESP = OKAY

// Beat 128: RRESP = SLVERR ← 错误!

// Beat 129-255: 还要继续吗?

根本原因

AXI4协议规定:突发传输一旦开始,必须完成所有Beats,即使中间有错误。

场景 规则
读突发出错 Slave必须在剩余Beats返回RDATA(值不确定),RRESP=SLVERR或DECERR
写突发出错 Slave可以立即返回BRESP=SLVERR,但必须接受完所有W数据
Master处理 检查RRESP/RESP,如果出错,丢弃整个突发数据

错误做法

verilog

// ❌ 错误1:读到错误后立即停止

always @(posedge aclk) begin

if (rvalid && rready) begin

if (rresp != 2'b00) begin

// ❌ 错误:直接停止接收

state <= S_ERROR;

end

.

// 后果:Slave还在发数据,Master不接收,协议违反

// ❌ 错误2:忽略RRESP,假设数据正确

assign data_valid = rvalid && rready;

// ❌ 没有检查rresp,错误数据被当成有效数据

正确做法(核心流程)

verilog

// ✅ 继续接收所有beats,但标记错误,丢弃本次突发所有数据

error_flag <= (rresp != 2'b00) ? 1'b1 : error_flag;

// 数据有效标志只在无错误时拉高

data_valid <= rvalid && rready && !error_flag;

// 突发结束后保持error_flag供上层重试

突发错误处理规则

规则 说明
必须完成突发 即使中间出错,也要接收完所有Beats
检查RRESP 每个Beat都要检查,标记错误
丢弃错误数据 如果突发中有错误,整个突发数据无效
重试机制 出错后可以重发AR请求(需要上层协议支持)

⚠️ 重要注意事项

注意事项一:AXI4和AXI3的突发长度不同

协议 最大突发长度
AXI3 16次(AxLEN=0~15)
AXI4 256次(AxLEN=0~255)

如果你的代码要兼容AXI3,必须把突发拆成多个16次的小突发。

注意事项二:突发传输的地址对齐要求

突发模式 地址对齐要求
FIXED 无要求
INCR 起始地址必须按AxSIZE字节对齐,否则Master报DECERR(很多DMA地址错位根源)
WRAP 必须对齐到WRAP边界(突发长度×传输大小)

💡 INCR地址对齐:AXI协议强制要求INCR/WRAP起始地址必须按AxSIZE对应字节对齐,否则Master直接返回DECERR。

注意事项三:ARSIZE/AWSIZE的含义

AxSIZE值 每次传输字节数
000 1 byte
001 2 bytes
010 4 bytes
011 8 bytes
100 16 bytes
101 32 bytes
110 64 bytes
111 128 bytes

💡 重要:AxSIZE ≠ 数据位宽!AxSIZE表示每次传输的字节数,实际数据位宽由WDATA/RDATA决定。同一AXI接口可通过AxSIZE配置单拍1/2/4/8Byte窄传输,这是窄传输的核心来源。

常见搭配

  • 32bit接口 → AxSIZE=010(4 bytes)

  • 64bit接口 → AxSIZE=011(8 bytes)

  • 128bit接口 → AxSIZE=100(16 bytes)

注意事项四:Cache属性(ARCACHE/AWCACHE)

Cache值 含义 典型场景
0000 Device Non-bufferable 外设寄存器
0011 Normal Non-cacheable 普通内存
1011 Write-Back, Read-Allocate DDR内存
0111 Write-Through 需要一致性的内存

建议:访问DDR用1011或0011,访问外设寄存器用0000。

注意事项五:调试突发传输用ILA抓完整序列

verilog

// ✅ ILA配置:抓取完整突发序列

ila_burst u_ila (

.clk(aclk),

.probe0(arvalid),

.probe1(arready),

.probe2(araddr),

.probe3(arlen),

.probe4(arburst),

.probe5(rvalid),

.probe6(rready),

.probe7(rdata),

.probe8(rresp),

.probe9(rlast),

.probe10(beat_cnt) // 内部计数器

);

// 触发条件:arvalid上升沿,抓取整个突发的完整波形


常见问题 FAQ

Q1:突发传输中途可以取消吗?

不能。AXI4协议规定,突发一旦开始必须完成。如果必须取消,Master只能设置超时忽略后续数据,上层协议重发请求。

Q2:如何知道一次突发传输了多少数据?

arlen+1计算。突发长度 = arlen + 1。更可靠的方法是:自己维护计数器,每个rvalid+rready时记录Beat数。

Q3:多个突发可以同时发出吗?

可以,AXI4支持乱序。Master可以连续发出多个AR请求,Slave可以按任意顺序返回R数据(用RID标识)。如果设计不支持乱序,可以等上一个突发完成再发下一个,或用AXI Interconnect的reorder_depth=0禁用乱序。

Q4:FIXED突发模式什么场景用?

FIFO读写(地址固定,数据流式传输)、外设寄存器轮询(每次读同一地址)、DMA到固定地址。FIXED模式下,地址始终等于起始地址,不递增。

Q5:突发传输的性能优势有多大?

对比项 单次传输 16次突发 256次突发
地址开销 每次都有AR 1次AR 1次AR
效率 ~50% ~90% ~98%
适用场景 零散访问 小块数据 大块DMA

建议:超过16次传输就用突发模式。

Q6:为什么我的突发传输实际速度远低于理论值?

原因 检查方法
突发长度太短 检查arlen是否充分利用
WSTRB导致窄传输 检查wstrb是否全1
Interconnect仲裁延迟 检查是否有其他Master抢占
Slave响应慢 检查rready/wready延迟

总结

痛苦点 根因 解法
突发长度算错 AxLEN=实际次数-1 统一用 arlen = beats - 1
WRAP传输出错 边界计算错误/地址不对齐 理解 WRAP边界 = 突发长度 × 传输大小
窄传输字节错位 WSTRB没处理 根据WSTRB逐字节写入
突发中途出错 数据残缺/协议违反 继续完成突发,丢弃错误数据

AXI4-Full的精髓在于突发------算对长度、理解WRAP、处理窄传输、正确应对错误。

关注我,AXI协议实战专题持续更新。FPGA定制开发、项目调试、IP定制,开发服务可私。

相关推荐
zlinear数据采集卡2 小时前
硅片里的“自动纠错“:硬核拆解LHAMP188自动归零技术原理与三种封装的PCB布局实战
arm开发·单片机·嵌入式硬件·fpga开发·开源
Mr-pn-junction14 小时前
clk_gate
单片机·嵌入式硬件·fpga开发
知行合一←_←1 天前
误码仪与时钟极性
fpga开发
upper20201 天前
vivado使用那些事之综合策略
fpga开发·vivado·vivado综合策略
2CM_Embed1 天前
Quartus II 工程编译与 FPGA 下载流程记录
嵌入式硬件·fpga开发
千寻xun1 天前
视频图像学习笔记
fpga开发
国科安芯2 天前
航天电子模拟前端三大支柱:精密运放、高速运放与电压监控的协同设计方法——ASL8522S/ASL622S/ASL706S技术解析
前端·单片机·嵌入式硬件·fpga开发·架构·安全性测试
謓泽2 天前
【6.26】芯片测试入门 从零搭自动化测试框架|PyVISA+OOP 保姆级教程
stm32·单片机·fpga开发·雷达·tr
乌恩大侠2 天前
【AI-RAN】面向电信行业的 NVIDIA DGX BasePOD
人工智能·fpga开发·o-ru