很多朋友装完 Quartus Prime Lite Edition,双击图标之后对着界面能愣十分钟——新版界面和网上搜到的那些 Quartus II 老教程完全对不上,工具栏密密麻麻的英文按钮,新建项目的入口找了半天才摸到,结果进了向导又不知道该勾什么、跳过什么。这篇我用自己的实际流程,把 Quartus Prime Lite Edition 从新建项目到 ModelSim 仿真的完整过程捋一遍,以 Cyclone IV 开发板为例,Cyclone V、MAX 10、Cyclone 10 LP 这些学习常用的器件操作完全一致。内容适合刚装好工具、还没跑通第一个仿真的初学者,也适合从老版本 Quartus II 迁移过来的朋友,照着一步步操作就能看到波形。
1. 把话说在前面:Lite Edition 和 ModelSim 的搭配逻辑
1.1 免费版不是“残废版”,先搞清楚它能干什么
Quartus Prime Lite Edition 是 Intel 在 Quartus II 基础上改版推出的免费工具,很多人一看“Lite”这个词心里就打鼓,觉得功能被砍得没法用。实际上对学习、竞赛、毕业设计这个量级的 FPGA 开发来说,它支持的范围完全够。Lite 版支持 Cyclone IV、Cyclone V、Cyclone 10 LP、MAX 10、MAX V 这些教学和 DIY 圈最常见的器件家族,市面上绝大多数开发板用的芯片都在这个列表里。Standard 版和 Pro 版支持的 Arria、Stratix、Agilex 这些高端系列,初学者基本碰不到。
所以选型这件事不用纠结:官方免费渠道能下载、能正常安装、能长期更新的版本,就是 Lite 版。而且它的授权方式也很干脆,装完不需要 License 文件,不需要额外激活,工具本身就能直接用。这点对刚入门的同学特别重要,少一个环节就少一个坑。
我还想多啰嗦一句:网上搜“ModelSim 破解”“ModelSim 激活”之类关键字,会出来一堆来路不明的安装包和注册机,真的别碰。Quartus Prime Lite 安装包里自带的 ModelSim Intel FPGA Starter Edition 就是免费的,功能上和商业版的核心能力基本一致,仿真 Verilog 和 VHDL 都没有问题,只是仿真性能以及个别高级调试特性有一些限制。对个人学习来说绰绰有余。折腾破解版既浪费时间,又容易引入安全风险,没必要。
1.2 版本匹配是第一道隐形坑
这是我见过初学者踩得最多的一处。Quartus Prime 的安装程序和 ModelSim 是组件关系,不是两个完全独立的软件。你下载 Quartus Prime Lite 的安装包之后,在安装界面勾选组件时,一定要留意里面有没有选上 ModelSim(具体名称一般是 ModelSim Intel FPGA Starter Edition)。安装包默认会勾上,但如果你手快把组件列表里的东西全取消了,后面想补装就麻烦一些。
还有个常见问题是版本错位。如果你电脑里已经装了一个 ModelSim SE 或者别的版本,然后又在 Quartus 的仿真设置里手动指到了那个路径,经常会出现启动仿真时打不开,或者打开后编译报错的情况。最稳妥的做法就是:用 Quartus Prime Lite 安装时自带的那个 ModelSim 组件,路径也让它自己配好。不同版本之间的兼容性虽然 Intel 官方一般有保证,但自己手动混搭版本,一旦出问题就很难判断是设计的问题还是工具环境的问题。
另外,Quartus Prime Lite 加上 ModelSim 全部装完,磁盘占用大约十个 G 起步,安装时间也比较长。装的时候耐心点,不要把安装窗口关了,也别边装边去打开其他大型软件,我遇到过安装过程中磁盘空间不足导致组件缺失的情况,后面排查起来很烦。
1.3 打开 Quartus 后先认识这几个地方
新版 Quartus Prime 的界面和老的 Quartus II 差别确实不小。最显眼的左边是 Project Navigator 面板,里面分了 Hierarchy、Files、Design Units 等几个标签页;中间是主工作区,显示器件视图或者代码编辑器;下方是 Messages 窗口,编译信息、错误提示都在这;最上面是菜单栏和工具栏。工具栏上最常用的就是那个开始编译的按钮,以及启动 RTL Simulation 的入口(在 Tools 菜单里),这两个后面都会用到。
第一次打开可能还会弹出一个欢迎页,可以关掉,不影响流程。版本之间小界面可能会有细微差别,但核心菜单和操作顺序基本是固定的,这篇文章里提到的按钮名称,你在 20.x、21.x、23.x 这些常见版本里都能找到。
2. 新建项目时最关键的三个设置
2.1 工程名和目录:别用中文路径
新建项目是从 File -> New Project Wizard 开始的(新版首页一般也有 New Project 按钮,点进去就是同一个向导)。第一步要填 Directory、Name 和 Top-Level Entity。这里有个非常容易忽略的细节:工程路径里绝对不能有中文,也最好不要有空格。ModelSim 在后台调用编译器时对路径比较敏感,路径里有中文会导致编译阶段莫名其妙报错,而且报错信息往往不直观,让人排查半天。
Top-Level Entity 默认会跟着工程名走,一般保持默认就行,但你要清楚这个字段表示的是顶层模块的名字。这个顶层模块必须和工程里实际存在的模块名一致,如果后面你写了模块叫 counter4 但顶层实体名还是别的,编译会直接报错。
2.2 器件选择:看开发板丝印,别瞎猜
向导中间有一个 family 和 device 选择的步骤。很多人在这一步卡住,不知道该选什么芯片。最简单的解决办法:看开发板上的芯片丝印。以常见的 Cyclone IV 开发板为例,板子上最大的那颗芯片上会印着类似 EP4CE10F17C8 这样的型号,你在器件选择界面的 Search 输入框里直接输入型号的一部分,或者先选 Family 为 Cyclone IV E,再在型号列表里找对应的封装和速度等级。
如果你用的板子是官方开发板或者某个大厂出的板卡,还可以在向导里选择开发板套件。不过对大多数学习场景来说,手动选具体芯片型号更可靠,因为兼容板太多,套件列表里不一定会收录。这一步选错的话,后面的引脚分配和编译都会有问题,所以下板之前一定确认好芯片型号。
2.3 EDA Tool Settings:在这里告诉 Quartus“仿真用 ModelSim”
很多初学者新建完项目就开始写代码,写完才发现仿真工具没配置。Quartus 里要通过 Assignments -> Settings -> EDA Tool Settings 找到 Simulation 这一栏,然后把 Tool name 选成 ModelSim Intel FPGA,Format 选 Verilog,这样才能用 RTL Simulation 一键把 ModelSim 拉起来。
这里有一处重点:如果你希望 Quartus 启动 ModelSim 时自动编译你的 testbench,就得在 Simulation 选项卡里勾选 Compile test bench,然后在 Test Benches 弹窗里点 New,填上 test bench name、顶层模块名,再添加对应的 .v 文件。这一步很多教程没讲透,导致不少人进了 ModelSim 之后发现没有仿真模块可用。我建议初学者从一开始就按这个规范来:设计文件放工程里,testbench 通过 Compile test bench 配置好,让工具帮你自动编译。
3. 从计数器开始:一个能完整跑通仿真的设计
3.1 为什么第一个仿真实例选计数器
计数器是 FPGA 入门最能说明问题的设计:有时钟输入,有异步复位,有寄存器输出,还能用波形直观看到数值变化。你不需要理解复杂协议,也不用关心状态机怎么写,把代码敲进去、编译通过、仿真看到波形,这一整套流程就闭环了。等这个最简单的流程跑通,后面写状态机、写通信协议时,遇到问题也知道去哪里排查。
3.2 先写一个 4 位计数器
用 Verilog 描述一个 4 位计数器,逻辑上就三件事:时钟上升沿触发、复位时清零、否则每个周期加一。完整的模块代码如下:
module counter4 ( input wire clk, input wire rst_n, output reg [3:0] count ); always @(posedge clk or negedge rst_n) begin if (!rst_n) count <= 4'd0; else count <= count + 1'b1; end endmodule这里有几个细节值得展开说一下。rst_n是低电平有效的异步复位信号,所以敏感列表里用negedge rst_n,if 里判断!rst_n。count在always块里被赋值,所以声明为reg,但它的实际硬件是一个寄存器,不是软件概念里的变量。<=是非阻塞赋值,在时序逻辑里必须用,这个看起来不起眼的写法,用成=会导致仿真行为完全不一样。
3.3 编译之前先想清楚一件事
代码写完之后,建议先点击 Processing -> Start Analysis & Synthesis,也就是只做分析和综合,快速检查语法和基本连接关系,而不要一上来就 Start Compilation。Start Compilation 是全流程综合加布局布线,虽然也可以,但对第一次跑通流程的人来说,Analysis & Synthesis 的反馈更直接,报错也容易定位。如果编译通过,Messages 窗口会给出零错误零警告,哪怕有 warning 也别慌,很多 warning 只是提醒你没有约束时序,初期不影响仿真。
如果编译报错,最常见的有几种可能:模块名和文件名不一致、顶层实体设置错误、endmodule 没写或者多写、信号位宽不匹配。这类错误信息都比较明确,顺着报错行号去看就行。
3.4 用 RTL Viewer 检查连接关系
Analysis & Synthesis 通过之后,可以顺手打开 RTL Viewer 看一下工具生成的原理图。路径是 Tools -> Netlist Viewers -> RTL Viewer。这一步强烈建议做一次,它能把你的代码翻译成寄存器传输级的电路连接,让你直观看到 clk、rst_n、count 之间的关系,也能验证代码里端口连接有没有意图之外的结果。我第一次看 RTL Viewer 的时候,发现工具把某些信号合并了,这才理解综合器会做优化,和预想的不完全一样。
4. Testbench 的写法:先给仿真器一个“激励剧本”
4.1 Testbench 和设计代码的本质区别
Testbench 在英语里直译是“测试台”,它和真正烧到 FPGA 里的设计代码是两套东西。设计代码要能被综合成硬件电路,所以里面不能写initial、不能写forever,这些语句在综合时没有对应的硬件结构。但 testbench 恰恰相反,它跑在仿真器里,目的就是产生时钟、复位、数据这些激励,所以可以随意使用initial和forever,完全不用考虑能不能综合。
理解这个区别很重要,因为很多初学者会把 testbench 里的initial写到设计代码里,然后综合时报一堆语法错误。记住一句话:设计代码写给硬件看,testbench 写给仿真器看。
4.2 时钟和复位信号怎么产生
Testbench 里最基础的三件事是:初始化信号、生成时钟、生成复位。时钟生成最常见的写法是:
initial begin clk = 1'b0; forever #10 clk = ~clk; end#10表示延迟 10 个时间单位,forever让时钟每 10 个单位翻转一次,周期就是 20 个时间单位。配合开头的timescale 1ns / 1ps,相当于每隔 10ns 翻转一次,得到一个 50MHz 的时钟。复位生成则更简单,先把复位拉低一段仿真时间,再拉高释放:
initial begin rst_n = 1'b0; #100; rst_n = 1'b1; end这里要注意顺序:clk和rst_n必须都要在 initial 块里赋初值。如果只写rst_n = 1'b0而忘记给clk赋初值,仿真的波形里clk就是 X 态(红色),整个仿真结果都会受影响。这是 ModelSim 波形改成红线的头号原因,后面专门说。
4.3 一份完整的 Testbench 代码
把前面提到的元素拼起来,再实例化待测模块 counter4,一份完整的 testbench 长这样:
`timescale 1ns / 1ps module counter4_tb; reg clk; reg rst_n; wire [3:0] count; counter4 uut ( .clk (clk), .rst_n (rst_n), .count (count) ); // 时钟:50MHz,周期 20ns initial begin clk = 1'b0; forever #10 clk = ~clk; end // 复位:先拉低 100ns,再释放 initial begin rst_n = 1'b0; #100; rst_n = 1'b1; end // 仿真到 600ns 时停止 initial begin #600; $stop; end endmoduleuut是 Unit Under Test 的缩写,这是业内通用的命名习惯。端口连接用的.clk(clk)这种写法叫名字例化,比位置例化安全得多,不会因为信号顺序写错导致连接错乱。最后的$stop是告诉仿真器在这里暂停,方便你打开波形查看;如果用$finish则直接结束仿真。
5. ModelSim 波形出炉:从启动到红线排查
5.1 一键启动 RTL Simulation 背后发生了什么
代码和 testbench 都准备好了,设置里也配好了 Compile test bench,下一步就是点 Tools -> Run Simulation Tool -> RTL Simulation。这时候 Quartus 会在后台自动调用 ModelSim,并传入一个根据当前工程生成的 do 脚本。这个脚本会自动把所有设计文件和 testbench 编译进 work 库,然后打开 ModelSim 界面。所以你会看到 ModelSim 启动后 Transcript 窗口里已经有一堆日志滚动,这一步是自动完成的,不需要你手动去 add file、compile。
等日志滚完,ModelSim 的 Library 标签页里 work 库下面会出现 counter4_tb 这个编译单元,Sim 面板里可以看到你加载的仿真对象。如果你之前没有勾选 Compile test bench,此时 work 库里只有设计模块,没有 testbench,那么你就得手动在 ModelSim 里编译 testbench 文件,步骤就繁琐了。这也是前面建议在 Settings 里配置 testbench 的原因。
5.2 把信号加进 Wave 窗口
ModelSim 打开后默认不一定会显示波形窗口,需要手动调出来。菜单栏 View -> Wave 打开 Wave 窗口,然后在 Sim 面板中选中counter4_tb下的uut实例,右键 Add Wave,选择 All Items in Region,就能把 counter4 内部的所有信号(包括 clk、rst_n、count)全部添加进去。你也可以同时选中 testbench 层级的 clk、rst_n,方便对照激励和输出的关系。
如果仿真已经跑完,Wave 窗口是空的,只要运行仿真后,添加的信号就会出现在波形窗口里。这里有个小技巧:先添加信号再 run,波形窗口会随着仿真自动刷新,观感上更流畅。
5.3 设置仿真时间并运行
ModelSim 默认的 run 长度是 100ns,可以在 Wave 窗口工具栏的 Run Length 输入框里改动,也可以直接在 Transcript 命令行输入run 600ns或者run -all。因为 testbench 里写了#600; $stop;,用run -all会在 600ns 处自动停下来。
运行结束后,你应该能看到这样的波形:刚开始 100ns 内rst_n是低电平,count保持 0;rst_n拉高之后,每个clk上升沿count加一,从 0 一直加到 15,然后回卷到 0 继续循环。看到这个波形,恭喜你,Quartus 到 ModelSim 的整条链路已经通了。
5.4 红线问题深度排查:为什么波形是红线
“ModelSim 仿真波形是红线”几乎每个初学者都遇到过,我把它单独拿出来讲。ModelSim 默认用红色表示 X 态,也就是未知态。X 态在 HDL 仿真里是一种特殊值,它不代表 0 也不代表 1,而是“不知道”。仿真器不会像真实硬件一样给寄存器一个确定的初值,所以你的计数器和信号在仿真刚开始时统统都是 X。
如果你是照着上面 testbench 写的,那大概不会看到红线,因为clk和rst_n都做了初始化。但如果你的 testbench 里漏了某个 reg 的初始化,或者你的设计模块里某个寄存器没有复位逻辑,就会出现一整片红线或者红白相间的波浪线。排查顺序我建议这样:
- 第一步,检查 testbench 里所有 reg 是否都在 initial 里赋了初值。漏了 clk 最常见的现象就是 clk 一直是红线。
- 第二步,检查设计模块里的寄存器是否有复位逻辑,复位信号是否在 testbench 里被正确拉高。如果复位释放之前看波形,count 是 X 也算正常,但复位释放后应该立刻变为 0。
- 第三步,检查例化时端口名字是否对得上。端口漏连或者名字拼错,对应信号就会一直 X 或者 Z。
- 第四步,如果以上都没问题,试着把仿真时间拉长,比如
run 10us。有时候你只跑了 100ns,而复位释放后的第一个时钟边沿恰好在你观察窗口之外,看起来就像没有输出。
6. 仿真跑不通时的高频问题与解决顺序
6.1 找不到 ModelSim 或者路径不对
点了 RTL Simulation 之后没有任何反应,或者弹窗提示找不到 ModelSim,十有八九是路径设置没对上。回到 Assignments -> Settings -> EDA Tool Settings -> Simulation,检查 Tool name 是不是 ModelSim Intel FPGA,同时看下方有没有 ModelSim 的可执行路径。正常情况下 Quartus 会自己识别安装路径,但如果你的 ModelSim 组件是后补装的,或者安装路径改过,这里就需要手动指一下。路径一般在C:\intelFPGA_lite\xx.x\modelsim_ase\win32aloem\modelsim.exe这样的位置,具体看你的安装根目录。
6.2 编译报错:大部分集中在语法和模块名
ModelSim 编译报错有好几种常见体型。cannot find module counter4这类错误,说明 testbench 里例化的模块名和设计代码里的模块名不一致,或者设计文件没有成功编译进 work 库。如果 Quartus 的 Compile test bench 设置里只添加了 testbench 文件而没添加设计文件,就会出现这个问题。解决办法是在 Test Benches 窗口确认设计文件也被工程包含,或者检查例化名拼写。syntax error类错误更简单,顺着报错行号去改语法就行,最常见的是缺分号、endmodule 忘写。
还有个容易忽略的场景:如果 testbench 文件也作为普通工程文件加入了项目,并且被设为了顶层,Quartus 在综合时会尝试综合 testbench,而 testbench 里的initial和forever不可综合,会报一堆难以理解的问题。遇到这类情况,打开 Settings -> General,确认 Top-Level Entity 是设计模块而不是 testbench,这才是正确姿势。
6.3 改了代码但仿真结果还是老样子
这个现象特别迷惑人。你在设计模块里改了逻辑,重新点 RTL Simulation,结果 ModelSim 里看到的波形和上次一模一样,好像改动没生效。其实原因往往是 Quartus 的编译流程没有重新跑,或者 ModelSim 打开的还是旧的编译结果。解决办法是在 Quartus 里先重新执行 Analysis & Synthesis 或 Start Compilation,再启动 RTL Simulation。如果仍然不对,在 ModelSim 里执行一次 clean 操作,把 work 库里旧的编译产物清掉再重新编译。
我个人的习惯是:每次改完设计代码,先在 Quartus 里编译一遍,再启动 RTL Simulation,这样能保证 ModelSim 得到的是最新代码。这个看似简单的顺序,能避免很多“改了没用”的假象。
6.4 功能仿真走通后,要不要碰时序仿真
RTL Simulation 属于功能仿真,它只验证逻辑功能是否正确,完全不包含布线延迟和器件内部延迟。对计数器、状态机、接口逻辑这类的学习项目,功能仿真已经完全够用。不过你要知道 Quartus 还提供了另一种仿真:Gate Level Simulation(门级仿真),也就是时序仿真。它在完整编译和布局布线之后,把路径延迟信息带进仿真,能验证时序是否满足要求。
时序仿真需要单独配置仿真库,过程中会涉及.vo网表文件和.sdo时序文件,如果设置不当很容易报错。我的建议是:初学阶段别一上来就啃时序仿真,先把 RTL 仿真波形看懂,把 testbench 写熟练,这才是 FPGA 调试的基本功。等你后面用到 PLL、DDR 这类对时序敏感的功能时,再回头研究时序仿真,那时候你会感谢自己已经能熟练编写各种激励了。