☰
AXI4总线验证实战:握手、突发与断言避坑指南
2026/10/28 23:51:19 网站建设 项目流程

简介:AXI总线是ZYNQ系列FPGA中处理器与外设通信的核心接口,理解AXI4-Lite与AXI4-Full协议对嵌入式开发和FPGA工程师至关重要。围绕“轻松搞定AXI总线”主题整理的配套源码与验证工程,正是面向希望快速上手AXI总线设计的学习者,涵盖从基础控制到高速数据传输的多种应用场景。包内包含基于AXI4-Lite的LED驱动实例、AXI4-Full接口仿真测试工程、可综合的AXI总线搭建模板,以及板级验证项目,帮助学习者在VIVADO环境下完成从代码编写、功能仿真到上板调试的完整流程。压缩包共约37.73MB,以Vivado工程源文件、Verilog/VHDL源码及仿真测试文件为主,结构清晰便于按需查阅。资源发布至今已有3128人学习下载,是系统理解AXI地址映射、读写时序与流水线机制的实用参考资料。

1. AXI 总线到底在忙什么:从一次卡死的读突发说起

第一次调 AXI4 接口的时候,我盯着波形看了一下午:arvalid已经拉高,arready始终不动,整条总线像被按了暂停键。后来才明白,AXI 总线的一切麻烦,都藏在这对 VALID/READY 握手信号里。AXI4 是 ARM AMBA 协议里性能最强的一条总线,五个独立通道、支持突发和乱序,SoC 内部几乎所有高带宽路径——DDR 控制器、DMA、PCIe 桥——都靠它互联。标题里这份“AXI 总线源码和验证工程 AXI4”,把 RTL 和 testbench 配套给你,目的就是让你不用从零啃协议,照着工程把读写事务跑起来,再改成自己可用的主机或从机。适合做 SoC 集成、FPGA 互联,以及刚转验证方向的工程师。

2. AXI4 的五通道与突发机制:验证前先看懂的三个模型

拿到验证工程先别急着开仿真器。AXI4 的协议文本几百页,但验证前真正要建立的模型只有三个:通道模型、握手模型、突发模型。这三个模型决定了你之后看波形时往哪儿看,写参考模型时往哪儿比,出了错往哪儿查。这一章把三个模型拆开讲,顺带把 AXI3 和 AXI4 的边界差异说清楚,因为很多从 AXI3 时代保留下来的源码,会在这里埋坑。

2.1 AMBA 家族里 AXI4 的位置:它比 AHB 强在哪

AMBA 协议族里常见的有 APB、AHB、AXI 三条主线,外加 AXI4 的两个变种 AXI-Lite 和 AXI-Stream。APB 最慢,只做单次寄存器读写;AHB 支持突发和流水,但它的总线结构决定了同一时刻只能有一个主机占用总线;AXI4 则把读通道和写通道彻底拆开,主机可以同时发读写请求,带宽和并行度完全不在一个量级。

总线通道结构突发支持乱序支持典型场景
APB单通道无无外设寄存器配置
AHB单通道分时复用支持无中低带宽 SoC 内部互联
AXI3五通道独立支持读乱序、写乱序早期高性能 SoC
AXI4五通道独立支持,突发长度上限提高读乱序,写保序DDR 控制器、DMA、高性能互联
AXI-Lite五通道但固定单拍无突发无寄存器访问型外设
AXI-Stream单数据流通道连续流无视频、DMA、数据流处理

AXI-Lite 在工程里出现频率极高,很多第三方 IP 的寄存器配置口就是 AXI-Lite,比如常见的控制器类 IP(包括 AXI Quad SPI 这类外设核),控制面走 AXI-Lite、数据面走 AXI-Stream,分工很清晰。而标题里的“AXI4 源码和验证工程”,主线是完整 AXI4,也就是带突发、带 ID、五通道全开的那条协议。验证工程里通常会把 AXI-Lite 从机也带上,方便主机用少量寄存器完成配置,再通过 AXI4 通道搬运数据。

2.2 五个独立通道:为什么读写要分开走

AXI4 一共有五个通道:读地址通道 AR、读数据通道 R、写地址通道 AW、写数据通道 W、写响应通道 B。前两个组成完整读事务,后三个组成完整写事务。每个通道都是一对 VALID/READY 独立握手,互不阻塞,这让 AXI4 天然适合做流水线式传输。

