这一篇在干嘛?

依据安路官方《TangDynasty® 工程仿真指南》(SWUG107,TD 6.0)撰写。很多人写完 Verilog 直接综合、下板、看 LED 灯闪不闪——灯不闪就完全抓瞎。仿真是在软件环境里模拟真实设计行为的过程:施加激励、观察输出,在代码写错的几分钟内就发现它,而不是上板后浪费一晚上。这篇讲清 TD 里四个仿真阶段各验证什么、怎么编译仿真库、testbench 怎么写、功能仿真和时序仿真分别怎么跑。本系列目录见设计仿真指南首页

为什么要仿真,四个阶段各管什么

TD 支持哪些仿真器

TD 的两个联合仿真工具

仿真前的三件准备工作

testbench 怎么写才好用

功能仿真实操:四个阶段逐一跑通

时序仿真与 SDF 反标

进阶:Linux 下用 VCS 仿真

为什么要仿真,四个阶段各管什么

先说结论:在较大的工程中通常需要进行反复的仿真测试,以保证功能和时序满足要求。TD 在 FPGA Flow 的每个阶段后都留了一个仿真窗口,越往后的阶段验证的内容越”接近真实硬件”。官方给出的全景图如下——横轴是 FPGA Flow 的推进方向,每个节点下挂一种仿真:

TD 工程仿真流程图:四个仿真阶段与 Flow 阶段的对应关系

四个阶段逐一拆解:

① Behavioral Simulation(RTL 行为级仿真)——在 FPGA Flow 运行完 Read Design 并执行 open run 操作后进行。这是综合前的源码级仿真,检查代码的语法错误以及代码行为的正确性。它最便宜、跑得最快,能在设计早期发现逻辑 bug,节约整个设计周期。

行为级代码本身也有四个好处,这解释了为什么前期都写 RTL 而不是直接画电路:

  • 行为级代码更具备可读性;
  • 行为级代码具备复用性,可在其他工程设计中使用相同的 RTL 代码;
  • 行为级代码具备可移植性,可移植到其他器件系列使用;
  • 行为级代码的仿真更便捷。

② Post RTL Simulation(后 RTL 级仿真)——Flow 运行完 Optimize RTL 并 open run 后进行。仿真的是 TD 优化后形成的门级电路网表,验证工程功能的正确性。换句话说,它检查”TD 把你的代码优化改写之后,功能有没有被改坏”。

③ Post Gate Simulation(后 Gate 级仿真)——Flow 运行完 Optimize Gate 并 open run 后进行。仿真的是门级电路转换成安路器件库底层物理电路的网表,验证综合后设计功能的正确性。到这里,你的设计已经映射到了 EG4S20 真实存在的 LUT、寄存器等物理单元上。

④ Post Route Simulation(后 Route 级仿真)——Flow 运行完 Optimize Placement 和 Optimize Routing 两步并 open run 后进行。仿真的是布局布线优化后的电路网表,它又分功能仿真和时序仿真两种:时序仿真需要包含 SDF 文件(由 TD 自动生成),能保证布局布线后的设计满足功能和时序的要求。

常见坑:跳过 Behavioral 直接跑时序仿真

有些同学觉得”仿真一遍就够”,直接跑到布局布线后做时序仿真。问题在于:行为级仿真 5 秒能暴露的逻辑 bug,拖到时序仿真阶段可能要编译十几分钟才能发现,而且此时报错信息被网表、SDF 包裹,定位困难得多。正确节奏是每个阶段都仿一遍,让每一层”翻译”(综合优化 → 门级映射 → 布局布线)都经过验证。

TD 支持哪些仿真器

TD 各器件库支持的第三方仿真工具及版本如下表。注意 EG 系列(EG4S20 所在系列)支持 Modelsim、Questa 和 VCS 三种

器件库第三方仿真工具版本
EF2 / EF3 / EG / PH1 / PH2 / SF1Mentor Graphics Modelsim Simulator2020
EF2 / EF3 / EG / PH1 / PH2 / SF1Mentor Graphics Questa Advanced Simulation2020
EF2 / EF3 / EG / PH1 / PH2 / SF1Synopsys Verilog Compiler Simulator2020 2018

