4. FSDB波形记录与UVM信号调试

在UVM验证环境中,波形记录是根因定位最直接的手段。Verdi能够读取FSDB(Fast Signal Database)格式波形,而FSDB的生成、控制与组织方式,直接决定了调试时能否快速找到问题信号。本节围绕FSDB dump控制、UVM信号与TLM端口记录、波形窗口分组、信号搜索与标记,以及事务级波形与RTL波形的关联展开。

一、FSDB dump控制:从$fsdbDumpfile到dump层次

FSDB波形由Synopsys Verdi的PLI接口生成,最基础的调用是$fsdbDumpfile与$fsdbDumpvars。典型写法如下:

initial begin
  $fsdbDumpfile("tb.fsdb");
  $fsdbDumpvars(0, tb_top, "+all");
  $fsdbDumpvars(1, tb_top.u_dut);
  $fsdbDumpvars(2, tb_top.u_axi_if);
end

其中第一个参数是dump深度:0表示当前层次及其所有子层次,1表示当前层次加下一层,2表示再下一层。第二个参数指定起始层次。第三个参数"+all"表示记录所有信号,包括结构体、数组和memory。实际项目中不建议全局使用+all,因为会显著增大FSDB体积并拖慢仿真速度。更合理的做法是:对DUT内部关键模块使用深度1~2,对接口和UVM组件按需记录。

FSDB还支持按时间窗口分段记录。通过$fsdbDumpoff和$fsdbDumpon可以在指定时间段内关闭或开启记录,例如在复位阶段关闭、在激励注入阶段开启:

initial begin
  $fsdbDumpoff;
  #100ns;
  $fsdbDumpon;
end

此外,$fsdbDumpflush用于在仿真中途强制刷新缓冲区,避免仿真崩溃时丢失已记录波形。对于长时间仿真,建议在关键检查点调用一次flush。

二、UVM信号与TLM端口记录

UVM组件中的信号分为两类:一类是RTL层次中的物理信号,另一类是UVM类对象中的成员变量和TLM端口。FSDB默认只能记录RTL信号,要记录UVM对象中的变量,需要使用$fsdbDumpvars配合UVM的uvm_hdl_deposit或Verdi的UVM调试接口。

更常用的方式是在UVM组件中直接调用$fsdbDumpvars并指定UVM层次路径。例如,在my_driver的build_phase中:

function void build_phase(uvm_phase phase);
  super.build_phase(phase);
  $fsdbDumpvars(0, "uvm_test_top.env.agent.driver");
endfunction

这样Verdi会在波形窗口中生成对应的UVM层次节点。对于TLM端口,如uvm_analysis_port、uvm_blocking_get_port,Verdi支持通过+fsdb+uvm编译选项开启UVM事务记录。开启后,TLM端口上的transaction会以事务块的形式出现在波形中,每个事务块包含起止时间、事务类型和关键字段。

建议在编译时加入-debug_access+all和+fsdb+uvm,并在仿真时使用$fsdbDumpvars(0, tb_top, "+UVM"),以同时记录RTL信号和UVM事务。

三、波形窗口分组与信号搜索标记

FSDB文件生成后,在Verdi中打开会看到默认的层次化信号列表。面对成千上万的信号,必须通过分组和搜索来组织视图。Verdi支持将信号拖入自定义分组(Group),每个分组可以命名并保存为.rc配置文件。典型分组策略包括:

  • 时钟与复位组:clk、rst_n、pll_lock等全局信号。
  • 接口组:按AXI、APB、SPI等协议划分,每组包含valid、ready、data、last等握手信号。
  • DUT内部关键路径组:状态机状态、计数器、FIFO指针、错误标志。
  • UVM事务组:driver、monitor、scoreboard中的transaction字段。

信号搜索使用Get Signals对话框,支持通配符*和正则表达式。例如输入*valid*可快速定位所有valid信号。找到目标信号后,可以右键选择Add to Wave或Mark,标记后的信号会以高亮颜色显示,便于在长波形中反复查看。

四、事务级波形与RTL波形关联

事务级波形(Transaction Waveform)与RTL波形关联是Verdi UVM调试的核心能力。当UVM事务被记录后,Verdi会在波形窗口上方生成一个事务条带,每个事务块对应一次TLM传输。点击事务块,可以自动跳转到该事务对应的RTL信号时间段,并高亮相关信号。

实现关联的关键是uvm_transaction的record属性。在自定义transaction中调用uvm_object_utils并设置record字段后,Verdi会自动解析事务的起止时间和字段值。例如:

class my_trans extends uvm_sequence_item;
  rand bit [31:0] addr;
  rand bit [31:0] data;
  `uvm_object_utils_begin(my_trans)
    `uvm_field_int(addr, UVM_ALL_ON)
    `uvm_field_int(data, UVM_ALL_ON)
  `uvm_object_utils_end
endclass

在波形中,事务块会显示addr和data的数值。当发现某个事务的data与预期不符时,可以直接在事务块上右键选择Trace to RTL,Verdi会定位到该事务在RTL中对应的信号跳变,从而将高层协议行为与底层电路行为对应起来。

FSDB波形记录与UVM信号调试关联链路 仿真环境 UVM Testbench Driver Monitor Scoreboard Sequencer DUT (RTL) AXI IF FSM FIFO Reg File FSDB 记录控制 $fsdbDumpfile("tb.fsdb") $fsdbDumpvars(0, tb_top, "+all") $fsdbDumpoff / $fsdbDumpon Verdi 波形窗口 事务级波形 (Transaction) WR addr=0x100 WR addr=0x104 RD addr=0x100 WR addr=0x108 RD addr=0x104 RTL 信号波形 clk awvalid awaddr 0x100 0x104 0x108 rdata 0xDEAD 0xBEEF Trace to RTL

五、实操建议与常见问题

在实际项目中,FSDB文件可能达到数十GB,直接打开会非常缓慢。建议按以下策略控制:

  • 按测试用例分段记录:每个testcase生成独立FSDB,避免单个文件过大。
  • 使用$fsdbDumpoff跳过空闲期:在等待中断或长时间复位期间关闭记录。
  • 只记录关键层次:对DUT内部使用深度1~2,对接口使用深度0,对UVM组件按需记录。
  • 开启+fsdb+uvm:确保事务级波形可用,否则无法进行事务与RTL的关联。
注意:$fsdbDumpvars的深度参数过大(如深度5以上)会导致FSDB体积急剧膨胀,且Verdi加载时间显著增加。建议先用深度0或1定位问题模块,再针对该模块单独增加深度重新仿真。

当波形中出现X态或不定态时,可以在Verdi中使用Event Search功能搜索信号跳变沿,或使用Signal Search按值搜索。例如搜索awvalid==1 && awready==0的时段,可以快速定位握手失败的位置。结合事务级波形中的错误事务,再Trace到RTL,就能形成从高层协议到低层信号的完整调试闭环。

最后,建议将常用的信号分组、搜索条件和标记保存为Verdi的.rc文件,并在团队内共享。这样每次打开新FSDB时,可以直接加载配置,避免重复劳动,显著提升调试效率。