简介:面向IC设计与验证工程师、微电子相关专业学生,这份Synopsys VCS用户手册(S-2021.09版)提供官方级使用指引,主要解决数字、模拟及混合信号仿真环境搭建、编译仿真流程与问题定位等实际问题,适合具备一定Verilog/SystemVerilog基础、希望系统上手VCS的中高级读者查阅。资源包为1个PDF文件,约11.36MB,内容从技术兼容性、仿真抢占支持、许可证获取与环境变量配置讲起,延伸到synopsys_sim.setup文件创建、库概念与库名映射、编译与仿真选项等核心章节,并包含命令行与图形界面两种使用方式及日志查看、调试工具等排错思路,目录层级完整,可按主题直接检索。目前已有4339人学习下载,可作为日常查阅的案头工具书,也可用于对照官方流程规范团队验证环境配置。
1. 装 VCS 2021.09 之前,先确认你手里那份手册是哪一版
前阵子某开发者拿着 VCS_User_Guide.pdf 来问,说照着第一章 Getting Started 一步步敲,vcs命令压根没起来。翻到版权页才发现,手册标的是 S-2021.09,2021 年 9 月那一版,而他机器上装的是另一个年份的包,环境变量还指着旧的安装目录。IC 设计这行里,仿真器版本和手册差一个季度,-debug_access的能力粒度、库文件格式、synopsys_sim.setup的解析规则就可能对不上,报错还特别玄学。这份手册的价值不在“读”,在于它把从环境搭建、许可证、库映射到 two-step/three-step 流程的每一步都写死了,你照着它把环境装对,后面才谈得上跑仿真。这篇就按装一台新机器的顺序,把 S-2021.09 这套环境从核对、安装、配库到验证走一遍。
2. 装前核对:系统、编译器与安装路径一次定死
装 VCS 最容易翻车的地方不在安装器本身,而在装之前那十分钟没核对。我见过太多人直接解包、跑安装脚本,装完发现vcs起来了但一编译就报链接错误,回头再改路径、改 gcc,等于重装一遍。这一章把三件事定死:系统与编译器版本、安装目录规划、环境变量脚本。这三样定完,后面 synopsys_sim.setup 和编译流程才有稳定的地基。
2.1 先对版本号,再看系统位数和编译器
拿到安装包第一件事不是解压,是对版本。手册封面写的是 S-2021.09,安装包目录名里通常也带这个串,两者对不上就先别装。版本对上之后,把下面这张表逐项过一遍,缺一项都别往下走。
| 检查项 | 合格线 | 怎么查 |
|---|---|---|
| CPU 架构 | x86_64 | uname -m |
| 操作系统 | 主流 64 位 Linux 发行版 | cat /etc/os-release |
| glibc | 不低于安装包 release note 标的下限 | ldd --version |
| gcc / g++ | 与手册标注的支持区间对齐 | gcc --version、g++ --version |
| 磁盘 | 安装目录预留 30 GB 以上 | df -h /tools |
| 内存 | 编译大型设计建议 32 GB 起 | free -g |
| Shell | bash 或 csh,团队统一 | echo $SHELL |
gcc 这一项值得单独说。很多人觉得编译器越新越好,实际正相反——VCS 在编译期要调 C 编译器去处理 DPI、PLI 那一层,gcc 版本太新,一些老代码里的警告会被提升成错误,报出来的错还跟你写的 Verilog 一点关系没有。血泪经验是:装之前先在团队里问一句“这台机器上别人用的哪个 gcc”,跟着装同版本,比自己挑最新的省事得多。如果系统自带的太新,常见做法是单独装一个老版本,编译时用-cc和-cpp显式指过去,这个后面第 4 章会写。
2.2 安装目录怎么规划,为什么尽量别装在共享盘上
路径规划的核心原则只有一条:同一个大版本装一次,路径里带版本号,升级不覆盖旧的。这样旧项目还能指着老版本跑,新项目切新版本,出问题能立刻回退。
# 目录规划:版本号进路径,权限归到统一的 eda 用户组 sudo mkdir -p /tools/eda/vcs/S-2021.09 sudo groupadd -f eda sudo chown -R root:eda /tools/eda/vcs sudo chmod -R 755 /tools/eda/vcs # 解包(安装器一般叫 setup.sh 或 installer,先 ls 确认名字) mkdir -p /tmp/vcs_install tar -xzf vcs_S-2021.09_linux64.tar.gz -C /tmp/vcs_install ls /tmp/vcs_install上面这几行的逻辑很直白:目录先按<工具>/<版本>建好,属主给 root、属组给 eda,普通用户只读,避免有人手滑改到安装目录里的东西;解包到/tmp而不是直接解到目标目录,是因为安装器需要先自检再落地,中间产物别污染正式路径。
参数上要注意两点。一是解包后的顶层目录结构,安装完成后$VCS_HOME必须指向包含bin和linux64的那一层,多一层少一层都会导致PATH拼错;二是安装介质尽量别直接装在 NFS 之类的网络盘上,VCS 编译和仿真期间会频繁读写库目录和临时文件,网络盘的文件锁和延迟在并行编译时特别容易出问题,常见做法是安装目录放本地盘,项目库目录按团队规范走。
2.3 环境变量脚本:三行就够,多一行都是坑
环境变量是这类 EDA 工具最容易被“祖传脚本”搞乱的地方。经常看到有人从老机器上拷一份几百行的bashrc过来,里面好几个版本的工具路径叠在一起,which vcs出来的结果跟他以为的完全不是一个。我一般会给每个工具、每个版本单独写一个几行的脚本,用的时候 source,不用就退出终端。
# /tools/eda/env/vcs-S-2021.09.sh # 只做三件事:指根目录、加 bin 到 PATH、加运行库路径 export VCS_HOME=/tools/eda/vcs/S-2021.09 export PATH=$VCS_HOME/bin:$PATH export LD_LIBRARY_PATH=$VCS_HOME/linux64/lib:$LD_LIBRARY_PATH # 注意:VCS_HOME 结尾不要带斜杠,带斜杠后拼出来的路径会出现双斜杠, # 在某些脚本的字符串比较逻辑里会被判成不同路径三行的分工:VCS_HOME是根,很多工具和脚本会读这个变量去定位安装目录下的doc、etc、include;PATH放进bin目录,vcs、vlogan、vhdlan、simv这些命令才找得到;LD_LIBRARY_PATH指向linux64/lib,负责运行期动态库加载,缺了它典型的症状是命令能启动但一执行就报找不到.so。
脚本加载完立刻做两件事验证:
which -a vcs vcs -IDwhich -a会把 PATH 里所有匹配的vcs都列出来,如果出现两个以上,说明你机器上还残留着别的版本,先清干净再继续,否则后面所有报错都可能是版本串了导致的假象。vcs -ID会打印版本号和构建日期,输出里的版本串必须和 S-2021.09 对得上,这一条比什么都直接。
提示:切换版本时不要在一个终端里反复覆盖变量,直接开新终端 source 新脚本。老变量叠加是最难查的一类问题。
2.4 许可证:变量、端口、feature 三件事
许可证出问题的表现很统一:命令能起来,一编译就卡在 checkout 上,报一句拿不到 license。排查顺序永远是变量、端口、feature 三层往下走。
# 第一层:变量写对 export LM_LICENSE_FILE=27020@lic-srv # 有些现场的老脚本里还会单独设一个厂商前缀的专用变量, # 两个都留着不冲突,谁生效看工具自己的读取顺序 # 第二层:端口通不通 nc -vz lic-srv 27020 # 第三层:这个 feature 到底有没有、有没有被占满 lmutil lmstat -c 27020@lic-srv -a | grep -i vcs三层里最容易被跳过的是第二层。很多人一看变量设了就直接编译,其实中间隔着防火墙、VLAN 策略、主机名解析。nc一行就能确认端口通不通,比在编译日志里猜快得多。第三层看的是 feature 名和占用数——有些现场许可证池里 VCS 的 feature 数量有限,白天跑批量回归的时候被别人占满,你这边就会莫名其妙拿不到,换个时段或者让管理员确认配额就行。
还有两个细节:变量里的主机名最好写解析稳定那个,别一会儿短名一会儿全名,某些版本的许可证客户端对大小写和域名后缀敏感;许可证服务器的时间不要比客户端快太多,时间偏差大了同样会拒绝签发。
3. synopsys_sim.setup:库名映射写错,编译全白干
环境变量配完,vcs -ID能出版本,很多人就以为装完了。其实还差最关键的一步:库映射文件。VCS 的所有编译产物不是丢在一个目录里,而是按“逻辑库名 → 物理路径”的映射存放,这份映射就写在synopsys_sim.setup里。这个文件写错,症状是vlogan明明没报错,vcs精化的时候却说模块找不到——你以为编译成功了,其实东西存到别的地方去了。
3.1 这个文件到底从哪儿读
VCS 找synopsys_sim.setup是有固定顺序的,先看当前工作目录,再看用户主目录,最后才看安装目录下的bin。这个顺序意味着:你在哪个目录下敲命令,就用哪个目录的 setup 文件。所以同一个工程里在不同子目录跑vcs,行为可能不一样。
常见做法是在项目根目录放一份,所有编译仿真都在这个目录或它的子目录里跑。子目录里如果没放 setup 文件,VCS 会一路往上一层找,但如果子目录里放了一份不完整的,就会覆盖掉上层的,这个坑后面第 5 章还会提。
# <project_root>/synopsys_sim.setup -- 注释用两个减号开头,不是 #,写错了整行会被当成库定义 WORK > DEFAULT DEFAULT : ./work这两行的含义:WORK是逻辑库名,>表示映射,DEFAULT是 VCS 的默认工作库;第二行:表示定义这个逻辑库对应的物理路径。合起来就是“把 WORK 映射到默认库,默认库的文件放在当前目录下的 work 里”。
3.2 库映射的两种符号,>和:
这个文件里只有两个符号要记:>是“别名映射”,:是“路径定义”。搞混了就是灾难。
-- 场景一:单库,所有东西进 work WORK > DEFAULT DEFAULT : ./work -- 场景二:多库,RTL 和 TB 分开放,便于复用 WORK > DEFAULT DEFAULT : ./work RTL_LIB : ./libs/rtl TB_LIB : ./libs/tb -- 场景三:引用别人已经编译好的公共库 COMMON_LIB : /proj/simlib/common/S-2021.09场景二的写法在多项目并行时特别有用:RTL 编译进RTL_LIB,TB 编译进TB_LIB,精化的时候指定-top和库搜索顺序,公共部分不用每次重编。场景三是引用别人编好的库,注意路径写绝对路径,写相对路径的话换目录跑就找不到了。
参数上有两个细节:物理路径可以是相对也可以是绝对,但如果这个 setup 文件会被多个子目录共用,一律写绝对路径更安全;库名建议全大写或用下划线分隔,避免和 Verilog 里的模块名撞名,撞了之后报错信息会非常难看懂。
注意:
synopsys_sim.setup里不要留空的DEFAULT定义,也不要定义两个同名库指向不同路径,这两种情况在解析阶段不一定报错,但在精化阶段会给出风马牛不相及的提示。
3.3 用 SYNOPSYS_SIM_SETUP 管多项目
当一台机器上并行跑好几个项目,每个项目一份 setup 文件,靠切换目录来切换配置就很容易出问题。这时候用环境变量把路径钉死。
# 在项目激活脚本里指定,避免 cwd 不同导致读到不同配置 export SYNOPSYS_SIM_SETUP=/proj/alpha/sim/synopsys_sim.setup这个变量一旦设置,优先级高于前面的目录查找顺序,相当于给当前 shell 强制绑定一份配置。我一般会把它写进项目的环境激活脚本里,和VCS_HOME放在一起,这样开发人员进项目先 source 一次,就不会出现“我在哪个目录跑”这种玄学问题。
代价是灵活性下降:如果你临时想在别的目录做个试验,得先unset SYNOPSYS_SIM_SETUP,否则读到的永远是项目那份。这个取舍看团队习惯,人多的项目我倾向钉死,一个人折腾的环境就靠目录自然切换。
3.4 怎么确认库真的落盘了
配置写完不能凭感觉,要实际编一个文件看产物落在哪。这是装完环境后我必做的一步。
# 造一个最小模块做落盘验证 mkdir -p /proj/alpha/sim && cd /proj/alpha/sim cat > smoke.v <<'EOF' module smoke; initial $display("SMOKE OK"); endmodule EOF # 分析进 RTL_LIB(对应 setup 里定义的库名) vlogan -full64 -sverilog -work RTL_LIB smoke.v -l vlogan_smoke.log # 看物理目录里有没有产物 ls -R ./libs/rtl | head -20这里-work指定的名字必须是 setup 文件里已经定义过的逻辑库名,写成没定义的名字会报错,这是好事,至少能立刻发现映射没生效。ls -R看./libs/rtl下有没有生成目录和库文件,有产物说明映射链路是通的;如果vlogan没报错但这个目录是空的,那基本可以断定产物落到别的地方去了,回去检查synopsys_sim.setup的路径写法和当前工作目录。
4. 三段式流程:vlogan、vcs、simv 的参数怎么给
环境和库都齐了,才轮到真正跑设计。VCS 的流程分两种:two-step 是vcs一把梭,编译加精化一起做;three-step 是vlogan/vhdlan先分析、vcs再精化、最后simv跑仿真。手册第 1 章和第 2 章把两种流程并列讲了,但没告诉你什么时候该用哪种。这一章按三段式的顺序拆参数,顺便说清取舍。
4.1 vlogan 把源码分析进库
分析阶段做的是语法检查和中间表示生成,产物按库名落到 setup 文件指定的路径。这一步的参数给对了,后面精化会快很多。
vlogan -full64 -sverilog \ -timescale=1ns/1ps \ -work RTL_LIB \ +incdir+./rtl/include \ +define+SIM_DEBUG \ -f rtl.f \ -l vlogan.log逐项说:-full64在较新的版本里已经是默认行为,老脚本里留着也无害;-sverilog打开 SystemVerilog 支持,纯 Verilog 工程可以不加,但加了不会有副作用;-timescale=1ns/1ps给没有显式时间单位的模块兜底,缺了它,仿真时间推进会按工具默认值走,波形上看到的时间和你想的差几个数量级;-work指定目标库,必须和 setup 文件对得上;+incdir+和+define+是包含路径和宏定义,可以写多个;-f从文件里读源文件列表,比命令行一长串好维护;-l把日志写文件,出问题第一件事就是看这个。
文件列表rtl.f的写法也有讲究,路径写相对的话,相对的是你执行命令的目录,不是.f文件所在目录。所以要么全写绝对路径,要么固定在项目根目录执行命令,别到处乱跑。
4.2 vcs 精化:-top 和 -debug_access 的取舍
精化是把分析好的模块实例化、连起来、生成可执行仿真器的过程,这一步最慢,参数也最值得琢磨。
vcs -full64 -sverilog \ -debug_access+all \ -top tb_top \ -timescale=1ns/1ps \ -l vcs.log \ RTL_LIB.dut TB_LIB.tb_top-top指定顶层模块,必须唯一,指错了会报“找不到顶层”或者干脆生成一个空仿真器。后面两个位置的写法库名.模块名是精化阶段的标准写法,明确告诉工具去哪个库里找,比让它自己猜靠谱。
-debug_access+all是这份手册第 4 章重点讲的东西,也是最容易吃亏的地方。它的作用是保留调试能力——信号可见性、波形可 dump、断点能设。+all最省事,但代价是编译变慢、生成的仿真器变大、运行时内存占用升高。手册里给了更细的粒度,我一般按实际需要挑:
| 写法 | 保留的能力 | 适用场景 |
|---|---|---|
-debug_access+all | 全部 | 前期调 bug、要设断点看类成员 |
-debug_access+line+wnode | 行信息与线网 | 只看波形、不改层次 |
-debug_access+class | 类与对象 | 验证平台以 UVM 为主 |
| 不加 | 无 | 回归批量跑、追求最快 |
早期版本里某些能力还需要额外加-lca才认,S-2021.09 上多数直接可用,但团队老脚本里留着-lca也很常见,不影响。真正要避免的是回归脚本里无脑+all——编译慢一倍、仿真慢三成,跑几千个 case 的时候这个差距非常可观。
4.3 simv 运行时的几个常用开关
精化成功后会生成simv,运行阶段参数就少很多。
./simv -l sim.log \ +ntb_random_seed=20210901 \ +vcdpluson \ +plusarg_save-l写运行日志,和编译日志分开放,出问题两边对照看。+ntb_random_seed固定随机种子,这条是复现问题的后悔药——不固定种子,同一个 case 跑两次结果不同,你连复现都做不到。+vcdpluson打开波形记录,产物是 VPD 文件,属于工具自带能力,不需要额外装别的软件就能看。+plusarg_save把命令行传进去的 plusarg 记到日志里,回归出问题时能直接看到当时用的什么参数。
提示:波形文件默认写在当前目录而且体积增长很快,长仿真一定配合
$vcdplusmemon之类的按需开关,别一上来就全量 dump。
4.4 two-step 和 three-step 什么时候各用哪个
两种流程没有优劣,只有场景:
| 场景 | 选哪种 | 原因 |
|---|---|---|
| 只改 TB 不动 RTL | three-step | RTL 库不用重分析,直接精化,快得多 |
| 单次调试、临时看个东西 | two-step | 一条命令到底,省事 |
| 多人共用同一套 RTL 库 | three-step | 分析产物可复用,避免重复劳动 |
| 混合语言(Verilog + VHDL) | three-step | vhdlan和vlogan各管一部分,分工清晰 |
| 需要按库控制精化顺序 | three-step | 库搜索顺序可控,结果稳定 |
我的习惯是:只要这个项目不是我一个人临时看两眼,一律 three-step。分析产物的复用价值在第二次编译的时候就回本了,而且分阶段出错时定位范围小得多——分析阶段报错就是语法和路径问题,精化阶段报错就是层次和库问题,不会混在一起。
5. 排错:这五种翻车我一年能遇上三四回
下面这五条是按遇到频率排的,基本覆盖了从装完到跑通之间 90% 的卡点。每条都按“看到什么 → 为什么 → 怎么办”写,照着对症状就行。
5.1 命令找不到,或者版本对不上
现象:敲vcs提示 command not found,或者vcs -ID出来的版本号跟安装目录名不一致。
原因:环境变量脚本没 source、source 了但顺序不对、机器上还残留别的版本。最常见的是.bashrc里既有系统默认路径又有一份老脚本,PATH里两个都在。
解决:先which -a vcs把候选全列出来,再echo $PATH看顺序。确认VCS_HOME指向的是/tools/eda/vcs/S-2021.09,PATH里它排在最前面。如果.bashrc里有多份配置,把老的注释掉或者干脆删掉,重新开终端 source。
5.2 一编译就卡在许可证上
现象:vcs能启动,输出几行之后停在 checkout 上,最后报拿不到 license 或 feature 不支持。
原因:变量没设对、端口不通、feature 配额被占满、服务器时间和客户端差太多。四种原因报错文本很接近,容易误判。
解决:按第 2.4 节的三层顺序查。先echo $LM_LICENSE_FILE确认变量,再nc -vz确认端口,最后lmutil lmstat -c ... -a | grep -i vcs看 feature 和占用量。如果三项都正常还是拿不到,看服务器与客户端的时间差,超过太多会被拒。
5.3 精化报模块找不到,但分析明明成功了
现象:vlogan跑完没报错,vcs精化时报某模块未定义,或者提示库搜索不到。
原因:synopsys_sim.setup的库映射和-work用的名字对不上;或者分析时的当前目录和精化时的当前目录不同,读到了两份不一样的 setup 文件。
解决:pwd确认当前目录,cat synopsys_sim.setup看映射,ls看物理路径下有没有产物。精化时把库名写全,用库名.模块名的形式,别让工具自己猜。如果设了SYNOPSYS_SIM_SETUP,echo一下确认是不是指到你以为的那份。
5.4 链接阶段报与 Verilog 无关的 C 错误
现象:精化进行到一半,报一堆undefined reference、cannot find -lstdc++、某个系统头文件里的警告被当成错误。
原因:gcc/g++ 版本和工具预期的不一致,通常是系统自带的太新。这类报错之所以难查,是因为错误信息全是 C/C++ 的,跟你的设计代码毫无关系。
解决:用-cc和-cpp显式指定编译器版本。
# 显式指定 C/C++ 编译器,绕开系统默认的新版本 vcs -full64 -sverilog \ -cc gcc-9 -cpp g++-9 \ -debug_access+all \ -top tb_top -l vcs.log \ RTL_LIB.dut TB_LIB.tb_top如果不知道装哪个版本,去看安装目录下 doc 里那份 release note,里面标了支持区间,照着挑一个就行。
5.5 仿真跑起来了但结果不对
现象:simv正常结束,没有报错,但输出和预期不一致,波形上某些信号一直是 X 或者一直是 0。
原因:时间单位和精度没统一、复位没生效、随机种子没固定、或者波形 dump 的层次不对导致看到的是未初始化值。
解决:先确认-timescale在分析和精化两处都给了且一致;再看波形里复位信号的时序对不对;最后固定随机种子重跑一遍,看结果是否稳定复现。如果每次结果都不一样,问题一定在种子或者初始化顺序,不在设计逻辑本身。
6. 装完怎么验证:一个三十行的计数器跑通全链路
验证一套环境装没装对,不要拿公司里最复杂的那个设计去试,那只会让你在几十个报错里分不清哪个是环境问题。我的做法是固定一个小 demo:一个带复位的计数器加一个 tb,三十行代码,能打印、能出波形、能设断点。每装一台新机器都先跑它。
# 目录结构:setup 文件 + rtl + tb 三样东西就够 mkdir -p /proj/smoke/{rtl,tb} && cd /proj/smoke cat > synopsys_sim.setup <<'EOF' WORK > DEFAULT DEFAULT : ./work RTL_LIB : ./libs/rtl TB_LIB : ./libs/tb EOF cat > rtl/counter.v <<'EOF' module counter(input clk, input rst_n, output reg [7:0] cnt); always @(posedge clk or negedge rst_n) if (!rst_n) cnt <= 8'd0; else cnt <= cnt + 8'd1; endmodule EOF cat > tb/tb_counter.v <<'EOF' module tb_counter; reg clk = 0, rst_n = 0; wire [7:0] cnt; counter u_counter(.clk(clk), .rst_n(rst_n), .cnt(cnt)); always #5 clk = ~clk; initial begin #20 rst_n = 1; #200; if (cnt == 8'd18) $display("TEST PASSED cnt=%0d", cnt); else $display("TEST FAILED cnt=%0d", cnt); $finish; end endmodule EOF三段式跑完:
vlogan -full64 -sverilog -work RTL_LIB rtl/counter.v -l vlogan_rtl.log vlogan -full64 -sverilog -work TB_LIB tb/tb_counter.v -l vlogan_tb.log vcs -full64 -sverilog -debug_access+all -top tb_counter \ -l vcs.log RTL_LIB.counter TB_LIB.tb_counter ./simv -l sim.log +vcdpluson跑通的标准不是“没报错”,而是下面这张表里每一项都对上:
| 验证项 | 命令 | 期望结果 |
|---|---|---|
| 版本 | vcs -ID | 输出含 S-2021.09 |
| 库映射 | ls libs/rtl libs/tb | 两个目录都有产物 |
| 精化 | ls simv | 生成可执行文件 |
| 仿真 | ./simv -l sim.log | 打印 TEST PASSED |
| 波形 | ls *.vpd | 文件存在且大小不为 0 |
| 许可证释放 | lmutil lmstat -c 27020@lic-srv -a | 跑完后占用数回落 |
这个 demo 还有个额外好处:它足够小,你可以随便改参数做对照实验。比如把-debug_access+all换成-debug_access+line,看波形里还能不能抓到cnt;比如把synopsys_sim.setup里的DEFAULT路径改错一位,看报错长什么样。这些刻意制造的翻车,比等生产环境出问题再学要便宜太多。
从那以后我每装一台新机器、每换一个大版本,都会先把这三十行跑一遍,六项全绿才敢往项目目录里放东西。装 EDA 工具这件事,最贵的从来不是安装时间,是装完之后那些说不清道不明的假象。希望这套核对流程能帮你少走两晚弯路。
本文还有配套的精品资源,点击获取