仿實戰(zhàn):Efinity+ModelSim全流程指南)
1. 項目概述為什么易靈思用戶繞不開聯(lián)仿這件事玩過易靈思FPGA的朋友應該都有體會這家公司在國內(nèi)雖然還算“新面孔”但它的Efinity工具鏈設(shè)計思路非?,F(xiàn)代甚至有點“反傳統(tǒng)”。它不像Xilinx或者Intel那樣把仿真環(huán)境一股腦打包進IDE而是默認讓你用外部仿真器做驗證尤其是ModelSim和Questa Sim這種行業(yè)通用工具。對我這種從Vivado轉(zhuǎn)過來的人來說一開始確實有點懵——明明寫好了testbench卻不知道在Efinity里怎么把仿真跑起來點遍了菜單也找不到一鍵啟動ModelSim的按鈕。后來踩了幾次坑才明白Efinity的定位就是“你負責代碼我負責布線”仿真這件事它鼓勵你交給更專業(yè)的工具去做。這里就引出了聯(lián)仿的概念所謂“聯(lián)仿”就是把FPGA設(shè)計工程和外部仿真工具連接起來由外部仿真器讀取你的RTL代碼和testbench執(zhí)行功能仿真或時序仿真再把結(jié)果送回來。相比Efinity自帶的輕量仿真功能ModelSim在波形調(diào)試、斷點設(shè)置、覆蓋率分析等方面成熟得多尤其當設(shè)計復雜度上來之后兩者的差距就更明顯了。這篇內(nèi)容面向兩類人一是剛接觸易靈思FPGA、被Efinity工具鏈整得有點頭大的新手二是已有其它FPGA平臺經(jīng)驗、想快速切換到易靈思生態(tài)的老手。我會把完整的聯(lián)仿思路、腳本和排查經(jīng)驗全部攤開來講。2. 環(huán)境準備版本匹配是聯(lián)仿的第一道門檻2.1 Efinity版本與計算機系統(tǒng)兼容性Efinity目前對Windows和Linux都有支持但不同版本的軟件對操作系統(tǒng)版本有隱性要求。以我常用的Efinity 2022.2和2023.1為例Windows版本建議Win10 1809以上Linux版本則建議Ubuntu 20.04 LTS或CentOS 7.9以上。這不是說低版本系統(tǒng)完全不能用但我在Win10老版本上遇到過莫名其妙的Licensing問題折騰半天最后升級系統(tǒng)才解決。所以有條件的話盡量保持系統(tǒng)在較新版本能減少很多不必要的麻煩。另外需要注意Efinity安裝路徑不能出現(xiàn)中文或空格這一點和ModelSim的要求一致。我見過有人把Efinity裝到D:\軟件\易靈思 下面結(jié)果綜合階段報出一堆路徑相關(guān)的詭異錯誤把路徑改成D:\eFinity之后一切正常。類似的坑在聯(lián)仿場景下會被放大因為仿真工具需要讀取工程里的絕對路徑如果有中文字符很容易在生成腳本或庫文件時出錯。2.2 ModelSim版本怎么選才能跟Efinity和平共處ModelSim的版本號很多Intel版、Mentor版、標準版、DE版……不同的版本在使用體驗上差別不小。結(jié)合我自己的測試和易靈思官方文檔的推薦建議選用ModelSim DE或SE版本盡量避開ModelSim Intel Starter Edition。Starter Edition對代碼規(guī)模有限制而且有些庫的支持不完整在仿真易靈思IP核如PLL、RAM時容易出幺蛾子。版本號方面我目前用的是ModelSim DE 2022.2配Efinity 2022.2穩(wěn)定運行大半年沒出過兼容性問題。2023.1的Efinity我也試過配ModelSim 2023.3同樣沒問題。一個基本判斷標準是ModelSim版本號不要比Efinity舊太多比如用ModelSim 10.x去配Efinity 2023.1就不是個好主意因為新版的IP生成腳本可能調(diào)用了老工具不支持的Tcl命令或編譯選項。2.3 License與環(huán)境變量的配置心得ModelSim的License問題幾乎是每個新手繞不開的坎。如果你用的是正版授權(quán)直接設(shè)置環(huán)境變量MGLS_LICENSE_FILE指向license文件即可。如果是學習用途的評估版需要注意激活方式和版本限制不同版本差異較大建議以官方渠道為準。我個人的建議是不論用什么方式獲取License都建議把License文件放在一個純英文、無空格的路徑下并且不要放在桌面或下載文件夾這種容易被清理的位置。環(huán)境變量方面除了MGLS_LICENSE_FILE還需要把ModelSim的bin目錄和Efinity的bin目錄分別加入PATH。這樣做的目的是讓你能在命令行里直接調(diào)用vsim、vlog和eFinity的相關(guān)命令方便后續(xù)腳本自動化運行。Windows用戶在“系統(tǒng)屬性→環(huán)境變量”里添加即可Linux用戶在~/.bashrc里export一下就行。配置好之后在命令行輸入vsim -version能看到版本信息就說明環(huán)境沒問題。3. 核心細節(jié)解析聯(lián)仿腳本到底在做什么3.1 為什么需要腳本而不是手動操作很多剛從Vivado轉(zhuǎn)過來的用戶習慣在GUI里點點點完成仿真添加文件、編譯庫、加載設(shè)計、跑仿真……這一套操作在ModelSim里當然也可以做但每次都手動操作效率太低而且無法保證一致性。今天我舉個例子當你修改了RTL代碼需要重新編譯再仿真如果手動操作至少要點五六次鼠標但如果是腳本一條命令搞定。更重要的是腳本可以放在版本管理庫里團隊成員拉下來之后一鍵復現(xiàn)仿真環(huán)境不會出現(xiàn)“你那邊跑出來的波形和我這邊不一樣”的扯皮問題。另外易靈思的Efinity工具鏈本身也是Tcl腳本驅(qū)動架構(gòu)它的工程文件、約束文件本質(zhì)上都是腳本。既然工具鏈本身就是腳本化的那我們做仿真再用腳本整體思路保持一致出了問題也更容易追溯。3.2 腳本整體結(jié)構(gòu)與關(guān)鍵命令拆解下面這段是我在項目里實際使用的聯(lián)仿腳本每次新建仿真工程我都是在這個基礎(chǔ)上改改路徑就上。我把它拆開講解確保你拿到手就能明白每一行在干什么。# ------------------------------------------------------------- # 腳本名稱sim_run.tcl # 功能說明使用ModelSim編譯并仿真易靈思FPGA工程 # 使用方法在ModelSim命令窗口執(zhí)行 source sim_run.tcl # ------------------------------------------------------------- # 1. 清空上一次的仿真工程 quit -sim rm -rf work file delete -force work vlib work # 2. 映射易靈思仿真庫關(guān)鍵步驟 vmap work work vmap altera_mf_ver C:/intelFPGA_lite/22.1/modelsim_ase/altera_libs/altera_mf_ver vmap lpm_ver C:/intelFPGA_lite/22.1/modelsim_ase/altera_libs/lpm_ver vmap cyclonev_ver C:/intelFPGA_lite/22.1/modelsim_ase/altera_libs/cyclonev_ver vmap twentynm_ver C:/intelFPGA_lite/22.1/modelsim_ase/altera_libs/twentynm_ver # 3. 編譯RTL源碼和Testbench vlog -sv defineSIMULATION -f ./filelist.f # 4. 加載仿真頂層 vsim -voptargsacc work.tb_matrix_top # 5. 添加需要觀察的波形信號 add wave -position insertpoint sim:/tb_matrix_top/clk add wave -position insertpoint sim:/tb_matrix_top/rst_n add wave -position insertpoint sim:/tb_matrix_top/start add wave -position insertpoint sim:/tb_matrix_top/done add wave -position insertpoint sim:/tb_matrix_top/data_in add wave -position insertpoint sim:/tb_matrix_top/data_out # 6. 設(shè)置仿真運行時間并啟動 run -all這段腳本標注了幾個易靈思聯(lián)仿中特別容易踩的坑我逐個說明。第一行的quit -sim是清理上一次仿真會話的。如果你上一次仿真進程沒有正常退出這一行能保證新腳本在干凈環(huán)境下運行。后面的rm -rf work和vlib work是用來重建工作庫的這樣每次編譯都是從零開始不會因為增量編譯導致一些莫名其妙的舊模塊殘留問題。第二步的vmap是很多人的認知盲區(qū)。ModelSim在編譯帶有廠商IP核的設(shè)計時需要把IP核對應的仿真庫映射到ModelSim中。易靈思的IP核比如PLL、RAM、FIFO在綜合后會產(chǎn)生仿真模型文件你需要把這些模型文件編譯進ModelSim的庫然后再在仿真時引用。上面的腳本中我映射了altera的庫因為有些通用IP核用的是Altera兼容方案如果你用的是易靈思原生IP你需要使用vlib和vlog把Efinity生成的仿真模型也編譯進去。這個環(huán)節(jié)特別容易出錯一點不夸張——我見過有同事在這個地方卡了兩天才搞定。第三步的vlog -sv defineSIMULATION -f ./filelist.f是編譯RTL文件和testbench。-sv表示支持SystemVerilog語法defineSIMULATION是定義一個宏方便代碼里做條件編譯-f ./filelist.f是告訴ModelSim從filelist文件讀取所有需要編譯的文件列表。這個filelist文件需要你自己維護把設(shè)計相關(guān)的.v文件和testbench文件路徑都寫進去。我習慣用相對路徑這樣整個工程目錄拷貝到別的電腦上也能直接跑。第四步的vsim -voptargsacc work.tb_matrix_top是加載仿真頂層。注意這里的work.tb_matrix_top指的是testbench模塊不是RTL頂層模塊。-voptargsacc參數(shù)的意思是允許在仿真過程中訪問所有信號這樣你才能在波形窗口里看到內(nèi)部信號的變化。如果省掉這個參數(shù)ModelSim可能會在優(yōu)化時把某些信號優(yōu)化掉波形窗口里就找不到了。第五步的add wave是添加需要觀察的波形信號。如果你不確定要觀察哪些信號可以先只添加testbench頂層的時鐘和復位等仿真跑起來之后再到Object窗口拖動信號到波形窗口。但腳本里預先添加的好處是每次重新仿真不需要再手動加一遍信號省時省力。最后一步run -all就是讓仿真一直跑下去直到testbench里的$finish被執(zhí)行。有些testbench里沒有$finish仿真就會無限跑下去這時候你可以設(shè)置仿真時間上限比如run 10us之類的。3.3 filelist文件的組織方式與易靈思工程對接filelist.f的主要內(nèi)容就是行為仿真需要的所有RTL文件和testbench文件。我一般把它放在工程根目錄內(nèi)容如下## RTL source files ../rtl/tb_matrix_top.v ../rtl/matrix_mult.v ../rtl/multiplier.v ../rtl/ram_wrapper.v ## Testbench ../tb/tb_matrix_top.sv這里需要強調(diào)一個和Efinity聯(lián)動的關(guān)鍵點如果你在Efinity里使用了IP核IP核的文件路徑往往是由工具自動生成的位置一般在你工程目錄下的ipcore文件夾中。這些IP核仿真模型文件也要加入filelist。麻煩的地方在于Efinity在不同版本里生成的IP核目錄結(jié)構(gòu)不完全一樣有時候是.v文件有時候是.sv文件需要你根據(jù)實際生成結(jié)果手動補充。我的經(jīng)驗是第一次做某個IP核的仿真時先看看Efinity生成的仿真文件有哪些把路徑記錄下來之后每次新建工程直接把這些路徑復制到filelist里就行。這一步雖然繁瑣但一次配好之后就可以一勞永逸。4. 實操過程從Efinity工程到ModelSim仿真的完整流程4.1 在Efinity中創(chuàng)建或定位仿真文件要在Efinity和ModelSim之間建立聯(lián)仿首先你的設(shè)計得有一個完整的testbench。在Efinity里testbench文件和普通RTL文件一樣都是工程文件的一部分。你可以在“File→Add File”里將testbench文件加入工程也可以在文件管理器里直接放在工程目錄下。我推薦后一種方式原因是testbench只參與仿真不參與綜合如果作為工程文件加入Efinity會嘗試對它做綜合約束盡管最終會被忽略可能引發(fā)一些多余的告警信息。還有個細節(jié)是Efinity工程的頂層模塊和testbench頂層模塊不能重名否則在后續(xù)的自動化腳本配置時會出現(xiàn)混亂。我在早期項目里就犯過這種低級錯誤頂層叫matrix_toptestbench也叫matrix_top結(jié)果ModelSim加載仿真時加載錯模塊跑了半天看到信號卻完全不對。4.2 用腳本一鍵完成ModelSim仿真的操作實錄假設(shè)你已經(jīng)有了一個完整的Efinity工程RTL代碼和testbench都有了下面是我實操中的步驟。第一步在工程目錄下新建一個名為sim的文件夾然后在里面創(chuàng)建filelist.f、sim_run.tcl兩個文件內(nèi)容參考上文。第二步在sim文件夾里打開ModelSim命令行Windows下是打開ModelSim后在Transcript窗口用cd命令切換路徑Linux下直接終端進入目錄后輸入vsim打開ModelSim GUI再在命令行執(zhí)行source sim_run.tcl。第三步執(zhí)行source sim_run.tcl然后觀察ModelSim的Transcript窗口輸出。正常情況下你會看到vlib創(chuàng)建work庫、vlog編譯文件、vsim加載設(shè)計的信息最后波形窗口自動彈出并開始運行。整個過程不到10秒。如果你手動操作可能需要5到10分鐘這還只是單次如果迭代修改代碼腳本的省時優(yōu)勢會成倍放大。4.3 易靈思IP核仿真的特殊處理如果你在設(shè)計中用到了易靈思的IP核比如PLL或Block RAM仿真處理上比Altera/Xilinx稍麻煩一點。Xilinx的Vivado在你生成IP核時會自動產(chǎn)出仿真模型文件并加入工程易靈思的Efinity也會生成仿真模型但位置和格式經(jīng)常讓人覺得不直觀。以PLL為例Efinity生成的PLL IP中有一個pll_sim.v或類似命名的文件這就是ModelSim仿真時需要編譯的模型文件。你要做的就是在filelist.f中加上這一行../ipcore/pll/pll_sim.v除了模型文件本身IP核可能還依賴易靈思提供的通用庫文件比如efx_prim.v之類的。這些文件一般位于Efinity安裝目錄的lib或prim目錄下。你可以在filelist.f里用絕對路徑引用也可以拷貝到工程目錄下。我傾向拷貝到工程目錄下的sim_lib文件夾方便隨工程一起交給團隊成員。編譯順序有講究先編譯底層庫文件和IP核模型再編譯RTL代碼最后編譯testbench。如果你把testbench排在最前面ModelSim編譯時會因為找不到testbench引用的模塊定義而報錯。我的filelist.f默認把IP核和底層庫放前面RTL放中間testbench放最后這個順序保持穩(wěn)定。5. 常見問題與排查技巧實錄聯(lián)仿路上我踩過的坑5.1 仿真波形顯示紅線或高阻態(tài)這個問題出現(xiàn)頻率最高幾乎每個新手都會遇到。仿真波形顯示紅線未知態(tài)通常有兩種原因一是testbench沒有正確產(chǎn)生復位和時鐘二是RTL代碼里有信號沒有初始化。排查方法很簡單先看時鐘和復位信號。如果時鐘信號本身就是紅線說明testbench產(chǎn)生了時鐘問題在編譯或加載環(huán)節(jié)如果時鐘是正常的方塊波但某個業(yè)務(wù)信號是紅線多半是RTL代碼里寄存器沒復位或者輸入信號沒有連對。我習慣在每個testbench的initial塊里先給所有輸入信號賦初值再拉高復位再拉低復位這樣能避免90%以上的紅線問題。initial begin clk 1b0; rst_n 1b0; start 1b0; data_in 32d0; repeat(5) begin #10 clk ~clk; end rst_n 1b1; end always #10 clk ~clk;注意testbench里時鐘用always永遠不能寫在initial塊內(nèi)部這是新手經(jīng)常犯的語法錯誤。5.2 vmap庫映射失敗怎么辦庫映射失敗是第二高發(fā)的錯誤。常見表現(xiàn)是編譯時報錯找不到某個庫或某個模塊或者加載仿真時報Cannot find module。這通常是因為IP核的仿真庫沒有正確映射或編譯。解決辦法分兩步第一步檢查你的filelist.f是否包含了所有IP核仿真模型文件第二步檢查vmap的路徑是否正確。如果路徑不對ModelSim不會給出“路徑錯誤”的提示而是報“無法打開庫”之類你需要結(jié)合自己的實際情況逐條核對。另外如果你在ModelSim中通過GUI執(zhí)行腳本注意工作目錄和你腳本所在目錄是否一致。ModelSim的vmap是相對于當前工作目錄解析相對路徑的不一致會導致路徑錯誤。一個穩(wěn)妥的做法是腳本開頭先用cd命令切換到腳本所在目錄cd [file dirname [info script]]這行Tcl命令的意思是“把當前目錄切換到腳本自身所在的目錄”加入之后腳本的路徑問題基本就不會再出現(xiàn)了。5.3 編譯報錯vlog cannot find systemverilog extension有些IP核模型文件是.sv格式的需要vlog開啟-sv選項才能編譯。如果你在filelist編譯時忘了加-svModelSim會報cannot find systemverilog extension但實際上并不是找不到文件而是文件后綴識別問題。加上-sv選項即可。我在腳本中默認一直帶著-sv即使當前工程沒有SystemVerilog文件也不影響。還有個細節(jié)如果filelist中既有.v又有.sv文件-sv是全局選項對混合格式的文件列表同樣適用。5.4 仿真運行時間過長或卡死有時候run -all執(zhí)行后仿真界面看起來像卡住了波形窗口沒有任何輸出進度條也不動。這種情況絕大多數(shù)是因為testbench的$finish沒觸發(fā)仿真一直在死循環(huán)中運行。比如testbench里寫了forever #10 clk ~clk;但沒有設(shè)置結(jié)束條件仿真就會無限跑下去。解決方法有幾個一是testbench中加一個initial塊讓它作為仿真超時看門狗initial begin #10000; $display(Simulation timeout!); $finish; end這樣即使主邏輯卡住仿真也會在10000個時間單位后自動退出并打印超時提示。第二種方法是手動在ModelSim命令行里執(zhí)行run 100us限制只跑100微秒看結(jié)果。第三種是檢查testbench里有沒有死循環(huán)比如往FIFO里寫數(shù)據(jù)時FIFO滿但代碼沒有等待full信號讀數(shù)據(jù)時FIFO空但代碼沒有等待empty信號。這類問題把testbench的邏輯梳理一遍通常就能發(fā)現(xiàn)。5.5 快速排查清單我把上面這些總結(jié)成一張速查表方便你在遇到問題時對照處理異?,F(xiàn)象可能原因處理辦法時鐘和復位都是紅線testbench時鐘未生成或復位未拉高檢查always時鐘塊、initial中復位時序部分信號是紅線RTL中寄存器和狀態(tài)機未初始化復位邏輯補全信號初值設(shè)置編譯找不到IP核模塊IP核仿真模型未加入filelist檢查ipcore目錄把仿真模型加入filelistvmap庫路徑報錯庫路徑和版本不匹配檢查vmap命令行確認Work庫路徑正確run -all 后窗口無響應testbench死循環(huán)或未設(shè)置$finish加看門狗initial塊或設(shè)置run時間上限add wave后波形窗口空信號被vopt優(yōu)化掉了使用-voptargsacc編譯選項編譯.sv報錯缺少SystemVerilog支持vlog加-sv參數(shù)5.6 和Vivado/ISE聯(lián)仿思路的核心區(qū)別如果你之前用過Vivado和ModelSim聯(lián)仿你會發(fā)現(xiàn)易靈思的聯(lián)仿過程有幾點明顯不同。首先是IP核處理Vivado的仿真庫由工具自動管理編譯好庫一次配置永久生效易靈思則需要手動維護模型文件和庫映射自動化程度稍低一點。其次是時序仿真的門檻Vivado里有完整的時間模型和SDF文件導出易靈思的Efinity也能生成SDF但流程上需要多幾步操作新手建議先從功能仿真入手等熟悉了再嘗試時序仿真。第三是工具鏈對Tcl腳本的支持差異Efinity的Tcl接口做得比較干凈熟悉之后會覺得很順手但前提是你需要花一點時間去讀它的命令參考手冊。6. 進階擴展腳本還能怎么玩6.1 模擬仿真與回歸測試自動化當你手里有了可用的聯(lián)仿腳本下一步可以做的事就是把它擴展成回歸測試工具。最簡單的做法是寫一個批處理或shell腳本循環(huán)運行多個testbench的仿真#!/bin/bash for tb in tb_matrix_mult tb_fifo_ctrl tb_uart_rx tb_uart_tx; do echo Running testbench: $tb vsim -c -do source sim_run_${tb}.tcl; run -all; quit -f done這里用到了ModelSim的命令行模式-c參數(shù)配合-do參數(shù)直接執(zhí)行Tcl腳本不需要打開GUI界面。這個方式在服務(wù)器上跑回歸測試特別方便可以把每個testbench的仿真結(jié)果輸出到日志文件再統(tǒng)一檢查有沒有Error關(guān)鍵字。6.2 覆蓋率收集與報告生成ModelSim自帶覆蓋率收集功能可以在vsim時加上相關(guān)的命令vsim -coverage -cover enable -voptargsacc work.tb_matrix_top仿真結(jié)束后使用coverage report命令查看當前仿真中代碼覆蓋率、行覆蓋率、條件覆蓋率等信息。項目后期做質(zhì)量驗證的時候這組命令幾乎是標配。不過要注意覆蓋率收集會讓仿真速度變慢30%到50%所以一般只在回歸版本或提交前做日常開發(fā)中我不會每次都開啟。6.3 斷言仿真與調(diào)試技巧SystemVerilog斷言SVA在ModelSim中可以直接支持。如果你在testbench里寫了assert property之類的斷言語句仿真運行時如果斷言失敗ModelSim會在Transcript窗口打印錯誤信息你可以通過腳本在遇到斷言失敗時自動停止仿真vsim -assertdebug -voptargsacc work.tb_matrix_top加上-assertdebug參數(shù)后你可以在仿真過程中查看斷言的覆蓋情況也能在斷言失敗時快速定位到時間點和信號狀態(tài)。這個功能對于我這種經(jīng)常和復雜狀態(tài)機打交道的人來說簡直是救命稻草。如果你只是仿真簡單的組合邏輯可能用不上但一旦設(shè)計復雜度上來早點掌握斷言仿真不會有壞處。7. 終極避坑心得三個讓我印象深刻的教訓回到最初的話題為什么易靈思的聯(lián)仿會讓新手覺得不友好核心原因是它把仿真環(huán)境的選擇權(quán)交給了用戶而不是像Vivado那樣“全家桶”式地幫你搞定一切。這種設(shè)計思路本身沒問題但它對使用者的工程素養(yǎng)要求更高你需要理解編譯庫的概念、明白仿真模型的區(qū)別、懂得Tcl腳本的基本語法。這些東西在圖形化界面時代逐漸被淡化了所以第一次接觸易靈思工具鏈的人會有些不適應。我個人在實際操作中最深的體會是聯(lián)仿腳本不是一蹴而就的而是一個持續(xù)迭代的過程。第一個版本可能很簡陋只是簡單的編譯和仿真隨著項目推進你會不斷往里面加內(nèi)容——新的文件路徑、新的仿真參數(shù)、新的信號列表。這時候保持腳本的模塊化很重要。我會把filelist、信號列表、編譯選項拆分成獨立的文件或變量這樣每次修改時不會牽一發(fā)而動全身。最后再分享一個小技巧在ModelSim的wave窗口里你可以給信號分組加顏色比如時鐘復位用白色、總線數(shù)據(jù)用黃色、狀態(tài)機狀態(tài)變量用綠色。配合腳本里的add wave -color命令可以在仿真一開始就自動生成帶顏色的波形顯示調(diào)試狀態(tài)機時一眼就能看出當前狀態(tài)的變化軌跡。這一步雖然簡單但能明顯提升調(diào)試效率屬于那種“用過就回不去”的小功能。聯(lián)仿這件事說難不難說簡單也不簡單關(guān)鍵是把思路理順把腳本備好。按照上面這套流程走一遍我相信你也能把自己的仿真環(huán)境搭起來跑通第一個波形。如果你在操作中遇到本文沒有覆蓋到的問題歡迎帶著具體報錯信息來交流很多坑確實需要在實戰(zhàn)中才能發(fā)現(xiàn)。