但有一个重要区别:Modelsim 和 Questa 已关联到 TD 设计环境中,可以在 TD 软件里点一下按钮就联合仿真;Synopsys VCS 暂未关联 TD,只能在 Linux 系统下搭建外部仿真环境(见后文第 8 节)。

按操作系统看支持的组合:

仿真工具Red Hat 64-bit LinuxWindows 10 64-bit
Mentor Graphics Modelsim Simulator
Mentor Graphics Questa Advanced Simulation
Synopsys Verilog Compiler Simulator (VCS)不支持,可使用外部仿真环境不支持

对大学生来说,Windows + Modelsim 是最省事的组合:全程不用离开 TD 界面,也不用手写脚本。

TD 的两个联合仿真工具

TD 软件集成了两个联合仿真工具,各司其职:

  • Simulation Libraries Compiler:编译 TD 器件库,让第三方仿真工具能够调用安路的器件模型。相当于把”安路硬件长什么样”翻译成你的仿真器听得懂的语言。
  • Project Simulation:在 TD 各个 flow 阶段自动生成对应的仿真文件并实现一键自动仿真。它可以自动化生成 testbench 文件、仿真脚本以及网表文件,用户只需编写 testbench 的激励部分代码即可。

Simulation Libraries Compiler 从菜单 Tools → Simulation Libraries Compiler 打开。注意一个贴心细节:启动 TD 就可以使用该功能,无需打开工程——也就是说你可以在建工程之前就先把库编译好。

Project Simulation 从菜单 Tools → Project Simulation 打开。使用前提是:必须打开并编译工程。它覆盖 Behavioral、Post RTL、Post Gate、Post Route 全部四个阶段的仿真。

记住分工:Simulation Libraries Compiler 管”库”(一劳永逸),Project Simulation 管”每次仿真”(日常使用)。

仿真前的三件准备工作

官方清单——仿真之前需要完成:

  1. 进行仿真相关的设置:选择第三方仿真工具及其可执行文件目录等(VCS 仿真时必须勾选 flow_sim_filelist 选项,不勾选默认按 Modelsim 的仿真设置);
  2. 编译器件库
  3. 创建 testbench 文件以及仿真脚本
  4. 生成网表(Post RTL / Post Gate / Post Route 仿真需要网表文件——这一步 Project Simulation 会自动做)。

第一步:仿真设置

选择 Project → Project Setting 打开 Properties Setting 窗口,点击 Simulation 选项卡。这些设置与当前创建的工程相关联:

Project Setting 窗口的仿真设置选项

三个关键选项:

  • simulator:选择仿真工具,目前支持 Modelsim 以及 Questasim;
  • simulator_location:选择仿真工具的可执行文件路径;
  • flow_sim_filelist:选择是否在各仿真阶段生成仿真所需的文件列表(包括 testbench 文件、源文件、IP 的仿真文件及其他源语文件)。打开后,用 Project Simulation 生成 testbench 和仿真脚本时还会在仿真目录下生成 .f 文件(filelist),可直接用于 VCS 仿真。

常见坑:.f 文件的位置

生成的 .f 文件用于 VCS 仿真时,需要放在 testbench 文件的同级目录,否则 VCS 找不到文件列表。

第二步:编译器件库

仿真库包括器件模型、IP 行为模型和时序模型。这些模型以库文件的形式随 TD 分发,需要用第三方仿真工具编译一次;编译后的库可以直接应用在多个工程设计中。

TD 把编译封装成了 GUI:Tools → Simulation Libraries Compiler 打开窗口:

Simulation Libraries Compiler 编译窗口

各选项含义:

  • Simulator:选择仿真工具,支持 Modelsim 以及 Questasim;
  • Executable Path:仿真工具可执行文件路径。Windows 版 TD 默认会自动识别目标仿真工具的路径;只有当仿真器没加入 PATH 环境变量、或者想覆盖环境变量中的路径时才需要手动设置;
  • Device Family:选择要编译的器件库,可选 common 库、EF2、EF3、EF4、EG、PH1、PH2、SF1 以及 all,默认编译全部;
  • Compiled Library Location:编译库的保存路径,TD 会在该路径下创建相应文件夹存放各器件库的编译结果;
  • Recompile:勾选后对已编译过的库重新编译,默认不重编译。

