这一篇在干嘛?
概念讲完了,现在真刀真枪跑一次。我们用 QuestaSim 自带的示例——一个 8 位二进制加法计数器和它的 testbench——把「建库 → 编译 → 优化 → 加载 → 运行 → 调试」六步完整走一遍。跟着做,你会对整个仿真闭环有体感。
本课的设计文件
示例设计是一个简单的 8 位二进制加法计数器(up-counter),带配套 testbench。路径如下:
- Verilog:
<install_dir>/examples/tutorials/verilog/basicSimulation/counter.v和tcounter.v - VHDL:
<install_dir>/examples/tutorials/vhdl/basicSimulation/counter.vhd和tcounter.vhd
本课以 Verilog 文件 counter.v 和 tcounter.v 为例演示。如果你是 VHDL license,就用 counter.vhd 和 tcounter.vhd;混合 license 的话,Verilog testbench 配 VHDL counter(或反过来)也可以。
本课涉及的命令:vlib、vmap、vlog、vcom、vopt、view、run。深入资料见 User’s Manual 中 Design Libraries、Verilog and SystemVerilog Simulation、VHDL Simulation 相关章节。
第一步:创建工作库(work)
仿真之前必须先有库,再把源代码编译进去。
操作步骤:
- 新建目录并拷贝设计文件。为本课建一个新目录(免得和其他人的练习混在一起),把 counter.v 和 tcounter.v(VHDL 则是 counter.vhd 和 tcounter.vhd)从安装目录的 examples 下拷进去。
- 启动 QuestaSim。在 UNIX shell 提示符下输入
vsim,或在 Windows 下点击 Questa SIM 图标。第一次打开会弹出 Welcome to Questa SIM 对话框,点 Close 关掉。然后选择 File > Change Directory,切换到你刚建的目录——后面的所有操作都在这个目录下进行。 - 创建工作库。选择 File > New > Library,弹出 Create a New Library 对话框(Figure 3-1)。这里既可以新建库,也可以映射到已有库,我们选前者。
- 在 Library Name 栏输入
work(如果没自动填上的话),点 OK。
Figure 3-1. The Create a New Library Dialog Box

点 OK 之后发生了两件事:
- QuestaSim 创建了一个名为
work的目录,并在里面写入一个特殊格式的文件_info。这个_info文件必须留在目录里,用来标识「这是一个 QuestaSim 库」。不要在操作系统里手动改这个文件夹的内容,所有变更都应通过 QuestaSim 完成。 - QuestaSim 把库加进 Library 窗口(Figure 3-2),并把库映射记录到初始化文件 modelsim.ini 里,供以后使用。
Figure 3-2. work Library Added to the Library Window
| Library | |||
| Name | Type | Path | |
| work | Library | work | |
| floatfixlib | Library | $MODEL_TECH/../o | |
| mtiAvm | Library | $MODEL_TECH/../o | |
| mtiOvm | Library | $MODEL_TECH/../o | |
| mtiUPF | Library | $MODEL_TECH/../o | |
| sv_std | Library | $MODEL_TECH/../o | |
| vital2000 | Library | $MODEL_TECH/../o | |
| ieee | Library | $MODEL_TECH/../o | |
| modelsim_lib | Library | $MODEL_TECH/../o | |
| std | Library | $MODEL_TECH/../o | |
- 留意 Transcript 窗口——你点 OK 的时候,它打印出了这两行:
vlib work
vmap work work这就是你刚才菜单操作对应的命令行版本。之后很多 GUI 操作都会这样在 Transcript 里回显等价命令——看懂这些回显,是学会用命令行跑仿真的捷径。
库的映射是怎么回事
vlib work在磁盘上创建了物理目录,vmap work work则建立「逻辑名 → 物理位置」的映射并写进 modelsim.ini。你也可以自己准备一个编译好的库(比如 FPGA 厂商给的仿真模型库),用 vmap 映射进来直接用——这在后仿真里非常常见。
第二步:编译设计单元
库建好了,接下来把源文件编译进去。既可以用图形界面的菜单和对话框,也可以在 QuestaSim> 提示符后直接敲命令。
操作步骤:
- 编译 counter.v 和 tcounter.v。
- 选择 Compile > Compile,打开 Compile Source Files 对话框(Figure 3-3)。
- 如果 Compile 菜单项是灰的不可用,多半是当前打开着一个工程。把 Library 窗口置为活动窗口,然后选 File > Close 关掉工程即可。
- 在对话框里同时选中 counter.v 和 tcounter.v 两个模块,点 Compile,文件会被编译进 work 库。
- 编译完成后点 Done。
Figure 3-3. Compile Source Files Dialog Box

