合仿真實戰(zhàn):從庫編譯到Verdi調(diào)試)
1. 為什么還要折騰 Vivado 與 VCS 聯(lián)合仿真如果你平時用 Vivado 自帶的仿真器跑功能驗證小規(guī)模模塊還湊合一旦設(shè)計里塞進幾個 DDR 控制器、多路 AXI 互聯(lián)或者帶時序約束的門級網(wǎng)表仿真速度就會慢到讓人懷疑人生。我最早做圖像處理流水線的時候一個 1080p 幀的仿真跑了四十多分鐘還沒出結(jié)果后來換成 VCS 編譯同一份 RTL同樣的激勵不到三分鐘就跑完了。這就是為什么很多團隊在 FPGA 項目進入中后期都會把仿真主力從 Vivado Simulator 切到 VCS再配 Verdi 看波形。這篇內(nèi)容面向的是已經(jīng)能跑通基本 Vivado 工程、但對 Linux 下編譯仿真庫和聯(lián)合仿真流程還不太熟的 FPGA 開發(fā)者。我會把 Vivado 2025.1 搭配 VCS 2024.SP1 的整套流程拆開講從編譯 Xilinx 仿真庫、生成仿真腳本到用 Verdi 加載 FSDB 波形做調(diào)試每一步都給出可復(fù)現(xiàn)的命令和踩坑記錄。整套流程在 CentOS 7 和 Ubuntu 20.04 上都驗證過工具版本雖然新但核心邏輯和幾年前的老版本是相通的理解了原理換版本也不慌。需要提前說明的是聯(lián)合仿真的本質(zhì)是讓 Vivado 負責(zé)“提供器件相關(guān)的仿真模型”VCS 負責(zé)“編譯和執(zhí)行仿真”Verdi 負責(zé)“波形查看和調(diào)試”。三者各司其職中間靠編譯好的庫文件和仿真腳本銜接。搞清楚了這條鏈路后面遇到任何報錯你都能定位到是哪一環(huán)出了問題。2. 環(huán)境準(zhǔn)備與工具版本匹配2.1 版本搭配不是隨便選的工具版本搭配這件事我踩過的坑比想象中多。Vivado 2025.1 是較新的版本它編譯出來的仿真庫對 VCS 的版本有最低要求。VCS 2024.SP1 屬于 2024 系列和 2025.1 的庫編譯腳本兼容性比較好。如果你手上是 VCS 2020 甚至更早的版本編譯 Xilinx 的某些 IP 庫尤其是帶 SystemVerilog 斷言的時大概率會報語法不支持的錯。一個實用的判斷原則Vivado 的版本年份不要比 VCS 領(lǐng)先太多領(lǐng)先一到兩年通常沒問題領(lǐng)先三年以上就要小心。另外VCS 的安裝路徑里不要帶空格和中文Verdi 同理這是很多新手第一次配置就翻車的地方。工具推薦版本作用注意事項Vivado2025.1提供仿真庫、IP 模型、生成腳本安裝時勾選完整器件庫VCS2024.SP1編譯 RTL 與庫、執(zhí)行仿真需配置 licenseVerdi隨 VCS 同版本查看 FSDB 波形、調(diào)試與 VCS 版本保持一致操作系統(tǒng)CentOS 7 / Ubuntu 20.04運行環(huán)境避免用最新內(nèi)核兼容性優(yōu)先2.2 環(huán)境變量配置要點環(huán)境變量是聯(lián)合仿真的“地基”配錯了后面全是玄學(xué)問題。我習(xí)慣把工具路徑統(tǒng)一寫進一個setup.sh每次開終端 source 一下。核心是三個變量VCS_HOME、VERDI_HOME、PATH以及 license 相關(guān)的LM_LICENSE_FILE或SNPSLMD_LICENSE_FILE。export VCS_HOME/opt/synopsys/vcs/2024.06-SP1 export VERDI_HOME/opt/synopsys/verdi/2024.06-SP1 export PATH$VCS_HOME/bin:$VERDI_HOME/bin:$PATH export SNPSLMD_LICENSE_FILE27020your_license_server注意license 服務(wù)器地址一定要用實際可用的配置完先用lmstat確認能連上否則 VCS 編譯到一半才報 license 錯誤白白浪費時間。Vivado 這邊如果你是在圖形界面里操作環(huán)境變量會自動帶上但如果要在純命令行下用compile_simlib需要先 source Vivado 的settings64.sh。我一般會在同一個終端里先 source Vivado 環(huán)境再 source Synopsys 環(huán)境順序不要反否則 PATH 里 Vivado 的某些工具可能被覆蓋。2.3 磁盤空間與權(quán)限的隱形坑編譯 Xilinx 仿真庫是個“吃磁盤”的活。全器件庫編譯下來幾十 GB 是常態(tài)。我建議單獨掛一塊數(shù)據(jù)盤把庫編譯到非系統(tǒng)盤路徑下。另外編譯過程會生成大量臨時文件如果/tmp分區(qū)太小中途會報“No space left on device”這個報錯很隱蔽因為看起來像是編譯錯誤實際是磁盤滿了。權(quán)限方面如果你用的是公司服務(wù)器庫目錄最好放在自己有寫權(quán)限的路徑下比如/home/yourname/sim_lib。放在/opt下雖然看起來規(guī)范但每次編譯都要 sudo反而麻煩。我個人的習(xí)慣是每個項目單獨建一個sim_lib目錄雖然占空間但項目之間互不干擾換 Vivado 版本時也不用擔(dān)心庫被覆蓋。3. 編譯 Xilinx 仿真庫的完整流程3.1 圖形界面編譯與命令行編譯怎么選Vivado 提供了兩種編譯仿真庫的方式圖形界面Tools - Compile Simulation Libraries和命令行compile_simlib。圖形界面適合第一次操作、想看清楚每一步在干什么的人命令行適合需要批量編譯、或者要在無圖形界面的服務(wù)器上操作的場景。我兩種都用過結(jié)論是第一次建議用圖形界面熟悉流程后全部轉(zhuǎn)命令行。原因是圖形界面編譯大庫時如果中途卡住你很難判斷是死機了還是在慢慢跑命令行有明確的進度輸出而且可以寫成腳本重復(fù)執(zhí)行。圖形界面里幾個關(guān)鍵選項要選對Simulator 選 VCSLanguage 根據(jù)你的設(shè)計選 Verilog 或 SystemVerilog混合設(shè)計選后者Library 選擇你實際用到的器件系列。不要圖省事選“All”全編譯一次可能要一兩個小時而且大部分庫你根本用不到。3.2 命令行編譯庫的實操命令命令行編譯的核心命令是compile_simlib它需要在 Vivado 的 Tcl 環(huán)境下執(zhí)行。我通常寫一個compile_lib.tcl腳本然后用vivado -mode batch -source compile_lib.tcl執(zhí)行。compile_simlib -simulator vcs_mx \ -simulator_exec_path /opt/synopsys/vcs/2024.06-SP1/bin \ -family kintex7 \ -family zynq \ -language verilog \ -library unisim \ -library simprim \ -dir /home/yourname/sim_lib/vivado2025.1 \ -no_systemc_compile這里有幾個參數(shù)值得展開說。-simulator vcs_mx表示用 VCS 的 MX 模式支持混合語言如果你只跑純 Verilog用vcs也行但 MX 模式兼容性更好。-simulator_exec_path指向 VCS 的 bin 目錄這個必須準(zhǔn)確否則編譯出來的庫可能和實際 VCS 版本不匹配。-family指定器件系列我一般只編譯項目實際用到的比如 Kintex-7 和 Zynq。-no_systemc_compile是跳過 SystemC 庫編譯除非你做 SystemC 聯(lián)合仿真否則沒必要編能省不少時間。編譯完成后目錄下會生成一堆.vdb、.so和映射文件。最關(guān)鍵的是modelsim.ini的等價物——VCS 用的是synopsys_sim.setup文件里面記錄了庫名到實際路徑的映射。這個文件后面在仿真腳本里要引用。3.3 編譯過程中的常見報錯與處理編譯庫時最容易遇到的是兩類問題一是 VCS 版本不兼容導(dǎo)致的語法報錯二是環(huán)境變量缺失導(dǎo)致的工具找不到。前者通常表現(xiàn)為某個.v文件編譯失敗報“SystemVerilog keyword not supported”之類后者會直接提示“vlogan: command not found”。遇到版本不兼容最直接的解決辦法是換 VCS 版本或者只編譯你真正需要的庫。有時候某個 IP 的仿真模型用了新語法你可以單獨把這個 IP 的庫排除掉用行為級模型替代。環(huán)境變量問題就簡單了檢查PATH里有沒有 VCS 的 bin 目錄which vlogan能不能找到。還有一個隱蔽的坑編譯庫時如果同時開了多個終端在跑可能會因為臨時文件沖突導(dǎo)致編譯失敗。我一般會確保同一時間只有一個編譯任務(wù)在跑編譯前先清理一下臨時目錄。4. 生成仿真腳本與聯(lián)合仿真配置4.1 從 Vivado 導(dǎo)出仿真腳本Vivado 可以自動生成 VCS 的仿真腳本路徑是 File - Export - Export Simulation。這里要選 VCS 作為目標(biāo)仿真器并指定之前編譯好的庫路徑。導(dǎo)出的腳本通常包括compile.sh、elaborate.sh、simulate.sh三個分別對應(yīng)編譯、精化和仿真三個階段。不過自動生成的腳本往往比較“通用”里面會包含很多你不需要的庫引用。我的做法是把它作為起點然后手動精簡。比如它會默認引用所有器件的庫你只需要保留實際用到的。精簡后的腳本跑起來更快也更容易排查問題。導(dǎo)出時還有一個關(guān)鍵選項是否包含-debug_access參數(shù)。如果你要用 Verdi 看波形必須確保編譯時加了調(diào)試信息。VCS 的-debug_accessall或者-kdb參數(shù)就是干這個的。自動生成的腳本有時會漏掉需要手動補上。4.2 手寫仿真腳本的骨架自動生成的腳本看懂了之后我更推薦手寫一份精簡版這樣每個參數(shù)都心里有數(shù)。一個典型的 VCS 聯(lián)合仿真腳本分三步vlogan編譯 Verilog 源文件和庫vcs精化生成可執(zhí)行文件simv執(zhí)行仿真。# 第一步編譯庫和源文件 vlogan -full64 -sverilog v2k -timescale1ns/1ps \ -work work \ -f filelist.f \ -y $SIM_LIB/unisim \ libext.v.sv \ -l compile.log # 第二步精化 vcs -full64 -debug_accessall -kdb \ -timescale1ns/1ps \ -top tb_top \ -l elaborate.log # 第三步仿真 ./simv -l sim.log fsdbautoflush-full64表示 64 位模式現(xiàn)在基本是標(biāo)配。-sverilog和v2k讓 VCS 支持 SystemVerilog 和 Verilog-2001 語法。-timescale要和你的設(shè)計一致否則時序會對不上。-y指定庫搜索路徑libext指定庫文件擴展名。-debug_accessall和-kdb是給 Verdi 用的前者生成調(diào)試信息后者生成 Verdi 的知識數(shù)據(jù)庫缺一不可。提示fsdbautoflush讓仿真過程中波形自動刷新到 FSDB 文件這樣即使仿真中途崩潰已經(jīng)產(chǎn)生的波形也不會丟。做長仿真時這個參數(shù)能救命。4.3 庫映射文件與路徑管理VCS 通過synopsys_sim.setup文件來定位庫。這個文件可以放在當(dāng)前工作目錄也可以放在$VCS_HOME/bin下作為全局配置。我傾向于放在項目目錄下每個項目獨立管理。文件內(nèi)容大致是這樣WORK DEFAULT DEFAULT : ./work UNISIM : /home/yourname/sim_lib/vivado2025.1/unisim SIMPRIM : /home/yourname/sim_lib/vivado2025.1/simprimWORK是默認的工作庫UNISIM和SIMPRIM指向編譯好的 Xilinx 庫。路徑一定要用絕對路徑相對路徑在不同終端下容易出問題。如果項目里用了多個 IP每個 IP 的庫也要在這里加一行映射。路徑管理的一個經(jīng)驗是把所有庫路徑寫進一個環(huán)境變量腳本里引用變量而不是硬編碼路徑。這樣換機器或者換庫版本時只改一個地方就行。5. Verdi 波形調(diào)試與 FSDB 加載5.1 生成 FSDB 波形的兩種方式Verdi 看波形的前提是有 FSDB 文件。生成 FSDB 有兩種方式一種是在 Testbench 里直接調(diào)用$fsdbDumpfile和$fsdbDumpvars系統(tǒng)函數(shù)另一種是用 VCS 的-fsdb編譯選項自動 dump。第一種方式更靈活可以精確控制 dump 哪些信號、從什么時間開始 dump。我通常會在 Testbench 的 initial 塊里加initial begin $fsdbDumpfile(wave.fsdb); $fsdbDumpvars(0, tb_top); end$fsdbDumpvars的第一個參數(shù)是層級深度0 表示 dump 所有層級。如果設(shè)計很大全 dump 會讓 FSDB 文件巨大這時候可以指定只 dump 某個模塊比如$fsdbDumpvars(1, tb_top.u_dut)。第二種方式是在編譯時加-fsdb和-P參數(shù)讓 VCS 自動插入 dump 邏輯。這種方式適合不想改 Testbench 的場景但控制粒度不如第一種。5.2 Verdi 加載波形的實操步驟Verdi 啟動命令是verdi -ssf wave.fsdb-ssf表示加載 FSDB 文件。如果同時要看 RTL 代碼可以加-sv和-f filelist.f這樣 Verdi 會把源代碼也加載進來方便做信號追蹤。Verdi 里幾個高頻操作Get Signal把信號加到波形窗口Trace Driver追蹤信號驅(qū)動源Trace Load追蹤信號負載。做調(diào)試時我習(xí)慣先用Trace Driver找到信號是被哪個模塊驅(qū)動的再順著看邏輯對不對。還有一個很實用的功能是nWave里的Analog顯示模式??纯偩€信號或者計數(shù)器時用模擬波形顯示比數(shù)字波形直觀得多。右鍵信號選Analog就能切換。5.3 用 Verdi 做后仿真的技巧后仿真門級仿真和 RTL 仿真最大的區(qū)別是時序信息。后仿真時Verdi 里可以看到門級網(wǎng)表的延遲這時候Trace Driver可能會追到標(biāo)準(zhǔn)單元內(nèi)部看起來比較亂。我的做法是先用 RTL 仿真確認功能正確再做后仿真確認時序。后仿真時 FSDB 文件會非常大因為每個門都有信號變化。這時候要控制 dump 范圍只 dump 關(guān)鍵模塊。另外后仿真跑得慢建議先用小激勵跑通再上完整激勵。注意后仿真時如果發(fā)現(xiàn) X 態(tài)傳播先檢查 memory 初始化。很多后仿真的 X 態(tài)問題都是 memory 沒有正確初始化導(dǎo)致的RTL 仿真時 memory 默認是 X但行為級模型可能掩蓋了這個問題。6. 常見問題排查與避坑經(jīng)驗6.1 編譯階段的典型報錯編譯階段最常見的問題是庫找不到和語法不兼容。庫找不到的報錯通常是“module not found”這時候要檢查synopsys_sim.setup里的路徑對不對以及-y參數(shù)有沒有指向正確的庫目錄。語法不兼容的報錯會具體指出哪個文件哪一行通常是 SystemVerilog 的新特性在舊版 VCS 里不支持。還有一個坑是timescale不一致。如果 Testbench 和設(shè)計模塊的timescale不同仿真時間會錯亂。我一般會在編譯時統(tǒng)一指定-timescale1ns/1ps覆蓋源文件里的設(shè)置。6.2 仿真階段的常見異常仿真跑起來之后常見的問題有仿真卡死、結(jié)果不對、FSDB 文件為空。仿真卡死通常是死循環(huán)或者握手信號一直不滿足這時候可以用 Verdi 打開 FSDB 看最后時刻的信號狀態(tài)。結(jié)果不對要先確認激勵有沒有正確加載再看時序?qū)Σ粚?。FSDB 為空多半是$fsdbDumpfile沒執(zhí)行或者-debug_access沒加。問題現(xiàn)象可能原因排查方法編譯報 module not found庫路徑錯誤檢查 synopsys_sim.setup仿真卡死死循環(huán)或握手不滿足Verdi 看最后時刻信號FSDB 文件為空dump 函數(shù)未執(zhí)行檢查 Testbench 和編譯選項后仿真 X 態(tài)傳播memory 未初始化檢查 memory 初始化邏輯Verdi 無法加載源碼未加 -sv 或 filelist補上源碼加載參數(shù)6.3 我踩過的幾個印象深刻的坑第一個坑是 license 超時。有一次跑長仿真跑到一半 VCS 報 license 失效仿真直接中斷。后來發(fā)現(xiàn)是 license 服務(wù)器設(shè)置了空閑超時解決辦法是在腳本里加licqueue參數(shù)讓 VCS 排隊等 license而不是直接失敗。第二個坑是 FSDB 文件太大導(dǎo)致磁盤滿。一個后仿真跑了兩個小時FSDB 文件漲到 80 多 GB直接把磁盤寫滿。后來我改成只 dump 關(guān)鍵信號并且用$fsdbDumpoff和$fsdbDumpon控制 dump 時間段只在關(guān)鍵窗口 dump。第三個坑是 Verdi 版本和 VCS 版本不一致。有一次 VCS 是 2024 版Verdi 是 2022 版加載 FSDB 時報格式不兼容。后來統(tǒng)一了版本就沒事了。所以前面強調(diào)版本匹配真的是血淚教訓(xùn)。7. 聯(lián)合仿真的效率優(yōu)化建議7.1 編譯緩存與增量編譯VCS 支持增量編譯第二次編譯時只重新編譯改動的文件。開啟方式是加-Mupdate參數(shù)。對于大項目增量編譯能省很多時間。不過增量編譯有時會出玄學(xué)問題如果結(jié)果不對先試試全量編譯排除緩存問題。庫編譯也可以緩存。編譯好的 Xilinx 庫可以復(fù)用不用每次換項目都重編。我一般把庫放在一個固定路徑所有項目共用。只有換 Vivado 版本時才重新編譯。7.2 并行仿真與資源分配VCS 支持多核并行仿真加-j參數(shù)指定核數(shù)。比如-j8用 8 個核。不過并行仿真對某些設(shè)計效果不明顯因為仿真本身是串行的并行主要加速編譯階段。真正加速仿真要靠優(yōu)化激勵和減少 dump 信號。資源分配上編譯階段吃 CPU 和內(nèi)存仿真階段吃內(nèi)存和磁盤 IO。如果服務(wù)器內(nèi)存不夠仿真會頻繁 swap速度反而更慢。我一般確保仿真時至少有 16GB 可用內(nèi)存。7.3 波形 dump 策略的取舍波形 dump 是仿真速度的最大影響因素之一。全 dump 和只 dump 關(guān)鍵信號速度可能差好幾倍。我的策略是功能調(diào)試階段 dump 關(guān)鍵模塊回歸測試階段只 dump 錯誤時刻。用$fsdbDumpoff在仿真開始時關(guān)閉 dump檢測到錯誤時再$fsdbDumpon打開這樣 FSDB 文件小仿真也快。還有一個技巧是用$fsdbDumpvars的深度參數(shù)控制 dump 層級。比如只 dump 頂層和第一層子模塊深度設(shè)為 1這樣既能看整體信號又不會 dump 太多內(nèi)部信號。8. 寫在最后的幾句實在話這套 Vivado 2025.1 加 VCS 2024.SP1 的聯(lián)合仿真流程我從第一次配置到跑通大概花了兩天其中大部分時間耗在庫編譯和版本兼容上?,F(xiàn)在回頭看最值得花時間的是把環(huán)境變量和庫路徑管理好這兩件事做扎實了后面換項目、換版本都能快速遷移。如果你剛開始接觸聯(lián)合仿真建議先用一個小設(shè)計比如一個計數(shù)器加 Testbench把整個流程跑通確認編譯、仿真、波形查看三個環(huán)節(jié)都沒問題再上大項目。大項目直接上出了問題很難定位是流程問題還是設(shè)計問題。另外工具版本不要盲目追新。Vivado 2025.1 和 VCS 2024.SP1 這個組合我實測下來比較穩(wěn)但如果你團隊里其他人用的是老版本最好統(tǒng)一否則腳本和庫文件互相不兼容協(xié)作起來很痛苦。工具是拿來干活的穩(wěn)定比新更重要。