器件库名字和器件系列的对应关系(EG4S20 对应 EG 库):

Library NameDevice Name
common器件公共库
EF2SALELF® 2 系列
EF3SALELF® 3 系列
EGSALEAGLE® 系列
PH1SALPHOENIX® 1A 系列
PH2SALPHOENIX® 2A 系列
SF1SALSWIFT® 系列

点击 Compile 后,编译日志会实时显示在 TD 的 console 窗口,能看到进度和告警,Log 文件自动保存在编译库目录下。典型日志长这样:

# Start time: 16:01:46 on Feb 01,2024
---- Compiling module common,current progress: 100.00%. ----
# End time: 16:01:47 on Feb 01,2024, Elapsed time: 0:00:01
# Errors: 0,Warnings: 0
# ** Warning: (vlog-2070) Existing unprotected design unit "apm_memory_base" is being recompiled as protected.
# ** Warning: (vlog-2070) Existing unprotected design unit "apm_memory_sprom" is being recompiled as protected.
---- Compiling module ph2,current progress: 45.95%. ----

看到 Errors: 0 就说明这批库编干净了。日志里那些 vlog-2070 告警属于”同一设计单元被重编译为 protected”的正常提示,不影响使用。

第三步:testbench 与仿真脚本

testbench 是用来仿真的激励文件,可用 Verilog 或 SystemVerilog 编写,三大功能:例化并初始化设计、为工程设计产生激励、模拟设计输出结果并验证功能准确性。它可以按顺序对特定输入施加激励,也可以包含子程序调用、从外部文件读取激励、条件激励等更复杂的结构。

相比交互式仿真,testbench 有两个独特优势:支持在整个设计过程中的重复仿真;可提供测试条件的文档

仿真脚本(如 Modelsim 的 .do 文件)用于配置仿真环境、控制仿真任务、查看波形、分析结果,让测试流程可自动化、可重复。如果你已经编译过器件库,Project Simulation 生成的脚本会以映射库的形式加载器件库:

已编译器件库时生成的仿真脚本 do 文件:使用 vmap 库映射

如果没编译过库,脚本会直接把器件源语所在路径写进去,跑脚本时现场编译源语——能跑,但仿真编译的时间可能稍长

testbench 怎么写才好用

必须遵守的四条铁律

创建 testbench 文件时要注意:

  1. **添加 timescale**,即时间单位与仿真精度,例如 timescale 1ns/1ps;
  2. 仿真开始时刻给设计的所有输入赋初始值,以正确开启仿真过程;
  3. 在释放全局复位(GSR)之后启动时钟源
  4. 使用安路器件源语时,testbench 需要调用全局复位文件

第 4 条最容易被忽略。不同器件系列用的 GSR 源语不同:PH1_PHY_GSR 用于 PH1 系列,PH2_PHY_GSR 用于 PH2 系列,glbl 源语用于 EF2、EF3、EF4、EG、SF1 器件库——你的 EG4S20 属于 EG 系列,要用 glbl:

全局复位模块(GSR)的例化写法

让 Project Simulation 替你搭骨架

Project Simulation 会自动生成 testbench 模板,你只需要在标注的位置填激励代码。模板长这样:

