从零到一:Quartus Prime 工程创建、IP核集成与 ModelSim 联合仿真实战指南

📅 发布时间:2026/7/6 18:27:49 👁️ 浏览次数:
从零到一:Quartus Prime 工程创建、IP核集成与 ModelSim 联合仿真实战指南
1. 从零开始搭建你的第一个Quartus Prime工程如果你是第一次接触FPGA开发看到Quartus Prime这个庞然大物可能会有点发怵。别担心我刚开始用的时候也是一头雾水感觉满屏的按钮和选项都不知道该点哪个。但说白了创建一个工程就像盖房子前先画好图纸、选好建材和施工队只要把这几步理顺了后面的事情就水到渠成。今天我就带你走一遍这个流程把我踩过的坑和总结出来的高效技巧都分享给你保证你跟着做一遍就能上手。首先你得把Intel Quartus Prime软件安装好。这个没什么好说的去Intel官网下载对应版本就行。我建议新手直接用最新的标准版功能全社区支持也好。安装路径千万不要包含中文或者空格这是很多奇怪错误的源头。我吃过亏有一次把软件装在了“D:\Program Files\FPGA 开发”这样的路径下结果编译IP核的时候各种库文件链接失败排查了半天才发现是路径惹的祸。所以老老实实用全英文路径比如“D:\FPGA_Projects”。安装完成后打开Quartus Prime我们正式开始。点击菜单栏的File - New Project Wizard这个向导会手把手带你完成工程创建。第一步是选择工程目录和名字。这里有个非常重要的习惯需要养成为每一个工程单独建立一个文件夹。我习惯的目录结构是这样的D:\FPGA_Projects\ ├── Project_1_Counter\ │ ├── source\ # 存放所有设计源文件 (.v, .sv) │ ├── ip\ # 存放生成的IP核文件 │ ├── simulation\ # 存放仿真相关文件 (testbench, .do脚本) │ └── output_files\ # 存放编译输出的网表、配置文件等 └── Project_2_UART\ └── ...在向导里把工程路径指向你新建的文件夹工程名就取一个有意义的名字比如“led_blink”。这样管理起来非常清晰以后工程多了也不会乱。第二步是添加已有文件。如果你是新建工程这里可以直接点“Next”跳过。如果你有一些现成的Verilog或VHDL文件要加入可以在这里添加。但根据我的经验更稳妥的做法是建好工程后再通过“Project Navigator”来添加这样能更好地控制文件在工程中的层次结构。第三步选择你的FPGA器件。这是关键一步你必须知道你用的是哪块开发板上面的FPGA芯片具体型号是什么。比如常用的Cyclone IV EP4CE6F17C8或者Cyclone 10 LP的10CL006。你可以在开发板的原理图或手册里找到。在“Device Family”里选对系列然后在“Available devices”列表里找到具体型号。如果实在不确定可以先选一个同系列引脚数差不多的型号但为了后续下载调试不出问题最好还是精确匹配。第四步设置EDA工具。这是我们后面进行联合仿真的关键在“EDA Tool Settings”页面找到“Simulation”这一栏。在“Tool name”下拉菜单里选择“ModelSim-Altera”如果你安装的是Intel和Mentor合作的特供版或者“ModelSim”。然后在“Format for output netlist”里通常选择“Verilog HDL”。最下面的“Run gate-level simulation automatically after compilation”可以先不勾我们更常用RTL级仿真。这里一定要设置对否则后面调用ModelSim时会报找不到可执行文件的错误。最后点“Finish”一个空白的Quartus Prime工程就创建好了。界面中间是代码编辑器左边是“Project Navigator”可以查看工程层次下方是消息窗口。虽然看起来有点复杂但我们目前只需要关注几个核心区域。2. 注入灵魂添加源代码与IP核工程架子搭好了接下来就要往里面填充内容了。FPGA设计的核心就是两部分你自己写的硬件描述语言代码以及Quartus提供的、已经封装好的功能模块也就是IP核。这两者结合能极大提高开发效率。2.1 编写与添加源代码我们先从最简单的开始写一个Verilog文件。在“Project Navigator”里右键点击工程名选择New - Verilog HDL File。一个空白的编辑器窗口就打开了。我们来写一个经典的LED闪烁模块作为例子module led_blink ( input wire clk, // 50MHz时钟输入 input wire rst_n, // 低电平复位信号 output reg led // LED输出 ); // 定义一个26位的计数器用于分频 (50MHz / 2^26 ≈ 0.75Hz) reg [25:0] counter; always (posedge clk or negedge rst_n) begin if (!rst_n) begin // 复位时计数器清零LED熄灭假设低电平点亮 counter 26d0; led 1b1; end else begin // 计数器累加 counter counter 1b1; // 取计数器最高位作为LED控制信号实现约1.5秒的闪烁周期 led counter[25]; end end endmodule写完后保存文件。我强烈建议你把它保存到之前规划好的source文件夹里文件名最好和模块名一致即led_blink.v。保存后这个文件并不会自动加入到工程中。你需要回到“Project Navigator”在“Files”上右键选择Add/Remove Files in Project...然后把你刚保存的.v文件添加进来。添加成功后你就能在“Project Navigator”的“Hierarchy”标签页下看到led_blink这个模块成为你设计的顶层模块了。2.2 集成强大的IP核很多时候我们不需要从零开始写所有代码比如PLL锁相环、RAM、FIFO、乘法器等常用模块Quartus都提供了优化过的IP核。使用IP核不仅能节省时间还能保证性能和资源利用的最优化。我们以添加一个PLL IP核为例它的作用是将板载的固定频率时钟如50MHz转换成我们需要的其他频率如100MHz、25MHz。点击工具栏上那个像魔法棒一样的图标“IP Catalog”或者在“Tools”菜单里选择“IP Catalog”。IP Catalog窗口打开后在“Library”选项卡下找到“Basic Functions” - “Clocks; PLLs and Resets” - “PLL” - “ALTPLL”。双击它会启动IP参数化向导。首先会弹出一个窗口让你选择IP核文件的保存路径和名称。这里我强烈建议你新建一个ip文件夹来统一存放所有IP核文件比如路径设为./ip/pll_clock。这样管理非常清晰也便于版本控制。接下来就是配置PLL参数了。第一个页面“General/Mode”选择你的器件系列和速度等级输入时钟频率比如50MHz。后续页面可以配置输出时钟的数量和频率。比如我们可以设置c0输出为100MHzc1输出为25MHz。每个输出时钟还可以独立设置相位偏移和占空比。配置过程中左边有图形化界面实时显示你的配置效果非常直观。所有参数设置完毕后点击“Finish”。Quartus会花一点时间生成这个PLL模块的封装文件。生成完成后它会问你是否要将生成的文件添加到当前工程一定要选“Yes”。这时你会在“Project Navigator”里看到新增了一个.qip文件Quartus IP File它包含了所有IP核的引用信息。同时在ip文件夹下你会看到一堆新生成的文件其中最关键的就是pll_clock.v或.vhd这就是我们可以在代码中直接实例化的PLL模块。现在我们需要修改顶层的led_blink模块使用这个PLL产生的时钟。假设我们用PLL的c0输出100MHz来驱动LED闪烁那么代码需要做相应调整实例化PLL并连接信号。2.3 第一次编译与排错代码和IP核都准备好后就可以进行第一次编译了。点击工具栏上那个蓝色的开始箭头“Start Compilation”或者按快捷键CtrlL。编译过程会执行分析综合、布局布线等一整套流程时间长短取决于设计复杂度和电脑性能。编译完成后重点关注下方的“Messages”窗口。如果有“Error”红色那必须解决否则设计无法进行。常见的错误有语法错误、模块名拼写错误、信号位宽不匹配等。更多的是“Warning”黄色。千万不要忽视Warning很多潜在的设计问题比如 latch 推断、信号未初始化、时钟域交叉警告等都会以Warning形式提示。比如我之前有一次把一个8位信号赋值给了7位寄存器Quartus没有报错但给出了一个“width mismatch”的警告结果仿真时数据完全对不上。所以养成习惯每次编译后都仔细阅读一遍Warning信息尽量消除它们。3. 仿真的艺术自动生成与修改Testbench硬件设计和软件编程最大的不同之一就是调试方式。我们不能像软件那样设个断点单步执行仿真Simulation就成了验证设计逻辑是否正确的最重要手段。而仿真的核心就是编写Testbench测试平台。好消息是Quartus可以帮我们自动生成一个Testbench框架省去了很多重复劳动。3.1 让工具为你打工生成Testbench模板要生成Testbench首先必须确保你的设计已经通过了编译没有Error。然后在“Processing”菜单里选择Start - Start Test Bench Template Writer。这个工具会扫描你的顶层模块分析其所有输入输出端口然后自动生成一个对应的Testbench模板文件。生成完成后它会提示你文件保存的位置。默认是保存在simulation/modelsim/目录下文件名是你的顶层模块名.vtVerilog Testbench。用任意文本编辑器或者Quartus自带的都行打开这个文件看看。你会发现它已经帮你定义好了测试模块module实例化了你的设计DUT Device Under Test并且将所有输入信号声明为reg类型输出信号声明为wire类型。最棒的是它还在一个initial块里为所有输入信号赋予了初始值通常是0。不过这个模板只是个架子里面的测试逻辑比如如何给时钟信号、如何模拟复位、如何施加特定的输入激励需要我们自己填充。这就是我们接下来要做的。3.2 编写有意义的测试逻辑我们打开自动生成的led_blink.vt文件。假设我们需要测试复位有效、以及LED是否能正常闪烁。我们需要修改initial块并添加一个时钟生成逻辑。timescale 1 ns/ 1 ns // 时间单位和精度很重要 module led_blink_vlg_tst(); // ... 端口声明部分由工具自动生成我们不用动 ... reg clk; // 测试时钟 parameter CLK_PERIOD 20; // 50MHz时钟周期为20ns // 实例化被测设计 led_blink i1 ( .clk(clk), .rst_n(rst_n), .led(led) ); // 生成时钟信号 initial begin clk 1b0; forever #(CLK_PERIOD/2) clk ~clk; // 每半个周期翻转一次产生方波 end // 主要的测试激励 initial begin // 初始化输入信号 rst_n 1b0; // 初始时复位有效 // 等待一段时间后释放复位 #100; rst_n 1b1; // 让仿真运行足够长的时间以观察LED的多次闪烁 #100_000_000; // 仿真100ms (以1ns为单位) // 结束仿真 $stop; end endmodule这段代码做了几件事1. 定义了一个50MHz的时钟。2. 一开始让复位有效rst_n0持续100ns后释放复位。3. 然后让仿真再运行100ms对于50MHz时钟这能看到很多个闪烁周期。4. 最后用$stop暂停仿真注意不是$finish$finish会直接结束Modelsim进程不便于观察波形。3.3 将Testbench纳入工程管理写好Testbench后我们需要告诉Quartus仿真时应该用这个文件。点击菜单Assignments - Settings在左侧找到EDA Tool Settings - Simulation。在“Test Benches…”按钮上点击会弹出一个对话框。点击“New…”输入Testbench的名字比如“led_blink_tb”然后找到你刚才修改好的led_blink.vt文件添加到“File name”里。在“Top level module in test bench”中填入测试模块的名字也就是led_blink_vlg_tst。你还可以在“Simulation period”里设置仿真运行时间。这些都设置好后点击“Add”然后“OK”。这样Quartus就知道在启动仿真时该调用哪个测试文件了。4. 强强联合配置Quartus与ModelSim联仿环境单独使用ModelSim仿真FPGA设计有个头疼的问题需要手动编译一堆Intel的器件库和IP核库过程繁琐易错。而Quartus和ModelSim的联合仿真NativeLink功能就是来解决这个痛点的。它让Quartus在后台自动帮我们处理好所有库的编译和映射我们只需要一键启动就能在ModelSim里看到仿真波形。4.1 路径配置打通任督二脉要让这两个软件协同工作首先得让Quartus知道你的ModelSim装在哪里。回到Assignments - Settings - EDA Tool Settings - Simulation页面。在“Tool name”里确认选的是“ModelSim-Altera”或“ModelSim”。然后最关键的一步在“EDA Netlist Writer settings”下面找到“More EDA Netlist Writer Settings…”这个超链接字很小容易忽略点进去。在弹出的窗口里我们需要添加一个选项。在“Option”栏输入GHDL_SIMULATION在“Setting”栏输入FALSE这是针对VHDL的我们主要用Verilog。更重要的我们需要设置ModelSim的安装路径。虽然新版本有时能自动识别但手动设置更保险。添加一个选项Option填MODELSIMSetting填你的ModelSim可执行文件modelsim.exe或vsim.exe所在的完整路径。例如C:\intelFPGA_lite\18.1\modelsim_ase\win32aloem。注意路径不要有中文和空格结尾也不要加反斜杠。网上有些老教程让加反斜杠在新版本里反而可能导致问题。4.2 一键启动仿真与初识波形环境配好了现在开始激动人心的仿真。点击菜单Tools - Run Simulation Tool - RTL Simulation。Quartus会先后台运行一系列操作编译你的设计、编译Testbench、编译所需的器件库、生成仿真模型、启动ModelSim、加载设计、运行仿真脚本。一切顺利的话ModelSim会自动打开并弹出一个波形窗口Wave。第一次打开波形窗口里可能只有Testbench顶层的一些信号。我们需要把真正要观察的信号也就是我们设计的led_blink模块内部的信号加进来。在ModelSim左侧的“sim”标签页仿真库视图你可以看到仿真的层次结构。通常最顶层是你的Testbench模块led_blink_vlg_tst展开后能看到被实例化的设计i1也就是我们的led_blink。点击这个i1实例中间的“Objects”窗口就会列出这个模块内部的所有信号clk,rst_n,led,counter。用鼠标选中你想要观察的信号可以按住Ctrl多选然后右键选择“Add Wave”。或者更快捷的方式直接把这些信号从“Objects”窗口拖拽到右边的“Wave”窗口里。信号添加后波形窗口里还看不到波形因为仿真还没运行。点击工具栏上那个像播放键的蓝色三角形“Run -All”或者直接在Transcript窗口输入命令run -all。仿真就会一直运行直到遇到我们Testbench里的$stop语句为止。这时你就能在波形窗口里看到漂亮的信号波形了可以看到clk在规律跳动rst_n从低变高后counter在不断增加led随着counter的最高位在缓慢翻转。这就证明我们的设计基本功能是正确的。5. ModelSim实战高效调试与波形管理看到波形只是第一步如何高效地分析波形、定位问题才是仿真调试的核心技能。ModelSim的波形窗口功能非常强大掌握几个小技巧能让你事半功倍。5.1 波形查看与格式调整技巧刚运行完仿真波形可能缩在一起看不清。快捷键F可以自动缩放让所有波形完整地显示在当前窗口范围内。如果你想看某个信号跳变附近的细节可以在波形上点击某个时间点然后按快捷键C视图就会以光标所在位置为中心进行显示。默认的信号显示格式是二进制Binary对于像counter这种多位宽的寄存器看二进制数很不直观。你可以右键点击波形图中的counter信号选择“Radix” - “Unsigned”无符号十进制或“Decimal”有符号十进制。这样counter就会显示成我们熟悉的数字方便观察其累加过程。对于像led这样的单比特信号除了高低电平还可以用“总线图”形式显示。右键点击led信号选择“Format” - “Analog”。你可以选择“Automatic”ModelSim会自动根据信号高低电平的电压值来显示一个模拟波形或者选择“Custom”自己设定“0”和“1”对应的显示高度。这种显示方式在观察时钟、使能等周期性信号时尤其清晰。当信号很多时波形窗口会显得杂乱。你可以对信号进行分组。比如把clk和rst_n归为“控制信号”组把counter和led归为“数据信号”组。按住Ctrl选中多个信号右键选择“Group” - “Create Group…”输入组名即可。更高效的是使用快捷键CtrlGModelSim会自动根据信号的来源层次如来自哪个模块实例进行分组这是我非常喜欢的一个功能。5.2 保存与加载波形配置省时省力调试一个复杂模块时我们可能会添加几十个信号设置好各种显示格式和分组。如果每次重启ModelSim都要重新操作一遍那就太痛苦了。ModelSim提供了保存波形配置的功能。当你把波形窗口调整到满意的状态后在波形窗口为当前焦点时按快捷键CtrlS会弹出一个保存对话框。默认的文件名是wave.do你可以改成更有意义的名字比如led_blink_wave.do并把它保存到工程的simulation文件夹下。这个.do文件实际上是一个Tcl脚本里面记录了你所有的“add wave”命令和格式设置命令。下次当你重新打开ModelSim运行仿真后不需要手动添加信号。只需要在Transcript窗口输入命令do led_blink_wave.do或者使用菜单File - Load - Macro File...来加载这个.do文件。之前保存的所有信号和格式就会瞬间恢复简直不要太方便这里有个小坑要注意加载.do文件是在当前波形窗口的基础上“追加”信号。如果你之前波形窗口里有其他信号会混在一起。我习惯的做法是在加载新配置前先在波形窗口里按CtrlA全选所有信号然后按Delete键清空然后再加载我的.do文件。5.3 设计修改后的迭代仿真流程开发过程中修改代码是家常便饭。修改了Verilog设计文件后如何快速看到新的仿真结果呢最“干净”的方法是关闭当前的ModelSim回到Quartus重新编译整个工程因为RTL代码变了然后再点击RTL Simulation。Quartus会重新启动ModelSim并运行仿真。但如果你只是微调了Testbench比如改变了测试激励的时序或者只修改了非关键的代码有一个更快捷的方法在ModelSim里直接重新编译和运行。首先在ModelSim的“Project”标签页找到你修改过的.v或.vt文件右键选择“Recompile”。如果修改的是设计文件你可能需要重新编译整个设计库有时右键点击最顶层的库名选择“Recompile All”更稳妥。编译成功后在Transcript窗口输入两个命令restart和run -all。restart命令会将仿真时间重置为零并清除之前的波形数据但不会清除波形窗口中已添加的信号列表。然后run -all开始新一轮仿真。仿真结束后波形窗口会自动更新为新一次的仿真结果。你可以和之前保存的波形文件进行对比快速验证修改是否达到了预期效果。这个“修改-编译-重启-运行”的循环非常高效是FPGA开发调试中的日常操作。熟练掌握这个流程能让你在调试中保持思路的连贯性快速定位和解决问题。记住仿真的目的不是看到波形而是通过波形验证你的设计思想是否正确每一个信号的变化是否符合你的预期。养成边仿真、边思考、边对比的好习惯你的硬件设计能力才会真正扎实起来。