菜单背后的命令
这个「Compile > Compile」操作对应的命令行就是
vlog counter.v tcounter.v(Verilog 用 vlog,VHDL 用 vcom)。养成看 Transcript 回显的习惯,命令行版仿真脚本以后写起来毫不费力。
- 查看编译结果。在 Library 窗口里点 work 库旁边的
+号,能看到两个设计单元(Figure 3-4),还有它们的类型(Modules、Entities 等)和源文件路径。
Figure 3-4. Verilog Modules Compiled into work Library
| Library | |||
| Name | Type | Path | |
| work | Library | work | |
| counter | Module | C:/modeltech | |
| test_counter | Module | C:/modeltech | |
| floatfixlib | Library | $MODEL_TECH/../floatfixlib | |
| mc2_lib | Library | $MODEL_TECH/../mc2_lib | |
| mtiAvm | Library | $MODEL_TECH/../avm | |
| mtiOvm | Library | $MODEL_TECH/../ovm-2.0.3 | |
| mtiPA | Library | $MODEL_TECH/../pa_lib | |
| mtiUPF | Library | $MODEL_TECH/../upf_lib | |
看到 counter(被测设计)和 test_counter(testbench)两个 Module 都躺在 work 里,编译这步就算过了。
第三步:优化设计(vopt)
优化能让仿真跑得更快。在 Transcript 窗口的 QuestaSim> 提示符后输入:
vopt +acc test_counter -o testcounter_opt按回车执行。两个开关的含义:
+acc:为调试保留对设计的可见性(visibility into the design);-o:指定优化后设计文件的名字(这里是 testcounter_opt)。
-o 后面的名字必须自己起
使用 vopt 命令时,必须给优化后的设计文件指定名字,否则命令无法继续。另外还记得上一篇说的吗——不加
+acc的话,信号和进程可能会被优化隐藏,调试时想看内部信号就会扑空。
第四步:加载设计
设计优化完了,可以往仿真器里加载了。
- 加载 test_counter 模块。用优化后的设计名配合 vsim 命令加载:
vsim testcounter_opt- 打开 Objects 和 Processes 窗口:
- 选择 View > Objects;
- 选择 View > Process。
这两个窗口是干什么的:
- Objects 窗口显示 Structure (sim) 窗口中当前选中区域里的数据对象的名字和当前值。数据对象包括信号、net、寄存器、常量、非进程内声明的变量、generics、parameters,以及 SystemC 模块的成员数据变量(Figure 3-5)。
- Processes 窗口列出进程,有四种查看模式:Active、In Region、Design、Hierarchical。Design 模式主要用于 ESL(电子系统级)设计的主导航;默认显示当前仿真中的活动进程(Active 模式)。
Figure 3-5. The Object Window and Processes Window

第五步:运行仿真
跑之前先打开 Wave 窗口,把信号加进去——不然跑完了也看不见波形。
- 打开 Wave 窗口。在命令行输入:
view waveWave 窗口会开在 Main 窗口右侧,必要时拖一下大小让它可见。也可以用菜单 View > Wave 达到同样效果——View 菜单下还有好几个调试窗口可以随时打开。

- 把信号加进 Wave 窗口:
- 在 Structure (sim) 窗口里右键点击 test_counter,弹出上下文菜单;
- 选择 Add Wave(Figure 3-6)。
设计里的所有信号都会被加进 Wave 窗口。
Figure 3-6. Using the Popup Menu to Add Signals to Wave Window

-
运行仿真,三种跑法由浅入深:
- 点 Run 图标:仿真默认跑 100 ns,Wave 窗口里画出波形;
- 在 Transcript 窗口的
VSIM>提示符后输入:
run 500仿真再往前推进 500 ns,累计 600 ns(Figure 3-7);
- 点 Run -All 图标:仿真一直跑到你执行 break 命令、或代码里撞上停仿真语句(比如 Verilog 的
$stop)为止; - 点 Break 图标可以随时停下仿真。
Figure 3-7. Waves Drawn in Wave Window