举一个最直观的场景:一个 DMA 从内存读一段数据再写到外设,AHB 下必须先等读完成再发起写;AXI4 下,主机的读请求和写请求可以同时挂在总线上,读数据返回的同时写数据也在流动,吞吐量几乎翻倍。验证时也要注意这一点——你设计的从机如果实现成“读的时候把写挡住”,实际上已经违背了 AXI4 的并行精神,虽然仿真能过,但性能上就打了折扣。

当多个主机同时访问时,需要一个 AXI 仲裁器来分配地址通道的占用权和数据通道的返回顺序。仲裁器是另一个独立 IP,不在标题这份工程的主线上,但验证多主机场景时,你经常会看到主机 A 的请求先到、主机 B 的读数据先返回的现象,这是仲裁器按 ID 做了乱序调度,不要当成 bug 报。

2.3 VALID/READY 握手:三种时序关系决定一切

AXI4 的握手只有一个规则:发送方把 VALID 拉高,接收方把 READY 拉高,只有两者在同一拍都为高,这一拍的数据或地址才被采样,事务才算推进。VALID 一旦拉高,在握手成功之前不允许撤销;READY 则可以提前拉高,也可以等 VALID 到来再拉高。

按时序关系看,握手会出现三种情况:

  • 双方同拍就绪:VALID 和 READY 在同一时钟沿都为高,直接握手成功,效率最高。
  • 发送方等待接收方:VALID 先拉高,READY 后拉高,中间的空等拍数据必须保持稳定。
  • 接收方等待发送方:READY 先拉高,比如从机在可接收状态下把 WREADY 常拉,等主机把数据送上来。

这里最容易被忽略的是“VALID 必须保持”。很多第一次写 RTL 的人,在状态机里让 VALID 只拉一拍,下一拍就撤销,如果对方 READY 没跟上,这一笔传输就无声无息地丢了。反过来,接收方如果把 READY 拉高后又因为内部状态变化立刻拉低,也可能导致发送方误判。AXI 验证中看到的“总线卡死”,十有八九是这两条纪律被破坏。

2.4 突发与 ID 乱序:AXI4 和 AXI3 的边界差异

突发传输是 AXI4 的另一个核心。一笔突发由一笔地址事务和若干拍数据事务组成,总拍数 = AX-LEN + 1,每拍字节数 = 2^AX-SIZE。地址变化方式有三种:FIXED 固定地址、INCR 递增地址、WRAP 回卷地址。INCR 最常见——下一拍地址等于当前地址加 2^AX-SIZE;WRAP 用于 Cache Line 这类场景,到达边界后地址回卷。

AXI4 相比 AXI3,把突发长度上限从 16 拍放宽到 256 拍,但去掉了一些特性。AXI3 允许写事务乱序完成,AXI4 明确规定同一 ID 的写事务必须按发出顺序完成,读事务则可以通过不同 ID 乱序返回。验证时如果发现 R 数据的返回顺序和请求顺序不一致,先别报错,去看 ID 字段是否正确关联。参考模型里维护一个 ID→请求队列,每笔 R 数据返回时按 ID 找到对应的地址和长度做比对,这是最稳妥的做法。

3. 从源码工程到首个波形:AXI4 验证怎么在本地跑通

这一章进入实操。拿到一个 AXI4 源码验证工程,第一步不是双击打开某个脚本,而是先花十分钟把目录结构摸清楚。RTL 写得再漂亮,如果分不清哪是设计、哪是测试、哪是脚本,后面跑出的波形你都不知道该信谁。

3.1 先按目录定位四类文件:RTL、Testbench、脚本、笔记

常见的 AXI4 源码验证工程一般分四层:RTL 源码、testbench、仿真脚本、文档。命令行里先看目录,再决定从哪儿入手。

# 常见 AXI4 源码工程的分层方式 rtl/ # 核心 RTL 与自建 IP,如 axi4_slave、axi4_master tb/ # testbench、接口类、断言文件 sim/ # 仿真脚本、filelist、do/tcl 文件 docs/ # 协议笔记、使用说明、地址映射

工程不一定用这四个名字,但按“设计、测试、脚本、文档”定位文件基本不会偏。我一般会先读 docs 里的笔记,再读 RTL,最后看仿真脚本。笔记里通常会写清这个从机的地址映射、支持的突发宽度、是 AXI4-Full 还是 AXI-Lite,这些信息比翻 RTL 快得多。

