2. Verdi基础操作与UVM编译加载

Verdi 的调试能力并不是“打开波形就能看”这么简单,它依赖一条完整的准备链路:仿真器在编译阶段生成 KDB 知识数据库,在运行阶段写出 FSDB 波形,Verdi 再通过 KDB 建立设计层次、验证平台层次与信号/对象索引。如果这条链路的任一环节缺失或参数不匹配,就会出现“层次树是空的”“UVM 组件看不到”“信号加不进波形”等典型问题。本节围绕这条链路,讲清启动方式、KDB/FSDB 生成、UVM 库编译选项,以及层次与可见性检查。

一、Verdi 的三种启动方式与适用场景

Verdi 的启动方式决定了它能否拿到完整的编译期信息,实际工程中常用三种:

  • 独立启动(verdi &):直接打开 Verdi 图形界面,再通过 File → Open 加载 FSDB 与 KDB。适合已有历史波形、只想做离线分析的情况。此时若没有对应的 KDB,层次树只能从 FSDB 中反推,UVM 类层次和源码关联会明显变弱。
  • 交互式联合仿真(verdi -ssf 或 -dbdir 配合仿真器):在仿真命令行中通过 -gui、-ssf 等选项让 Verdi 与仿真器同步启动,仿真暂停时可直接在 Verdi 中查看当前层次与信号。适合需要边跑边查的调试场景。
  • 后处理启动(verdi -dbdir simv.daidir -ssf dump.fsdb &):仿真结束后用 KDB 目录加 FSDB 文件启动,这是最常用的方式,既能拿到完整层次,又能反复回看波形。

关键点是:KDB 目录必须与生成 FSDB 的那次编译一致。如果重新编译后 KDB 被覆盖,而 FSDB 是旧版本,Verdi 打开时会出现信号名对不上、层次错位等问题。

二、KDB 与 FSDB 的生成

KDB(Knowledge Database)是 Verdi 的编译期知识库,包含设计层次、源码行号、信号声明、UVM 工厂注册信息等。以 VCS 为例,生成 KDB 的典型编译命令为:

vcs -full64 -sverilog -debug_access+all \
    -kdb -lca \
    -ntb_opts uvm-1.2 \
    -f filelist.f \
    -o simv

其中 -kdb 是生成 KDB 的核心开关,-debug_access+all 保证信号和对象可被访问,-lca 启用部分受限功能。编译完成后会在 simv.daidir 目录下生成 KDB 相关文件。

FSDB 的生成则依赖仿真时的系统任务。在 testbench 顶层或 initial 块中加入:

initial begin
    $fsdbDumpfile("dump.fsdb");
    $fsdbDumpvars(0, tb_top, "+all");
    $fsdbDumpMDA();
end

$fsdbDumpvars(0, tb_top, "+all") 中的 0 表示转储 tb_top 以下所有层次,+all 表示包含多维数组和部分内部信号。$fsdbDumpMDA() 用于转储多维数组,UVM 中大量 transaction 字段是数组类型,缺少它会导致波形里看不到这些字段。

FSDB 文件大小与转储范围直接相关。调试初期建议先用 $fsdbDumpvars(0, tb_top) 控制范围,定位到具体模块后再用 $fsdbDumpvars(1, tb_top.u_env.u_agent) 精确加dump,避免波形过大拖慢 Verdi 加载。

三、UVM 库编译选项与可见性

UVM 的类层次、factory 注册、config_db 信息要能被 Verdi 识别,编译时必须显式启用 UVM 支持。常见选项包括:

选项作用缺失后果
-ntb_opts uvm-1.2指定 UVM 库版本并链接UVM 类无法解析,编译报错
-debug_access+all开放信号与对象访问权限Verdi 中信号变灰、无法加入波形
-kdb生成知识数据库无层次树、无源码关联
+define+UVM_OBJECT_MUST_HAVE_CONSTRUCTOR强制对象构造检查部分对象注册信息不完整

编译完成后,在 Verdi 中通过 Tools → UVM Debug 或 View → UVM Hierarchy 可以打开 UVM 层次视图。如果这里为空,优先检查 -ntb_opts 是否生效、KDB 是否重新生成。

四、层次加载与信号/对象可见性检查

Verdi 加载后,左侧通常有两个层次来源:Design Hierarchy(RTL 设计层次)和 UVM Hierarchy(验证平台类层次)。前者来自 KDB 中的模块实例树,后者来自 UVM 工厂注册信息。两者不是同一棵树,调试时需要明确当前问题属于哪一侧。

信号可见性检查的实操路径是:在 Design Hierarchy 中展开到目标模块,右键信号选择 Add to Waves → New Waveform。如果信号显示为灰色或无法添加,说明该信号在编译时未被 -debug_access 覆盖,需要回到编译选项调整。对象可见性则通过 UVM Hierarchy 展开 component,查看其内部 transaction、sequence 等对象,若对象字段为空,通常是 $fsdbDumpMDA() 未调用或 dump 范围未覆盖。

Verdi 调试准备链路:编译期 → 运行期 → 加载期 编译期(VCS) -kdb -lca -debug_access+all -ntb_opts uvm-1.2 运行期(仿真) $fsdbDumpfile("dump.fsdb") $fsdbDumpvars(0, tb_top, "+all") $fsdbDumpMDA() 加载期(Verdi) verdi -dbdir simv.daidir -ssf dump.fsdb & Design / UVM Hierarchy 产物:simv.daidir(KDB) 层次树 / 源码行号 / UVM 注册信息 产物:dump.fsdb(波形) 信号值 / 数组 / 事务字段 检查点:可见性 信号可加波形 / 对象字段非空 可见性检查路径 Design Hierarchy 展开模块实例树 右键 Add to Waves 信号是否可添加 UVM Hierarchy 展开 component 对象 字段是否非空 判断 dump 范围

从图中可以看到,编译期、运行期、加载期三段是串联的:编译期决定 KDB 里有什么,运行期决定 FSDB 里有什么,加载期只是把两者组合起来呈现。任何一段的参数不匹配,最终都会表现为“看不到”或“对不上”。因此,遇到层次或信号问题时,建议按“先确认 KDB 是否重新生成 → 再确认 FSDB 是否覆盖目标范围 → 最后检查 Verdi 加载参数”的顺序排查,而不是直接在 Verdi 界面里反复尝试。

常见误区:只重新编译了 RTL 但没有重新生成 KDB,或者只重新跑了仿真但 FSDB 文件名与旧文件相同导致覆盖混乱。建议在 Makefile 中把 KDB 目录和 FSDB 文件名与编译时间戳或版本号关联,避免新旧数据混用。

掌握这条链路后,后续的 UVM 调试才有稳定的基础:层次树能展开、信号能加波形、对象字段能查看,才谈得上进一步用 Verdi 做事务级调试和根因定位。