
1. 为什么要在ModelSim里仿易灵思工程搞过FPGA的人都知道仿真验证是开发流程里最花时间、也最容易翻车的一环。易灵思Efinix这几年在国产FPGA里势头很猛Ti60F225这种片子接口资源丰富、逻辑密度也够用很多人拿它做TDC直方图采集、图像预处理、MIPI收发这类项目但不少朋友在把Efinity工程和ModelSim联起来的时候卡了壳。有人是不确定用哪个仿真库有人是编译网表报一堆错还有人干脆不知道Efinity导出哪些文件才能给ModelSim用。先说结论易灵思官方IDE叫Efinity工具本身是自带在线逻辑分析仪ILA的但那个东西只能在板子上跑起来之后抓信号适合看真实硬件波形。你要在代码写对之前就验证RTL行为、做时序走查还是得靠外部仿真器。ModelSim作为最普及的通用仿真工具对易灵思网表的支持是够用的关键是把“编译库、网表、SDF反标”这三件事的顺序和路径搞清楚。这篇文章不聊空理论直接按我实际踩过的坑来讲从软件版本怎么搭配、路径避开哪些雷到Efinity导出网表和SDF、ModelSim编译易灵思库、写do脚本跑联合仿真再到波形全是红线和时序反标警告的排查方法。整套流程我自己在Ti60F225的项目里跑通过你按这个顺序走基本半小时内能出波形。2. 环境准备版本、路径和库文件很多联仿失败根本不是代码问题而是环境没配对。易灵思的Efinity和ModelSim之间的配合对版本和路径比官方文档写的还要敏感。2.1 软件版本怎么选Efinity目前主流的稳定版本是2022.x和2023.x系列ModelSim这边建议用Intel FPGA Starter Edition也就是大家常说的ModelSim-Intel。为什么要强调这个版本因为易灵思的仿真库是基于Verilog-2001和SystemVerilog写的老版本的ModelSim SE在某些语法解析上会直接报错尤其是接口数组和带参数化的模块新版本对SystemVerilog的支持明显更稳。我自己测试过ModelSim 10.5b、10.7和ModelSim-Intel 10.5b都能和Efinity 2022.2配合使用。注意一点别用太新的ModelSim版本去配老Efinity有时反而会出现时间精度单位不兼容的问题。提示如果你的电脑上装了多个仿真器记得在系统PATH里把ModelSim的bin目录放在一个不会被其他版本干扰的位置联仿时ModelSim是从PATH里找vsim/vlib/vlog这些命令的。2.2 安装路径的两个雷第一个雷是安装路径里不能有中文和空格。Efinity如果装在C:\Program Files\Efinity这种带空格的路径下生成do文件或调用仿真器时路径字符串经常被截断报一个莫名其妙的file not found。我习惯装在D:\eda\efinityModelSim装在D:\eda\modelsim全路径纯英文一次跑通。第二个雷是两个软件的安装目录最好在国际盘符下。有人图省事装在系统默认目录仿真跑起来产生的临时文件越来越大C盘满了之后ModelSim直接罢工波形出不来还以为是库有问题。2.3 库文件清单ModelSim需要认识易灵思的什么易灵思的网表仿真不像Xilinx的uni9000那么复杂核心库就三个来源你一定要在联仿前确认它们的存在Efinity安装目录下的lib/verilog文件夹里面有易灵思原语库比如Efx_prim.v、Efx_seu.v这类文件。工程导出仿真文件时生成的顶层网表文件通常是xxx.vm或xxx.v。布局布线后导出的SDF时序文件后缀是.sdf。有些教程会建议直接把易灵思的库文件夹全部vlog编译进ModelSim我实测不需要全部只要把当前工程用到的原语库编译进去就够了。但你如果图省事全部编译也没问题最多多花几十秒。3. 实操Efinity侧网表和SDF的生成联仿的源头在Efinity工程里如果Efinity侧没把仿真产物生成对ModelSim那边再折腾也白搭。我见过太多人卡在这一步代码综合没问题但不知道在哪里导出布局布线后的仿真文件。3.1 创建工程与约束检查先把Efinity工程建好管脚约束和时序约束最好在综合之前就写清楚尤其是时钟约束。联仿时的SDF反标依赖时序约束约束写得不准仿真波形出来但时序检查会报一堆hold violation看起来像设计问题实际是约束问题。我有个习惯工程里单独建sim目录和src、constr分开。导出仿真文件时输出路径直接指到sim目录ModelSim工程也建在这个目录下两边共享路径避免跨盘符带来的权限问题。3.2 布局布线后导出仿真产物Efinity完成布局布线之后在菜单里找File Export Simulation或Tools Generate Simulation Netlist不同版本菜单位置略有差异但核心选项一致输出格式选Verilog网表。勾选SDF输出选项生成时序反标文件。选择输出目录建议用sim文件夹。这一步做完你会在sim目录下看到top_module.vm布局布线后的网表模块名通常是顶层名加后缀。top_module.sdf时序反标文件包含单元延迟和互连延迟。可能还有一些约束文件的格式化副本。导出时有一个容易忽略的选项是Use gated clock如果你的设计里有门控时钟这个选项务必按Efinity提示勾选否则后续时序仿真时门控逻辑会变成不定态波形上一片红色。3.3 导出目录里到底有什么我把自己项目里的仿真目录列个参考sim/ ├── top_module.vm ├── top_module.sdf ├── testbench_ti60.v ├── run_ti60.do └── modelsim.initestbench_ti60.v是手写的测试激励run_ti60.do是ModelSim批处理脚本modelsim.ini是ModelSim库映射文件。modelsim.ini这个文件你不一定要手动建ModelSim运行vlib和vmap时自动生成但如果你要固定库映射提前放一份也是好的。4. 实操ModelSim侧库编译与仿真脚本到了ModelSim这一侧所有动作都可以在一个do文件里完成。我建议别在GUI里手动点一方面慢另一方面一错就乱了。脚本化是联仿效率的关键。4.1 手动vlib/vlog的完整流程打开ModelSim先切到sim目录然后按顺序执行下面几条命令。第一条是建库vlib work vmap work work接着编译易灵思原语库。这里路径根据你自己的Efinity安装位置改vlog -work work D:/eda/efinity/lib/verilog/Efx_prim.v vlog -work work D:/eda/efinity/lib/verilog/efx_technology.v再看你的设计是否用到易灵思的硬核IP比如MIPI、DDR、RISC-V软核。如果有还要编译对应IP库。硬核IP的仿真模型一般在Efinity安装目录的ip子目录或工程生成的IP目录下文件名一般带_sim_model后缀。然后编译顶层网表vlog -work work sim/top_module.vm最后编译测试激励vlog -work work sim/testbench_ti60.v编译顺序不能乱。先原语库再网表最后testbench因为testbench里会例化顶层模块如果顶层模块还没编译到work库里vlog会报找不到模块名。4.2 写一个do文件跑通仿真完整的do文件参考如下vlib work vmap work work vlog -work work D:/eda/efinity/lib/verilog/Efx_prim.v vlog -work work D:/eda/efinity/lib/verilog/efx_technology.v vlog -work work sim/top_module.vm vlog -work work sim/testbench_ti60.v vsim -L work -t 1ps work.testbench add wave -position end sim:/testbench/* run -all这段脚本里有两个地方值得解释。第一是-t 1ps这是时间精度设置。易灵思SDF文件里的延迟精度通常是皮秒级别时间精度设成1ps能保证反标不丢小数位。第二是-L work这个选项告诉vsim在work库里搜索用户自定义的模块缺少它时经常报Load of top failed。跑起来之后如果你在wave窗口看到信号全都是红色或全X先别怀疑代码看下面第5部分的排查。4.3 SDF反标与时序检查上面的do脚本能跑功能仿真但严格来说还没把时序检查带进去。要做带时序的仿真需要把SDF文件反标到网表模块上。在vsim命令后面加一行vsim -L work -t 1ps work.testbench -sdftyp /testbench/dut_instancesim/top_module.sdf这里的dut_instance是testbench里例化顶层模块的实例名路径必须和testbench中的层次一致。如果反标成功ModelSim的Transcript窗口会打印一行SDF反标的信息包括反标文件路径和模块名。如果没打印说明路径写错了时序检查不会报错但时序数据完全没生效。反标之后你可以通过打开Simulate Runtime Options里的Enable timing checks选项来开启时序检查。或者直接在vsim命令行加notimingchecks注意这个选项是关闭时序检查用的只有在你只关心功能、不关心时序时才加。调试SDF问题时要避免误加。5. 常见问题与排查技巧实录联仿设置本身不难难的是报错信息经常不直白。我把这几个月被问得最多的问题统一整理成速查表再补充几个我亲身踩过的坑。5.1 编译报错排查报错关键词可能原因解决方案Library work not found没有先执行vlib/vmap确认do脚本里先建库再编译Cannot find moduletestbench例化名和网表顶层名不一致打开top_module.vm文件确认顶层module名vlog-13069原语库编译语法不兼容换ModelSim-Intel版本或升级EfinityNear ,: syntax error原语库版本和ModelSim不匹配尝试只编译用到的原语文件而非全部编译问题暴露最多的场景是全部编译易灵思库时报语法错。因为有些原语文件依赖特定的仿真器宏定义ModelSim不认识。解决思路是只编译当前设计用到的模块配合define做宏定义。比如编译原语库时加vlog -work work defineSIMULATION D:/eda/efinity/lib/verilog/Efx_prim.v很多宏定义在官方文档里有说明仿真目录下通常也有一个编译脚本模板优先参考那个模板。5.2 SDF警告与反标失败SDF反标时报$sdf_annotate警告最常见原因是实例路径写错。ModelSim里的SDF反标路径取决于你的网表层级不一定等于testbench里的例化路径。我的经验是先在testbench里加一行initial $sdf_annotate(sim/top_module.sdf, dut_instance);这个系统任务的好处是路径写法和-sdftyp一致而且如果反标失败仿真器会给出更明确的报错层级。用$sdf_annotate定位问题后再改正vsim命令行的-sdftyp参数。还有一种情况是反标成功但波形里没有延迟检查一下vsim启动时的log里有没有这一行# Loading SDF file: sim/top_module.sdf如果没有说明SDF没被加载看看文件是否存在、路径是否相对ModelSim当前工作目录。5.3 波形全是红线红线就是不定态出现原因通常集中在三种可能。第一时钟或复位没有正确初始化。testbench里的initial块只给寄存器赋值没有驱动复位信号和时钟。第二SDF反标成功但时序约束没写导致仿真器认为所有路径都在hold violation输出全X。第三编译库时缺少易灵思原始未驱动信号的定义比如某些硬核复位引脚悬空。我建议先跑一遍纯功能仿真不带SDF看波形是不是正常。如果功能仿真是好的加上SDF之后才变红就排查时序约束如果功能仿真就全红那就是testbench激励的问题。5.4 回归与效率提升联仿设置好之后还有一个使用习惯问题值得提。项目迭代过程中RTL每改一次就要重跑一遍综合和布局布线网表变了SDF也要重新导出。我习惯在do脚本里把编译网表和SDF反标的过程拆成两段先编RTL快速跑功能仿真确认逻辑无误后再编网表跑时序仿真。这样能省不少时间。尤其在做TDC直方图这类对延迟敏感的项目时关心的是延迟链的进位逻辑和时钟偏斜功能仿真看不出问题必须靠时序仿真验证。但每次只为了看一眼布局布线效果就去跑整个流程效率太低分开跑是更务实的方案。说到易灵思库精度和延迟的一个细节ModelSim默认时间单位为1ns如果你不设置-t 1psSDF里0.01ns级别的延迟会被舍入成0仿真波形看起来像没有延迟但某些触发沿却因为实际有延迟而采样出错。所以这个参数不要省。6. 一些值得养成的习惯最后分享一个我在多项目联仿配置里沉淀下来的习惯。把所有易灵思库文件放到ModelSim工作目录下的efx_lib子目录用vmap efx_lib ./efx_lib映射成逻辑库名而不是全部堆在work库。网表和原语库分离后回归测试时只需要重编网表和testbench原语库不用动编译时间明显缩短。另外testbench尽量写成自检形式不要纯看波形。比如TDC直方图这种设计输出一个bin值后testbench里用$display或assert自动比对预期值跑完看Transcript窗口的结果即可不用肉眼看几十路波形。联仿不仅是让波形出来更要让验证结果可自动判定这样才能在迭代中真正省心。我个人在实际操作中的最大体会是联仿配置这一关难的不是ModelSim命令而是对工具链“谁生成什么、谁消费什么”的整体理解。Efinity负责把设计变成可仿真的网表和时序文件ModelSim负责把这些文件变成可观察的波形和时序报告。当路径、版本、库映射这三样都顺了之后后续所有FPGA项目都能复用同一套流程一次搭好长期受益。