ModelSim 使用教程
什么是 ModelSim?
ModelSim 是由 Mentor Graphics(现为 Siemens EDA)开发的一款业界领先的硬件描述语言 仿真器,它支持 VHDL 和 Verilog 两种主流的 HDL 语言,并且支持混合仿真,ModelSim 主要用于:

- 功能仿真:在综合之前,验证你的代码逻辑是否正确。
- 时序仿真:在综合和布局布线之后,加入实际的延迟信息,验证电路在真实硬件环境下的工作情况。
本教程主要讲解功能仿真的基本流程。
环境准备
- 安装 ModelSim:确保你已经成功安装了 ModelSim,常见的版本有 ModelSim PE (Personal Edition) 和 SE (Student Edition),本教程的界面和操作在大多数版本中通用。
- 选择界面:ModelSim 有两种界面:
- 图形用户界面:通过点击菜单和按钮进行操作,直观易学,适合初学者。
- 命令行界面:通过输入命令行指令进行操作,适合脚本化和自动化。
本教程将主要使用 图形用户界面。
一个完整的仿真流程:以一个简单的 2-1 MUX 为例
我们将按照以下步骤,使用 ModelSim 对一个 2-1 选择器 进行仿真。
步骤概览:

- 创建项目
- 创建设计文件
- 编译设计文件
- 创建仿真文件
- 运行仿真
- 分析波形
- 调试(高级)
- 生成仿真报告
步骤 1:创建新项目
- 打开 ModelSim。
- 在菜单栏选择
File->New->Project...。 - 弹出 "Create Project" 对话框:
- Project Name: 输入项目名称,
my_mux。 - Project Location: 选择一个你想要保存项目的文件夹。
- Default Library: 保持默认的
work库即可。work库是 ModelSim 的当前工作库,用于存放编译后的结果。
- Project Name: 输入项目名称,
- 点击
OK。
右侧会出现一个 Project 窗口,里面是空的。
步骤 2:创建设计文件
我们将创建一个 Verilog 模块 mux_2to1.v。
- 在 Project 窗口中,点击右键,选择
Add file to Project...。 - 在弹出的对话框中:
- File name: 输入
mux_2to1.v。 - Add file as Type: 选择
Verilog。
- File name: 输入
- 点击
OK。
mux_2to1.v 文件已经添加到项目中,双击该文件,在编辑器中输入以下代码:
// mux_2to1.v
// 一个简单的 2-1 选择器
module mux_2to1 (
output out,
input [1:0] in, // 输入数据 in[1] 和 in[0]
input sel // 选择信号
);
// 当 sel 为 0 时,选择 in[0];当 sel 为 1 时,选择 in[1]
assign out = sel ? in[1] : in[0];
endmodule
保存文件(快捷键 Ctrl + S)。

