4. Synopsys VCS编译与仿真流程

VCS 的签核效率,很大程度上不取决于仿真跑得多快,而取决于“编译一次、仿真多次”这条链路上每个环节是否被正确配置。VCS 采用两阶段模型:编译阶段把 Verilog/SystemVerilog/VHDL 源码、UVM 库、断言与覆盖率模型一起分析、细化并生成可执行的仿真二进制(simv);仿真阶段运行 simv,通过运行时选项控制激励、随机种子、波形、覆盖率与调试行为。理解这两个阶段各自接受哪些选项、哪些选项会触发重新编译,是提升签核吞吐量的第一步。

编译阶段:把设计、验证平台与覆盖率一次性固化

典型编译命令由三部分组成:源文件列表、库与语言选项、编译期优化与覆盖率选项。一个可参考的示例(参数为教学示例,非实测结果):

vcs -full64 -sverilog -ntb_opts uvm-1.2 \
    -timescale=1ns/1ps \
    -f filelist.f \
    -top tb_top \
    -debug_access+all -kdb \
    -cm line+cond+fsm+tgl+branch \
    -cm_dir ./cov.vdb \
    -cm_hier cm_hier.cfg \
    -l compile.log \
    -o simv

其中 -sverilog 启用 SystemVerilog,-ntb_opts uvm-1.2 引入 UVM 库,-f filelist.f 用文件列表管理上千个源文件,-top 指定顶层模块。-debug_access+all 与 -kdb 是调试接口的关键:前者开放信号、类、断点等调试能力,后者生成 Verdi 可读的知识数据库(KDB),使后续可以用 Verdi 直接加载 simv 做后处理调试,而不必重新编译。覆盖率方面,-cm 指定采集类型,-cm_dir 指定覆盖率数据库目录,-cm_hier 用配置文件限定采集范围,避免对无关 IP 采集覆盖率而拖慢仿真。

编译期选项一旦改变(如增删 -cm 类型、修改 -debug_access 级别、更换 UVM 版本),必须重新编译。因此签核前应尽早冻结编译配置,把“需要调试”和“需要覆盖率”的能力一次性编入 simv,避免反复重编。

仿真阶段:用运行时选项控制行为而不重编

仿真阶段通过 simv 加运行时参数控制。常用控制项包括:+ntb_random_seed=auto 让每次运行使用不同随机种子以扩大激励空间;+UVM_TESTNAME=xxx 选择要跑的 UVM 测试用例;+UVM_VERBOSITY=UVM_LOW 控制日志详细程度;-cm_name 与 -cm_dir 指定本次覆盖率写入位置;+fsdb+... 或 -ucli 控制波形与交互调试。例如:

./simv +UVM_TESTNAME=smoke_test \
       +ntb_random_seed=12345 \
       +UVM_VERBOSITY=UVM_LOW \
       -cm line+cond+fsm+tgl+branch \
       -cm_dir ./cov.vdb \
       -l sim_smoke.log

这里的关键判断是:哪些选项属于编译期、哪些属于运行期。测试用例名、随机种子、日志级别、覆盖率写入目录都属于运行期,可以在不重编的前提下反复切换;而覆盖率采集类型、调试能力、UVM 版本属于编译期,改动即触发重编。把这两类选项分清,才能设计出高效的回归策略。

VCS 两阶段流程与签核效率关键路径 编译阶段(一次) 源码 + UVM 库 -sverilog / -ntb_opts -debug_access+all -kdb -cm line+cond+fsm... -cm_hier 限定采集范围 → 生成 simv + KDB 仿真阶段(多次) +UVM_TESTNAME=... +ntb_random_seed=auto +UVM_VERBOSITY=... -cm_dir ./cov.vdb 运行 simv → 日志 + 波形 + 覆盖率 simv 调试接口 KDB → Verdi 后处理调试 -ucli / +fsdb → 交互与波形 签核效率优化 冻结编译配置 · 并行回归 · 覆盖率合并 -cm_hier 裁剪 · 种子复用与增量 判断原则:测试名、种子、日志级别、覆盖率写入目录 → 运行期可切换,不重编; 覆盖率类型、调试能力、UVM 版本 → 编译期固化,改动即重编。签核前应尽早冻结编译配置。

调试接口:让一次编译支撑多轮定位

调试接口的价值在于“编译一次、反复定位”。-debug_access+all 打开全部调试访问能力,配合 -kdb 生成 KDB,Verdi 可以直接加载 simv 与 KDB,查看信号波形、类层次、事务流和断言失败点,无需重新编译。若只需有限调试,可用 -debug_access+class 或 -debug_access+pp 降低编译开销。运行时用 -ucli 进入交互命令行,可在仿真中途设置断点、强制信号、dump 指定层次波形;用 +fsdb+... 或 $fsdbDumpfile 控制 FSDB 波形输出范围。实践中常见做法是:日常回归只开 -debug_access+class 并关闭全波形,仅在失败用例复现时用全调试 simv 加 -ucli 定位。

签核效率优化:把重编次数降到最低

签核效率的核心指标是“单位时间内完成的验证用例数”和“覆盖率收敛速度”。可操作的优化手段包括:

  • 冻结编译配置:在回归启动前确定 -cm 类型、-debug_access 级别与 UVM 版本,避免回归中途重编。
  • 用 -cm_hier 裁剪覆盖率采集范围:只对 DUT 和关键验证组件采集,排除参考模型、第三方 VIP 内部,可显著降低仿真与合并开销。
  • 并行回归与种子管理:用 +ntb_random_seed=auto 或指定种子列表并行跑多个 simv 实例,失败种子单独记录以便复现。
  • 覆盖率合并:用 urg 把多个 -cm_dir 的 vdb 合并,统一查看 line/cond/fsm/tgl/branch 收敛情况,避免逐目录人工比对。
  • 增量与分区:按模块或测试类型拆分回归批次,优先跑高价值用例,缩短反馈周期。
常见误区:为了“方便调试”在每次回归都开 -debug_access+all 并 dump 全波形,导致编译时间与磁盘 I/O 大幅上升。正确做法是区分“调试编译”和“回归编译”两套配置,回归用轻量配置,失败后再用调试配置复现。

一个可复用的签核检查清单

检查项关键选项/命令判断依据
编译配置是否冻结-cm、-debug_access、-ntb_opts回归期间无重编记录
覆盖率采集范围是否裁剪-cm_hier cm_hier.cfg排除非 DUT 层次,仿真时间下降
调试能力是否可用-kdb、-debug_access+allVerdi 能加载 simv 与 KDB
种子是否可复现+ntb_random_seed=12345失败用例可用同种子复现
覆盖率是否合并urg -dir cov1.vdb cov2.vdb生成统一覆盖率报告

把上述配置固化为回归脚本的一部分,VCS 的编译与仿真就不再是“每次从头再来”,而是一条可预测、可复现、可并行的签核流水线。编译期决定能力边界,运行期决定激励与观测,调试接口决定定位速度,三者配合才能把签核效率真正提上去。