如果工程里只有源码没有笔记,就先看顶层模块的端口列表。端口里带ar/aw/w/r/b五组信号的,是完整 AXI4;只有aw/w/b三组或者ar/r的,是半接口;全部信号只有一对握手且没有awlen/arlen,多半是 AXI-Lite。确认接口类型再往下走,否则拿 AXI-Lite 的验证环境去测 AXI4 突发,仿真器会报一堆你根本看不懂的协议违例。

3.2 用仿真器跑一次最小验证:以 Questa/Verilator 为例

我最常用的一套最小流程是命令行编译加跑批,不依赖 IDE 界面。以 Questa/ModelSim 为例,三轮命令就能看到结果:

# 编译 RTL 与 testbench,filelist 里列好所有 .v/.sv 路径 vlog -sv -f rtl/filelist.f vlog -sv tb/tb_axi4_top.sv # 命令行跑仿真,run -all 跑完自动退出 vsim -c work.tb_axi4_top -do "run -all; quit" -logfile sim.log # 结束后直接看日志里的 PASS/FAIL 计数 grep -E "PASS|FAIL|Error" sim.log

-c表示命令行模式,-do后面的字符串是仿真器启动后要执行的命令,-logfile把输出存进 sim.log。如果测试平台在$finish之前卡住,仿真器会一直挂着,这时要看 sim.log 里最后一条打印到哪里,基本能定位是哪个通道在等握手。

如果不想用商业仿真器,Verilator 也可以做 AXI4 的初步验证,但它是四值逻辑不支持者,对x/z的处理和商用仿真器有差异,跑数没问题,跑复位阶段的状态要小心:

verilator --binary -j 0 -f filelist.f --top-module tb_axi4_top

--binary会直接生成可执行文件,-j 0表示用所有 CPU 核并行编译。Verilator 对 SystemVerilog 的支持非常激进,class 和 interface 都能编,但有些断言语法不支持,遇到编译报错先看是不是断言语法,再决定要不要换回 Questa。

3.3 手写一个 AXI4 Slave 写通道:状态机里的握手顺序

跑通最小验证之后,我建议亲手写一个最简单的 AXI4 从机写通道。这个练习的价值在于:你只有写一遍,才会真正理解“BVALID 为什么要等 WLAST 之后”以及“WREADY 为什么不能只拉一拍”。

module axi4_slave_write #( parameter ADDR_W = 8, parameter DATA_W = 32 )( input wire aclk, input wire aresetn, // AW 写地址通道 input wire [ADDR_W-1:0] awaddr, input wire [3:0] awlen, input wire awvalid, output reg awready, // W 写数据通道 input wire [DATA_W-1:0] wdata, input wire [DATA_W/8-1:0] wstrb, input wire wlast, input wire wvalid, output reg wready, // B 写响应通道 input wire bready, output reg bvalid, // 简化存储,真实工程里换成 FIFO 或 RAM output reg [DATA_W-1:0] wmem [0:15] ); localparam IDLE = 2'd0, DATA = 2'd1, RESP = 2'd2; reg [1:0] state; reg [3:0] beat_cnt; always @(posedge aclk or negedge aresetn) begin if (!aresetn) begin state <= IDLE; awready <= 1'b0; wready <= 1'b0; bvalid <= 1'b0; beat_cnt <= 4'd0; end else begin case (state) IDLE: begin // 地址通道常开,等 AW 握手成功 awready <= 1'b1; if (awvalid && awready) begin state <= DATA; beat_cnt <= 4'd0; end end DATA: begin // 进入数据阶段,AW 不再接收新地址 awready <= 1'b0; // WREADY 保持常开,直到最后一拍握手成功 wready <= 1'b1; if (wvalid && wready) begin wmem[beat_cnt] <= wdata; // 按拍存数据 if (wlast) begin state <= RESP; // 最后一拍,转响应 wready <= 1'b0; end else begin beat_cnt <= beat_cnt + 1'b1; end end end RESP: begin // WLAST 握手成功后才允许给写响应 bvalid <= 1'b1; if (bvalid && bready) begin state <= IDLE; // 一笔事务彻底结束 bvalid <= 1'b0; end end endcase end end endmodule

