尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

易灵思Efinity与ModelSim联仿实战:从原语库编译到波形调试

易灵思Efinity与ModelSim联仿实战:从原语库编译到波形调试 1. 为什么易灵思Efinity的联仿总在第一步就卡住如果你是从Xilinx或Altera生态转过来的第一次在易灵思Efinity里点开ModelSim联仿大概率会经历一个非常迷惑的阶段RTL代码明明综合通过了时序约束也写了但仿真一跑就报错要么是找不到原语模块要么是波形里全是红线要么干脆连编译都过不去。这不是你的代码有问题而是Efinity的仿真流程和Vivado那一套有本质区别。易灵思的FPGA器件架构比较特殊它用的是Quantum架构底层是LUT4加可配置寄存器还有大量硬核IP和专用原语。这些原语在综合时会被映射成Efinity自己的库文件但ModelSim默认不认识这些东西。所以联仿的核心矛盾就一个怎么让ModelSim认识Efinity的原语库并且把仿真模型正确加载进来。这篇文章面向的是已经能跑通Efinity基本流程、但卡在仿真环节的开发者。我会从原语编译开始一步步拆到波形调试把整个链路讲清楚。不管你是用Ti60、Trion还是其他Efinity支持的器件流程都是通用的。关键词里的“易灵思Ti60F225”“Efinity”“ModelSim联仿”这些我都会在具体步骤里对应上。先说一个我踩过的坑很多人以为Efinity的仿真和Vivado一样点一下“Run Simulation”就完事了。实际上Efinity的仿真需要你先手动编译原语库生成ModelSim能识别的仿真模型然后再把设计文件和测试平台一起编译。这个顺序错了后面全是白费功夫。2. Efinity仿真库的生成逻辑与ModelSim的对接方式2.1 Efinity原语库到底放在哪里Efinity安装完成后原语库文件通常位于安装目录下的sim文件夹里。以Windows环境为例路径大概是C:\Efinity\version\sim\。这里面会有几个关键文件夹primitive存放原语仿真模型ip存放硬核IP的仿真模型modelsim存放ModelSim专用的编译脚本。很多人找不到这些文件是因为Efinity的安装目录结构不像Vivado那么直观。Vivado会把仿真库统一放在data\verilog下面而Efinity是按器件系列和功能分类的。你需要先确认自己用的是哪个器件系列Ti60对应的是titanium目录Trion对应的是trion目录。提示如果你在安装目录下找不到sim文件夹检查一下安装时是否勾选了“Simulation Libraries”选项。有些精简安装包默认不装仿真库需要重新运行安装程序补上。2.2 用Efinity自带的脚本编译原语库Efinity提供了一个叫compile_simlib的脚本工具位置在sim\modelsim\目录下。这个脚本的作用是把Verilog原语模型编译成ModelSim的.mti库文件。操作步骤如下打开Efinity自带的命令行终端不是系统CMD是Efinity Console。切换到sim\modelsim\目录。执行命令compile_simlib -simulator modelsim -family titanium -language verilog -library efinity_prim等待编译完成会在当前目录生成一个efinity_prim文件夹里面就是编译好的库。这里有几个参数需要解释一下。-family指定器件系列Ti60属于titanium系列Trion属于trion系列选错了后面仿真会找不到对应的原语。-language可以选verilog或vhdl取决于你的设计语言。-library是自定义的库名建议用efinity_prim方便后面在ModelSim里引用。编译过程大概需要几分钟取决于你的机器性能。编译完成后你会看到类似Compiled 245 modules的输出。如果中途报错大概率是路径里有中文或空格Efinity的工具链对路径比较敏感建议全部用英文路径。2.3 在ModelSim里映射Efinity库库编译好了但ModelSim还不知道它的存在。你需要手动在ModelSim里创建一个库映射。打开ModelSim在Transcript窗口里执行vlib efinity_prim vmap efinity_prim ./efinity_prim这两条命令的意思是创建一个逻辑库efinity_prim然后把它映射到刚才编译生成的物理目录。注意路径要写对如果你是在其他目录启动的ModelSim需要用绝对路径。映射完成后可以用vdir efinity_prim检查一下库里面有没有内容。正常情况下会列出一堆模块名比如EFX_LUT4、EFX_FF、EFX_IO之类的。看到这些说明原语库已经就绪了。2.4 为什么不能直接用Vivado的仿真库有人可能会想都是FPGA原语能不能把Vivado的仿真库拿来用答案是绝对不行。不同厂商的原语命名、端口定义、时序模型完全不一样。Vivado的LUT6和Efinity的EFX_LUT4在仿真行为上就有差异更别说硬核IP了。用错了库仿真结果要么是红线要么是功能完全不对。我见过一个案例有人把Vivado的BUFG仿真模型拿来跑Efinity的设计结果时钟路径完全乱了波形里时钟信号一直是高阻态。查了半天才发现是库用错了。所以这一步千万别偷懒老老实实用Efinity自带的脚本编译。3. 联仿环境的目录结构与文件组织3.1 推荐的工程目录布局Efinity的联仿对目录结构有一定要求如果文件放得太乱ModelSim编译时会找不到include文件。我一般推荐这样的布局project/ ├── rtl/ # 设计源码 │ ├── top.v │ └── sub_module.v ├── sim/ # 仿真相关 │ ├── tb_top.v # 测试平台 │ ├── wave.do # 波形脚本 │ └── run_sim.tcl # 自动化脚本 ├── efinity_prim/ # 编译好的原语库 └── ip/ # IP核相关文件这个结构的好处是职责清晰RTL和仿真分离原语库独立存放。后面写自动化脚本的时候路径引用也方便。3.2 测试平台的编写要点Efinity的测试平台和普通Verilog测试平台写法基本一样但有几个细节需要注意。首先是时钟和复位的初始化Efinity的器件上电后有一个全局复位信号GSR仿真时如果不处理这个信号寄存器可能一直处于复位状态。initial begin // 模拟GSR释放 #100; $display(GSR released); end其次是原语的实例化。如果你在RTL里直接调用了EFX_LUT4这样的原语测试平台里不需要额外处理ModelSim会自动从映射的库里找。但如果你用了Efinity的IP核比如PLL或DDR控制器就需要把IP的仿真模型也编译进来。3.3 用Tcl脚本串联整个仿真流程手动在ModelSim里敲命令太累而且容易出错。我习惯写一个run_sim.tcl脚本把编译、加载、运行、波形保存全部串起来。核心内容大概是这样# 创建work库 vlib work vmap work work # 映射Efinity原语库 vmap efinity_prim ./efinity_prim # 编译设计文件 vlog -sv ../rtl/*.v vlog -sv tb_top.v # 加载仿真 vsim -t 1ps -L efinity_prim work.tb_top # 添加波形 do wave.do # 运行仿真 run -all这个脚本的关键点是-L efinity_prim参数它告诉ModelSim在加载设计时去efinity_prim库里找原语。少了这个参数仿真会报“Module not found”错误。注意vlog编译时如果设计里用了SystemVerilog语法要加-sv参数。Efinity的某些IP仿真模型是SystemVerilog写的不加这个参数会编译失败。4. 波形调试中最容易误判的几种现象4.1 红线不等于错误ModelSim波形里的红线红色高阻态经常被误认为是仿真错误其实不一定。Efinity的某些原语在未初始化时输出就是高阻态比如IO缓冲器在未配置方向之前输出就是Z。这种情况下红线是正常现象只要后续信号有正确翻转就行。真正需要警惕的是信号一直是红线从头到尾没变过。这通常意味着原语库没加载成功或者端口的连接方式有问题。排查方法是选中红线信号右键选择“Examine”看看它的驱动源是什么。如果驱动源显示为not found那就是库的问题。4.2 时钟信号不翻转的几种原因时钟不翻转是联仿里最常见的问题之一。原因可能有很多种我按出现频率排个序现象可能原因排查方法时钟一直为0测试平台没给时钟激励检查initial块里有没有forever #5 clk ~clk时钟一直为X时钟源未初始化给时钟信号加initial clk 0时钟有翻转但频率不对PLL仿真模型未加载确认IP仿真库是否编译时钟在某个时刻停止仿真时间不够检查run命令的时间参数其中PLL仿真模型未加载是最隐蔽的。Efinity的PLL IP在综合时会生成一个仿真模型文件通常叫pll_sim.v或类似的名字。这个文件需要和设计文件一起编译否则ModelSim会用一个空的模块替代导致时钟输出一直是X。4.3 复位信号亚稳态的仿真表现关键词里提到了“FPGA复位信号亚稳态”这在仿真里也有体现。如果复位信号是异步的而且释放时没有同步处理波形上会看到寄存器输出出现短暂的X态。这不是仿真工具的问题而是真实的亚稳态现象。在Efinity里建议复位信号统一用同步复位或者在异步复位后面加两级同步器。仿真时如果看到复位释放后寄存器输出有毛刺基本可以确认是亚稳态问题。解决方法是在RTL里加同步逻辑reg [1:0] rst_sync; always (posedge clk or negedge rst_n) begin if (!rst_n) rst_sync 2b00; else rst_sync {rst_sync[0], 1b1}; end wire rst_synced rst_sync[1];这样仿真波形里就不会出现X态了。4.4 用ModelSim的Dataflow窗口追踪信号来源当波形里某个信号行为异常时ModelSim的Dataflow窗口是个好东西。选中信号右键选择“Dataflow”-“Trace Inputs”它会自动追踪这个信号的所有驱动源。对于Efinity的原语Dataflow能直接跳到原语内部的仿真模型帮你确认是原语行为不对还是外部逻辑有问题。我遇到过一种情况一个计数器在仿真里偶尔跳变波形上看不出原因。用Dataflow追踪后发现计数器的使能信号来自一个EFX_FF原语而这个原语的时钟输入接的是一个未初始化的PLL输出。问题根源找到了解决起来就快了。5. 从Ti60F225实战案例看联仿的完整链路5.1 案例背景UART接收模块的仿真验证Ti60F225是易灵思Titanium系列里比较热门的一款器件225个IO适合做接口桥接和中等规模的逻辑设计。我拿一个UART接收模块的仿真案例来串一遍完整流程。这个模块的功能很简单接收波特率115200的串行数据解析成8位并行数据输出。RTL代码里用到了Efinity的EFX_FF原语来做输入同步还用了一个EFX_LUT4做简单的组合逻辑。测试平台里模拟了一个UART发送端按115200的波特率往接收模块发数据。5.2 原语编译时的器件系列选择在编译原语库的时候-family参数要选titanium因为Ti60F225属于Titanium系列。如果你选成了trion编译出来的库里面没有Ti60对应的原语模型仿真时会报“EFX_FF not found”。编译命令compile_simlib -simulator modelsim -family titanium -language verilog -library efinity_prim编译完成后检查efinity_prim目录下有没有EFX_FF和EFX_LUT4的.v文件。如果没有说明器件系列选错了重新编译。5.3 测试平台中的波特率生成与数据比对UART仿真的核心是波特率要匹配。115200波特率对应的位周期是8.68微秒。在测试平台里我用一个计数器生成位周期localparam BIT_PERIOD 8680; // 单位ns对应115200波特率 reg [13:0] baud_cnt; always (posedge clk) begin if (baud_cnt BIT_PERIOD - 1) baud_cnt 0; else baud_cnt baud_cnt 1; end发送数据时在每个位周期的中间采样确保数据稳定。接收模块的输出和发送的数据做比对如果一致就打印“PASS”否则打印“FAIL”。仿真跑起来后波形上能看到rx_data在rx_done拉高的同时输出正确的数据。如果rx_data是X态检查一下EFX_FF原语的复位端口有没有正确连接。5.4 波形里看到的“意外”跳变及解释在这个案例的仿真波形里我注意到rx_data在rx_done拉高之前有一个短暂的跳变。一开始以为是逻辑错误后来用Dataflow追踪发现这是EFX_FF原语的建立保持时间导致的。Efinity的EFX_FF仿真模型里包含了时序检查当输入数据在时钟边沿附近变化时输出会出现短暂的不确定态。这不是设计问题而是仿真模型的行为。实际硬件上只要满足建立保持时间就不会出现这个跳变。如果不想在波形里看到这个现象可以在EFX_FF实例化时加上-no_timing_check参数或者在ModelSim里关闭时序检查。6. 联仿效率提升与常见报错速查6.1 增量编译避免重复劳动每次改一点RTL就重新编译整个原语库太浪费时间。ModelSim支持增量编译只编译改动的文件。在Tcl脚本里用vlog的时候加上-incr参数vlog -incr -sv ../rtl/*.v这样ModelSim会检查文件的时间戳只编译有改动的文件。对于大型设计增量编译能把编译时间从几分钟缩短到几秒钟。但要注意如果你改了原语库或者IP仿真模型增量编译可能不会自动检测到。这种情况下需要手动删除work库重新全量编译。6.2 常见报错与对应解决表报错信息原因解决方法Module EFX_FF not found原语库未映射执行vmap efinity_prim ./efinity_primFailed to open include file路径不对检查vlog的-I参数Signal clk has no driver测试平台未给激励检查initial块Simulation terminated by $finish测试平台提前结束检查$finish的调用条件Library efinity_prim already exists重复映射先vdel再vmap这张表里的报错我基本都遇到过其中Module not found是最常见的。90%的情况是库映射没做或者vsim的时候忘了加-L参数。6.3 用Do文件固化波形配置每次仿真都要手动添加波形信号太麻烦。ModelSim的Do文件可以把波形配置固化下来。在波形窗口里调好信号和分组后执行save wave.do下次仿真时用do wave.do加载。我习惯把常用的信号分组时钟复位一组、输入输出一组、内部状态一组。这样波形窗口看起来清爽调试的时候也方便定位。提示Do文件里的信号路径是相对于顶层实例的。如果你改了顶层模块名Do文件里的路径也要跟着改否则加载时会报“Signal not found”。6.4 仿真速度优化的几个实用技巧Efinity的设计规模大了之后仿真速度会明显变慢。几个提速的方法第一减少不必要的波形记录。ModelSim默认记录所有信号但很多信号你根本不看。在vsim命令里加上-novopt参数关闭优化虽然仿真速度会慢一点但波形更准确。如果追求速度可以用-voptargsacc只记录需要的信号。第二用when条件触发记录。比如只在rx_done拉高的时候记录rx_data其他时间不记录。这样能大幅减少波形数据量。第三把仿真时间分段跑。先跑前100微秒确认复位和初始化没问题再跑后面的数据接收阶段。不要一上来就run -all出了问题很难定位。7. 从联仿到板级验证的衔接要点仿真跑通了不代表板上就能跑。Efinity的联仿和实际硬件之间还有几个差距需要注意。首先是时序约束。仿真里没有时序信息信号翻转都是理想的。但实际硬件上如果时序不满足信号会出现毛刺或亚稳态。所以仿真通过后一定要跑一遍时序分析确认建立保持时间都满足。其次是IO标准。仿真里IO缓冲器的行为是理想化的但实际硬件上IO标准选错了信号电平可能不对。比如LVCMOS33和LVCMOS18的阈值电压不一样仿真里看不出来但板上会出问题。最后是复位释放的时机。仿真里复位释放是瞬间完成的但实际硬件上复位信号从FPGA外部进来经过IO缓冲器和全局时钟网络会有延迟。如果复位释放时时钟还没稳定寄存器可能进入亚稳态。建议在RTL里加复位同步逻辑仿真和实际硬件都受益。我在Ti60F225上跑UART案例的时候仿真一次通过但板上第一次跑的时候数据偶尔出错。后来发现是复位释放太快PLL还没锁定就开始了数据接收。在复位逻辑里加了一个PLL锁定信号作为复位释放的条件问题就解决了。这个细节在仿真里完全看不出来只有实际调试才会暴露。所以联仿的价值在于验证功能逻辑但不能替代板级调试。两者结合才能保证设计真正可靠。
返回列表