Quartus Prime Lite + ModelSim仿真入门:从建工程到波形调试

📅 发布时间:2026/9/29 20:58:20
Quartus Prime Lite + ModelSim仿真入门:从建工程到波形调试
前阵子有个读者私信我说装了Quartus Prime Lite Edition写了半天的Verilog点开ModelSim却不知道从哪里下手对着满屏英文界面和一根根红色波形发呆了一下午。这场景我太熟了当年我刚接触FPGA的时候光是把工程建对、把仿真跑起来就折腾了整整一个周末。其实这套流程本身并不复杂只是网上很多教程要么只讲安装要么直接把代码一扔说“你们自己跑”中间最关键的那几步偏偏没人讲透。这篇文章我就从零开始把Quartus Prime Lite Edition里新建FPGA工程、编写RTL代码、配置ModelSim仿真环境到最终跑出正确波形的完整流程捋一遍。全程用一个小而完整的计数器案例来做演示你看完照做一遍基本就能把这个工具链跑顺。适合刚入门FPGA、被Quartus和ModelSim折磨得怀疑人生的同学也适合那些以前只写代码、没真正跑过仿真验证的工程师。1. 认识你的工具Quartus Prime Lite 和 ModelSim 到底是什么关系1.1 版本认知Lite、Standard、Pro和ModelSim有什么区别很多人下载软件的时候根本分不清Quartus Prime Lite Edition、Standard Edition、Pro Edition之间的差异看到官网上一堆版本直接懵了。简单说Quartus Prime就是Intel FPGA的集成开发环境负责工程管理、代码编译、引脚分配、下载配置这一整套流程。Lite Edition是免费版本功能上有限制但绝不是阉割到不能用它支持Cyclone IV、Cyclone 10 LP、MAX 10这些常见器件对学生、入门玩家和小规模项目来说完全够用。Standard和Pro则是面向更复杂器件的付费版本普通学习和做小项目根本用不上。再说ModelSim它是业界老牌的硬件描述语言仿真器能对Verilog或者VHDL代码做功能仿真。Quartus管“编译布线”ModelSim管“逻辑验证”两者是配合关系。我见过不少新手以为装了Quartus就自带仿真功能结果在Quartus界面上找半天“模拟器”按钮其实Quartus本身不做仿真它是调用外部ModelSim来完成的。换句话说ModelSim就是Quartus请来的外援专门负责把你写的代码“运行”起来看结果。1.2 版本匹配为什么我不建议单独装最新版ModelSim这里有个特别容易踩的坑很多同学自己从网上下了一个最新版的ModelSim SE或者ModelSim DE结果在Quartus里怎么配置都连不上或者打开后许可证报错。原因很简单Quartus Prime Lite Edition内部集成的仿真工具是“ModelSim Intel FPGA Starter Edition”也可以叫ModelSim-Altera它和Quartus之间有一套自动配置的库和脚本。你手动安装的ModelSim SE虽然功能更强但两者之间缺少那层自动衔接新手很难配置成功。所以我的建议是除非你确实有特殊需求否则直接用Quartus安装包里自带的ModelSim组件就行。它虽然叫“Starter Edition”但功能上做常规的RTL功能仿真绰绰有余而且与Quartus版本严格匹配省去一堆配置烦恼。记住一句话工具链匹配比版本新更重要。2. 环境准备下载、安装和免费许可一次说清2.1 下载与安装的选型建议去Intel官网下载Quartus Prime Lite Edition时安装包通常有好几个选项有的叫“Quartus Prime Lite Edition (includes Questa?)”有的叫“Device files”独立包。这里不纠结具体文件名你只要记住下载的时候确认是Lite版本的安装包并且包含ModelSim组件即可。下载安装包时会要求注册Intel账号注册过程不复杂就是正常填邮箱、设密码之后下载链接会发到邮箱或者直接能在网页下载实测都方便。安装有几个硬性建议安装路径不要带中文不要有空格更不要装在C:\Program Files这种系统受保护目录下。我习惯装到C:\intelFPGA_lite\21.1这种路径干净又好找。组件选择时建议把常用的器件系列都勾上尤其是Cyclone系列。如果硬盘紧张可以先只装你手头板子对应的器件但教学演示建议勾上Cyclone IV和MAX 10这两个器件资料多、例子多。ModelSim组件一定要记得勾选否则装完Quartus后你找不到仿真器还得重新安装或者单独装非常折腾。2.2 免费许可配置为什么Lite版不需要“折腾”Quartus Prime Lite Edition本身是免费使用的不需要额外买License。安装完成后第一次打开Quartus如果弹出License提示通常是因为你误选了Standard或者Pro模式检查一下License Setup页面把模式切回Lite Edition即可。它不会限制你的编译次数也不会限制工程规模仅仅在支持器件和部分高级功能上有取舍。至于自带的ModelSim Starter Edition正常情况下安装完Quartus后就已经把许可环境配置好了直接双击打开就能用。如果你打开ModelSim时遇到许可证报错十有八九是环境变量没生效。可以手动打开系统环境变量检查是否有一条指向C:\intelFPGA_lite\版本\modelsim_ase\win32aloem或类似路径的LM_LICENSE_FILE变量。缺了就把这条补上然后重启ModelSim。再多说一句这个Starter Edition的许可只能配合Quartus Lite使用你不能指望拿它去跑其他EDA厂商的流程。2.3 验证安装打开ModelSim后看一眼这里安装结束后建议做一个快速验证从开始菜单找到ModelSim Intel FPGA Edition并打开如果界面能正常起来Transcript窗口没有大段红色错误说明环境基本OK。然后再打开Quartus随便建一个空工程试一下编译流程如果也能正常走完工具链就算通了。很多人跳过这一步直接开始写代码结果后面出了问题都不知道是工具链坏了还是代码写错了。花五分钟做个冒烟测试后面省几个小时。3. 从New Project Wizard到第一次编译新建工程实操3.1 新建工程的四步关键操作打开Quartus Prime Lite Edition后点击File - New Project Wizard这是新建FPGA工程的入口。第1步是设置工程目录、工程名和顶层实体名。这里有个经验工程目录不要直接放在桌面建议建一个专门的工作目录比如E:\fpga_prj\counter_test工程名叫counter_test顶层实体名也叫counter_test。虽然工程名和顶层实体名可以不同但新手阶段保持一致最省心后面生成Testbench或者调用ModelSim时不容易弄混。第2步选择工程类型默认Empty project即可不需要勾选“Create top-level design file from template”因为我们会自己写代码。第3步是选择目标器件如果你手里有具体开发板就选对应的Family和具体型号比如Cyclone IV E系列的EP4CE10F17C8如果没有硬件只是想学仿真直接选择Cyclone IV或者MAX 10系列里的任意型号就行。第4步进入EDA Tool Settings这是很多人跳过的关键步骤具体看下一节。3.2 EDA Tool Settings仿真能不能跑起来就看这一步在New Project Wizard的第4步有一个EDA Tool Settings页面里面分Design Entry/Synthesis、Simulation、Formal Verification、Board-Level等几个子页。你需要切到Simulation页把Tool name从None改成ModelSim-Altera不同版本可能显示为ModelSim Intel FPGA或者Questa。旁边还有个Format下拉框选Verilog。这一步非常关键。如果你不在这里指定仿真工具等工程建好之后Tools - Run Simulation Tool - RTL Simulation这个菜单项就是灰色的点不了。很多新手在Quartus里找半天“仿真按钮”其实问题就出在这里——你根本没有告诉Quartus你要用哪个仿真器。设置好后点Finish完成工程创建。3.3 第一个设计文件4位计数器的Verilog实现工程建好后点击File - New - Verilog HDL File新建一个Verilog文件把下面的代码写进去module counter_test #( parameter WIDTH 4 )( input wire clk, input wire rst_n, output reg [WIDTH-1:0] q ); always (posedge clk or negedge rst_n) begin if (!rst_n) q {WIDTH{1b0}}; else q q 1b1; end endmodule这个模块的作用非常简单在时钟上升沿如果复位信号rst_n为低电平输出q清零如果复位无效q就加1。因为是4位计数器所以q的范围是0到15计数满了会自动回绕。保存文件时注意文件名必须和模块名一致也就是保存为counter_test.v否则编译时Quartus会报错找不到顶层模块。保存完成后把该文件添加到工程中。添加的方式有三种在Project Navigator窗口里右键Files选Add/Remove Files in Project或者在工程创建向导时直接添加也可以在Assignments - Settings - Files里添加。添加完毕后Project Navigator里应该能看到counter_test.v。3.4 编译检查先让Quartus帮你把关语法写好的代码先别急着仿真先做一次全编译确认语法没有问题。点击Processing - Start Compilation或者直接按CtrlLQuartus会进行分析和综合并生成下载文件。底部Messages窗口如果显示Full Compilation was successful说明代码没有语法错误工程链路也正常。有人会问我明明只是做仿真为什么还要先编译因为Quartus的完整编译过程包含Analysis Synthesis它本质上就是检查代码能否被综合成电路。很多低级错误比如端口名写错、模块名不匹配、括号不匹配在综合阶段就会被抓出来。先编译一遍相当于让Quartus帮你做一次免费的语法检查后面进ModelSim时就能少踩一半的坑。纯仿真其实不需要做全编译但如果你是从学习FPGA的角度出发每次写完代码先编译一次是很好的习惯。4. 手把手跑通ModelSim仿真从Testbench到波形查看4.1 Testbench到底是个什么东西很多新手第一次看到“Testbench”这个英文词就头大其实它就是一个用来“测试”你的设计模块的Verilog文件。打个比方你做了一台空调counter_test模块Testbench就是测试台它负责给空调接上电源时钟、按一下开关复位、然后观察空调吹出来的风是不是冷的检查输出q。Testbench和普通设计模块最大的区别是它通常不需要被综合成电路它只是仿真环境里的一段驱动代码。你可以把它理解成一段“剧本”规定好时钟怎么跳、复位什么时候拉高、仿真到什么时间点结束。它不需要对应任何实际硬件所以怎么写都行完全不考虑面积、时序这些物理限制。4.2 编写Testbench的核心要素在Quartus中再新建一个Verilog文件命名为tb_counter_test.v写入下面的Testbench代码timescale 1ns / 1ps module tb_counter_test; reg clk; reg rst_n; wire [3:0] q; // 例化被测试模块 counter_test uut ( .clk (clk), .rst_n (rst_n), .q (q) ); // 生成时钟信号周期20ns频率50MHz initial begin clk 0; forever #10 clk ~clk; end // 复位与仿真结束控制 initial begin rst_n 0; #100; rst_n 1; #1000; $finish; end // 可选在控制台打印仿真信息 initial begin $monitor(time%0t, rst_n%b, q%d, $time, rst_n, q); end endmodule这里有几个关键点需要解释timescale 1ns / 1ps声明仿真时间单位和精度。#10就代表10纳秒#100代表100纳秒。如果不写这一行很多仿真器会按默认时间单位处理可能出现你预期跑1秒结果它只跑了1纳秒的尴尬情况。forever #10 clk ~clk;用于产生无限翻转的时钟信号。它在0时刻先给clk赋0之后每过10ns翻转一次所以时钟周期是20ns。这个写法是仿真里生成时钟最常用的方式必须学会。两个initial块是并行执行的一个管时钟一个管复位。复位先拉低100ns让计数器清零然后释放复位让计数器开始正常计数。$finish用于结束仿真。如果忘了写ModelSim会一直跑下去有时候会让人觉得像卡死了。$monitor会在仿真过程中自动打印信号变化方便我们在Transcript窗口里直接看输出结果不用一直盯着波形图。4.3 调用ModelSim的两种方式自动和手动写好Testbench后剩下的就是让ModelSim跑起来。这里有两种方式我建议把两种都学会。第一种是通过Quartus的NativeLink自动调用第二种是手动打开ModelSim自己跑。自动方式的步骤是先把tb_counter_test.v文件添加到工程中然后在Assignments - Settings - EDA Tool Settings - Simulation里找到Compile test bench选项点击Test Benches按钮新建一个Testbench条目在File name中填tb_counter_test在Top level module in test bench也填tb_counter_test然后在File name那一栏把tb_counter_test.v添加进去。完成后点击Tools - Run Simulation Tool - RTL SimulationQuartus会自动调用ModelSim编译设计文件和Testbench打开仿真界面然后停在仿真时间0点。你只需要在ModelSim里添加波形、运行仿真即可。自动方式的好处是Quartus会自动处理设计文件、Testbench和IP的编译顺序不容易出错尤其是当你用到PLL、FIFO这些IP核时自动方式能帮你省去大量库配置工作。缺点是你得提前在工程设置里正确填Testbench信息否则Quartus不知道你要仿哪个文件。手动方式的步骤是打开ModelSim在Transcript窗口里敲命令或者通过菜单操作。最直接的方法是在ModelSim的菜单里选择File - New - Project新建一个工程然后添加counter_test.v和tb_counter_test.v两个文件接着点击Compile - Compile All。编译完成后Library窗口里会出现一个work库展开它能看到tb_counter_test模块。双击这个模块ModelSim会把它加载为仿真顶层。接下来在命令行输入add wave -position end sim:/tb_counter_test/*把所有信号加到波形窗口再输入run -all仿真就会自动跑完波形窗口里能看到结果。手动方式的核心命令我整理在下面以后你会经常用到vlib work vmap work work vlog counter_test.v tb_counter_test.v vsim work.tb_counter_test add wave -position end sim:/tb_counter_test/* run -all这五行命令的意思分别是创建work库、把work库映射为当前工作库、编译两个源文件、指定tb_counter_test为仿真顶层、添加所有信号到波形窗口、运行整个仿真。4.4 波形怎么看以计数器为例的验证方法仿真跑完后波形窗口应该能看到clk、rst_n、q三条信号。你看到的可能是一堆密密麻麻的波形不知道怎么验证对不对。先做这几步右键q信号选择Radix - Unsigned把q从二进制显示改成无符号十进制显示这样更容易读值。用波形窗口的缩放工具放大镜图标或者快捷键Ctrl滚轮把波形放大到能看到每个时钟周期的程度。用鼠标在波形上点击拖动光标到不同时间点查看q的值。正确的仿真结果应该是在刚开始0到100ns内rst_n为低电平q保持0100ns之后rst_n拉高每个时钟上升沿到来时q加1依次显示0、1、2、3……一直到15然后回绕为0。如果你看到的波形是这个规律恭喜你整个工具链已经跑通了。5. 波形变红不用慌红线问题排查与调试技巧5.1 “红线”到底是什么信号状态接触ModelSim后你会频繁看到一个现象波形窗口里信号不是我们熟悉的绿色表示0或者黄色表示1或高阻而是一条红色线交织着一些深浅不一的区域。红色在ModelSim中表示X状态也就是未知状态信号既不是0也不是1可能是电路里某个寄存器没有初始化也可能是信号压根没有被驱动。还有一种情况是蓝色或紫色线通常表示Z高阻状态多出现在三态总线上。很多新手一看到红线就慌觉得代码写错了。其实红线是仿真调试中最常见的信息它只是告诉你“这个信号此刻的值是未知的”你要做的是顺着信号往下追是没初始化的原因还是驱动源的问题还是连错线了。5.2 最常见的五个红线原因根据我自己的经验90%的红线问题都逃不过这五类第一Testbench里面没有给寄存器信号赋初值。比如你声明了reg clk; reg rst_n;但initial块里只写了rst_n 0;却忘记给clk赋初值结果时钟信号一直是X整个设计完全动不了。第二复位时间太短或者根本没有复位信号。如果你的设计依赖复位把寄存器清零但Testbench里始至终没有拉低过复位信号那所有寄存器上电后都是X状态计数器输出自然是一片红。第三忘记了例化DUT只写了一个空的Testbench模块。这种情况最哭笑不得你辛辛苦苦写了tb_counter_test结果里面只声明了一堆信号没有实例化counter_test模块那被测试模块当然是完全没有驱动信号全是X。第四时钟always或forever语句写错了。比如forever #10 clk clk;这种写法等于没翻转仿真只有静态电平或者把#10写成了#10ns而timescale又没有正确声明导致时钟频率偏离预期。第五仿真运行时间不够。你把#1000写成了#100仿真还没跑几个周期就结束了看起来像信号没有变化实际上只是时间太短。5.3 红线排查三步走遇到红线我建议按下面三步来排查效率最高。第一步看输入信号。把波形缩放到整个时间轴先检查clk和rst_n有没有正常翻转和跳变。如果clk根本没有波形那是Testbench时钟生成的问题如果rst_n一直是X那是复位初值的问题。输入信号都不对就不要浪费时间看后面的输出了。第二步看DUT的中间信号。把波形窗口里所有信号都加上尤其是DUT内部信号。在ModelSim里可以右键DUT的实例选择Add Wave把内部信号也拉出来看。如果输入正常、输出为X那问题大概率在DUT内部比如某个寄存器没有复位逻辑或者组合逻辑产生了X传播。第三步用force命令强制赋值。如果怀疑某个信号有问题可以在ModelSim命令行里直接输入force -freeze sim:/tb_counter_test/rst_n 0把复位强制拉低然后run 100ns看看信号有没有变化。如果强制赋值后波形能恢复说明是驱动源的问题如果强制赋值后依然是X那可能是信号本身存在多驱动冲突或者连接错误。5.4 几个能救命的ModelSim调试小技巧除了排查方法我再分享几个随手就能用上的小技巧。第一个是$display和$monitor在Testbench里加一句$display(time%0t q%0d, $time, q);仿真时Transcript窗口就会打印出q的实时值比看波形更直观。第二个是force命令仿真过程中可以随时强制某个信号等于指定值适合临时修改变量观察现象。第三个是configure wave -justify 0这类波形优化命令设置起来比较繁琐但能调整波形显示的可读性有兴趣可以查一下ModelSim帮助文档。我自己的习惯是新写的模块第一次仿真如果出现红线先不急着改代码而是打开Transcript窗口看有没有Error或WarningModelSim会在编译阶段提示大部分问题。如果编译没有报错但波形就是红的再用上面的三步走思路排查基本都能定位到原因。6. 把仿真流程工程化脚本、库配置和避坑清单6.1 用.do脚本固化你的仿真流程每次打开ModelSim都要手动敲vlib、vlog、vsim这些命令其实很烦而且容易敲错。更工程化的做法是把它们写到一个.do脚本文件里以后直接执行脚本就行。比如在工程目录下创建run_sim.do文件内容就是前面提到的那五行命令vlib work vmap work work vlog counter_test.v tb_counter_test.v vsim -voptargsacc work.tb_counter_test add wave -radix unsigned sim:/tb_counter_test/* run -all以后打开ModelSim在命令行输入do run_sim.do仿真流程全自动走完。注意这里我加了-voptargsacc参数它会让ModelSim在优化编译时保留所有信号的访问能力否则有些内部信号在波形窗口里可能看不到。用脚本的方式做仿真最大的好处是可复现不管三个月后还是三分钟后跑出来结果一样不用担心遗忘操作步骤。6.2 使用IP核时仿真库怎么配如果你后面开始用Quartus自带的IP核比如PLL锁相环、FIFO、RAM等仿真时就会涉及到仿真库的问题。原因很简单这些IP核本质上是对底层器件原语的封装仿真时需要对应的仿真模型和库文件。Quartus在生成IP核时通常会生成一个名为ip_name_sim的目录里面有仿真用的源文件同时会提醒你添加对应的仿真库比如altera_mf、altera_lnsim等。如果你用Quartus自动调用ModelSim的NativeLink方式这些库一般会被自动编译配置好不需要手动处理。如果你是自己打开ModelSim手动仿真就需要手动把这些库编译进ModelSim。具体方法是在ModelSim菜单里选择Tools - Compile Simulation Libraries然后选择Quartus安装目录下的对应库源文件路径让ModelSim自动编译生成带altera_mf等库名的库文件。这一步配置一次就能复用避免每次新建工程都重复操作。6.3 避开这几个常见的“低级坑”最后整理几个我见过无数人踩过的坑说多了都是眼泪。路径问题排第一。工程路径、Quartus安装路径、ModelSim工程路径任何一级都不能有中文最好不要有空格。我之前接过一个朋友的问题他工程建在D:\学习\FPGA\计数器下面Quartus编译没问题但ModelSim一打开就找不到模块最后改成纯英文路径才解决。时间尺度问题排第二。Testbench里的timescale一定要记得写而且建议统一写1ns / 1ps。如果写的是1ps / 1ps那#100只有100ps仿真1000个单位也才1微秒计数器当然看不到几个周期。复位极性问题排第三。我的示例代码用的是低电平复位rst_n所以Testbench里先拉低再拉高。如果你用的是高电平复位rst那Testbench里就必须反着写。这个看似简单但经常有人把复位极性搞反导致波形一直保持在复位状态或者完全不复位。文件名和模块名不一致的问题排第四。Verilog里文件名通常要求跟模块名相同尤其是在多文件工程里Quartus按文件名搜索模块不一致就会报错。养成“一个文件一个模块文件名等于模块名”的习惯能省很多事。7. 写在最后这套流程走通之后你会发现Quartus和ModelSim其实没有网上说的那么难难的是第一步不知从何下手。我自己带过不少新人发现大家最需要的就是一份能照着做的完整路线图而不是零散的知识点。这篇教程里的计数器只是个小例子但整个流程——新建工程、写RTL、写Testbench、配置仿真工具、跑ModelSim、排查红线——是完全可复用的。你后面做任何FPGA功能验证本质都是这套流程换了个模块名而已。最后分享一个我坚持了很多年的习惯每写完一个模块不管逻辑多简单都强迫自己先写一个对应的Testbench把最基本的功能跑一遍仿真再往下做。仿真比上板调试快得多也能提前发现大量隐藏问题。别嫌麻烦前期几十次的“麻烦”换来的是后面少掉几百次的头发。