步骤 3:编译设计文件
编译的作用是将你的 HDL 代码(如 Verilog)转换成 ModelSim 可以执行的中间格式。
- 在 Project 窗口中,右键点击
mux_2to1.v文件。 - 选择
Compile->Compile。
如果编译成功,Project 窗口中的文件图标会变成一个绿色的对勾 ,并且底部的 Transcript 窗口会显示 # ** Compile of mux_2to1.v was successful.**。
如果编译失败,Transcript 窗口会显示错误信息,你需要根据错误提示返回编辑器修改代码,然后重新编译。
步骤 4:创建仿真文件(Testbench)
Testbench 是一个没有输入输出的模块,它实例化你的设计模块,并生成激励信号来驱动设计模块,从而观察其输出行为。
- 再次在 Project 窗口中右键,选择
Add file to Project...。 - 文件名输入
tb_mux_2to1.v,类型选择Verilog,然后点击OK。 - 双击
tb_mux_2to1.v并输入以下代码:
// tb_mux_2to1.v
// 2-1 选择器的测试平台
`timescale 1ns / 1ps // 定义时间尺度:1纳秒为基本时间单位,精度为1皮秒
module tb_mux_2to1();
// 定义内部信号,用于连接测试平台和 DUT (Design Under Test)
reg sel;
reg [1:0] in;
wire out;
// 实例化被测试的模块
// 将 DUT 的端口与我们定义的内部信号连接起来
mux_2to1 uut (
.out (out),
.in (in),
.sel (sel)
);
// 生成激励信号的 initial 块
initial begin
// 初始化输入
in = 2'b00;
sel = 1'b0;
// 打印仿真开始信息
$display("Simulation started at time %0t", $time);
// 测试场景 1: sel=0, in[1]=0, in[0]=1. 预期 out=1
#10 in = 2'b01; // 在 10ns 时刻改变 in
#10;
// 测试场景 2: sel=1, in[1]=0, in[0]=1. 预期 out=0
#10 sel = 1'b1;
#10;
// 测试场景 3: sel=1, in[1]=1, in[0]=0. 预期 out=1
#10 in = 2'b10;
#10;
// 测试场景 4: sel=0, in[1]=1, in[0]=0. 预期 out=0
#10 sel = 1'b0;
#10;
// 打印仿真结束信息
$display("Simulation finished at time %0t", $time);
$finish; // 结束仿真
end
// 监控信号变化的 always 块
// 每当 in, sel, or out 变化时,打印当前时间和信号值
initial begin
$monitor("Time = %0t, in = %b, sel = %b, out = %b", $time, in, sel, out);
end
endmodule
保存文件。
步骤 5:运行仿真
现在我们有了一个设计文件和一个测试文件,我们需要将它们一起加载到仿真器中。
-
加载设计:
- 在 Project 窗口中,确保
work库被展开。 - 按住
Ctrl键,同时选中mux_2to1和tb_mux_2to1。 - 右键点击,选择
Simulate->Simulate。
- 在 Project 窗口中,确保
-
设置仿真:
- 弹出 "Simulate" 对话框,确保
Design标签页下,Top-level module in simulation是tb_mux_2to1。 - 点击
OK。
- 弹出 "Simulate" 对话框,确保
ModelSim 的界面会发生一些变化:
- Objects 窗口:显示了
tb_mux_2to1模块中的所有信号(in,sel,out)。 - Wave 窗口:一个空的波形图,等待你添加信号。
- Transcript 窗口:显示仿真器加载成功的信息。
-
添加信号到波形窗口:
- 在 Objects 窗口中,找到
in,sel,out信号。 - 选中它们,然后右键点击,选择
Add -> Wave -> Signals in Region。
波形窗口中就会出现这些信号的名称。
- 在 Objects 窗口中,找到
-
运行仿真:
- 在菜单栏选择
Simulate->Run->Run -All,或者点击工具栏上的绿色 "运行" 按钮。 - 你会看到波形窗口中出现了信号的变化波形。
- 在菜单栏选择
-
停止仿真:
- 当仿真运行到
$finish语句时,它会自动停止,你也可以手动点击工具栏上的红色 "停止" 按钮来停止仿真。
- 当仿真运行到
步骤 6:分析波形
这是仿真中最关键的一步,通过观察波形,判断你的设计是否按预期工作。
- 缩放和平移:
- 使用鼠标滚轮可以缩放波形。
- 按住
Shift键并拖动鼠标可以平移波形。 - 使用工具栏上的放大镜和手形图标也可以进行缩放和平移。
- 检查信号值:
- 在波形上,光标所在位置的信号值会显示在波形图的顶部。
- 对比波形和 Testbench 中的
#10时间点,验证每个测试场景的输出是否符合预期。- 在
10ns到20ns之间,sel=0,in=01,out应该为1。 - 在
20ns到30ns之间,sel=1,in=01,out应该为0。 - ...以此类推。
- 在
如果波形正确,恭喜你,你的设计逻辑通过了功能仿真!
步骤 7:调试(高级技巧)
如果仿真结果不正确,你需要进行调试。
-
使用断点:
- 在 Source 窗口中,找到你的设计文件
mux_2to1.v。 - 在某一行代码的行号前面点击,会出现一个红色的圆点,这就是一个断点。
- 运行仿真后,当程序执行到断点处会暂停,你可以检查此时各个信号的值。
- 在 Source 窗口中,找到你的设计文件
-
单步执行:
- 在 Transcript 窗口下方的 VSIM 提示符后,可以输入命令进行单步调试。
step或s:单步执行一条语句。next或n:单步执行,但会跳过过程块(如initial块)。run 100:运行 100 个时间单位。restart:重新开始仿真。
- 在 Transcript 窗口下方的 VSIM 提示符后,可以输入命令进行单步调试。
-
查看信号值:
- 在 Objects 窗口中,右键点击一个信号,选择
Format -> Literal或Binary等,可以改变其显示格式。 - 在 Transcript 窗口中,可以直接输入命令查看信号值,
print in。
- 在 Objects 窗口中,右键点击一个信号,选择
步骤 8:生成仿真报告
为了记录和分享仿真结果,可以生成一个包含波形和数据的报告文件。
- 在 Wave 窗口中,确保你已经添加了所有需要分析的信号。
- 在菜单栏选择
File->Export->Image...。 - 选择你想要的图片格式(如 PNG, JPG),然后保存,这将导出当前波形窗口的截图。
- 对于更详细的文本报告,可以在 Transcript 窗口中选择仿真日志,然后复制粘贴到文本文件中。
总结与最佳实践
- 项目结构:养成良好的项目习惯,将设计文件和测试文件分开存放,并清晰地命名。
timescale:在 Testbench 的开头一定要加上timescale,这关系到你的仿真时间精度。$monitor和$display:$monitor会持续监控信号变化并打印,而$display只在调用时打印一次。$monitor在调试时非常有用。- 仿真控制:使用 来延迟,
$finish来结束仿真,这是 Testbench 的标准做法。 - 勤于编译:每次修改代码后,务必重新编译,确保仿真运行的是最新的版本。
通过以上步骤,你已经掌握了 ModelSim 的基本使用流程,这只是冰山一角,ModelSim 还有许多高级功能,如 SystemVerilog 支持、Coverage 分析、与其它工具(如 Quartus, Vivado)的集成等,可以在你熟悉基础后进一步学习。