这段代码有三个关键点。第一,IDLE 状态下awready常拉高,AW 握手在当拍就能完成,不需要额外的“等待地址握手”状态。第二,DATA 阶段的wready必须保持为 1,直到wlast握手成功才拉低,否则多拍突发的中间数据会被丢掉。第三,RESP 状态的进入条件必须是wvalid && wready && wlast,而不是wvalid && wlast——后者会把“数据有效但还没被握手成功”的拍子也当成成功,造成 BVALID 提前。这里我为了可读性省略了awlen与计数器的比较,实际工程里必须把每笔事务的实际拍数和awlen对齐,否则遇到主机不按协议拉wlast的时候,从机不会报错,只会写错数据。

3.4 如何在波形里判断一次突发是否合法

仿真跑完,打开波形先看三件事。

第一件事,找 AW 和 W 的握手点。波形上同一拍awvalid=1、awready=1才算地址握手成功;数据通道同理。看到一个高一个低、下一拍互换的,是典型的握手不合作,按 5.2 的死锁套路查。

第二件事,看wlast的位置。写突发的最后一拍数据,必须在wdat = 最后一拍 && wvalid && wready && wlast同时为高的那一拍,wlast不能提前也不能延后。提前拉wlast,从机会提前收尾,后面的数据拍全部丢失;延后拉wlast,从机会一直等,总线卡死。

第三件事,看bvalid相对wlast谁先谁后。合法顺序永远是数据最后一拍握手成功之后,bvalid才会拉高。看到bvalid先高、wlast后到的,这条事务的协议已经破坏了,往下查状态机的跳转条件。

4. 把验证工程扩展成自己的:driver、monitor 与断言

跑通最小验证只是热身。真正把这份 AXI4 源码验证工程变成自己的工具,需要把 testbench 从“一段能跑的代码”扩展成“能帮你找到问题的代码”。这一章讲验证组件的分工方式,以及两个最值得写的组件:握手 monitor 和协议断言。

4.1 验证组件分工:从 driver 到 scoreboard 一张表说清

工程自带的 testbench 里通常只有一个顶层模块和几个 initial 块,激励写完直接调任务。这种写法验证简单功能没问题,但一涉及多通道、乱序、背靠背事务,调试就成了灾难。标准做法是把验证环境拆成组件,各干各的。

组件职责与 AXI4 的关系
Driver产生激励事务按场景产生 AW/W/AR 通道的地址、数据、突发长度
Monitor采样总线信号只观察,不驱动,记录每次握手成功的信息
Checker检查协议规则断言或过程检查,验证握手时序、wlast 位置等
Reference Model模拟从机行为根据请求计算期望响应和数据
Scoreboard比对实际与期望把 monitor 采到的结果和参考模型输出比对

实际写的时候不需要一上来就把五个组件全部配齐。先从 monitor 加 checker 开始,monitor 负责把总线上发生了什么记录下来,checker 负责在协议层面做第一道拦截。数据正确性的比对留给 scoreboard,等协议层稳定了再补。

4.2 编写握手 monitor:把每拍事务打印出来

一个最小的 AXI4 写通道 monitor,核心逻辑是找到握手成功的拍子,然后打印这一拍的信息。最容易犯的错误是在valid为高时打印,或者在ready为高时打印,结果同一笔事务被打印两次。正确的触发条件只有一个:两者同拍为高。

class axi4_write_monitor; virtual axi4_if vif; int aw_count = 0; int w_count = 0; task run(); forever begin @(posedge vif.aclk); // 地址通道:AW 握手成功才算一笔事务开始 if (vif.awvalid && vif.awready) begin aw_count++; w_count = 0; // 新事务,数据拍计数清零 $display("[AXI_MON] AW burst: addr=0x%0h len=%0d size=%0d", vif.awaddr, vif.awlen, vif.awsize); end // 数据通道:W 握手成功才算一拍数据被接收 if (vif.wvalid && vif.wready) begin w_count++; if (vif.wlast) $display("[AXI_MON] W done: expect %0d beats, got %0d beats", vif.awlen + 1, w_count); end // 响应通道:B 握手成功,事务结束 if (vif.bvalid && vif.bready) $display("[AXI_MON] B resp=%0b", vif.bresp); end endtask endclass

这个 monitor 用aw_count统计事务数,用w_count统计每个事务内的数据拍数。awlen + 1是写突发的期望拍数,如果和实际w_count对不上,说明主机或从机有一方没按长度做事。这里只用$display打印,真正工程里会把信息包成 transaction 对象送给 scoreboard,但打印这一步先做出来,调试时能直接看到问题。

