ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FPGA验证提速:Vivado+VCS+Verdi+AXI VIP仿真流程实战

FPGA验证提速:Vivado+VCS+Verdi+AXI VIP仿真流程实战 前言做FPGA验证的人十有八九都遇到过这种尴尬代码逻辑对着波形看半天没问题结果一上板就挂回头查仿真波形又发现Vivado自带仿真器的层次里信号密密麻麻想定位一笔AXI写操作的握手时序鼠标滚轮都快滚出火星子了。换个思路把Vivado、VCS、Verdi三件套组合起来跑AXI VIP仿真效率完全不一样。这套组合的核心思路很简单Vivado负责生成IP和仿真库VCS负责高速仿真Verdi负责快速查波形AXI VIP负责把AXI协议的主从设备行为模拟出来。三件套各自干自己最擅长的事中间用仿真脚本串起来形成一个完整闭环。对于需要验证AXI接口的工程师不管是初学协议的新手还是做SoC集成的老手这套流程都能帮你把验证周期缩短一大截。这篇文章我会从工具链的搭建思路讲起把编译、仿真、波形查看的完整链路和实操脚本全部摊开最后附上我踩过的坑和排查技巧。内容尽量讲得细适合照着一步步操作也适合遇到问题时翻出来对一下。1. 内容整体设计与思路拆解1.1 三件套分工谁负责生成、谁负责跑、谁负责调先说清楚这套组合里每个工具是干嘛的。Vivado是Xilinx家的FPGA开发环境它的强项是IP定制、综合、布局布线但它的仿真器xsim在大型验证场景下确实捉襟见肘。VCS是Synopsys的仿真工具编译优化做得好跑大型testbench速度快尤其在UVM验证环境里几乎是行业标配。Verdi也是Synopsys的调试工具它的核心优势在于FSDB格式的波形文件、层次化的信号追踪、以及把RTL行为和事务级行为对应起来的能力。AXI VIP在这套组合里扮演的是协议模型角色。它不是一个实际的硬件模块而是一个验证IP可以被配置成AXI Master、AXI Slave或者Monitor用来在你的DUT被测设计周围搭出一个完整的AXI协议环境。比如你要验证一个自己写的AXI Slave模块VIP就模拟Master发起读写事务你要验证一个AXI Master逻辑VIP就扮演Slave回应事务。三个工具加一个VIP正好覆盖了验证流程的三个阶段Vivado把环境和IP准备好VCS把仿真跑起来Verdi把波形呈现出来。整个流程的衔接点在于仿真库和波形文件这也是后面脚本的核心处理对象。1.2 为什么不用Vivado自带仿真器非要折腾这套组合很多人一开始会问Vivado自带仿真器不也能看波形吗为什么非要装VCS和Verdi这个问题我以前也纠结过实际对比之后就明白了。第一是仿真速度。VCS的事件调度引擎比xsim高效尤其当testbench里有大量AXI事务、DMA搬运、多核互连等并发活动时VCS的优势非常明显。我实测过同一个测试用例同样的UVM环境xsim跑完要四十多分钟VCS十几分钟就跑完了。这在频繁回归的时候差距是巨大的。第二是波形调试能力。Verdi不是简单的看波形它能做信号间追溯、协议分析、事务级抽象还能在发送FSDB时保留完整的设计层次信息。你在Verdi里点一个信号可以直接看到驱动它的逻辑锥这在定位问题时比在xsim里手动翻找要高效得多。AXI协议本身是突发式读写经常出现outstanding请求和乱序返回用普通波形工具翻很难看出事务之间的关系但Verdi可以配合VIP的事务接口把事务级别的收发情况展示出来定位问题一目了然。第三是生态兼容。VCSVerdi是工业界非常成熟的组合大部分IP厂商提供的参考验证环境都是基于这套工具链的。你用Vivado里自带的仿真器可能跑不动某些商业VIP或者要额外做很多适配工作而用VCS基本可以无缝对接。所以这套组合不是炫技而是实际项目里被验证过的高效方案。1.3 AXI VIP在实际项目里的典型应用场景AXI VIP能用在很多地方我举几个最常见的场景。第一验证自研AXI Slave。比如写了一个DDR控制器、PCIe控制器、或者自定义的SRAM控制器接口是AXI协议。这时候用AXI VIP配置成Master模式通过脚本来发起各种类型的读事务、写事务、混合突发覆盖窄位传输、对齐/非对齐地址、不同burst长度、乱序返回等情形比自己手写BFM总线功能模型省事太多。第二验证自研AXI Master。比如设计了一个DMA引擎或者加速器需要主动发起总线传输。那就用AXI VIP配置成Slave模式由VIP来响应DUT发出的请求。你可以通过VIP的回放机制检查响应时序是否正确还可以故意让VIP延迟响应测试DUT的容错能力。第三互连IP和SoC级验证。在SoC集成验证阶段经常需要验证AXI Interconnect和多个外设之间的通信。把多个AXI VIP挂在不同端口上每个VIP配置成不同角色模拟多主多从的真实流量这种场景用Vivado自带的仿真器很容易跑崩用VCS就稳得多。2. 干活前的准备环境、文件与工程配置2.1 版本对齐Vivado、VCS、Verdi的版本搭配建议这一步看似基础但很多人一开始就栽在这里。不同版本的Vivado、VCS、Verdi之间兼容性差异很大尤其是编译仿真库的时候VCS编译器版本太老或者太新都会导致库编译失败。我目前用得比较顺的组合是Vivado 2022.2配VCS 2020.12、Verdi 2021.12。Vivado 2022.2的xsim库支持VCS 2020.06以上的版本VCS 2020.12在这个范围内Verdi的PLI版本也和VCS匹配得很好。如果是Vivado 2023.1建议至少用VCS 2021.09以上的版本。Verdi版本一般跟着VCS走同一个大版本内的PLI接口是兼容的。如果你用的是更新的Vivado 2024.x系列VCS就建议用2022.12以上版本否则编译仿真库时可能出现unsupported compiler version或者某些仿真原语报错。这里建议开工前先查一下Vivado官网的仿真工具支持矩阵把版本对应关系确认好再动手。2.2 在Vivado里生成AXI VIP并检查关键文件在Vivado里新建工程后在IP Catalog里搜索AXI Verification IP就能找到。双击配置时主要关注几个选项Protocol根据自己的DUT选择AXI4、AXI3、AXI4-Lite或AXI4-Stream。Data Width要和DUT的接口位宽一致不然连接时会报位宽不匹配。Interface Mode选择Master、Slave或者Monitor。Master用于主动发起事务Slave用于响应外部请求Monitor只做监测不主动发起。Read/Write Address Width地址位宽需要覆盖DUT的地址空间。Protocol Constraints有些版本里有关于outstanding transaction、burst length等参数的约束选项按需设置。生成IP之后Vivado会输出一个以axi_vip_开头的IP核目录里面有.src、sim和example design目录。其中example design很有价值里面给出了例化方式以及一套可以运行的testbench模板新手可以拿它作为起点省去了从零开始写测试的麻烦。另外要注意AXI VIP的仿真模型在综合时是会被排除的它只存在于仿真环境里。所以你在连接VIP时通常在testbench顶层例化而不是在RTL顶层里例化。2.3 编译仿真库把Vivado生成的东西喂给VCS这是整套流程里最关键的环节之一。VCS不能直接识别Vivado导出的IP核仿真模型需要先把Xilinx的仿真库用VCS编译一遍。最方便的方式是在Vivado里用Tcl命令compile_simlib -simulator vcs -family all -language all -library all -dir /path/to/simlib这段命令会把Xilinx的Unisim、SecureIP、Simprim等仿真库编译成VCS能够识别的库文件并生成一个vivado_simlib.log供排查错误。编译过程中如果报错优先检查VCS和Verdi的安装路径是否被正确识别以及license是否能满足VCS编译模式的要求。编译完成之后Vivado的仿真脚本里会生成一个fifo文件通常叫scfifo或者vcs_elaborate.csh打开看一下你会发现里面其实已经把vlogan、vhdlan等命令串好了这些命令会作为后面自己写脚本的参考。如果你用的是命令行非工程模式也可以直接用vivado -mode batch -source compile_simlib.tcl的方式来跑效果一样。2.4 仿真文件的组织方式要在VCS里跑Vivado工程最核心的是整理好文件列表。工程模式下Vivado在生成仿真脚本时会自动整理filelist但自己写独立脚本时通常需要手动维护一个文件列表至少包含以下几个部分Xilinx仿真库路径AXI VIP的源码路径通常是PWD/ip/axi_vip_xxx/simDUT的RTL源码测试bench源码包括interface、testcase、sequence等UVM源码路径如果使用UVM验证环境我习惯把文件列表分成两个文件一个放DUT和VIP的RTL一个放testbench和验证环境。这样做的好处是当某个文件改动时只需要重新编译对应文件列表不用每次都重新编译整个工程。3. 实操过程与核心环节实现3.1 一步一步写一个最小可跑的仿真脚本这一节直接给出一份我常用的脚本骨架照抄即可入门。假设项目文件列表叫filelist_dut.f和filelist_tb.f我一般用这样的结构来跑编译和仿真。第一步定义环境变量export VIVADO_LIB/path/to/vivado_simlib export WORK_DIR./work export LOG_DIR./log第二步用vlogan编译Verilog文件用vhdlan编译VHDL文件。AXI VIP的仿真模型通常是VerilogDUT可能是混合语言所以需要在编译前判断文件类型。vlogan -sverilog -timescale1ns/1ps \ incdir$WORK_DIR \ -f filelist_dut.f \ defineDUMP_FSDB \ -l $LOG_DIR/vlogan_dut.log注意这里的defineDUMP_FSDB这一步是为了让后续的波形转储宏生效。如果你在testbench里用的是ifdef DUMP_FSDB包住$fsdbDumpvars那么不加这个宏定义就不会产生波形。第三步vcs构建仿真可执行文件。这是关键命令我会这么写vcs -sverilog -debug_accessall \ -ntb_opts uvm \ -timescale1ns/1ps \ -f filelist_tb.f \ -o simv \ -P ${VERDI_HOME}/share/PLI/VCS/LINUX64/novas.tab \ ${VERDI_HOME}/share/PLI/VCS/LINUX64/pli.a \ -l $LOG_DIR/vcs.log解释一下几个选项。-debug_accessall是让VCS保存足够多的信号访问信息后续Verdi才能正确使用Waveform和Schema功能-ntb_opts uvm是让VCS加载UVM库-P指定Verdi的PLI接口文件这是让VCS能调用$fsdbDumpvars等Verdi系统函数的关键不加这个运行仿真时就会报未知的$fsdbDumpvars任务。第四步跑仿真./simv UVM_TESTNAMEaxi_rw_test \ fsdb_start_time0ns \ fsdb_end_time10000ns \ -l $LOG_DIR/sim.log如果testbench里写好了$fsdbDumpfile(tb.fsdb)和$fsdbDumpvars(0, tb)这一步就会生成一个tb.fsdb文件。后续用Verdi打开这个文件即可查看波形。3.2 AXI VIP的初始化与事务驱动要点拿到AXI VIP的example design后你会发现它已经在testbench里帮你把VIP初始化好了但实际项目里需要自己重新初始化的地方不少。一个常见的做法是在testbench顶层例化VIP后通过VIP的接口句柄发送初始化命令配置地址映射、数据宽度、默认响应等。然后针对不同testcase在virtual sequencer或者sequence里发起具体的AXI事务。比如你配置了一个Master模式的VIP想发起一笔写事务典型的Sequence伪代码如下class axi_write_seq extends uvm_sequence #(axi_vip_master_transaction); uvm_object_utils(axi_write_seq) function new(string name axi_write_seq); super.new(name); endfunction task body(); axi_vip_master_transaction tr; uvm_do_on_with(tr, p_sequencer.m_axi_vip_master_sequencer, { addr 32h0000_1000; burst_type AXI4_BURST_INCR; data_size AXI4_SIZE_64BIT; burst_length 15; }) endtask endclass这段代码的核心作用就是生成一笔起始地址0x1000、64位宽度、16次突发的增量为8字节的写事务。通过修改constraint可以覆盖几乎所有AXI协议规定的传输模式。在你的DUT里需要准备好AXI从机接口的应答逻辑也就是要正确响应AWREADY、WREADY、BVALID等信号。如果DUT反馈握手不完整VIP会自动发起重试或者报告超时这时可以通过Verdi观察波形来精确定位是哪一拍握手出了问题。3.3 FSDB波形怎么转储以及Level和Scope怎么选FSDB是Verdi的专用波形格式优点是体积小、加载快。很多人在这一步踩坑最常见的是转储文件为空或者只转储了顶层信号没有内部信号。转储FSDB的核心是将下面几句话放到testbench合适的位置initial begin if ($test$plusargs(DUMP_FSDB)) begin $fsdbDumpfile(dump.fsdb); $fsdbDumpvars(0, all, dut_top); end end这里有两个关键点。$fsdbDumpvars的第一个参数是0表示转储整个层次下所有信号如果你只关心DUT内部可以把第一个参数设为1并把作用域限定到某个子模块这样生成的fsdb文件大小会小很多。all参数是转储所有信号状态包括寄存器和net如果不需要内部寄存器只关注端口信号可以去掉all。另一个实用小技巧是可以在运行simv时通过fsdb_start_time和fsdb_end_time控制FSDB的转储窗口。在大型仿真实测中全量转储可能生成几十GB的FSDB文件磁盘不够是分分钟的事。限定时间窗口和层次之后文件可以缩小到原来的1/10甚至更小而调试需要的关键信息一点都不会丢。3.4 UVM环境下运行VCS的专属配置如果你搭的是标准UVM环境有几个配置细节需要特别注意。第一-ntb_opts uvm这个选项在VCS新版本里已经默认支持UVM但为了显式控制UVM版本还是建议加上。同时如果你使用了UVM的宏定义比如UVM_NO_DEPRECATED等也要在编译命令里用define定义。第二UVM test的传递。传统方式是在仿真命令里输入UVM_TESTNAMExxx但如果你希望在波形里看到每个事务的开始和结束时间可以使用Verdi的-uvm调试选项来把UVM的factory信息、sequence信息都dump到FSDB里。这一点在大型验证环境里非常有用能直接定位到某个sequence的某个transaction。第三VCS支持增量编译。也就是vcs -incremental当你只改了testbench而没改RTL时用增量编译能大幅缩短build时间。我自己通常会做一个Makefile把文件列表按照最近修改时间进行一次分类只编译修改过的部分实测下来能节省40%以上的构建时间。3.5 把Vivado IP的SecureIP问题绕过去Vivado的很多IP核比如MIG、GT收发器、部分AXI接口IP在仿真时会用SecureIP的加密模型。SecureIP模型在VCS下编译时偶尔会碰到兼容性问题表现是编译报错或者运行仿真时模型打印出一堆加密信息后停止。解决办法有两个方向。第一在Vivado工程的仿真设置里把IP核的仿真模型切换成非安全模型即生成仿真模型时选择仿真只使用行为级模型这可以在IP配置时勾选。第二如果IP本身不得不使用SecureIP那在编译Vivado仿真库时就要确保SecureIP的仿真库被正确编译并且编译完成后保留secureip仿真库的路径。我自己遇到MIG IP时通常会把MIG的仿真模型单独编译而不是和企业all一并编译这样错误定位起来更清晰。4. Verdi快速查看波形的心得4.1 从零打开Verdi并加载仿真的正确姿势仿跑通并生成了FSDB文件后接下来就是Verdi登场。我习惯用命令行方式打开Verdi命令如下verdi -f filelist_tb.f -top tb_top -dbdir simv.daidir -ssf dump.fsdb -f filelist_tb.f让Verdi加载之前仿真用的文件列表这样层次结构和源码能对应上-top tb_top指定顶层模块-dbdir simv.daidir让Verdi能读取VCS编译时生成的中间数据库保证信号的访问和追踪可用-ssf dump.fsdb是直接打开FSDB文件。打开之后Verdi会显示设计层次窗口和FSDB窗口。这时可以把需要观察的信号拖入波形窗口。对AXI接口我通常一次把以下信号都拖进去避免漏看关键接口ARVALID、ARREADY、ARADDR、ARLEN、ARSIZE、ARBURSTRVALID、RREADY、RDATA、RRESP、RLASTAWVALID、AWREADY、AWADDR、AWLEN、AWSIZE、AWBURSTWVALID、WREADY、WDATA、WSTRB、WLASTBVALID、BREADY、BRESP4.2 AXI握手的波形判读从valid/ready到outstandingAXI协议的核心是valid/ready握手机制看波形时最需要关注的就是这两个信号是否能正确配合。握手完成的唯一条件是在同一个时钟上升沿valid和ready同时为高。如果valid拉高但ready一直没拉高大概率是接收方没有准备好需要检查接收方的状态机。在波形中定位这类问题我会直接在Verdi的波形窗口里加两个光标一个放在valid拉高的沿一个放在ready拉高的沿看它们之间隔了几个周期。如果两个信号同时为高的周期数超过预期就说明握手延迟了原因可能在从机的FIFO满了、内部状态机卡住、或者响应通道没有及时返回。还有一点要特别留神outstanding transaction。AXI协议允许Master在没有收到前一笔事务响应的情况下继续发起新的事务这就是outstanding。如果你的VIP配置了outstanding数量但DUT没实现对应的缓冲能力就会出现响应通道堵塞或者事务丢失。看波形时如果发现连续多个AWVALID都成功握手但BVALID迟迟不来那么基本可以断定DUT的响应通道有瓶颈。4.3 用Verdi把事务级视图和信号级视图打通只看离散的波形信号对于复杂AXI场景来说还是低效。Verdi的nTrace和Schema功能能把UVM里的事务对象和RTL波形对应起来。具体操作是在Verdi的nTrace窗口打开你的testbench源码找到sequence发起事务的那一行然后右击选择Open Schema或者Add to Waveform。Verdi会尝试把transaction的起始时间映射到FSDB里并在FSDB时间轴上画一个事务条。这个功能一旦用熟了定位协议层的问题可以从对着信号猜变成直接看哪笔事务失败。对于AXI VIP如果你在UVM环境里打印了事务信息Verdi还能把这些信息挂到时间轴上。这样当你发现波形里有一个异常响应时可以直接跳到打印事务日志的时间点几秒钟就把信号和事务对应起来。4.4 保持波形文件体积可控的几个实用设置FSDB虽然比VCD小很多但在长时间仿真中依然可能膨胀得很快。我有几个习惯用来控制文件体积。第一在$fsdbDumpvars时限制转储层次而不是从头dump到尾。很多情况下顶层testbench的信号不需要看只看DUT内的信号就够了。第二使用$fsdbDumpvars(0, force, scope)的force选项只在特定时间点转储特定数据。对于大型SoC仿真这个方式特别实用。第三利用Verdi的波形再处理。如果已经生成了一个很大的FSDB也可以在Verdi里通过Format - Filter或时间轴选择功能把不需要的信号从波形窗口里隐藏视觉上更清爽。这不减小FSDB文件本身但至少能提升查看效率。5. 常见问题与排查技巧实录5.1 编译报错的典型原因和定位思路这个环节我整理了一张实用速查表基于我遇到过的频率排序。现象最可能原因解决办法vlogan编译AXI VIP时报未知类型缺少incdir或者-sverilog没加上在vlogan命令里补incdiraxi_vip_sim目录并加上-sverilog$fsdbDumpvars任务无法识别VCS没加Verdi的PLI文件路径检查-P后面的novas.tab和pli.a路径是否正确环境变量VERDI_HOME是否设置UVM库报版本不兼容VCS内嵌UVM版本和testbench引用的版本不一致确认-ntb_opts uvm的版本或者改用外部UVM库并指定-ntb_opts uvm-1.2仿真启动后立刻退出报license问题VCS或Verdi的license配置不正确检查环境变量LM_LICENSE_FILE确认工具能正常启动vcs -id编译vivado_simlib时某个IP仿真库失败Vivado版本和VCS版本不在支持列表内查Vivado官方编译仿真工具支持矩阵升级或降级VCS版本这几种问题里我遇到最多的是第二类也就是PLI路径没配置对。很多新手照搬网上的脚本但对VERDI_HOME环境变量没有设置导致VCS在编译阶段找不到Verdi的PLI库出现一堆undefined references的报错。解决起来也简单在bashrc或者编译脚本前面加一行export VERDI_HOME/opt/Synopsys/Verdi/2021.12 export PATH$VERDI_HOME/bin:$PATH export LD_LIBRARY_PATH$VERDI_HOME/lib:$LD_LIBRARY_PATH5.2 波形为空、波形不更新、波形乱码的排查技巧FSDB文件生成了但Verdi里打开全是空波形这属于高频问题。第一步确认FSDB文件有内容。用fsdbdump命令读取FSDB文件统计信息或者在Verdi中打开后看状态栏的信号数量和采样点数。如果文件接近0字节说明$fsdbDumpvars没有正确执行。这时先检查testbench的initial块里是否加了DUMP_FSDB条件宏再检查仿真运行日志里有没有出现fsdb相关的warning。第二步确认VCS编译时用了-debug_accessall。如果没有加调试访问权限VCS生成的simv可能无法提供足够的信号访问信息FSDB里即使有数据也无法对应到设计层次。第三步如果波形能显示但某些信号是红线或者X态说明该信号没有被正确驱动。这种情况在AXI VIP环境里通常意味着复位时序不对VIP在复位释放之前就开始发起事务或者DUT的时钟和VIP的时钟不同步。我自己调试时有个习惯先拉出rst_n和clk两个信号确认它们复位时序正常再去看AXI接口这样能快速排除最基础的问题。5.3 AXI接口握手卡死的定位方法论握手卡死也就是valid一直拉高但ready一直不拉高这种问题在AXI验证里最折磨人。首先是缩小范围。在Verdi里把AXI五个通道的valid/ready都拉出来看具体是哪一通道先卡住。因为AXI通道之间是有依赖关系的比如W通道的数据没发完B通道就不能响应AW通道没握手W通道的写数据也不应该开始。通过看五路通道的握手情况通常能快速找到问题的源头通道。其次是回溯依赖。找到卡住的通道后往前回溯引起这个通道卡住的原因。比如WVALID一直为高但WREADY一直为低可能是因为从机的写FIFO满了。从机的写FIFO为什么会满可能是VIP发出的写事务数量超过了从机的缓冲能力也可能是从机的读侧还在占用共享资源。沿着这个逻辑链把相关状态信号加入波形很快就能定位到是哪一段逻辑挡住了。我个人还有一个经验在testbench里通过$display对关键状态加打印把AXI事务的发送和接收过程打出来这样不仅能看波形还能配合日志定位卡死的时刻点。两者结合定位效率非常高。5.4 慢仿真和视波失真如何正确取舍有时候仿真跑得非常慢文件越来越大想知道是不是有配置不当的地方。我通常从三个角度排查。第一FSDB转储层次过大。全量转储在大型设计中会产生巨大的IO开销直接影响仿真速度。如果只是验证某个IP核只在testbench顶层限制转储层次即可。第二UVM的objection机制设置不当。当UVM环境中所有task都满足raise/drop objection之后仿真才会结束。如果某个sequence的objection没有正确drop仿真会一直运行而且大量事务都阻塞在同一个sequencer上看起来很慢。在日志里如果用UVM_VERBOSITYUVM_MEDIUM观察到底层在反复执行哪些事务就能发现这类问题。第三VIP的参数配置。有些AXI VIP的配置里如果开了delay injection或者随机延迟虽然更贴近真实场景但同时也会大幅拖慢仿真。在做快速冒烟测试时我通常把这类随机延迟关了等回归测试时再开。6. 后续还可以怎么玩这套三件套流程跑通之后能扩展的方向比想象得多。一个很值得做的扩展是把Verdi和UVM的objection机制结合起来做覆盖率驱动的验证。VCS支持覆盖率收集Verdi支持覆盖率查看二者配合可以直观地看到AXI总线上的读写事务覆盖率判断验证环境是否已经把协议的边界情况都覆盖到了。另一个方向是把脚本进一步自动化。现在我的做法是做一个Makefile目标分为compile、sim、debug三个层次。compile层只做编译sim层只做仿真并生成FSDBdebug层自动打开Verdi并加载FSDB。这样每次修改代码后只需要执行make sim就可以一键回到调试界面不用再重复敲一长串命令。再往后还可以把VCS的UVM regression脚本和Jenkins持续集成接起来。每次代码提交后自动编译仿真生成FSDB和测试报告出问题自动打开Verdi定位。到了这个阶段三件套已经不只是调试工具而是整个验证流程的基座了。最后再分享一个小技巧。在testbench里加一个全局变量用来控制FSDB转储的开关这样在跑大量回归测试时可以选择不生成FSDB只跑功能对错等到真正需要调试时再用带FSDB的模式跑一次。这个方法能帮你在回归阶段节省大量磁盘空间和时间需要定位问题时又能快速拿到波形。这套流程用到今天已经帮我处理过不少AXI接口的疑难杂症希望也能帮你省点时间。
返回列表