1. 内容整体设计与思路拆解1.1 为什么选择Modelsim SE 2020.4而不是其他版本先说结论如果你打算在FPGA入门阶段踏实学仿真Modelsim SE 2020.4是一个性价比非常高的选择。它稳定、易上手、资料多最关键的是它支持SystemVerilog和VHDL混合仿真能覆盖从组合逻辑到复杂状态机的大部分验证需求。很多朋友会问为什么不直接装Vivado或Quartus自带的仿真器这就要说到FPGA开发中的一个现实问题了——集成开发环境自带的仿真器比如Vivado的xsim虽然方便但调试体验和波形查看能力确实不如专业的独立仿真工具。Modelsim的波形界面、信号分组、断点调试、覆盖率分析等功能在入门阶段能帮你节省大量排查逻辑错误的时间。另外2020.4这个版本相对特殊它既不像2019.x那样在部分新CPU上存在兼容性问题也不像2022.2那样对旧工程的文件结构要求苛刻。实测下来SE-64 2020.4在Win10和Win11系统上运行都非常稳定配合Quartus Prime 20.1和Vivado 2020.2都能实现联合仿真。换句话说你不需要为了匹配不同厂商的FPGA工具链而装多个版本的Modelsim这一个版本基本通吃。1.2 安装破解的整体思路license授权机制的原理在动手安装之前有必要先把破解这件事的原理讲清楚否则你遇到问题时会一头雾水。Modelsim SE采用FlexNet授权机制简单来说就是软件本身可以正常安装但没有合法的License文件启动时会提示License checkout failed之类错误。所谓破解本质上就是做两件事第一用特定的工具生成一个本机的License文件第二通过环境变量告诉软件去哪个路径读取这个文件。很多第一次接触的朋友会误以为破解是修改软件主程序或者绕过验证其实不是。你只需要把mgls.dll和mgls64.dll这两个文件替换掉再配置好MGLS_LICENSE_FILE环境变量指向你生成的License文件路径软件就会认为你拥有一份合法的授权。理解了这个机制后面不管装哪个版本思路都是一套。整个安装流程我用一句话概括装软件不急着破解先把环境变量想清楚再把License文件放到位最后验证。1.3 这篇文章能帮你解决什么问题我把这次的内容定位成一篇从零到能跑仿真的完整实战记录重点覆盖三块第一安装与激活的完整步骤每一步都告诉你为什么这么做第二以UART_RX接收模块为例演示从新建工程到波形输出的仿真全流程第三把我在实际使用中踩过的坑、以及新手问得最多的问题整理成一个速查表方便你以后排查。如果你目前正卡在Modelsim装好了但仿真波形是红线不知道为什么仿真没输出License老激活失败这类问题上这篇文章应该能直接对症下药。2. 核心细节解析与实操要点2.1 安装前的环境准备与版本选择建议先说系统要求。Modelsim SE 2020.4官方支持Windows 10 64位系统实测Windows 11 64位下运行也没有问题。需要注意的是路径中尽量不要出现中文和空格我见过不少初学者把软件装在D:\软件\Modelsim下面后续在编译和仿真时经常出现莫名的路径错误。安装之前建议先关闭杀毒软件和Windows Defender的实时防护。这不是什么必须绕过安全机制的操作而是因为FlexNet的授权工具会生成注册表项和本地服务部分杀毒软件会把授权相关的dll文件误判为风险程序并直接隔离导致激活后打开软件仍然报错。如果装完才发现dll被隔离了恢复起来比较麻烦。另外要强调一点Modelsim SE和Modelsim DE、Modelsim Intel FPGA Edition也就是OEM版虽然界面长得一模一样但授权机制和功能范围是有差异的。SE版是完整功能版支持SystemVerilog、VHDL、混合仿真Intel FPGA Edition只能配合Quartus使用比如你在Quartus里跑的ModelSim-Altera就属于这类。如果你只是为了学习FPGA仿真SE版是首选如果你主要用Quartus做工程也可以直接用OEM版但本文中的授权方法只适用于SE版。2.2 安装过程的详细步骤拆解拿到安装包之后你会看到一个自解压的exe文件。双击后它会先解压到临时目录然后弹出安装向导。这里有几个细节值得注意第一选择安装路径时建议直接装在根目录下比如D:\modelsim_2020.4不要套多层目录。第二到了选择License类型的界面时选择Single User License然后点击Browse手动指定License文件位置。虽然这时候你还没有License文件但不要担心后面我们会补上。第三安装过程中会提示是否创建桌面快捷方式和开始菜单项建议都勾上方便后续快速启动。安装完成后先不要急着打开软件直接打开肯定会报错这是正常现象。此时我们需要先完成授权配置再启动Modelsim。2.3 破解激活的完整流程与环境变量配置这里我详细写一下我自己的操作流程按步骤来基本一次通过。第一步找到安装目录下的win64文件夹比如D:\modelsim_2020.4\win64。确认里面有mgls.dll和mgls64.dll两个文件后面替换时会用到。第二步用授权工具生成License文件。注意这里生成License文件时需要填网卡的MAC地址。怎么查打开命令行WinR输入cmd然后在命令行中输入ipconfig /all找到物理地址一栏把类似1A-2B-3C-4D-5E-6F的字符串记下来。生成License文件时将MAC地址中的横杠去掉填成1A2B3C4D5E6F的格式。第三步把生成的License.dat文件放到一个固定目录比如D:\modelsim_2020.4\license\这个路径后续会用到。第四步替换mgls.dll和mgls64.dll。建议先把原来两个文件复制备份到一个子目录里再把破解工具中的两个文件复制过去覆盖。第五步设置环境变量。在此电脑上右键进入属性选择高级系统设置点击环境变量在系统变量区域点击新建变量名填MGLS_LICENSE_FILE变量值填License文件的完整路径比如D:\modelsim_2020.4\license\license.dat。注意有些教程会让你填1800localhost这种格式那是针对服务器版License的方式本地文件授权用路径即可。第六步重启电脑或者重启一次资源管理器让环境变量生效。然后就可以启动Modelsim了。注意如果启动后弹出对话框提示Unable to checkout a license先检查三件事环境变量是否生效在命令行输入echo %MGLS_LICENSE_FILE%看输出是否正确License文件中的MAC地址是否填错mgls64.dll是否被杀毒软件隔离了。按这个顺序排查90%的问题能解决。3. 实操过程与核心环节实现以UART_RX接收仿真为例3.1 为什么要拿UART_RX做第一个仿真工程很多教程喜欢用计数器或者LED灯做例子但我觉得对于入门仿真UART接收模块才是最合适的练手项目。原因有三第一UART是串行通信的基础无论是调试传感器、连接WiFi模块还是与PC交互几乎每个嵌入式项目都会碰到学完就能用第二UART接收涉及时钟分频、数据采样、边沿检测、状态机跳转这些核心数字逻辑知识仿真时你能直观地看到每一个时钟周期数据的变化过程第三它的波形内容丰富能看到串行数据在一条信号线上逐位移动的过程非常有利于建立时序的直觉。3.2 新建工程、添加源文件与Testbench编写打开Modelsim后界面分几个区域菜单栏、命令窗口Transcript、工作区Project/Workspace。如果你是第一次打开工作区是空的这时候需要创建一个新工程。点击菜单栏的File - New - Project弹出对话框后填工程名比如uart_rx_test项目路径选择一个空文件夹。创建完成后需要往工程里添加源文件点击Project窗口空白处右键选择Add to Project - New File分别创建uart_rx.v和uart_rx_tb.v两个文件。这里给出一份简化版的uart_rx模块代码也是入门最常看到的写法module uart_rx( input wire clk, // 系统时钟假设50MHz input wire rst_n, // 低电平复位 input wire rx, // 串口输入 output reg [7:0] data, // 接收到的数据 output reg data_valid // 数据有效信号 ); // 波特率960050MHz时钟一个位周期的计数上限为5208 localparam BAUD_CNT_MAX 5208 - 1; localparam MID_BIT 2604 - 1; reg [12:0] baud_cnt; reg baud_flag; reg [3:0] bit_cnt; reg rx_d0; reg rx_d1; // 打拍消除亚稳态 reg rx_negedge; // 下降沿检测 reg rx_busy; reg [7:0] rx_data_temp; always (posedge clk or negedge rst_n) begin if (!rst_n) begin rx_d0 1b1; rx_d1 1b1; end else begin rx_d0 rx; rx_d1 rx_d0; end end assign rx_negedge rx_d1 (~rx_d0); always (posedge clk or negedge rst_n) begin if (!rst_n) begin rx_busy 1b0; baud_cnt 13d0; baud_flag 1b0; bit_cnt 4d0; data_valid 1b0; data 8d0; rx_data_temp 8d0; end else begin data_valid 1b0; if (rx_negedge !rx_busy) begin rx_busy 1b1; baud_cnt 13d0; bit_cnt 4d0; end if (rx_busy) begin baud_cnt baud_cnt 1b1; if (baud_cnt BAUD_CNT_MAX) begin baud_cnt 13d0; baud_flag 1b1; end else begin baud_flag 1b0; end if (baud_flag) begin bit_cnt bit_cnt 1b1; if (bit_cnt 4d1 bit_cnt 4d8) rx_data_temp[(bit_cnt - 4d1)] rx; if (bit_cnt 4d9) begin data rx_data_temp; data_valid 1b1; rx_busy 1b0; end end end end end endmodule对应的Testbench文件如下timescale 1ns / 1ps module uart_rx_tb; reg clk; reg rst_n; reg rx; wire [7:0] data; wire data_valid; initial begin clk 0; rst_n 0; rx 1; #100; rst_n 1; // 模拟发送一个字节 0x55波特率9600 // 起始位(0) 8个数据位(10101010) 停止位(1) // 发送顺序先LSB后MSB #100; (posedge clk); rx 0; // 起始位 #(5208 * 2 * 20); rx 1; // LSB 1 (bit0) #(5208 * 2 * 20); rx 0; // bit1 0 #(5208 * 2 * 20); rx 1; // bit2 1 #(5208 * 2 * 20); rx 0; // bit3 0 #(5208 * 2 * 20); rx 1; // bit4 1 #(5208 * 2 * 20); rx 0; // bit5 0 #(5208 * 2 * 20); rx 1; // bit6 1 #(5208 * 2 * 20); rx 0; // bit7 0 #(5208 * 2 * 20); rx 1; // 停止位 #(5208 * 2 * 20); $display(UART RX simulation finished. data%h, data_valid%b, data, data_valid); #1000; $stop; end always #20 clk ~clk; // 50MHz时钟周期20ns endmodule这段代码里有几个关键点要说明一下。Testbench中模拟串口发送时延时是用5208 * 2 * 20来算的因为一个位周期是5208个时钟周期每个时钟周期是20ns乘以2是我故意留的余量保证采样点落在每个bit的中间位置。实际工程中如果时钟是50MHz波特率9600一位的持续时间就是1/9600 ≈ 104.17us对应104167ns / 20ns ≈ 5208个时钟周期。你以后写别的波特率用同样方法算。3.3 编译、仿真与波形观察的完整流程文件添加好之后回到Modelsim主界面。在Project窗口可以看到这两个文件。这时候需要先编译再仿真。编译操作很简单在Project窗口右键点击文件名选择Compile - Compile Selected或者直接在菜单栏选Compile - Compile All。编译的结果会显示在Transcript窗口中如果出现语法错误双击错误信息可以自动跳到对应代码行。编译通过后点击菜单栏Simulate - Start Simulation在弹出的对话框中选择uart_rx_tb作为顶层模块点击OK。如果一切正常Transcript中会提示仿真已经启动。此时波形窗口默认是不显示的需要手动添加信号。点击菜单栏View - Wave打开波形窗口然后在Object窗口默认在工作区下方选中你想要观察的信号拖动到波形窗口即可。通常我会把clk、rst_n、rx、data、data_valid、rx_busy、bit_cnt、baud_cnt这些信号全部拖进去这样能完整看到接收状态的推进过程。接下来设置仿真时间并运行。在波形窗口的命令行中输入run 20ms或者点击带Run字样的绿色按钮。如果一切正常你会看到波形像流水一样展开先是rx信号拉低表示起始位然后bit_cnt依次递增8个bit的数据按顺序被采样进rx_data_temp最后data_valid拉高一个周期data输出0x55。看到data_valid成功拉高的那一刻你基本上就把Modelsim仿真的核心流程走通了。3.4 仿真波形是红线快速定位问题来源新手在使用Modelsim时碰到最多的一个现象就是波形窗口里所有信号都是红色线条或者红色虚线。红色线条代表未知状态X态。最常见的几个原因如下第一rst_n复位信号没有正确拉高导致电路一直处于复位状态所有寄存器保持复位值之外的状态未知。解决办法在Testbench中写好复位逻辑确保仿真开始后复位释放比如我们上面写的#100; rst_n 1;就是做这个事。第二信号之间没有建立正确的连接也就是说你观察的信号在设计中根本没被驱动。比如你拖了一个内部信号到波形窗口但这个信号在代码里没有赋值那它就会一直显示X态。解决办法回到代码里确认信号是否在always块中有赋值以及端口连接是否正确。第三仿真时间不够长。有些初学者运行了run 1us但UART的一个bit周期就要104us仿真时间不够自然看不到完整的数据传输过程。解决办法根据你的波特率和发送字节数估算仿真时间一般加上余量。还有一种情况是红色虚线这通常表示高阻态Z态多出现在没有连接的输出端口。检查是否漏了信号赋值或者端口脱离。4. 常见问题与排查技巧实录4.1 激活与启动阶段的高频问题速查下面这个表格是根据我自己安装时遇到的问题以及论坛上新手问得最多的场景整理出来的按出现频率排序现象原因解决办法启动弹出Unable to checkout a license环境变量未生效或License文件路径不对检查MGLS_LICENSE_FILE是否设置正确重启后重试激活后第一次关闭再打开又报错dll被杀毒软件恢复或隔离关闭杀毒软件重新替换mgls64.dllLicense文件生成提示MAC地址错误填了带横杠的MAC地址去掉横杠只填12位十六进制字符启动时提示Could not load license librarymgls.dll替换失败或被占用先打开任务管理器关闭Modelsim进程再替换能启动但仿真时提示无授权模块使用了OEM版License用在SE版上确认使用SE版对应的授权文件不能混用值得注意的是如果你电脑上还装了其他使用FlexNet授权的软件比如某些EDA工具它们之间可能会存在环境变量冲突。遇到这种情况在启动Modelsim前临时修改MGLS_LICENSE_FILE即可。4.2 仿真过程中的典型问题与解决思路仿真过程中除了红线问题还有一个高频问题是编译报错。我在很多初学者代码里见到过这类错误Module not found或Cannot find module。这个是因为Modelsim编译文件时需要按依赖顺序编译。如果Testbench模块引用了被测试模块就应该先编译被测试模块再编译Testbench。如果你在Project窗口右键Compile AllModelsim会按照文件添加顺序编译文件顺序不对就会报找不到模块。解决办法是Project窗口右键有Compile Order选项可以手动调整编译顺序。第二个典型的仿真问题是波形出来了但数据完全不对。比如data输出不是期望的0x55而是一堆乱码。这种情况多数是波特率时钟计数算错了。你可以用波形窗口放大看看baud_cnt的计数上限和bit_cnt的跳变时刻如果采样点偏了半个位周期就会采到错误的电平。建议先画一条理想的时间轴标出起始位、数据位和停止位的位置再对照波形核实。4.3 我建议你养成的几个好习惯装好Modelsim之后我非常建议你花点时间做三件事它们能让后续的学习效率提高不少。第一把Testbench模板保存下来。不要每次都重新写timescale、时钟翻转、复位逻辑这些东西做一份自己的模板以后建新工程直接复制能省很多时间。第二学会用do脚本自动执行编译和仿真流程。不要老靠鼠标点按钮当你需要反复改动代码重新跑仿真时脚本化的好处立刻体现出来。比如你可以创建一个run_sim.do文件内容大致是vlib work vlog uart_rx.v uart_rx_tb.v vsim work.uart_rx_tb add wave -position insertpoint sim:/uart_rx_tb/* run 20ms然后在Modelsim的Transcript命令窗口输入do run_sim.do一条命令就完成编译、启动仿真、加波形、跑完整个流程。这在你以后做复杂仿真时会非常有用。第三波形窗口的保存功能。每次调整好波形布局后可以用File - Waveform Save把格式保存成.do文件下次重新仿真时直接执行它波形窗口的位置、颜色、信号分组就都恢复了。5. 最后的实战建议与个人体会装完Modelsim SE 2020.4并成功跑通第一个UART_RX仿真之后你会发现FPGA调试的底气完全不一样了——写代码不再是写完直接上板碰运气而是可以随时在电脑上把每一拍的信号变化看得清清楚楚。我个人在实际使用中的体会是Modelsim能不能真正用好关键不在于装了多新的版本而在于你有没有建立一套固定的流程新建工程怎么组织、Testbench怎么写、波形看哪些信号、出错了从哪里排查。这套流程一旦固化下来你后续无论是学状态机、图像处理、还是做串口通信都会顺畅很多。最后再分享一个小技巧如果你发现自己经常需要修改模块代码后重新仿真不要每次用鼠标点半天把上面那段run_sim.do脚本存好改完代码后直接在Transcript里执行一条do run_sim.do20秒内就能看到最新的仿真结果。这个习惯是我在看别人调试时学到的后来自己试了下确实能省掉大量重复操作。FPGA入门的路还长但仿真工具用熟了这条路会好走很多。
阅读完成 · 觉得有帮助?