参数说明:awlen是突发长度减一,0 表示单拍。awsize是每拍字节数的对数,0 表示 1 字节,2 表示 4 字节。读写这些字段时按无符号数处理,不要用有符号数,否则长度超过 7F 会算出负数,打印出的数字让你怀疑人生。

4.3 用断言守护协议:让非法的 BVALID 提前暴露

打印只能帮你看到问题,断言才能在问题发生的当拍就把错误定性。SVA(SystemVerilog Assertions)是 AXI 验证里性价比最高的一层守护,写一次断言,跑遍所有向量。我最常写的一条是“BVALID 不能抢在 WLAST 握手之前”,这是第 3 章那个状态机最容易写错的地方。

// 断言:BVALID 拉起的前一拍,必须已经发生过 WLAST 握手成功 a_b_after_wlast : assert property( @(posedge aclk) disable iff (!aresetn) $rose(bvalid) |-> $past(wvalid && wready && wlast));

逻辑说明:$rose(bvalid)检测 bvalid 从 0 变 1 的拍子;$past(...)取上一拍的值。整条断言的意思就是“凡是有 bvalid 上升沿的那一拍,它的前一拍必须已经握手成功过 wlast”。如果从机在数据没收完时就拉 bvalid,这条断言会在当拍报 failure,并且打印出具体时间和信号值,比盯着波形找快得多。

再加一条覆盖性质的断言:地址握手之后,数据通道必须最终出现。这条防的是“主机发了地址但数据永远没来”的悬空场景。

// 断言:AW 握手成功后,最终一定会有 WLAST 握手 a_aw_then_wlast : assert property( @(posedge aclk) disable iff (!aresetn) $rose(awvalid && awready) |-> ##[1:$] (wvalid && wready && wlast));

##[1:$]表示“从下一拍开始,直到仿真结束前,必定发生一次”。这个写法在实际回归里会一直跑到事务完成才结束,能抓出一类非常隐蔽的 bug——地址通道和数据通道之间没有正确建立关联,数据被发到了别的从机。

5. AXI4 验证避坑:五个最容易翻车的握手细节

AXI4 协议好懂,但细节里全是玄学。下面五条是 RTL 验证工程里最常翻车的地方,每一条我都按“现象 → 原因 → 解决”的顺序写清楚,方便你在自己的工程里对照排查。

5.1 读突发在中间拍丢掉:ARLEN 没有被完整锁存

现象:读事务启动后,R 通道握手到一半,rlast迟迟不来,主机收到的数据比请求的少一拍,仿真器随后报数据超时。

原因:从机在接收 AR 通道时,只把arlen的低位锁进寄存器,高位在下一拍被覆盖,导致内部计数器的目标拍数比实际请求少。或者把arlen和arsize搞混,拿arsize当成长度去计数,突发长度完全对不上。

解决:arlen必须用完整位宽的寄存器锁存,并用独立计数器在每拍 R 握手时递增,在rlast到来时把计数值和arlen比对。想更省事,直接在验证环境里加一条断言:每笔 AR 握手成功后,R 通道的数据握手次数必须等于arlen + 1。断言能把这个坑变成回归里的一行失败报告,而不是半夜盯着波形数拍子。

5.2 WVALID 与 WREADY 互相等待:死锁复现与解除

现象:波形上wvalid=1、wready=0,下一拍变成wvalid=0、wready=1,交叉出现但永远没有同拍为高。仿真时间一直在走,事务没有任何推进。

原因:状态机把 WVALID 拉高和 WREADY 拉高放在了两个互斥的状态里,双方都在等对方先动。AXI4 规范里,发送方只要把 VALID 拉高就不能撤销,接收方可以在任何时刻拉高 READY。如果一段 RTL 让 WREADY 只在看到 WVALID 为高时才拉高,同时又让 WVALID 只在 WREADY 为高时才拉高,就形成了典型的互相等待死锁。

解决:把 WREADY 改成组合逻辑,只要从机处于可接收数据的 DATA 状态,WREADY 就为高,不依赖 WVALID 的当前值。发送则保持数据稳定直到握手成功。这条修完,死锁在下一轮仿真里通常会直接消失。

5.3 WSTRB 错位导致数据错乱:地址对齐的隐性规则