第六步:设断点、单步调试
最后看一眼 QuestaSim 的交互式调试:在 Source 窗口设断点、跑仿真、然后单步执行被测设计。注意:断点只能设在可执行行上,可执行行的行号是红色的。
-
在 Source 窗口打开 counter.v:
- 选择 View > Files 打开 Files 窗口;
- 点 sim 文件名旁的
+号,展开 vsim.wlf dataset 的内容; - 双击 counter.v(VHDL 用户则是 counter.vhd),在 Source 窗口打开。
-
在第 36 行设断点(VHDL 是 counter.vhd 的第 39 行)。滚动到第 36 行,在行号(Ln#)栏点行号旁边。第 36 行的行号栏出现一个红点(Figure 3-8),表示断点已设好。
Figure 3-8. Setting Breakpoint in Source Window

-
练习断点的禁用、启用和删除:
- 点红点 → 断点禁用,变成灰点;
- 再点灰点 → 重新启用,变回红点;
- 右键红点,选 Remove Breakpoint 36 → 删除断点;
- 再在行号栏点一次 → 重新创建断点。
-
重启仿真并跑到断点:
- 点 Restart 图标:重新加载设计单元、把仿真时间归零。弹出的 Restart 对话框可以选择重启时保留哪些东西(Figure 3-9),点 OK;
- 点 Run -All 图标。仿真一直跑到撞上断点:停下、Source 视图里用蓝色箭头高亮当前行(Figure 3-10)、Transcript 窗口给出 Break 消息。
Figure 3-9. Setting Restart Functions

Figure 3-10. Blue Arrow Indicates Where Simulation Stopped.

-
停下来之后,怎么查信号值? 断点命中时你最想知道的通常就是一个或多个信号的值,有四种办法:
- 看 Objects 窗口(Figure 3-11):
Figure 3-11. Values Shown in Objects Window
Objects
Name Value Kind Mode
tpd_reset_to_count 32'h00000003 Parameter Internal
tpd_clk_to_count 32'h00000002 Parameter Internal
count 8'hxx Packed Array Out
clk 1'h0 Net In
reset 1'h1 Net In- 鼠标悬停:把鼠标移到 Source 窗口里的变量上,会弹出黄色小框,显示变量名和它在 Wave 窗口当前光标时刻的值(Figure 3-12);
Figure 3-12. Hover Mouse Over Variable to Show Value
es/tutorials/verilog/basicSimulation/counter.v (/test_counter/dut) - Default
Ln#
35
36
always @ (posedge clk or posedge reset)
if (reset)
count /test_counter/dut/reset 8'h00;
else 1
count <- #cpu_clk_to_count increment(count);- 右键 Examine:在 Source 窗口里选中一个信号、parameter 或变量,右键选 Examine,弹出的 Source Examine 窗口会显示变量名和当前值(Figure 3-13);
Figure 3-13. Parameter Name and Value in Source Examine Window

- examine 命令:在
VSIM>提示符后用 examine 命令把变量值输出到 Transcript 窗口,例如:
examine count- 试试单步命令。点 Step 工具栏上的 Step Into 图标,调试器单步执行一行。剩下的自己玩:随便设断点、清断点,把 Step、Step Over、Continue Run 都按一遍,直到用顺手为止。
收尾:结束仿真
课程到这里,继续之前要把当前仿真结束掉:
- 选择 Simulate > End Simulation;
- 提示确认退出仿真时,点 Yes。
小结
六步流程复盘一遍:
| 步骤 | GUI 操作 | 等价命令 |
|---|---|---|
| 建库 | File > New > Library,命名 work | vlib work + vmap work work |
| 编译 | Compile > Compile,选文件点 Compile | vlog counter.v tcounter.v |
| 优化 | (命令行) | vopt +acc test_counter -o testcounter_opt |
| 加载 | (命令行) | vsim testcounter_opt |
| 运行 | Run 图标 / Run -All / Break | run 500 |
| 调试 | 行号栏点红点设断点、Step Into | examine count |
下一篇我们改用**工程(Project)**的方式重做这套流程——工程会自动帮你建 work 库,还能把源文件、库、仿真配置一起收纳管理。
自测
自测
- 创建 work 库后,QuestaSim 在 Transcript 里回显了哪两条命令?它们各自做了什么?
- work 目录里的
_info文件有什么作用?可以直接在操作系统里编辑这个文件夹吗?vopt +acc test_counter -o testcounter_opt中+acc和-o各是什么含义?- 断点可以设在任意行上吗?如何禁用、启用和删除一个断点?
- 仿真停在断点处时,查看信号值有哪几种方法?