| 特性 | Verilator | Icarus Verilog | ModelSim DE | Vivado xsim |
|---|---|---|---|---|
| 许可证 | 开源 (LGPL) | 开源 (GPL) | 商业 | Vivado 捆绑 |
| 语言支持 | 可综合 Verilog/SystemVerilog | Verilog-2005 + 有限 SV | 完整 VHDL + Verilog + SV | 完整 VHDL + Verilog + SV |
| 输出形式 | C++ 周期精确模型 | VVP 中间形式 | 原生编译仿真 | 原生编译仿真 |
| 波形格式 | VCD / FST (通过 --trace) | VCD / FST / LXT | WLF (专有格式) | WDB (专有格式) |
| 仿真速度 | 比 Icarus 快 10-50 倍 | 基准 | 比 Icarus 快 2-5 倍 | 比 Icarus 快 3-8 倍 |
| 编译速度 | 中等(含 C++ 编译步骤) | 快 | 慢(需要大量 elaboration) | 中等 |
| SVA 断言 | 有限(仅基本立即断言) | 不支持 | 完整并发 SVA | 完整并发 SVA |
| 覆盖率 | 无内置支持 | 无 | 完整功能 + 代码覆盖率 | 完整功能 + 代码覆盖率 |
| 验证 (UVM) | 通过 Verilator+UVM 桥接 | 不支持 | 完整 UVM-1.2 | 完整 UVM-1.2 |
| CI/CD 友好度 | 优秀 | 优秀 | 需要许可证服务器 | 需要许可证服务器 |
| GUI 调试器 | 无(外接 GTKWave) | 无(外接 GTKWave) | 完整交互式调试器 | Vivado 集成逻辑分析仪 |
测试对象为一个中型 RISC-V 核心(约 15K 行 Verilog,约 3K 个触发器),在 AMD Ryzen 5950X(16 核 32 线程)、64 GB 内存、Ubuntu 24.04 上进行。
| 工具 | 首次运行 | 缓存后 | 说明 |
|---|---|---|---|
| Icarus | 2.1s | 2.1s | 始终完整编译 |
| Verilator | 4.8s | 0.3s | 首次后利用 C++ 增量构建 |
| Vivado xsim | 12.3s | 6.1s | Elaboration + 优化 |
| ModelSim | 18.7s | 9.2s | vlog + vopt elaboration |
| 工具 | 实际耗时 | 相对速度 | 说明 |
|---|---|---|---|
| Verilator | 0.9s | 1.0x(最快) | C++ 编译模型,无事件调度开销 |
| Vivado xsim | 6.4s | 慢 7.1 倍 | 事件驱动引擎 |
| ModelSim | 8.1s | 慢 9.0 倍 | 事件驱动引擎 |
| Icarus | 18.2s | 慢 20.2 倍 | 纯解释执行 VVP |
| 工具 | 格式 | 文件大小 | 说明 |
|---|---|---|---|
| Verilator | FST | 48 MB | 块级压缩 |
| Icarus | FST | 52 MB | 同格式,略大 |
| Verilator | VCD | 1.8 GB | ASCII 格式——长时间仿真应避免使用 |
| ModelSim | WLF | 95 MB | 专有格式,查看器响应快 |
| Vivado xsim | WDB | 110 MB | 专有格式,与 Vivado GUI 绑定 |
| 特性 | Verilator | Icarus | ModelSim | Vivado xsim |
|---|---|---|---|---|
always_ff, always_comb |
支持 | 部分支持 | 支持 | 支持 |
接口 (interface/modport) |
支持 | 不支持 | 支持 | 支持 |
包 (package/import) |
支持 | 不支持 | 支持 | 支持 |
枚举类型 (enum) |
支持 | 不支持 | 支持 | 支持 |
结构体 (struct/typedef) |
支持 | 不支持 | 支持 | 支持 |
| 断言(立即断言) | 支持 | 不支持 | 支持 | 支持 |
| 断言(并发 SVA) | 有限支持 | 不支持 | 支持 | 支持 |
覆盖率 (covergroup) |
不支持 | 不支持 | 支持 | 支持 |
约束 (rand/constraint) |
不支持 | 不支持 | 支持 | 支持 |
| 类 (OOP) | 不支持 | 不支持 | 支持 | 支持 |
| UVM | 通过桥接 | 不支持 | 支持 | 支持 |
generate / genvar |
支持 | 支持 | 支持 | 支持 |
| 多维数组 | 支持 | 部分支持 | 支持 | 支持 |
$clog2, $bits |
支持 | 支持 | 支持 | 支持 |
DPI-C (import "DPI-C") |
支持 | 部分支持 | 支持 | 支持 |
force / release |
支持 | 支持 | 支持 | 支持 |
Verilator 的 lint 模式是代码质量的第一道防线。它能零仿真成本地捕获综合不匹配、位宽截断和组合逻辑环路等问题。
# .github/workflows/verilog-lint.yml
name: Verilator Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: 安装 Verilator
run: sudo apt install -y verilator
- name: 运行 Lint 检查
run: |
verilator --lint-only -Wall -Wno-DECLFILENAME \
-I rtl/ -I ip_common/rtl/ \
-f rtl/filelist.f \
--top-module top
Icarus 非常适合 CI 中的回归测试,因为它启动快,且能完美兼容标准 Verilog-2001/2005。
# .github/workflows/regression.yml
name: Icarus 回归测试
on: [push, pull_request]
jobs:
regression:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: 安装工具
run: sudo apt install -y iverilog
- name: 运行回归测试
run: |
for tb in sim/tb_*.v; do
module=$(basename "$tb" .v)
echo "运行 $module..."
iverilog -g2012 -I rtl/ -I ip_common/rtl/ -o sim/$module.vvp $tb
vvp sim/$module.vvp | tee sim/${module}.log
if grep -q "FAIL" sim/${module}.log; then
echo "失败: $module"
exit 1
fi
done
echo "所有测试通过"
要让任何 CI 流程正常工作,Testbench 必须具备自检能力。以下是一个良好的模式:
// sim/tb_alu.v
module tb_alu;
reg clk = 0;
always #5 clk = ~clk;
// DUT 实例化
reg [31:0] a, b;
reg [3:0] op;
wire [31:0] result;
alu dut (.clk(clk), .a(a), .b(b), .op(op), .result(result));
integer pass = 0, fail = 0;
task check(input [31:0] expected, input [255:0] msg);
if (result !== expected) begin
$display("失败: %s | 得到 %h, 期望 %h", msg, result, expected);
fail = fail + 1;
end else begin
$display("通过: %s", msg);
pass = pass + 1;
end
endtask
initial begin
$dumpfile("tb_alu.fst");
$dumpvars(0, tb_alu);
// 加法测试
a = 32'd10; b = 32'd20; op = 4'd0; #10;
check(32'd30, "加法 10+20");
// 减法测试
a = 32'd100; b = 32'd30; op = 4'd1; #10;
check(32'd70, "减法 100-30");
// 最终报告
$display("=== 汇总: %0d 通过, %0d 失败 ===", pass, fail);
if (fail > 0) $fatal(1, "回归测试失败");
$finish;
end
endmodule
ModelSim 在 CI 中使用需要网络可达的许可证服务器。使用 vsim -c 进入批处理模式并捕获退出码。
#!/bin/bash
# ci_modelsim.sh — Jenkins/GitHub Actions Runner 上的 ModelSim 回归测试
export MGLS_LICENSE_FILE="[email protected]:[email protected]"
# 编译所有源文件
vlib work
vlog +acc +cover -work work -f rtl/filelist.f
vlog +acc +cover -work work sim/tb_top.sv
# 运行仿真并收集覆盖率
vsim -c -coverage -do "coverage save -onexit cov.ucdb; run -all; quit" work.tb_top
# 检查结果
if [ $? -ne 0 ]; then
echo "ModelSim 仿真失败"
exit 1
fi
# 生成覆盖率报告
vcover report -html cov.ucdb -output coverage_report/
echo "覆盖率报告: coverage_report/index.html"
┌─────────────────────────────┐
│ 是否需要代码覆盖率 │
│ 或功能覆盖率? │
└──────────────┬──────────────┘
是 │ │ 否
┌──────────┘ └───────────┐
▼ ▼
使用 ModelSim ┌──────────────────────┐
或 Vivado xsim │ 是否使用 SystemVerilog│
│ 接口/结构体/包/SVA? │
└──────────┬───────────┘
是 │ │ 否
┌──────────┘ └──────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Verilator 或 │ │ 需要最快仿真 │
│ ModelSim │ │ 速度? │
└──────────────┘ └──────┬───────┘
│ 是 │ │ 否
▼ ▼ ▼
这是 CI Lint 步骤 Verilator Icarus
(不需要波形)?
│ │
是 │ │ 否
▼ ▼
Verilator ModelSim
--lint (含波形+调试)
--lint-only。在仿真开始前即可捕获 90% 的 bug,几秒内完成。covergroup、cover property 和 UCDB/WDB 覆盖率数据库格式。| 特性 | GTKWave | ModelSim Wave | Vivado Wave |
|---|---|---|---|
| 信号搜索/过滤 | 基础正则 | 高级 + 层次结构 | 层次树 |
| 模拟波形视图 | 支持 | 支持 | 支持 |
| 总线基数(十六进制/二进制/十进制/ASCII) | 全部 | 全部 | 全部 |
| 时间光标 + 差值测量 | 支持 | 支持 | 支持 |
| 信号比较(差异) | 不支持 | 支持 | 不支持 |
| 数据流(驱动源追踪) | 不支持 | 支持 | 不支持 |
| 存储器内容查看器 | 有限 | 完整 | 完整 |
| Tcl 脚本化 | 通过 Tcl 命令 | 完整 Tcl API | 完整 Tcl API |
| 远程查看 | FST 文件可移植 | 需转换 WLF | 需转换 WDB |
对于一个既做 FPGA 又做 ASIC 工作的团队,理想的工具配置是:
这样既能享受开源工具在 CI 中的速度优势,又能在需要时获得商业工具的调试能力,无需为每台 CI Runner 都购买额外的商业许可证。