现象:DMA 写正常,但读回内存后,字节位置错位——明明是写到地址 0 的数据,出现在地址 4 的位置上。

原因:AXI4 里 WSTRB 的每一位对应 WDATA 的一个字节,wstrb[0]对应wdata[7:0],与地址的低位没有额外偏移关系。很多从机代码为了省事,在接收时用awaddr[1:0]去偏移 WSTRB,或者在做 64 位转 32 位的位宽转换桥时直接把 WSTRB 原样搬过去,导致字节使能错位。

解决:正确做法是 WSTRB 按数据位宽一一对应,位宽转换时做真正的移位和掩码。验证时在 scoreboard 里对每拍数据做字节使能掩码后再比对,一旦发现写入数据和预期在字节层面不一致,优先查 WSTRB 的处理逻辑,而不是先怀疑存储阵列。

5.4 BVALID 提前到达:写响应不能抢在 WLAST 之前

现象:主机收到 B 响应后立刻发起下一笔写事务,但上一笔数据的最后一拍还没真正握手成功,两笔数据在后端混在一起。

原因:从机的 B 通道在wvalid && wlast时就拉高,没有等wready。wvalid && wlast只表示“最后一拍已经出现在总线上”,并不代表“最后一拍被成功接收”。只有当wvalid && wready && wlast三者为高时,最后一拍才算真正完成。

解决:把状态机跳转到 RESP 的条件改成三者同时为高,用第 4 章那条断言a_b_after_wlast做回归拦截。这个坑在仿真里不一定会立刻暴露,因为主机通常不会在同一拍收到 B 响应后立刻发起新事务,但一旦时序压到背靠背,数据就会错乱,而且错得非常隐蔽。

5.5 复位释放后的第一拍事务丢失:复位与握手竞态

现象:复位释放后第一次写事务时好时坏,仿真十次有两次丢第一笔地址握手,上板复现概率更高,表现成“偶发写失败”。

原因:主机在复位释放沿之后立刻拉高awvalid,但从机的复位释放沿也在同一拍附近。从机的 awready 拉高逻辑在复位状态下被强制为 0,复位释放的同一拍,状态机还在初始化路径里,awready 本应拉高的赋值被复位逻辑覆盖,导致地址握手错过。

解决:在复位释放后加一拍固定延迟再开放握手通道,或者在复位释放沿后的第一个时钟沿主动屏蔽所有 VALID/READY 采样。再在回归里加一条断言:复位释放后的第一个时钟沿,握手信号不允许为高。这条断言能把这个玄学的时序问题变成确定性的检查点。

6. 把断言写进回归:AXI 验证从看波形变成看报告

前几章写的断言都是零散的,最后一步是把它们组织进回归体系,让每次仿真结束后直接看报告,而不是打开波形一帧帧翻。我自己的习惯是三类断言必写:握手类、突发完整类、事务边界类。握手类检查所有 VALID/READY 的同拍完成;突发完整类检查每笔事务的实际拍数等于 AX-LEN + 1;事务边界类检查 BVALID 这类信号不能跨事务越界。三类断言合起来,几乎能把 AXI4 从机 90% 的协议缺陷拦住。

断言之外,覆盖率也很重要。一个只测正常突发的测试,永远不知道背靠背事务有没有问题。用 cover property 记录边界场景是否被跑到,是验证工程成熟的标志。

// 覆盖:地址握手成功后下一拍立即出现数据握手(背靠背无气泡) c_back2back : cover property( @(posedge aclk) disable iff (!aresetn) (awvalid && awready) ##1 (wvalid && wready));

Questa 里运行完回归后,直接在报告中看 assertion 表格:绿色的 pass 是常态,黄色的 vacuous 需要留意,红色的 fail 就是 bug 清单。如果一条断言长期是“设计中从未发生过”,要么这个场景确实不会被触发,要么测试向量根本没打进去,后者比前者常见得多。

把这套断言机制搭进工程后,我再也没回过“盯着波形找 wlast 位置”的日子。有一次回归报告红了一整列,查了半天是一个位宽转换桥把 WSTRB 原样搬了过去,如果是靠人工看波形,那个 bug 可能要到上板联调才会暴露。AXI4 验证的最终形态,不是你会不会看波形,而是你有没有一套能让协议错误自己浮出来的检查体系。这一条,是这几年排 AXI 总线的坑里,我最想留给你的经验。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询