`timescale 1ns/1ps
module top_tb();
reg clk;
reg rst_n;
wire led;
//Clock process
parameter PERIOD = 10;
always #(PERIOD/2) clk = ~clk;
 
PH2_PHY_GSR PH2_PHY_GSR();
//Unit Instantiate
top u_dut(
    .clk(clk),
    .rst_n(rst_n),
    .led(led)
);
//Stimulus process
initial begin
//To be inserted
end
 
endmodule

常见坑:时钟周期没改

自动生成的 testbench 默认时钟周期 PERIOD 为 10ns(100MHz)。务必根据目标工程设计修改 PERIOD,否则仿真时钟频率和真实板子对不上,可能掩盖时序问题。

六条激励编写规范

以下规范来自官方建议,能显著提高测试的有效性和可维护性:

(1)用 initial 块或 always 块:initial 块适用于一次性的初始化和测试,always 块适用于循环测试。

(2)添加时间延迟:确保测试激励的顺序和时序正确:

initial begin
//Stimulate input signals
    input_signal = 1'b0;
    #10;
    input_signal = 1'b1;
    #20;
    input_signal = 1'b0;
end
//Additional testbench code

(3)用 task 或 function 封装:把重复使用的激励封装起来,提高可维护性和复用性:

task apply_test_pattern;
//Your testbench code here
endtask
 
//……
 
initial begin
    apply_test_pattern;
end

(4)添加注释:解释测试激励的目的、顺序和预期结果。

(5)使用测试配置参数:用 parameter 配置测试,不同场景可复用同一个 testbench:

parameter TEST_DELAY = 10;
initial begin
//Stimulate input signals
    input_signal = 1'b0;
    #TEST_DELAY;
    input_signal = 1'b1;
    #TEST_DELAY;
    input_signal = 1'b0;
end

(6)模拟结束:在最后添加结束语句,确保仿真正确收尾:

initial begin
//Your testbench code here
#100; //Run Simulation for 100 time units
$finish; //Finish simulation
end

当然,规范是手段不是目的——最重要的是确保 testbench 能准确、全面地验证设计的功能和时序

Modelsim 仿真脚本常用指令也值得存一份,手动跑 .do 文件或排查脚本问题时会用到:

命令参数释义
vlib创建一个新的库或者设置当前工作库
vlog编译 Verilog 源代码文件
-incr启用增量编译
-vopt启用编译优化
-sv指示编译 SystemVerilog 源文件
vcom编译 VHDL 源代码文件
vmap设置库映射,将库名映射到具体的目录路径
vsim启动 Modelsim 仿真的指令
-t指定仿真的时间精度
-vopt启用编译优化
-L指定库的搜索路径
-sdftyp指定特定实例的 sdf 仿真文件

功能仿真实操:四个阶段逐一跑通

四个阶段的操作模式完全一致,区别只在于 Flow 跑到哪一步、菜单点哪一项。以 Post Route Simulation 为例,先看它的设置窗口:

Post Route Simulation 窗口:可选功能仿真或时序仿真

窗口选项解读(这套选项在四个阶段的窗口里基本通用):

  • Add an existing testbench:添加一个已写好的 testbench;
  • Create a new testbench:创建新 testbench,选中并点击 OK 后,TD 会在工程目录下自动创建 testbench 文件并关联顶层模块;
  • Function Simulation / Timing Simulation只有 Post Route Simulation 阶段有这个二选一,其他阶段默认做功能仿真。选 Timing Simulation 并点 OK 后,TD 会在工程对应仿真目录下生成 SDF 延时文件;
  • Run:勾选后,点 OK 即启动第三方仿真工具执行仿真脚本并生成仿真波形。

逐步操作

Behavioral Simulation:Flow 运行完 Read Design 阶段并执行 open run 后,选择 Tools → Project Simulation → Behavioral Simulation,添加准备好的 testbench,勾选 Run,点 OK 即自动执行行为级功能仿真。

Post RTL Simulation:Flow 运行完 Optimize RTL 并 open run 后,选 Tools → Project Simulation → Post RTL Simulation,添加 testbench、勾选 Run、点 OK。

Post Gate Simulation:Flow 运行完 Optimize Gate 并 open run 后,选 Tools → Project Simulation → Post Gate Simulation,同样操作。

Post Route Simulation(功能仿真):Flow 运行完 Optimize Placement 和 Optimize Routing 并 open run 后,选 Tools → Project Simulation → Post Route Simulation,添加 testbench,选择 Function Simulation,勾选 Run,点 OK。

如果选了 Timing Simulation,点 OK 后 TD 会生成 SDF 反标文件。SDF 文件是时序反标文件,用于后仿真时适配网表文件中 cell 的延迟信息:

SDF 延时文件的生成选项

选择 Create a new testbench 并选 Timing Simulation 后,TD 会在指定目录下一口气自动生成 testbench 文件、仿真脚本文件、网表文件以及 SDF 文件:

Project Simulation 自动生成的文件目录(Post Route Simulation)

注意:在 Post RTL、Post Gate、Post Route 三个阶段,Project Simulation 会自动生成综合或布局布线后的网表文件,不需要你手动跑网表导出。

时序仿真与 SDF 反标

时序仿真只在 Post Route Simulation 阶段进行。前提是 TD 已计算出最差情况下布局布线后的延时信息——TD 做时序分析时会按最坏工艺角算延迟,所以 SDF 里的延时是保守值,时序仿真通过意味着真实芯片大概率也满足时序。

操作流程:Flow 运行完 Optimize Routing 并 open run 后,选择 Tools → Project Simulation → Post Route Simulation,添加 testbench,选择 Timing Simulation,勾选 Run,点 OK,TD 即调用第三方仿真工具自动执行后 Route 级时序仿真。这时的波形里能看到信号翻转的真实延迟,建立/保持时间违例会以警告形式暴露。

常见坑:忘了 SDF 的作用范围

SDF 适配的是网表文件中 cell 的延迟信息,不包含你 testbench 里自己写的 #10 延迟。如果发现波形里”延迟怎么这么小”,先确认仿真的对象是网表而不是 RTL——拿 RTL 顶层的端口直接对照 SDF 延迟是查不到东西的。

时序仿真报错后不要急着改 RTL:先看时序分析报告的 WNS/TNS 负了多少,是关键路径太长(改 RTL)还是扇出/布线拥塞(加约束、改物理优化),对症下药。

进阶:Linux 下用 VCS 仿真

VCS 未关联 TD,但竞赛里如果用到 Linux 服务器做大规模仿真,VCS 依然可用。流程五步:

(1)设置环境变量:让系统能找到 VCS 的可执行文件。

(2)生成 filelist 文件:文件列表包括 testbench 文件、源文件、IP 的仿真文件及其他源语文件。仿真设置必须勾选 flow_sim_filelist,然后在对应 flow 阶段用 Project Simulation 工具,即可在仿真目录下自动生成 testbench 和 filelist 文件。

(3)编写 Makefile 脚本:在对应仿真目录下创建 Makefile,添加编译命令和选项。官方示例:

## vcs run options
VCS_FLAGS = vcs -full64 -R -sverilog -kdb -lca +v2k +lint=TFIPC-L -debug_access+all \
+nospecify \
-timescale=1ps/1fs \
-v2k_generate \
+incdir+. \
-ucli -i vcs_ucli.tcl \
-t ps -l ./$(LOG)/test_fec_only$(COMPILE_TIME).log
run:
    mkdir -p $(LOG)
    rm -rf simv* csrc
    $(VCS_FLAGS) $(TB_TOP) $(SIMDefines) -f $(FILELIST)
    mv *.fsdb $(LOG)

(4)运行 VCS 编译:执行 make 命令启动仿真编译。

(5)查看波形:编译完成后通过 DVE 或 verdi 工具查看仿真波形。若添加了 verdi 环境变量并在 Makefile 中加了 verdi 命令选项,可用 make verdi 命令直接启动。

VCS 做 SDF 反标有两种方式:

  1. 在 Makefile 中调用vcs -sdf min|typ|max:instance_name:file.sdf,其中 min|typ|max 选择最小/典型/最大时序信息,instance_name 指定时序信息应用的实例名称,file.sdf 是 SDF 文件;
  2. **使用 sdf_annotate (“sdf_file”[,module_instance][,“sdf_configfile”][,“sdf_logfile”][,“mtm_spec”][,“scale_factors”][,“scale_type”])`,参数细节查 VCS 文档。

常见坑:VCS 时序仿真的参数冲突

用 VCS 做 SDF 时序仿真时,需要把 +notimingcheck+nospecify屏蔽时序检查的参数去掉——官方示例 Makefile 里恰恰带着 +nospecify,那是为了功能仿真提速;做时序仿真前务必删掉,否则 SDF 反标形同虚设。另外一个已知限制:PH2 仿真模型没有 SDF 相关的 specify 描述,暂不支持时序仿真(EG 系列不受影响)。

通关标准:

① 能说出四个仿真阶段分别验证什么、对应 Flow 的哪个节点;② 能独立完成”设置仿真器 → 编译 EG 器件库 → 写 testbench 激励 → 一键跑 Post Route 时序仿真”的完整闭环;③ 遇到时序仿真失败时,知道从 SDF、时序报告两条线索定位问题。