3. VCS覆盖率编译与仿真流程
覆盖率不是仿真跑完自动出现的“副产品”,它需要在编译阶段被显式打开、在仿真阶段被持续采集、在仿真结束后被写入数据库,最后还要把多次仿真的数据库合并成一份可分析的整体。VCS 的覆盖率闭环正是围绕这条链路展开的:编译期决定采什么,仿真期决定记什么,合并期决定看什么。本节把这条链路拆成可执行的命令与工程配置,让覆盖率从“能跑出来”变成“可控、可复现、可累积”。
一、编译期:用选项打开覆盖率采集
VCS 的覆盖率采集能力由编译选项控制,最核心的是 -cm。它后面跟的字母组合决定了采集哪几类覆盖率:
line:行覆盖率,统计 RTL 每一行是否被执行;cond:条件覆盖率,统计 if/case 等条件表达式的取值组合;fsm:状态机覆盖率,统计状态与状态转移的覆盖情况;tgl:翻转覆盖率,统计信号 0→1、1→0 的翻转;branch:分支覆盖率,统计分支路径是否被走到;assert:断言覆盖率,统计 SVA 断言的触发情况。
工程中常用组合写法,例如同时采集行、条件、状态机和翻转:
vcs -full64 -sverilog \
-cm line+cond+fsm+tgl+branch \
-cm_dir ./cov.vdb \
-cm_name compile_base \
-debug_access+all \
-f filelist.f \
-o simv_cov
这里有几个关键点需要理解。-cm_dir 指定覆盖率数据库的根目录,VCS 会在该目录下生成 .vdb 结构;-cm_name 给本次编译的覆盖率数据一个名字,便于后续区分不同编译版本。注意:编译选项决定的是“采集能力”,真正是否记录数据由仿真运行时的 -cm 决定,两者必须匹配,否则会出现“编译开了但仿真没记”的常见问题。
另外,-cm_hier 用于限定采集范围,避免把整个 SoC 都纳入采集而拖慢仿真。例如只关心 DUT 内部、排除验证平台:
vcs -full64 -sverilog \
-cm line+cond+fsm+tgl \
-cm_hier cm_hier.cfg \
-f filelist.f -o simv_cov
其中 cm_hier.cfg 的典型内容如下,+tree 表示包含整棵子树,-tree 表示排除:
+tree tb_top.u_dut
-tree tb_top.u_dut.u_ram
+module tb_top.u_dut.u_ctrl
二、仿真期:让覆盖率数据真正落盘
编译完成后,运行仿真时必须再次带上 -cm,否则覆盖率不会被记录。同时用 -cm_name 为本次运行命名,用 -cm_dir 指向同一个数据库目录,实现多次运行累积:
./simv_cov -cm line+cond+fsm+tgl \
-cm_dir ./cov.vdb \
-cm_name test_smoke_01 \
+ntb_random_seed=12345 \
+UVM_TESTNAME=smoke_test
每次仿真结束后,VCS 会在 cov.vdb 下生成一个以 -cm_name 命名的子目录,里面包含本次运行的覆盖率数据。这样做的价值在于:不同测试用例、不同随机种子、不同回归批次的数据可以独立保存,又能在同一数据库下统一合并。
如果希望仿真过程中实时观察覆盖率增长,可以加 -cm_log 或使用 URG 的增量报告;如果只想在仿真结束时输出一次汇总,保持默认即可。对于长回归,建议在脚本中为每个用例设置唯一的 -cm_name,例如 test_${TESTNAME}_${SEED},避免同名覆盖导致数据丢失。
-cm 必须一致或仿真阶段包含编译阶段的子集。若编译只开了 line+cond,仿真却写 -cm tgl,翻转覆盖率不会产生有效数据。
三、合并期:用 URG 把多次仿真汇成一份报告
多次仿真的覆盖率数据分散在 cov.vdb 的各个子目录中,需要用 Synopsys 的 URG(Unified Report Generator) 合并并生成报告。基本命令如下:
urg -full64 \
-dir ./cov.vdb \
-format both \
-report ./urg_report \
-show tests \
-metric line+cond+fsm+tgl+branch
其中 -dir 指向覆盖率数据库根目录,URG 会自动扫描其下所有 -cm_name 子目录并合并;-format both 同时生成文本和 HTML 报告;-report 指定输出目录;-show tests 会在报告中列出每个测试对覆盖率的贡献,便于定位“哪个用例补了哪块覆盖”。
如果只想合并指定几次运行,可以用 -dir 多次指定具体子目录,或使用 -cm_name 过滤。合并后的报告通常包含 dashboard.html、tests.html 以及各模块的覆盖率明细,是覆盖率收敛分析的主要入口。
四、工程配置建议与常见问题
把上述命令固化到 Makefile 或回归脚本中,是覆盖率闭环落地的关键。一个可参考的工程结构如下:
cov/
├── cov.vdb/ # 覆盖率数据库根目录
│ ├── compile_base/ # 编译阶段数据
│ ├── test_smoke_01/ # 各次仿真数据
│ └── test_regress_07/
├── cm_hier.cfg # 采集范围配置
└── urg_report/ # URG 合并报告输出
常见问题有三类:第一,编译开了覆盖率但仿真没加 -cm,导致数据库为空;第二,多次仿真用了相同 -cm_name,后一次覆盖前一次;第三,-cm_hier 排除范围写错,把真正关心的模块排除了,报告里看不到目标覆盖率。排查时先确认 cov.vdb 下是否有对应子目录,再用 URG 的 -show tests 检查每个用例是否被识别。