引言
在 FPGAer/ICer 的实际项目中,仿真无疑占了大量的时间。对于仿真工具,有人更倾向于使用 Vivado、ModelSim、QuestaSim 这些编译 - 仿真 - 看波形一体化的工具,也有人更倾向于 VCS(编译仿真)、Verdi 和 DVE(看波形)这些独立功能的工具。两者各有优劣。
数字 IC 前端设计前仿阶段主要涉及 VCS、DVE 和 Verdi 工具链。VCS 采用编译型仿真技术,支持一步或两步编译模式,提供丰富的编译与仿真选项以优化性能及覆盖率采集。仿真可生成 VCD、VPD 或 FSDB 格式波形文件,配合 Verdi 或 DVE 进行波形查看与信号追溯。通过 ALU 工程示例展示 Linux 环境下从文件管理、编译仿真到波形调试的完整流程,适用于 ASIC 项目开发。

在 FPGAer/ICer 的实际项目中,仿真无疑占了大量的时间。对于仿真工具,有人更倾向于使用 Vivado、ModelSim、QuestaSim 这些编译 - 仿真 - 看波形一体化的工具,也有人更倾向于 VCS(编译仿真)、Verdi 和 DVE(看波形)这些独立功能的工具。两者各有优劣。
前者工具链简单易上手,甚至 Vivado 除了编译、仿真和看波形以外还能实现综合、布局布线等功能,可谓神器。但是前者也有明显的缺点,比如说综合、编译、仿真速度很慢。
而后者工具链较为复杂,编译和看波形为独立的工具。如果在做 ASIC 项目中,后者会更加方便和专业。首先,VCS 编译和仿真速度极快,效率极高,能够大量节约仿真时间(仿真速度:FPGA>VCS>ModelSim/QuestaSim>Vivado)。而 Verdi 查看波形也十分方便,支持信号追溯等功能。
综上所述,为了提高开发效率,下面将以一个简单的 ALU 的工程来展示如何在 Linux 下使用 VCS 和 Verdi 进行逻辑仿真。此部分只涉及前仿,后仿涉及 DC 等综合工具。
VCS(Verilog Compiled Simulator)是 Synopsys 公司开发的一款高性能仿真工具,它采用编译型仿真技术,将 Verilog/SystemVerilog 代码编译成优化的 C 代码,再编译成可执行文件,从而实现高速仿真。虽然 VCS 本身不直接提供图形化调试界面,但它可以与 Synopsys 的其他工具(如 Verdi)集成,实现高效的调试和波形查看。
同时,VCS 提供了丰富的编译和仿真选项,可以根据设计需求进行灵活配置。VCS 提供了丰富的覆盖率分析选项,包括行覆盖率、条件覆盖率、状态机覆盖率和翻转覆盖率等,有助于 Verifier 全面评估测试的充分性。
为什么 VCS 会更快?因为 VCS 采用了编译型仿真。相较于解释型仿真(传统模式),其优点在于仿真速度极快、内存使用效率高、支持大规模设计以及优化程度高,但是编译时间较长、调试较为复杂并且修改代码需要重新编译。
DVE(Design Verification Environment)是由 Synopsys 公司开发的一款强大的硬件设计验证工具,主要用于协助工程师分析和调试仿真结果。DVE 是集成在了 VCS 中。
Verdi 是 Synopsys 提供的一款强大的自动化电子设计自动化(EDA)工具,主要用于功能验证和调试。Verdi 综合了多种调试功能,如波形查看、信号追踪、时序分析和覆盖规划等,为设计验证工程师提供了一个全面的环境进行设计错误的识别和修正。Verdi 是比 DVE 更强大的调试平台,尤其在协议分析、性能分析和根本原因分析(RCA)方面表现出色。
Verdi 工具集包括以下几个组件:
值得注意的是 VCS 本身不提供图形化界面,因此只能通过 terminal 来运行。
VCS 采用两阶段编译模式,提供灵活性和高性能。
RTL 源码—>vlogan 前端编译—>生成数据库文件—>vcs 后端编译—>生成 simv 可执行文件—>./simv 仿真执行—>生成波形和日志
因此,VCS 也提供了两种编译方式,分别为一步编译(推荐用于简单项目),两步编译(推荐用于复杂项目)。
# 一步编译 vcs [编译选项] [源文件] -o [输出文件名]
# 两步编译 vlogan [编译选项] [源文件] # 前端编译
# vcs [链接选项] [顶层模块] -o [输出文件名] # 后端编译
该文以一步编译模式为主。
| 指令 | 功能 | 示例 | 描述 |
|---|---|---|---|
| -help | 显示帮助文档 | vcs -help | 查看 vcs 的可用选项 |
| -full64 | 64 位编译模式 | vcs -full64 | |
| -sverilog | 支持 SystemVerilog | vcs -sverilog | |
| +v2k | 支持 Verilog-2001 | vcs +v2k | |
| -timescale | 指定时间精度 | vcs -timescale=1ns/1ps | 也可以 tb 中指定 |
| -o | 输出文件名 | vcs -o my_sim | 默认 simv |
| -kdb | 输出 fsdb 文件需要 | vcs -kdb |
| 指令 | 功能 | 示例 | 描述 |
|---|---|---|---|
| -debug_access+all | 完全调试访问 | vcs -debug_access+all | 查看所有信号 |
| -debug_access+r | 只读调试访问 | vcs -debug_access+r | 只读模式 |
| -line | 启用行号调试 | vcs -line | |
| +lca | 生成覆盖率数据库 | vcs +lca | 用于覆盖率分析 |
| -cm | 覆盖率采集类型 | vcs -cm line+cond+fsm+tgl | 采集 line/cond/fsm/tgl 覆盖率 |
| -cm_dir | 指定存放覆盖率数据库的目录 | ||
| -cm_name | 为当次仿真产生的覆盖率数据命名 |
NOTE: 收集行覆盖率 (line)、条件覆盖率 (cond)、有限状态机覆盖率 (fsm) 和翻转覆盖率 (tgl)
覆盖率类型:
代码覆盖率 (Code Coverage):
功能覆盖率 (Functional Coverage):通过 SystemVerilog 的 covergroup 定义,衡量设计规格中的功能点是否被测试到。
断言覆盖率 (Assertion Coverage):衡量 SVA 断言被触发、成功和失败的次数。
| 指令 | 功能 | 示例 | 描述 |
|---|---|---|---|
| -Mupdate | 增量编译 | vcs -Mupdate | 只编译修改的文件 |
| -j | 并行编译核心数 | vcs -j8 | 8 个 CPU 核心 |
| -comp | 优化编译 | vcs -comp | 编译时优化 |
| -no_save | 不保存中间文件 | vcs -no_save | 节省空间 |
| -fast | 快速模式 | vcs -fast |
| 指令 | 功能 | 示例 | 描述 |
|---|---|---|---|
| -f | 文件列表 | vcs -f filelist.f | 包含源文件路径 |
| -v | 库文件 | vcs -v my_lib.v | 单个库文件 |
| -y | 库目录 | vcs -y ./lib | 单个库目录 |
| +libext+ | 库文件扩展名 | +libext+.v+.sv | 搜索文件类型 |
| +incdir+ | include 目录 | +incdir+./inc | `include 文件路径 |
| +define+ | 预定义宏 | +define+SIM_MODE | 编译时宏定义 |
| 指令 | 功能 | 示例 | 描述 |
|---|---|---|---|
| -R | 编译后立即运行 | vcs -R tb.v | 一步完成 |
| -gui | 启动图形界面 | ./simv -gui=dve | DVE 调试界面,也可以-gui=verdi |
| -l | 日志文件 | ./simv -l sim.log | 指定仿真日志路径 |
| -s | 交互模式 | ./simv -s | 在时间 0 停止 |
| 指令 | 功能 | 示例 | 描述 |
|---|---|---|---|
| +ntb_random_seed= | 随机种子 | ./simv +ntb_random_seed=123 | 确定性随机序列 |
| +vcs+lic_wait | 等待 license | ./simv +vcs+lic_wait | license 不足时等待 |
| +vcs+stop+ | 指定停止时间 | ./simv +vcs+stop+1000 | 1000 时间单位后停止 |
| 指令 | 功能 | 示例 | 描述 |
|---|---|---|---|
| -ucli | 启动 UCLI | ./simv -ucli | 统一命令行界面 |
| -vpd_file | VPD 文件名 | ./simv -vpd_file sim.vpd | 指定波形文件 |
| -cm_name | 覆盖率名称 | ./simv -cm_name test1 | 覆盖率数据库名 |
| -cm_dir | 覆盖率目录 | ./simv -cm_dir ./cov | 覆盖率存储路径 |
执行 vcs 指令后一般会生成一些文件。其中比较关键的是:
vcs 可以生成不同格式的波形文件。常见的有以下三种:
| 格式 | 优点 | 缺点 | 查看工具 |
|---|---|---|---|
| VCD | 通用性强,可读 | 文件大,速度慢 | DVE,Verdi |
| VPD | 压缩率高,VCS 原生 | Synopsys 生态 | DVE,Verdi |
| FSDB | 压缩率极高,功能强 | Verdi 生态 | Verdi |
以上这些波形文件格式的生成代码需要放置在 testbench 中,指定波形文件格式和保存的内容。
//在 Testbench 中添加系统任务
initial begin
$dumpfile("tb.vcd");
$dumpvars(0, top_module_name); // 0 表示 dump 所有层级
end
//在 Testbench 中添加 $vcdpluson; 系统任务,并在编译时开启调试选项。
initial begin
$vcdpluson();
end
//需要 Verdi 的环境支持,并在 Testbench 中调用特定系统任务。
initial begin
$fsdbDumpfile("tb.fsdb");
$fsdbDumpvars(0, "top_module_name");
end
$fsdbDumpfile(fsdb_name[,limit_size])
指定波形文件名,第二个参数可选择用来限制波形的大小 (MB)。
$fsdbDumpvars([depth, instance][, "option"])
depth 表示要加载波形的层次:
0 表示当前 instance 下的所有变量以及其它 module 实例的波形;
1 表示当前 instance 中的变量的波形,不包括当前 instance 中的其它 module 实例的波形;
2 表示包含当前 instance 以及其中的第一级子 instance 的波形;以此类推。
instance 指定要加载波形的 module 名。
option 加载波形的选项:
+IO_Only – 只加载 IO port 信号;
+Reg_Only – 只加载 reg 类型信号;
+mda – 加载 memory 和 MDA 信号;
+packedmda – 加载 packed MDA;
+struct – 加载 structs;
+parameter – 加载 parameter;
+fsdbfile+filename – 指定 fsdb 文件名字。(可覆盖 dumpfile 操作)
DVE 的启动很简单,只需要在 vcs 执行完生成 vpd/vcd 波形文件后,即可用以下指令打开。
dve -vpd vcdplus.vpd &
dve -vcd tb.vcd &
Verdi 的启动也很简单,只需要在 vcs 执行完生成 vpd/vcd/fsdb 波形文件后,即可用以下指令打开。
verdi -f filelist.f -ssf tb.fsdb &
建议采用以下文件结构:rtl 用来放置 RTL 代码,makefile 为运行脚本,sim 用来保存 vcs 仿真的结果和波形,tb 用来放置 testbench 文件。此外,还有一个比较重要的便是设计文件列表 filelist.f(注意文件的路径正确)。
在 sim 路径下打开 terminal 并执行以下指令。单步执行的在编译 vcs 时候加入了-R 选项,使得 vcs 在编译完后直接运行./simv。
# -kdb 为生成 fsdb 所需,否则无法使用 verdi 打开
vcs -R -full64 -debug_access+all -timescale=1ns/1ps -f filelist.f
执行完后得到一些文件,可见 第 3 小节文件生成物。值得关注的便是 tb.fsdb 波形文件。
单步编译后可以直接查看波形。
在 sim 路径下打开 terminal 并执行以下指令,启动 verdi。
verdi -f filelist.f -ssf tb.fsdb &
一开始可以看到没有波形,需要右键选中 alu,添加波形。
添加波形后即可查看。
# 使用 dve 查看波形(vcd,vpd)
dve -vpd vcdplus.vpd &
dve -vcd my_tb.vcd &
两步执行的步骤在于先用 vcs 进行编译得到 simv 可执行文件,然后再运行./simv 文件产生波形文件,./simv 可以指定 DVE 或者 Verdi 来查看仿真结果。
在 sim 路径下打开 terminal 并执行以下指令。
# 步骤一,编译,生成 simv 可执行文件
vcs -full64 -debug_access+all -timescale=1ns/1ps -f filelist.f
# 步骤二,仿真并使用 dve 打开 gui 界面
./simv -gui=dve &
添加波形。
在命令行中运行 run,开始仿真。
在 sim 路径下打开 terminal 并执行以下指令。
# 步骤一,编译,生成 simv 可执行文件
vcs -full64 -debug_access+all -kdb -timescale=1ns/1ps -f filelist.f
# 步骤二,仿真并使用 verdi 打开 gui 界面
./simv -gui=verdi &
NOTE: 需要注意的是这里 vcs 的编译需要加-kdb 选项,不然会无法打开 verdi。
可以将上述命令,添加到 makefile 脚本中,提高工作效率。
module alu(
input clk,
input rst_n,
input [7:0] in1,
input [7:0] in2,
input [1:0] in_ctrl,
output [7:0] out
);
reg [7:0] A,B;
reg [1:0] C;
reg [7:0] D;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
A <= 8'd0;
B <= 8'd0;
C <= 2'd0;
end
else begin
A <= in1;
B <= in2;
C <= in_ctrl;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n) D <= 8'd0;
else case (C)
2'b00 : D <= A + B;
2'b01 : D <= ~A;
2'b10 : D <= A & B;
2'b11 : D <= A | B;
default: D <= 8'd0;
endcase
end
assign out = D;
endmodule
`timescale 1ns/1ps
module tb();
reg clk=0;
reg rst_n=1;
reg [7:0] in1=0;
reg [7:0] in2=0;
reg [1:0] in_ctrl=0;
wire [7:0] out;
always #5 clk=~clk;
initial begin
#10 rst_n=0;
#10 rst_n=1;
#100 repeat(10)begin
@(posedge clk) in1 = {$random}%(2**8);
in2 = {$random}%(2**8);
in_ctrl = {$random}%(2**2);
end
#100 $finish();
end
alu alu(
.clk(clk),
.rst_n(rst_n),
.in1(in1),
.in2(in2),
.in_ctrl(in_ctrl),
.out(out)
);
initial begin
$fsdbDumpfile("tb.fsdb");
$fsdbDumpvars();
end
/* initial begin
$dumpfile("alu.vcd");
$dumpvars(0, tb);
end */
endmodule

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online