
简介这份资源是面向硬件验证工程师、芯片设计师及半导体设计自动化从业者的 Cadence Xceliumxrun操作指南兼顾初学者与有经验的技术人员。内容从 Linux 环境下的安装检查、单步与三阶段分离仿真讲起系统梳理基础仿真选项并深入解析 xcelium.d 目录作用、shm/db/fsdb 等波形文件生成、覆盖率收集策略以及 Gate Level Simulation 中的参数调整还针对复杂工程常见报错与 license 问题给出排查思路。资源包为 1 个 pdf 文件约 505KB便于随身查阅与快速检索。目前已有 2050 人学习下载读者可借此掌握 xrun 的常用命令与高级特性在项目规划、日常仿真实施和故障排查中提升效率与准确性是一份实用性较强的数字仿真参考手册。1. 从一次跑不通的回归说起Xcelium 与 xrun 到底解决什么问题数字前端验证做到一定规模绕不开一个现实设计越来越大用例越来越多仿真时间从几分钟涨到几小时。这时候你会发现真正拖慢进度的往往不是写 testbench而是仿真器怎么起、怎么编、怎么跑。Cadence 的 Xcelium 就是干这件事的——它是新一代并行逻辑仿真器而 xrun 是它的统一命令行入口。很多人第一次接触 xrun是因为接手了一个老项目脚本里写着irun跑起来一堆警告换成xrun之后行为又不太一样。这个标题要讲的就是怎么用 xrun 把仿真跑顺以及那些藏在开关背后的高级功能。这篇文章适合两类人一类是刚接手数字仿真环境、需要把用例跑起来的验证工程师另一类是用过其他仿真器、想迁移到 Xcelium 但不确定参数怎么设的老手。我会从最小可跑命令讲起一路说到多核并行、覆盖率收集、UVM 加速这些实际会用到的功能中间穿插我自己踩过的坑。不堆概念每个参数都告诉你改了会怎样。2. xrun 最小可跑闭环从编译到波形的完整命令链2.1 一条命令背后的三段式流程xrun 最大的特点是「一条命令干三件事」分析analyze、精化elaborate、仿真simulate。传统仿真器要分三步敲xrun 把它们串起来了。但串起来不等于黑盒你得知道每一步在干什么出问题才知道去哪找。最小可跑的场景是这样一个 Verilog 模块加一个 testbench用 xrun 直接跑出波形。# 最小可跑命令编译 精化 仿真一步到位 xrun \ -f filelist.f \ # 文件列表列出所有 .v/.sv 源文件 -top tb_top \ # 指定顶层模块名 -access rwc \ # 开放读写权限波形和 force 都需要 -timescale 1ns/1ps \ # 时间精度不设会用默认值导致时序对不上 -sv \ # 启用 SystemVerilog 支持 -waves waveform.shm \ # 指定波形输出文件 -run \ # 立即启动仿真 -exit # 仿真结束自动退出这段命令里-f读文件列表是最常用的组织方式比在命令行里堆一长串文件名清晰得多。-access rwc是新手最容易漏的——不开放读写权限testbench 里对 DUT 内部信号的 force/release 会直接报错波形里也看不到内部节点。-timescale建议显式写因为不同源文件如果各自定义了 timescale仿真器会按最小精度对齐一旦有 1ps 和 1ns 混用时序检查就会出玄学问题。-waves指定的是 shm 格式波形这是 Xcelium 的原生格式比 VCD 小得多也快得多。如果你后续要用 Verisium 或者第三方工具看波形shm 是首选。-run和-exit搭配使用适合回归脚本交互调试时把-run去掉会停在命令行让你手动敲run。2.2 filelist 怎么写才不出乱子filelist 看着简单但它是编译报错的重灾区。常见做法是按目录分组用incdir指定 include 路径用-v指定库文件。# filelist.f 示例 incdir./rtl/include # 头文件搜索路径 incdir./tb/include # RTL 源文件按依赖顺序排列 ./rtl/core/alu.v ./rtl/core/regfile.v ./rtl/top/chip_top.v # 验证平台文件 ./tb/tb_top.sv ./tb/driver.sv ./tb/monitor.sv # 库文件用 -v 引入只编译被引用的模块 -v ./lib/tech_lib.v -y ./lib/gates # 库目录配合 libext 使用 libext.v.sv这里有个血泪经验filelist 里的顺序在 SystemVerilog 里比 Verilog 敏感得多。package 必须排在 import 它的模块之前否则会报「package not found」。我一般会把所有 package 单独放一个文件列表用-f packages.f先读进来再读模块列表。另外-y和libext要成对出现只写-y不写libext仿真器不知道去目录里找什么后缀的文件会静默跳过最后报顶层模块找不到排查半天。2.3 编译日志里该盯哪几行xrun 跑完会输出一大堆日志新手容易被淹没。我一般只看三个地方第一是xmvlog和xmvhdl的编译摘要看有没有 error 和 warning 数量第二是精化阶段的xmelab输出看顶层模块有没有被正确识别第三是仿真启动时的xmsim版本和 license 信息。如果编译报错日志里会带文件名和行号直接跳过去看。如果精化报错说「module not found」九成是 filelist 路径写错或者-top名字拼错。如果仿真跑起来但波形是空的先检查-access权限再检查 testbench 里有没有$dumpvars或者-waves有没有生效。提示xrun 默认会把中间产物放在xcelium.d目录里下次跑如果源文件没变会跳过编译直接精化。想强制全量重编加-clean或者手动删掉这个目录。但注意-clean会连波形一起删调试阶段慎用。3. 多核并行与性能调优让回归时间砍半的参数组合3.1 多核仿真的两种模式多种子并行 vs 单用例多核Xcelium 的并行能力分两个层面。第一种是「多种子并行」同一个用例跑不同随机种子用-mce或者脚本层面起多个 xrun 进程每个进程绑不同核。第二种是「单用例多核」针对单个大用例用-parallel把设计切分到多个核上跑。两者适用场景完全不同。多种子并行适合回归阶段用例之间独立直接起 N 个进程就行。单用例多核适合一个用例就要跑几小时的场景比如 SoC 级仿真。但单用例多核有前提设计要能切分testbench 的并发活动要能分布到不同分区。如果 testbench 里大量使用#delay或者全局信号切分后反而更慢。# 多种子并行起 8 个进程每个用不同种子 for seed in $(seq 1 8); do xrun -f filelist.f -top tb_top -sv -access rwc \ -seed $seed \ # 随机种子保证每次激励不同 -waves waves_$seed.shm \ -run -exit done wait这段脚本里-seed是关键不指定的话每次跑都是同一个种子回归覆盖率上不去。和wait让 8 个进程并行跑机器核数够的话总时间约等于单个用例的时间。但要注意内存每个 xrun 进程都会吃一份设计内存8 个进程就是 8 倍内存不够会触发 swap反而拖慢。3.2 单用例多核的开关与限制单用例多核用-parallel系列参数。常见做法是# 单用例多核4 核并行自动分区 xrun -f filelist.f -top tb_top -sv -access rwc \ -parallel \ # 启用多核并行 -par_options auto \ # 自动分区策略 -par_cpu 4 \ # 使用 4 个核 -run -exit-par_options auto让工具自动决定怎么切分设计。但自动分区不是万能的它按层次结构切如果设计是扁平的切出来负载不均可能 4 个核里 1 个跑满 3 个闲着。这时候要手动指定分区用-par_options partitionxxx把特定模块分到独立核。手动分区需要对设计结构很熟一般先跑一次 auto看日志里的分区报告再针对性调整。有个限制要注意多核并行对 SystemVerilog 的某些构造支持不好比如fork...join_any跨分区、动态数组的跨分区访问。如果 testbench 里大量用这些开了-parallel可能报错或者结果不对。我的习惯是先用单核跑通确认功能正确再开多核对比波形确认结果一致后才用于回归。3.3 性能调优的四个必调参数除了并行还有几个参数对仿真速度影响很大参数作用建议值代价-access rwc开放读写权限调试时开回归时关开权限会降低仿真速度-waves波形记录回归时关或只记关键信号波形是最大的性能杀手-sv_seedSV 随机种子回归时随机调试时固定无-mce多核精化大设计编译慢时开吃内存回归时我一般把-access降成r只读波形只记顶层和关键接口速度能快 30% 以上。如果不需要调试直接去掉-waves用覆盖率驱动回归速度还能再快。-mce是多核精化针对编译阶段大设计编译要十几分钟的时候开这个能砍一半但内存占用翻倍。注意-access rwc和-parallel同时开可能冲突多核模式下对内部信号的读写权限会受限。如果发现开了并行后 force 不生效先检查这两个参数的组合。4. 覆盖率收集与 UVM 加速高级功能的落地姿势4.1 覆盖率收集的三种粒度与合并覆盖率是验证闭环的核心。Xcelium 支持代码覆盖率、功能覆盖率和断言覆盖率用-coverage系列参数控制。# 覆盖率收集代码 功能 断言 xrun -f filelist.f -top tb_top -sv -access rwc \ -coverage all \ # 收集所有类型覆盖率 -covfile cov.ccf \ # 覆盖率配置文件 -covoverwrite \ # 覆盖已有覆盖率数据 -run -exit-coverage all会同时开代码、功能和断言覆盖率但代价是仿真变慢、数据库变大。实际项目中我一般分阶段冒烟测试只开功能覆盖率回归阶段开代码覆盖率最后合并。覆盖率数据库默认存在cov_work目录多次跑的结果用imc工具合并。覆盖率配置文件cov.ccf用来排除不需要统计的模块比如第三方 IP 或者验证平台自身。不排除的话代码覆盖率永远上不去因为 testbench 的分支没人去覆盖。# cov.ccf 示例排除验证平台和 IP select_coverage -module tb_top -none select_coverage -module tech_lib -none select_coverage -module chip_top -all这里-none是排除-all是包含。先全局排除再逐个包含需要统计的模块比反过来清晰。4.2 UVM 加速从 UVM 1.2 到 UVM 1800.2 的迁移注意Xcelium 对 UVM 的支持通过-uvm参数控制。不同 UVM 版本行为有差异迁移时容易翻车。# UVM 环境编译 xrun -f filelist.f -top tb_top -sv -access rwc \ -uvm \ # 启用 UVM 支持 -uvmhome $UVM_HOME \ # 指定 UVM 库路径 -uvmversion 1.2 \ # 指定 UVM 版本 -run -exit-uvmhome指向 UVM 源码目录-uvmversion指定版本。如果不指定版本xrun 会用内置的默认版本可能和你的 testbench 不兼容。常见坑是 UVM 1.2 和 1800.2 的uvm_config_db行为差异1.2 里set的优先级和 1800.2 不同迁移后原本能拿到的配置拿不到了。解决办法是在build_phase里显式检查uvm_config_db::get的返回值拿不到就报错别让它静默失败。另一个加速点是 UVM 的 objection 机制。如果 testbench 里 objection 提放不平衡仿真会提前结束或者卡死。Xcelium 有个-uvm_objection_debug参数打开后会在日志里打印 objection 的提放记录排查卡死很好用。4.3 用 xrun 跑 UVM 回归的脚本模板把上面的东西串起来一个可复用的回归脚本大概长这样#!/bin/bash # run_regression.sh - UVM 回归脚本模板 SEED$1 TEST$2 xrun \ -f filelist.f \ -top tb_top \ -sv \ -access r \ # 回归时只读提速 -uvm \ -uvmhome $UVM_HOME \ -uvmversion 1.2 \ -seed $SEED \ -coverage functional \ # 回归只收功能覆盖率 -covfile cov.ccf \ -covoverwrite \ UVM_TESTNAME$TEST \ # 指定跑的 UVM test -run \ -exit # 检查退出码非零说明仿真失败 if [ $? -ne 0 ]; then echo TEST $TEST SEED $SEED FAILED exit 1 fiUVM_TESTNAME是 UVM 的标准参数指定跑哪个 test。-seed保证每次随机不同。退出码检查是回归脚本的后悔药没有它仿真失败了脚本还继续跑最后看日志才发现一堆 fail。提示-access r在回归时够用但如果 testbench 里有 force/release还是要rwc。可以先跑一次带rwc的确认功能回归时再降级。5. 避坑与排查xrun 最常见的五类翻车现场5.1 编译通过但精化报 module not found现象xmvlog编译全部通过xmelab报某个模块找不到。原因通常是 filelist 里路径写错或者-y库目录没配libext。解决先用ls确认文件存在再检查 filelist 里的相对路径是相对于运行目录还是 filelist 所在目录。xrun 默认按运行目录解析不是 filelist 目录这点和某些仿真器不同。5.2 波形为空或只有顶层信号现象仿真跑完波形文件生成了但打开只有顶层几个信号。原因-access权限不够或者-waves指定的信号范围太窄。解决加-access rwc检查-waves后面有没有跟信号过滤表达式。如果用了-waves waveform.shm但没指定深度默认只记顶层要加-wave_depth 0记全部。5.3 多核并行后结果和单核不一致现象单核跑通过的用例开-parallel后结果不对或者报错。原因testbench 里有跨分区的并发访问或者用了不支持的 SV 构造。解决先看日志里的分区报告确认关键模块有没有被切到不同核。把fork...join_any改成fork...join或者把跨分区访问改成通过接口信号。实在不行就放弃多核用多进程并行替代。5.4 覆盖率合并后数据对不上现象多次跑的覆盖率用 imc 合并合并后的数字比单次还低。原因-covoverwrite没加每次跑覆盖了上次的数据或者 cov.ccf 里排除规则不一致。解决每次跑用独立的覆盖率目录用-covdir指定合并时把所有目录一起读进去。cov.ccf 要统一别这次排除下次不排除。5.5 UVM 仿真卡死不出结果现象仿真跑起来后卡住日志不更新CPU 占用高但没进展。原因objection 提放不平衡或者fork...join_none里的进程没结束。解决加-uvm_objection_debug看 objection 记录找到谁提了没放。如果是fork...join_none检查有没有wait fork或者disable fork来收尾。6. 把 xrun 用顺的几个私房技巧第一个技巧是善用-l参数把日志重定向到文件同时用tee在终端看关键行。回归的时候日志文件按 test 和 seed 命名出问题直接 grepError和UVM_ERROR比翻整个日志快得多。第二个技巧是-defparam和-g参数做编译期配置。比如-g可以覆盖 parameter 值不用改源码就能跑不同配置。我一般把常用配置写成脚本变量跑回归时循环传入。第三个技巧是波形按需记录。调试阶段用-waves全记定位到问题后把波形范围缩到出问题的模块速度能快好几倍。Xcelium 支持-wave_signal指定信号列表把关键信号写在一个文件里比全记省空间。最后一个习惯每次改完 testbench 或 filelist先跑一个最小冒烟用例确认编译和精化没问题再跑完整回归。冒烟用例不用长几秒钟跑完就行但能挡住 80% 的低级错误。这个习惯帮我省了无数次「跑了三小时才发现 filelist 少写一个文件」的后悔药。希望帮到你。本文还有配套的精品资源点击获取