这一篇在干嘛?

概念讲完了,现在真刀真枪跑一次。我们用 QuestaSim 自带的示例——一个 8 位二进制加法计数器和它的 testbench——把「建库 → 编译 → 优化 → 加载 → 运行 → 调试」六步完整走一遍。跟着做,你会对整个仿真闭环有体感。

本课的设计文件

示例设计是一个简单的 8 位二进制加法计数器(up-counter),带配套 testbench。路径如下:

  • Verilog:<install_dir>/examples/tutorials/verilog/basicSimulation/counter.vtcounter.v
  • VHDL:<install_dir>/examples/tutorials/vhdl/basicSimulation/counter.vhdtcounter.vhd

本课以 Verilog 文件 counter.v 和 tcounter.v 为例演示。如果你是 VHDL license,就用 counter.vhd 和 tcounter.vhd;混合 license 的话,Verilog testbench 配 VHDL counter(或反过来)也可以。

本课涉及的命令:vlibvmapvlogvcomvoptviewrun。深入资料见 User’s Manual 中 Design Libraries、Verilog and SystemVerilog Simulation、VHDL Simulation 相关章节。

第一步:创建工作库(work)

仿真之前必须先有库,再把源代码编译进去。

操作步骤:

  1. 新建目录并拷贝设计文件。为本课建一个新目录(免得和其他人的练习混在一起),把 counter.v 和 tcounter.v(VHDL 则是 counter.vhd 和 tcounter.vhd)从安装目录的 examples 下拷进去。
  2. 启动 QuestaSim。在 UNIX shell 提示符下输入 vsim,或在 Windows 下点击 Questa SIM 图标。第一次打开会弹出 Welcome to Questa SIM 对话框,点 Close 关掉。然后选择 File > Change Directory,切换到你刚建的目录——后面的所有操作都在这个目录下进行。
  3. 创建工作库。选择 File > New > Library,弹出 Create a New Library 对话框(Figure 3-1)。这里既可以新建库,也可以映射到已有库,我们选前者。
  4. 在 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
NameTypePath
workLibrarywork
floatfixlibLibrary$MODEL_TECH/../o
mtiAvmLibrary$MODEL_TECH/../o
mtiOvmLibrary$MODEL_TECH/../o
mtiUPFLibrary$MODEL_TECH/../o
sv_stdLibrary$MODEL_TECH/../o
vital2000Library$MODEL_TECH/../o
ieeeLibrary$MODEL_TECH/../o
modelsim_libLibrary$MODEL_TECH/../o
stdLibrary$MODEL_TECH/../o
  1. 留意 Transcript 窗口——你点 OK 的时候,它打印出了这两行:
vlib work
vmap work work

这就是你刚才菜单操作对应的命令行版本。之后很多 GUI 操作都会这样在 Transcript 里回显等价命令——看懂这些回显,是学会用命令行跑仿真的捷径

库的映射是怎么回事

vlib work 在磁盘上创建了物理目录,vmap work work 则建立「逻辑名 → 物理位置」的映射并写进 modelsim.ini。你也可以自己准备一个编译好的库(比如 FPGA 厂商给的仿真模型库),用 vmap 映射进来直接用——这在后仿真里非常常见。

第二步:编译设计单元

库建好了,接下来把源文件编译进去。既可以用图形界面的菜单和对话框,也可以在 QuestaSim> 提示符后直接敲命令。

操作步骤:

  1. 编译 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 回显的习惯,命令行版仿真脚本以后写起来毫不费力。

  1. 查看编译结果。在 Library 窗口里点 work 库旁边的 + 号,能看到两个设计单元(Figure 3-4),还有它们的类型(Modules、Entities 等)和源文件路径。

Figure 3-4. Verilog Modules Compiled into work Library

Library
NameTypePath
workLibrarywork
counterModuleC:/modeltech
test_counterModuleC:/modeltech
floatfixlibLibrary$MODEL_TECH/../floatfixlib
mc2_libLibrary$MODEL_TECH/../mc2_lib
mtiAvmLibrary$MODEL_TECH/../avm
mtiOvmLibrary$MODEL_TECH/../ovm-2.0.3
mtiPALibrary$MODEL_TECH/../pa_lib
mtiUPFLibrary$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 的话,信号和进程可能会被优化隐藏,调试时想看内部信号就会扑空。

第四步:加载设计

设计优化完了,可以往仿真器里加载了。

  1. 加载 test_counter 模块。用优化后的设计名配合 vsim 命令加载:
vsim testcounter_opt
  1. 打开 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 窗口,把信号加进去——不然跑完了也看不见波形。

  1. 打开 Wave 窗口。在命令行输入:
view wave

Wave 窗口会开在 Main 窗口右侧,必要时拖一下大小让它可见。也可以用菜单 View > Wave 达到同样效果——View 菜单下还有好几个调试窗口可以随时打开。

  1. 把信号加进 Wave 窗口
    • 在 Structure (sim) 窗口里右键点击 test_counter,弹出上下文菜单;
    • 选择 Add Wave(Figure 3-6)。

设计里的所有信号都会被加进 Wave 窗口。

Figure 3-6. Using the Popup Menu to Add Signals to Wave Window

  1. 运行仿真,三种跑法由浅入深:

    • 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 窗口设断点、跑仿真、然后单步执行被测设计。注意:断点只能设在可执行行上,可执行行的行号是红色的。

  1. 在 Source 窗口打开 counter.v

    • 选择 View > Files 打开 Files 窗口;
    • 点 sim 文件名旁的 + 号,展开 vsim.wlf dataset 的内容;
    • 双击 counter.v(VHDL 用户则是 counter.vhd),在 Source 窗口打开。
  2. 在第 36 行设断点(VHDL 是 counter.vhd 的第 39 行)。滚动到第 36 行,在行号(Ln#)栏点行号旁边。第 36 行的行号栏出现一个红点(Figure 3-8),表示断点已设好。

Figure 3-8. Setting Breakpoint in Source Window

  1. 练习断点的禁用、启用和删除

    • 点红点 → 断点禁用,变成灰点;
    • 再点灰点 → 重新启用,变回红点;
    • 右键红点,选 Remove Breakpoint 36 → 删除断点;
    • 再在行号栏点一次 → 重新创建断点。
  2. 重启仿真并跑到断点

    • 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.

  1. 停下来之后,怎么查信号值? 断点命中时你最想知道的通常就是一个或多个信号的值,有四种办法:

    • 看 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
  1. 试试单步命令。点 Step 工具栏上的 Step Into 图标,调试器单步执行一行。剩下的自己玩:随便设断点、清断点,把 Step、Step Over、Continue Run 都按一遍,直到用顺手为止。

收尾:结束仿真

课程到这里,继续之前要把当前仿真结束掉:

  1. 选择 Simulate > End Simulation
  2. 提示确认退出仿真时,点 Yes

小结

六步流程复盘一遍:

步骤GUI 操作等价命令
建库File > New > Library,命名 workvlib work + vmap work work
编译Compile > Compile,选文件点 Compilevlog counter.v tcounter.v
优化(命令行)vopt +acc test_counter -o testcounter_opt
加载(命令行)vsim testcounter_opt
运行Run 图标 / Run -All / Breakrun 500
调试行号栏点红点设断点、Step Intoexamine count

下一篇我们改用**工程(Project)**的方式重做这套流程——工程会自动帮你建 work 库,还能把源文件、库、仿真配置一起收纳管理。

自测