試?yán)鱅LA:從HDL實(shí)例化到Block Design的5個(gè)實(shí)戰(zhàn)技巧)
搞FPGA調(diào)試的人對(duì)ILA這個(gè)名字基本都不陌生。Vivado里的集成邏輯分析儀Integrated Logic Analyzer說白了就是把一個(gè)邏輯分析儀塞進(jìn)FPGA片內(nèi)靠BRAM、觸發(fā)器和LUT把你要看的信號(hào)給抓回來再通過JTAG送回電腦上顯示波形。真正上了板子之后仿真里面再完美的代碼也可能在最樸素的接口時(shí)序上翻車這種時(shí)候ILA幾乎是排查硬件問題的第一選擇。很多人一開始接觸ILA要么是直接在RTL里例化IP要么是在Block Design里拖一個(gè)核進(jìn)來兩條路我都走過。今天這篇就是把我實(shí)際跟蹤過的ILA調(diào)試過程整理出來從HDL實(shí)例化到Block Design配合5個(gè)實(shí)戰(zhàn)技巧講清楚怎么配、怎么連、怎么排查適合剛開始用Vivado調(diào)試硬件的新手也適合那種正被“抓不到信號(hào)”折磨的開發(fā)者。1. 從宏觀到微觀用ILA之前先把機(jī)制弄明白1.1 嵌入式邏輯分析儀到底在FPGA內(nèi)部干了什么ILA在Vivado里屬于Debug IP核它不是一個(gè)獨(dú)立的軟件工具而是被綜合進(jìn)你的設(shè)計(jì)里的一段硬件邏輯。你可以把它想象成在FPGA內(nèi)部裝了一個(gè)帶觸發(fā)功能的記錄儀它會(huì)按照某個(gè)時(shí)鐘節(jié)拍把連接到probe端口上的信號(hào)采樣下來然后寫進(jìn)片內(nèi)的BRAM。當(dāng)觸發(fā)條件滿足時(shí)它會(huì)根據(jù)你設(shè)置的時(shí)間位置把一段連續(xù)的波形數(shù)據(jù)保留下來最后通過JTAG鏈路回傳到電腦上的Hardware Manager窗口展示。理解這一點(diǎn)很重要因?yàn)楹芏嗳艘詾镮LA是在“實(shí)時(shí)顯示”信號(hào)其實(shí)它更像一個(gè)黑匣子。它工作在循環(huán)記錄模式一邊采一邊丟只有觸發(fā)發(fā)生后才會(huì)把觸發(fā)點(diǎn)前后的有效數(shù)據(jù)鎖存住。這也是為什么觸發(fā)器配置對(duì)不對(duì)會(huì)直接影響你能不能看到想要的波形。ILA核在FPGA內(nèi)部主要包括三塊東西用于采樣輸入的寄存器鏈、用于觸發(fā)條件判斷的比較器邏輯、以及用于存儲(chǔ)數(shù)據(jù)的BRAM。采樣時(shí)鐘、probe寬度、采樣深度這幾個(gè)參數(shù)在創(chuàng)建IP的時(shí)候就必須定下來因?yàn)檫@會(huì)直接決定BRAM和LUT的消耗。一個(gè)常見誤區(qū)是“ILA是免費(fèi)的隨便加多少路都行”實(shí)際上一不小心就能把BRAM耗盡導(dǎo)致implementation跑不過去。1.2 一條信號(hào)從片內(nèi)到波形窗口的完整旅程我曾經(jīng)帶過一個(gè)學(xué)生他以為ILA是通過USB直接把信號(hào)“透?jìng)鳌被仉娔X的所以一直搞不明白為什么下載完bitstream后還要再開Hardware Manager連接。實(shí)際上ILA的數(shù)據(jù)回傳路徑是這樣的目標(biāo)信號(hào)進(jìn)入probe端口在ILA核內(nèi)部被采樣并寫入BRAM然后通過JTAG接口送到Vivado的硬件服務(wù)器hw_server最終由Hardware Manager解析并顯示成波形。所以整個(gè)調(diào)試鏈路里除了ILA核本身還涉及三樣?xùn)|西JTAG連接器比如Digilent FTDI芯片或者Xilinx Platform Cable USB、硬件服務(wù)器進(jìn)程、以及Vivado里的硬件管理界面。只要其中一環(huán)斷掉你都會(huì)遇到“看不到ILA核”或者“抓不了信號(hào)”的問題。后面我會(huì)重點(diǎn)講硬件連接排查因?yàn)檫@是實(shí)操中翻車最多的地方。1.3 ILA的代價(jià)資源、時(shí)序和編譯時(shí)間ILA不是白嫖的它占用的資源往往是工程里被低估的一塊。以一個(gè)常見的配置為例采樣深度1024、probe寬度32bitILA大概要占用1到2個(gè)BRAM和不少觸發(fā)器。如果把probe寬度加到128bit、深度拉到8192BRAM消耗會(huì)成倍往上翻綜合面積也會(huì)明顯增加。更麻煩的是對(duì)高速時(shí)鐘域里加ILA如果插入邏輯帶來了額外的布線擁塞時(shí)序收斂可能直接從綠燈變紅。我個(gè)人的經(jīng)驗(yàn)是調(diào)試階段可以暫時(shí)放開時(shí)序約束去抓信號(hào)但確認(rèn)問題后一定要把多余的ILA核移除或者裁剪掉。這不僅是省資源的問題更是為了避免“加了ILA之后功能正常去掉ILA反而出bug”這種莫名其妙的現(xiàn)象。因?yàn)镮LA接在信號(hào)上會(huì)引入額外的負(fù)載對(duì)時(shí)序敏感的設(shè)計(jì)會(huì)產(chǎn)生肉眼可見的影響。2. 技巧一HDL實(shí)例化ILA老思路解決新問題2.1 哪些場(chǎng)景更適合在RTL里直接例化剛開始學(xué)Vivado的時(shí)候我喜歡在Block Design里通過右鍵菜單加ILA因?yàn)椴挥脤懘a鼠標(biāo)點(diǎn)幾下就完事。但后來做了一些純HDL工程之后發(fā)現(xiàn)RTL實(shí)例化其實(shí)有它不可替代的優(yōu)勢(shì)。第一種場(chǎng)景是工程本身沒有BD只有純verilog或者VHDL源碼為了一個(gè)調(diào)試核去建一個(gè)Block Design再加個(gè)wrapper反而折騰。第二種場(chǎng)景是你只想觀察某個(gè)模塊內(nèi)部的中間信號(hào)而這些信號(hào)沒有引到頂層端口用Set Up Debug又容易被綜合優(yōu)化掉直接在模塊內(nèi)部例化ILA最直接。第三種場(chǎng)景是你在做別人維護(hù)過的舊工程里面已經(jīng)有ILA例化代碼你只需要照著格式改個(gè)名字、改幾個(gè)probe就行不需要重新走一遍IP配置流程。RTL實(shí)例化ILA最大的好處是“所見即所得”信號(hào)連到哪里一眼就看得清。缺點(diǎn)是每次改probe寬度或者采樣深度都要重新生成IP并改例化代碼不能像Set Up Debug那樣在布局布線后半自動(dòng)調(diào)整。2.2 從IP Catalog創(chuàng)建ILA核并配置參數(shù)先走一遍標(biāo)準(zhǔn)流程。打開Vivado工程后點(diǎn)擊左側(cè)IP Catalog在搜索欄輸入ILA找到“Integrated Logic Analyzer (ILA)”雙擊打開配置界面。Configuration頁面里最常用的是這樣幾項(xiàng)Component Name給ILA核起個(gè)名字比如ila_top生成后你會(huì)在IP Sources里看到這個(gè)核。Number of Probes你要連接的probe端口數(shù)量。這里的probe指的不是一個(gè)信號(hào)而是一組信號(hào)比如一個(gè)32bit的數(shù)據(jù)總線就是一個(gè)probe一個(gè)1bit的復(fù)位信號(hào)也是一個(gè)probe。Probe Width每個(gè)probe的信號(hào)寬度。需要注意probe的寬度是在例化時(shí)固定下來的改動(dòng)后需要重新生成IP。Sample Data Depth這是采樣深度通??蛇x項(xiàng)有1024、4096、8192等。這個(gè)值決定BRAM中能存多少個(gè)時(shí)鐘周期的數(shù)據(jù)。Number of Trigger Conditions觸發(fā)條件數(shù)量很多入門用戶會(huì)忽略這個(gè)選項(xiàng)默認(rèn)1個(gè)就行但如果你需要多條件觸發(fā)可以提前配置為2或者4。配置完成后點(diǎn)Generate。此時(shí)Vivado會(huì)生成一個(gè)名為ila_top的IP核里面包括一份例化模板。你可以在Sources面板里找到該IP的HDL源文件打開后能看到“Instancing Template”的注釋塊直接復(fù)制到你的RTL代碼里把probe端口連上目標(biāo)信號(hào)就行。2.3 RTL例化的標(biāo)準(zhǔn)寫法和保持信號(hào)技巧舉一個(gè)最簡(jiǎn)單的例子。假設(shè)我的設(shè)計(jì)里有一個(gè)32bit的數(shù)據(jù)總線data_in一個(gè)寫使能wr_en一個(gè)時(shí)鐘clk想在RTL里直接觀察這三路信號(hào)。那么我可以把ILA核配置成兩個(gè)probeprobe0連wr_en寬度1probe1連data_in寬度32。例化代碼類似這樣ila_top u_ila_top ( .clk (clk), .probe0 (wr_en), .probe1 (data_in) );注意clk必須是真實(shí)存在的時(shí)鐘信號(hào)不能是某個(gè)邏輯生成的臨時(shí)脈沖因?yàn)镮LA需要穩(wěn)定的時(shí)鐘做采樣。另外一個(gè)非常關(guān)鍵的點(diǎn)是如果你連的信號(hào)在綜合時(shí)被優(yōu)化掉了ILA就抓不到有效數(shù)據(jù)。這種情況下要做兩件事一是在信號(hào)聲明處加(* mark_debug true *)綜合屬性二是確認(rèn)在綜合設(shè)置里沒有把ILA相關(guān)的優(yōu)化開得過激。比如一個(gè)在verilog里定義但最后沒被使用的中間變量綜合器很可能直接優(yōu)化掉你在ILA里看到的就是恒定的0或者根本沒有這個(gè)信號(hào)可以選擇。(* mark_debug true *) wire [31:0] debug_data;加了mark_debug之后就算這個(gè)信號(hào)不接到任何輸出端口綜合器也會(huì)盡力保留它供調(diào)試使用。配合IP核里的“Include debug attributes in core”選項(xiàng)Vivado會(huì)在綜合時(shí)自動(dòng)把標(biāo)記信號(hào)關(guān)聯(lián)到已有的ILA核上這就是Set Up Debug能實(shí)現(xiàn)的基礎(chǔ)邏輯。3. 技巧二Block Design圖形化插入ILA上手最快但坑也不少3.1 在BD里手動(dòng)添加ILA核并連接信號(hào)使用Block Design做IP集成時(shí)插入ILA的流程很簡(jiǎn)單。打開BD后在Diagram空白處雙擊輸入ILA搜索單擊添加IP。添加后你會(huì)看到一個(gè)小方塊上面只暴露了clk和probe端口。此時(shí)你需要手動(dòng)把想要觀察的信號(hào)連線到probe上。這里有個(gè)容易踩的坑BD中的信號(hào)類型多種多樣有寄存器總線也有AXI接口、GPIO接口等。ILA的probe端口是普通wire類型所以你沒法直接把它拖到AXI總線上只能連接到像gpio_io_t、data[31:0]這種明確的bit或vector端口。如果你想抓AXI通道里的信號(hào)得先把總線拆成單個(gè)信號(hào)或者用IP Integrator里的“Slice”功能把總線的某一段引出來再接ILA。連接完成后雙擊ILA核可以重新配置probe數(shù)量、寬度和深度。此時(shí)你不需要手動(dòng)改例化代碼ILA的通道會(huì)自動(dòng)更新。不過要注意手動(dòng)連接的方式在一些舊版本的Vivado里存在了一個(gè)限制當(dāng)你修改上游模塊名稱或信號(hào)名時(shí)ILA的連接有可能出現(xiàn)懸空重新生成后常常會(huì)報(bào)“probe0 is not connected”的警告。解決方案是每次改完BD后運(yùn)行Validate Design確認(rèn)所有probe都有實(shí)際的連接。3.2 利用Set Up Debug自動(dòng)插入ILA除了手動(dòng)在BD里拖ILA核還有一個(gè)在工程后期非常實(shí)用的操作Set Up Debug。這個(gè)方式的前提是你的RTL代碼里已經(jīng)給某些信號(hào)加上了(* mark_debug true *)屬性。做過一次完整的流程之后你會(huì)發(fā)現(xiàn)這個(gè)方式非常適合調(diào)試階段頻繁改探測(cè)信號(hào)的場(chǎng)景。具體操作是先完成綜合打開綜合后的Design在菜單欄里選“Set Up Debug”。此時(shí)Vivado會(huì)掃描所有帶mark_debug屬性的信號(hào)把它們列在一個(gè)表中。你可以勾選要觀察的信號(hào)然后選擇是創(chuàng)建一個(gè)新的ILA核還是把信號(hào)附加到已有的ILA核上。配置好采樣深度和時(shí)鐘域后Vivado會(huì)自動(dòng)完成ILA連接并重新綜合。Set Up Debug最大的好處是它省去了手寫例化代碼和手動(dòng)畫線的麻煩而且可以非常自由地決定“這次只抓哪幾個(gè)信號(hào)”。壞處是它只適用于綜合后還能看到的信號(hào)。如果你的某個(gè)內(nèi)部信號(hào)因?yàn)榫C合優(yōu)化被刪掉了那么在Set Up Debug列表里根本找不到它。所以回到第一章節(jié)說的把關(guān)鍵信號(hào)加上mark_debug屬性這件事越早做越好。3.3 HDL實(shí)例化與Block Design方式怎么取舍我把兩種方式放在一張表里對(duì)比方便你在實(shí)際項(xiàng)目中快速?zèng)Q定用哪種對(duì)比項(xiàng)HDL實(shí)例化Block Design手動(dòng)連接/Set Up Debug工程要求純HDL或任意工程均可必須有Block Design或用綜合后流程改probe寬度需重新生成IP和改例化代碼BD中改配置比較直觀對(duì)綜合優(yōu)化容忍度RTL級(jí)聲明mark_debug后較穩(wěn)Set Up Debug依賴綜合后信號(hào)仍在可讀性代碼里一眼看出連了什么圖形界面直觀但層次復(fù)雜后容易亂集成自動(dòng)化低高典型場(chǎng)景小模塊快速調(diào)試、舊工程維護(hù)IP集成設(shè)計(jì)、大規(guī)模SoC調(diào)試我自己的經(jīng)驗(yàn)是小工程用HDL實(shí)例化最舒服因?yàn)槟愫苌傩枰磸?fù)改動(dòng)配置大工程特別是用了Zynq或者M(jìn)icroBlaze的我更喜歡BD里配合Set Up Debug因?yàn)楹芏郃XI外設(shè)的內(nèi)部信號(hào)用鼠標(biāo)點(diǎn)選比翻代碼定位快得多。兩種方式不沖突甚至可以在一個(gè)工程里混合使用只要注意不同ILA名字不要重復(fù)就行。4. 技巧三觸發(fā)條件怎么設(shè)才不浪費(fèi)每次抓取窗口4.1 觸發(fā)條件決定了你能看到什么很多人把ILA抓信號(hào)失敗的原因歸結(jié)為連接問題實(shí)際上有相當(dāng)一部分情況是觸發(fā)條件設(shè)置得不合理。ILA不是從頭到尾把信號(hào)錄像然后全量傳給電腦它是在循環(huán)采樣一旦觸發(fā)條件滿足就把觸發(fā)點(diǎn)前后的一段數(shù)據(jù)保留下來。所以如果你觸發(fā)條件設(shè)得太寬采樣緩沖里存的全是無關(guān)數(shù)據(jù)設(shè)得太嚴(yán)又可能永遠(yuǎn)等不到觸發(fā)。一個(gè)最簡(jiǎn)單的例子你想抓一個(gè)讀FIFO的時(shí)序關(guān)心的是fifo_rd_en拉高之后數(shù)據(jù)線上出現(xiàn)了什么。那么觸發(fā)條件就應(yīng)該設(shè)置為“fifo_rd_en 1”而不是“fifo_rd_en 0”或者在某個(gè)不相關(guān)的計(jì)數(shù)器上觸發(fā)。這一點(diǎn)聽起來像是廢話但我在實(shí)際調(diào)試中見過太多人把觸發(fā)信號(hào)選錯(cuò)導(dǎo)致Hardware Manager里波形就是不動(dòng)。4.2 多條件觸發(fā)與、或、比較器和計(jì)數(shù)器Vivado ILA支持在每個(gè)probe上設(shè)置觸發(fā)條件包括等于、不等于、大于、小于、變化沿等。比如probe0設(shè)置為“上升沿”觸發(fā)probe1設(shè)置為“等于某個(gè)特定值”。在Trigger Condition配置里可以添加多個(gè)條件并通過AND或者OR連接它們。這里有一個(gè)實(shí)用技巧如果你要抓一個(gè)突發(fā)傳輸?shù)拈_始你可以在寫數(shù)據(jù)總線上設(shè)置“data_out 8hA5”作為觸發(fā)條件。但更穩(wěn)的做法是同時(shí)加上寫使能信號(hào)作為“等于1”的條件兩個(gè)條件用AND連接。因?yàn)楣饪繑?shù)據(jù)總線上的一個(gè)特定值可能在非預(yù)期時(shí)刻也出現(xiàn)了同樣的值導(dǎo)致你抓到一堆誤觸發(fā)波形。如果你需要等原信號(hào)出現(xiàn)一定次數(shù)后才觸發(fā)ILA還支持在觸發(fā)條件里加計(jì)數(shù)器。這個(gè)功能在抓“第N個(gè)中斷”或者“第N次FIFO半滿”時(shí)特別有用。配置界面里設(shè)置“Trigger Condition Counter”為某個(gè)值即可硬件邏輯會(huì)自動(dòng)計(jì)數(shù)滿足次數(shù)后才給出觸發(fā)信號(hào)。4.3 存儲(chǔ)位置Begin/Center/End的選擇訣竅ILA的存儲(chǔ)位置有三個(gè)選項(xiàng)Begin、Center、End。它們決定了觸發(fā)點(diǎn)相對(duì)于存儲(chǔ)窗口的位置。Begin模式觸發(fā)點(diǎn)保存的是觸發(fā)事件之后的數(shù)據(jù)適合觀察“觸發(fā)之后發(fā)生了什么”。Center模式觸發(fā)點(diǎn)前后各保存一半數(shù)據(jù)適合觀察一個(gè)事件的完整上下文。End模式保存的是觸發(fā)事件之前的數(shù)據(jù)適合觀察“出事之前發(fā)生了什么”。我個(gè)人在排查故障時(shí)最喜歡用Center模式因?yàn)槟憧梢酝瑫r(shí)看到原因和結(jié)果。但如果你是在捕捉一個(gè)偶發(fā)性的毛刺想了解毛刺之前的狀態(tài)End模式更合適。Begin模式則更常用于確認(rèn)某個(gè)功能是否被正確觸發(fā)比如你想看啟動(dòng)狀態(tài)機(jī)之后到底走了哪幾步。這里有個(gè)會(huì)被新手忽略的點(diǎn)如果采樣深度只有1024而你要觀察的波形跨越了幾千個(gè)周期那么無論用哪種存儲(chǔ)位置你看到的都只是其中一小段。這時(shí)候要么加大采樣深度要么把觸發(fā)條件設(shè)置得更加精準(zhǔn)一次只看關(guān)鍵的一小段這樣還能減少BRAM占用。5. 技巧四采樣頻率范圍和采樣深度的取舍5.1 ILA沒有采樣頻率設(shè)置關(guān)鍵是采樣時(shí)鐘網(wǎng)上經(jīng)常有人問“Vivado中ILA的采樣頻率是不是有范圍限制”其實(shí)ILA核本身并不提供一個(gè)可選的采樣頻率參數(shù)。它只有一個(gè)clk端口采樣頻率完全取決于你接進(jìn)來的時(shí)鐘信號(hào)。你想抓100MHz的DDR接口邏輯那就用這個(gè)域里的100MHz時(shí)鐘給ILA采樣你想抓1MHz的UART信號(hào)也同樣可以用這個(gè)1MHz時(shí)鐘。所以“采樣頻率范圍”這個(gè)說法對(duì)ILA來說并不成立真正限制你的是FPGA內(nèi)部所能達(dá)到的工作時(shí)鐘頻率也就是時(shí)序約束約束下來的Fmax。如果你的目標(biāo)是觀察一個(gè)很慢的信號(hào)但你只有一個(gè)100MHz的系統(tǒng)時(shí)鐘可用那ILA會(huì)按100MHz去采樣這個(gè)慢信號(hào)。只要慢信號(hào)相對(duì)于100MHz不是變化那么快你依然能看清它的高低電平變化。反過來如果你用1MHz時(shí)鐘去采樣一個(gè)10MHz的信號(hào)那就會(huì)產(chǎn)生混疊看到的波形完全是錯(cuò)誤的。所以在設(shè)計(jì)調(diào)試方案時(shí)應(yīng)該先明確待測(cè)信號(hào)所在的時(shí)鐘域。如果設(shè)計(jì)里面有好幾個(gè)時(shí)鐘域而且你想觀察的信號(hào)跨越了不同時(shí)鐘最合理的做法是分別在每個(gè)時(shí)鐘域里創(chuàng)建一個(gè)ILA核而不是指望一個(gè)ILA把所有域的波形都采回來??鐣r(shí)鐘域的信號(hào)如果送到某個(gè)時(shí)鐘域ILA里采樣可能出現(xiàn)亞穩(wěn)態(tài)采樣出來的值可能不是穩(wěn)定的0或者1。補(bǔ)充一句ILA能工作的最高頻率和FPGA器件的速度等級(jí)、布局布線質(zhì)量都有關(guān)系。曾經(jīng)在某個(gè)工程里我加了ILA后時(shí)序報(bào)告顯示這個(gè)調(diào)試核對(duì)系統(tǒng)時(shí)鐘造成了明顯惡化最后通過降低探測(cè)信號(hào)數(shù)量和縮小采樣深度才把這條路徑的時(shí)序修回去。所以它確實(shí)有一個(gè)實(shí)際的“頻率上限”但這個(gè)上限不是ILA核自己規(guī)定的而是你的整體實(shí)現(xiàn)結(jié)果決定的。5.2 跨時(shí)鐘域信號(hào)抓取的注意事項(xiàng)抓跨時(shí)鐘域信號(hào)是FPGA調(diào)試?yán)镒钊菀追嚨膱?chǎng)景。比如你的設(shè)計(jì)里有一個(gè)31.25MHz的Ethernet GMII時(shí)鐘還有一個(gè)125MHz的接口時(shí)鐘。GMII的rx_clk上升沿采到的數(shù)據(jù)如果接到125MHz時(shí)鐘域的ILA里采樣點(diǎn)可能落在數(shù)據(jù)變化窗口中間導(dǎo)致讀回來的值不穩(wěn)定波形在Vivado里看起來就是毛刺亂跳。這里有三種常見做法在目標(biāo)域里先對(duì)信號(hào)做兩級(jí)同步再送進(jìn)ILA。這樣在ILA上看到的信號(hào)雖然比真實(shí)信號(hào)晚一到兩個(gè)時(shí)鐘但至少是穩(wěn)定可讀的。直接在該信號(hào)自己的時(shí)鐘域里建ILA確保采樣時(shí)鐘和數(shù)據(jù)同步變化。對(duì)需要跨多個(gè)時(shí)鐘域觀察的總線信號(hào)用異步FIFO先把數(shù)據(jù)緩存成單一時(shí)鐘域的格式再接ILA。很多人在ILA里看到波形“時(shí)不時(shí)跳出一個(gè)毛刺”第一反應(yīng)是設(shè)計(jì)邏輯有問題其實(shí)大概率是采樣方式不合理。先檢查ILA使用的時(shí)鐘域是否和信號(hào)一致往往能省下半天排查時(shí)間。5.3 采樣深度與BRAM資源的換算采樣深度1024意味著SRAM能存1024個(gè)采樣周期的數(shù)據(jù)4096就是存4096拍。這個(gè)深度和probe寬度相互作用共同決定BRAM的使用量。一個(gè)粗略的估算公式可以這么理解如果probe總位寬是32bit采樣深度是1024那么存儲(chǔ)總量就是32 × 1024 32768bit約等于4KB。FPGA里的BRAM通常一塊是36Kb左右所以這個(gè)配置大約占用不到一塊BRAM。但如果位寬加到128bit深度加到8192就變成128 × 8192 1Mbit也就是約30塊BRAM。對(duì)于某些資源緊張的器件這足以讓實(shí)現(xiàn)階段爆出資源錯(cuò)誤。我的習(xí)慣是在調(diào)試初期先用較低采樣深度把關(guān)鍵波形看個(gè)大概確認(rèn)問題范圍之后再?zèng)Q定要不要加大深度。不要說“既然都加ILA了就弄大一點(diǎn)”因?yàn)樯疃仍酱蟛粌HBRAM越緊數(shù)據(jù)回傳時(shí)間也越長(zhǎng)一個(gè)8192深度的ILA在JTAG 30MHz頻率下回傳數(shù)據(jù)會(huì)有可感知的延遲體驗(yàn)并不好。6. 技巧五硬件連接與“沒反應(yīng)”的完整排查思路6.1 從板卡上電到在Vivado看到ILA的全流程硬件調(diào)試和仿真不一樣仿真里你跑測(cè)試平臺(tái)結(jié)果幾乎是“確定性”的。硬件調(diào)試第一步就是連接這塊流程一旦不順后面全是空白。標(biāo)準(zhǔn)的流程是給FPGA板卡上電用JTAG線連接板卡調(diào)試接口和電腦。如果你的開發(fā)板是Digilent做的通常插上USB線電腦就能識(shí)別出一個(gè)串口號(hào)和一個(gè)JTAG設(shè)備。然后打開Vivado在左下角Flow Navigator里選擇“Open Hardware Manager”點(diǎn)擊“Open Target”后選擇“Auto Connect”。如果一切正常Hardware窗口里會(huì)列出你的FPGA器件右鍵點(diǎn)擊器件后選擇“Program Device”加載bitstream。加載完成后ILA核會(huì)自動(dòng)出現(xiàn)在Hardware窗口的列表里。雙擊某個(gè)ILA核就能打開波形界面在Trigger Setup窗口配置觸發(fā)條件最后點(diǎn)擊運(yùn)行按鈕開始等待觸發(fā)。這一步看似簡(jiǎn)單實(shí)際遇到的問題相當(dāng)多。最常見的一種就是插上USB線后電腦根本沒有反應(yīng)設(shè)備管理器里是黃色感嘆號(hào)。還有一種情況是Vivado能識(shí)別到JTAG鏈但打開device后一直停留在“Loading device information”此時(shí)往往是硬件服務(wù)器進(jìn)程死掉了。6.2 驅(qū)動(dòng)識(shí)別不了板子怎么辦“Vivado安裝驅(qū)動(dòng)無法識(shí)別板子”是我見過頻率極高的問題。大多數(shù)Zynq和Artix開發(fā)板用的都是FTDI芯片比如FT2232H。在Windows下第一次插上板子時(shí)系統(tǒng)有可能把它識(shí)別為“USB Serial Port”而不是JTAG設(shè)備。Vivado自帶的驅(qū)動(dòng)安裝程序不一定能自動(dòng)關(guān)聯(lián)到正確驅(qū)動(dòng)。此時(shí)不要忙著換線換板子先在設(shè)備管理器里找到帶感嘆號(hào)的設(shè)備右鍵更新驅(qū)動(dòng)選擇手動(dòng)查找驅(qū)動(dòng)“瀏覽計(jì)算機(jī)以查找驅(qū)動(dòng)程序”路徑指向Vivado安裝目錄里的data\xicom\cable_drivers\nt64\dlc10_win7或者對(duì)應(yīng)版本目錄一般能解決FTDI識(shí)別問題。對(duì)于部分平臺(tái)還需要使用Zadig工具把驅(qū)動(dòng)替換為WinUSB驅(qū)動(dòng)這個(gè)方式對(duì)很多第三方JTAG調(diào)試器都很管用。如果驅(qū)動(dòng)都裝好了但Vivado仍舊報(bào)“Cannot find cable”可以嘗試在Hardware Manager里點(diǎn)“Open Target”下的“Open New Target”手動(dòng)選擇Cable類型而不是Auto Connect。Auto Connect有時(shí)會(huì)選錯(cuò)設(shè)備手動(dòng)指定后常常就好了。還有一個(gè)容易被忽略的點(diǎn)是如果有多個(gè)Vivado版本共存后臺(tái)可能會(huì)有多個(gè)hw_server進(jìn)程搶占同一個(gè)JTAG口把所有hw_server進(jìn)程全部結(jié)束重新連接一次是最快的修復(fù)方式。6.3 ILA抓不到信號(hào)的8個(gè)常見原因先說結(jié)論ILA“抓信號(hào)沒反應(yīng)”大概能歸結(jié)為下面幾類原因。我按出現(xiàn)概率從高到低排了個(gè)序你可以直接對(duì)照排查現(xiàn)象可能原因解決思路波形窗口始終全0或全1probe連了信號(hào)但信號(hào)本身恒值檢查RTL邏輯確認(rèn)是否真的發(fā)生跳變點(diǎn)擊Run之后狀態(tài)一直Waiting觸發(fā)條件沒有滿足檢查觸發(fā)條件降低觸發(fā)門檻ILA核在Hardware Manager里根本不顯示bitstream沒有下載成功或ILA被優(yōu)化掉了看Program Device時(shí)有無報(bào)錯(cuò)檢查mark_debug屬性波形出現(xiàn)但不更新觸發(fā)窗口只有一段采樣緩沖滿了重新點(diǎn)擊Run或者修改觸發(fā)條件數(shù)據(jù)明顯錯(cuò)亂采樣時(shí)鐘跨域、信號(hào)沒同步換到信號(hào)所在時(shí)鐘域采樣抓到的信號(hào)少了一些bitprobe寬度配置不匹配核對(duì)IP配置和例化代碼下載bitstream后板卡功能異常ILA加了過多負(fù)載或影響了布局布線裁剪ILA、換低采樣深度Vivado一直連不上目標(biāo)JTAG驅(qū)動(dòng)或hw_server問題重裝驅(qū)動(dòng)、結(jié)束hw_server進(jìn)程這里特別提醒一點(diǎn)如果你在ILA里看到的信號(hào)一直保持一個(gè)固定值先不要懷疑ILA壞了先懷疑是不是觸發(fā)條件設(shè)錯(cuò)了。比如你想觸發(fā)“data 8h80”但實(shí)際數(shù)據(jù)總線上一直從來沒出現(xiàn)過這個(gè)值那當(dāng)然永遠(yuǎn)等不到。你不妨先把觸發(fā)條件改成“不等于某個(gè)值”或者干脆設(shè)為“always true”看能不能抓到數(shù)據(jù)。如果設(shè)為always true還是抓不到那再往連接和硬件方向排查。7. 實(shí)戰(zhàn)報(bào)錯(cuò)速查Vivado調(diào)試中常見問題復(fù)盤7.1 implement design變紅還能救嗎很多人一看到implement design變紅就頭大。實(shí)際上這個(gè)紅色信息有兩類一類是綜合或?qū)崿F(xiàn)的error彈窗這種通常是代碼或者IP配置有硬錯(cuò)誤另一類是工程狀態(tài)欄上的紅叉多半是某一步?jīng)]有成功運(yùn)行或者運(yùn)行結(jié)果里存在嚴(yán)重的時(shí)序失敗。ILA調(diào)試場(chǎng)景里最常見的implement失敗原因是資源不夠。加了一堆ILA之后BRAM占滿實(shí)現(xiàn)工具直接報(bào)resource utilization exceeded。這種情況的應(yīng)急處理是砍掉不用的ILA核或者降低采樣深度。如果是時(shí)序失敗可以先打開Implementation的Timing Summary看看是哪些路徑超了。很多時(shí)候是ILA所在的采樣時(shí)鐘路徑太長(zhǎng)導(dǎo)致關(guān)鍵路徑變差。一個(gè)實(shí)用的做法是把ILA核的采樣時(shí)鐘引腳改成來自BUFG的高速時(shí)鐘避免用普通邏輯出來的時(shí)鐘。還有一個(gè)低級(jí)但常見的錯(cuò)誤在Block Design里加了ILA但忘記把ILA的s_axi控制接口連接到Zynq或者JTAG調(diào)試鏈路。此時(shí)ILA在硬件管理器里就不可見。BD里使用ILA時(shí)通常需要把S_AXI和S_AXI_ACLK做相應(yīng)連接NoC和AXI接口的版本還會(huì)涉及更多配置。出現(xiàn)這種問題時(shí)檢查一下ILA核的s_axi接口是否處于未連接懸空狀態(tài)。7.2 生成比特流失敗與WinPcap的坑生成比特流失敗往往出現(xiàn)在步驟3實(shí)現(xiàn)和步驟4生成比特流之間。有時(shí)候提示信息是“route_design failed”有時(shí)候是“DRC failed”。DRC失敗中我遇到過比較多的項(xiàng)是“AVAL-47”或“LUTLP-1”這類關(guān)于未連接管腳或布線的檢查。做了ILA調(diào)試之后一定記得檢查是否把probe信號(hào)接到了不合理的時(shí)鐘網(wǎng)絡(luò)上這會(huì)在DRC階段直接攔下來。另一個(gè)高度相關(guān)的話題是WinPcap。很多人會(huì)把WinPcap和Vivado混到一起其實(shí)WinPcap主要用于仿真和網(wǎng)絡(luò)抓包但某些版本的Vivado安裝程序會(huì)在安裝界面勾選安裝WinPcap如果安裝失敗會(huì)導(dǎo)致后續(xù)部分網(wǎng)絡(luò)相關(guān)功能異常。對(duì)于純ILA調(diào)試來說WinPcap安裝失敗一般不影響JTAG調(diào)試因?yàn)橛布?wù)器走的是USB/JTAG鏈路不依賴WinPcap。所以如果你在Vivado安裝時(shí)提示W(wǎng)inPcap失敗不必太焦慮最壞情況只是個(gè)別以太網(wǎng)相關(guān)的仿真功能受影響。真正影響ILA連接的是前面說過的FTDI驅(qū)動(dòng)和hw_server服務(wù)。7.3 串口調(diào)試助手與ILA配合的混合調(diào)試技巧在嵌入式FPGA項(xiàng)目里除了ILA這種寄存器級(jí)觀測(cè)手段UART串口打印依然是快速確認(rèn)系統(tǒng)狀態(tài)的好幫手。比如在Zynq上跑軟核或者在一個(gè)小規(guī)模的FPGA設(shè)計(jì)里通過UART輸出一些狀態(tài)碼你完全可以同時(shí)開兩個(gè)工具一邊用ILA看總線時(shí)序細(xì)節(jié)一邊用串口調(diào)試助手確認(rèn)上層的狀態(tài)切換是否符合預(yù)期。我的習(xí)慣是先用串口打印把問題定位到某個(gè)模塊再用ILA去精確抓該模塊的接口波形。這樣能避免一開始就把幾十路信號(hào)塞進(jìn)ILA導(dǎo)致BRAM和調(diào)試時(shí)間雙雙失控。串口調(diào)試助手的波特率、數(shù)據(jù)位、校驗(yàn)位一定提前確認(rèn)否則看到亂碼會(huì)誤以為邏輯本身有問題。ILA抓到的是芯片內(nèi)部的真實(shí)硬件行為串口打印出來的是CPU或狀態(tài)機(jī)處理后“認(rèn)為”自己看到的兩者結(jié)合時(shí)如果結(jié)果不一致那往往意味著接口時(shí)序上存在隱患這是最有價(jià)值的排查線索。7.4 一次完整的問題定位演示說一個(gè)我印象很深的案例。某個(gè)FPGA工程里用AXI接口讀寫外部SRAM仿真全通過上板后讀回來的數(shù)據(jù)偶爾會(huì)錯(cuò)幾個(gè)字節(jié)。一開始我用串口調(diào)試助手把讀回的數(shù)據(jù)打印出來發(fā)現(xiàn)錯(cuò)誤看起來沒有明顯規(guī)律有時(shí)連續(xù)讀一千次錯(cuò)兩三次有時(shí)又完全正常。這時(shí)候單純靠打印很難定位因?yàn)殄e(cuò)誤已經(jīng)發(fā)生了你并不知道是控制器發(fā)錯(cuò)地址還是總線時(shí)序出了問題。于是我打開Hardware Manager創(chuàng)建了一個(gè)ILA掛在AXI接口的地址、數(shù)據(jù)和寫使能信號(hào)上采樣深度設(shè)成4096觸發(fā)條件設(shè)為“寫操作發(fā)生且數(shù)據(jù)等于某個(gè)壞值”。第一次運(yùn)行等了很長(zhǎng)時(shí)間沒反應(yīng)。我把觸發(fā)條件放寬到“只要寫請(qǐng)求拉高就觸發(fā)”很快抓到了一段寫時(shí)序。對(duì)比IP手冊(cè)里的波形后發(fā)現(xiàn)問題出在片選使能信號(hào)上CE拉低的時(shí)機(jī)比數(shù)據(jù)有效時(shí)間晚了半個(gè)時(shí)鐘周期導(dǎo)致在特定時(shí)鐘頻率和布線延遲組合下偶發(fā)讀錯(cuò)。最后在RTL里對(duì)CE加了一級(jí)寄存器問題消失。這個(gè)案例很有代表性仿真沒有暴露問題是因?yàn)榉抡姝h(huán)境里沒有體現(xiàn)實(shí)際的PCB走線延遲和時(shí)序抖動(dòng)ILA抓不到信號(hào)則是因?yàn)樽畛醯挠|發(fā)條件設(shè)得太苛刻。把這個(gè)過程寫出來是想強(qiáng)調(diào)兩件事第一ILA的調(diào)試思路要像偵探一樣先放寬條件找線索再逐步收緊確認(rèn)原因第二不要把ILA當(dāng)成萬能的示波器它只能看到你加在probe上的信號(hào)信號(hào)沒引出來一切都是白搭。在真正接觸ILA之前我也以為調(diào)試FPGA就是“跑仿真、看波形”兩件事直到在板級(jí)調(diào)試?yán)锉桓鞣N時(shí)序問題教訓(xùn)過之后我才明白ILA最值錢的不是它能采樣而是它能把代碼運(yùn)行時(shí)的真實(shí)行為暴露出來。這里再分享一個(gè)個(gè)人經(jīng)驗(yàn)每次在大工程里加ILA之前都先花幾分鐘確認(rèn)自己的采樣時(shí)鐘是哪個(gè)域的、觸發(fā)條件設(shè)的是什么、深度夠不夠看完整一段傳輸。這三個(gè)問題想清楚了基本能避免大多數(shù)“抓不到信號(hào)”的尷尬。調(diào)試嘛本來就是一個(gè)不斷縮小懷疑范圍的過程ILA用得好整個(gè)過程的效率能提升一個(gè)量級(jí)。