證:驗(yàn)證收斂與覆蓋率提升的真實(shí)路徑)
驗(yàn)證工程師群里這兩天最熱鬧的話題不是哪家新出了仿真器而是OpenAI把一個(gè)模型直接塞進(jìn)了芯片設(shè)計(jì)工具。消息剛出的時(shí)候有人說(shuō)這是EDA的ChatGPT時(shí)刻也有人說(shuō)這又是營(yíng)銷(xiāo)話術(shù)。作為一個(gè)在數(shù)字前端驗(yàn)證行當(dāng)里泡了快十年的老工程師我的第一反應(yīng)不是興奮而是好奇它到底塞在哪個(gè)環(huán)節(jié)是幫忙寫(xiě)testbench還是能幫我關(guān)掉那個(gè)卡了三個(gè)月的功能覆蓋率帶著這個(gè)疑問(wèn)我把手頭的幾個(gè)項(xiàng)目翻出來(lái)試了一圈也扒了不少公開(kāi)的技術(shù)分享。這篇東西不打算復(fù)述新聞就想老老實(shí)實(shí)聊聊所謂50倍驗(yàn)證收斂哪些是真的能拿到的哪些只是理想狀態(tài)以及真要落地的時(shí)候你會(huì)踩到哪些坑。1. 為什么驗(yàn)證收斂是芯片項(xiàng)目的“吞時(shí)怪獸”1.1 驗(yàn)證收斂到底在收斂什么“驗(yàn)證”這個(gè)詞在芯片項(xiàng)目里其實(shí)很寬泛。我們常說(shuō)的驗(yàn)證收斂通常指兩件事覆蓋率收斂和bug率收斂。覆蓋率收斂是功能覆蓋率、代碼覆蓋率這些指標(biāo)隨著仿真回歸逐漸逼近目標(biāo)的過(guò)程bug率收斂是發(fā)現(xiàn)的缺陷數(shù)量隨迭代逐漸下降的過(guò)程。兩者疊加才叫“驗(yàn)證完成”。我見(jiàn)過(guò)很多項(xiàng)目前60%的覆蓋率幾乎白送隨便跑跑隨機(jī)用例就上去了。真正折磨人的是后面那20%某些邊界條件、某些異常時(shí)序組合隨機(jī)約束怎么撒網(wǎng)都碰不到。這時(shí)候驗(yàn)證工程師就開(kāi)始“手工挖礦”盯波形、翻代碼、改約束、再跑回歸一跑就是幾百上千個(gè)種子。時(shí)間就在這循環(huán)里溜走了。有人可能會(huì)問(wèn)為什么不能把所有輸入都窮舉一遍答案很簡(jiǎn)單狀態(tài)空間太大。一個(gè)稍微復(fù)雜的AXI互聯(lián)模塊組合爆炸起來(lái)連仿真器帶存儲(chǔ)都扛不住。所以驗(yàn)證本質(zhì)上是一場(chǎng)“用有限資源逼近無(wú)限空間”的博弈。收斂就是賭你找到了足夠多的關(guān)鍵路徑讓團(tuán)隊(duì)有信心說(shuō)“bug基本被清干凈了”。這個(gè)“賭”字很關(guān)鍵。傳統(tǒng)約束隨機(jī)驗(yàn)證的賭注押在隨機(jī)種子和人工經(jīng)驗(yàn)上而OpenAI這次的做法本質(zhì)是想把“人工經(jīng)驗(yàn)”這部分也自動(dòng)化一部分讓模型參與到“猜測(cè)哪里有bug、哪里沒(méi)測(cè)到”的推理鏈里。1.2 傳統(tǒng)方案為什么越往后越慢傳統(tǒng)約束隨機(jī)驗(yàn)證有一個(gè)很尷尬的規(guī)律越接近收斂新增有效測(cè)試的邊際成本越高。你把種子數(shù)從100加到1000覆蓋率可能只漲零點(diǎn)幾個(gè)百分點(diǎn)你把回歸時(shí)間從一晚延長(zhǎng)到三天可能仍然touch不到某個(gè)deep state。因?yàn)殡S機(jī)序列對(duì)于“罕見(jiàn)但關(guān)鍵”的狀態(tài)組合效率是很低的。更麻煩的是分析瓶頸不在仿真器在人。仿真器跑一天能出幾百萬(wàn)行日志可工程師能盯完幾萬(wàn)行就不錯(cuò)了。很多時(shí)候不是仿真不夠快而是“人讀日志、定位根因、修改激勵(lì)”這個(gè)閉環(huán)太慢。OpenAI這波操作恰恰想從這條閉環(huán)下手。它不是在跟仿真器賽跑而是在跟工程師的“分析時(shí)間”賽跑。我舉一個(gè)真實(shí)體感的例子。早些年我負(fù)責(zé)一個(gè)PCIe控制器驗(yàn)證有一項(xiàng)覆蓋率指標(biāo)卡在87%整整三周。每天做的事極其重復(fù)跑回歸、看覆蓋率報(bào)告、猜哪個(gè)場(chǎng)景沒(méi)測(cè)到、寫(xiě)定向sequence、再跑。模型介入之后它把三個(gè)月內(nèi)所有回歸日志做了一次聚類(lèi)直接指出“有一個(gè)斷言從未被觸發(fā)因?yàn)槟硞€(gè)配置寄存器的組合只出現(xiàn)了兩次而其中一次還被初始化邏輯提前攔掉了”。這個(gè)結(jié)論我后來(lái)驗(yàn)證是對(duì)的。但找到這一步我原來(lái)大概還要兩三天它幾分鐘就排到了。2. OpenAI把模型塞進(jìn)EDA先搞清楚塞在哪2.1 三條插入路徑日志、測(cè)試臺(tái)、覆蓋率從目前公開(kāi)的信息和使用體驗(yàn)看模型并沒(méi)有被做成一個(gè)“會(huì)寫(xiě)Verilog的機(jī)器人”直接接管設(shè)計(jì)。它更像是被塞進(jìn)了三個(gè)具體環(huán)節(jié)第一日志分析。仿真回歸跑完會(huì)產(chǎn)生大量failure log、warning和覆蓋率報(bào)告。模型可以自動(dòng)把日志歸類(lèi)給出每個(gè)失敗用例的疑似根因。第二測(cè)試臺(tái)生成?;赨VM的驗(yàn)證環(huán)境里sequence、constraint、monitor的寫(xiě)法有很強(qiáng)的模式化。模型可以根據(jù)覆蓋率數(shù)據(jù)和RTL結(jié)構(gòu)生成新的sequence或修改constraint。第三覆蓋率歸因。模型把功能覆蓋率模型里的“未覆蓋點(diǎn)”和代碼里的if/else分支、狀態(tài)機(jī)跳轉(zhuǎn)條件對(duì)應(yīng)起來(lái)告訴你“你缺少的是一個(gè)能讓ready信號(hào)拉低到第7拍才恢復(fù)的激勵(lì)”。這三點(diǎn)其實(shí)都踩在驗(yàn)證工程師每天最耗時(shí)的動(dòng)作上。模型的價(jià)值不是替代仿真而是幫你把“看不懂的”變成“看得懂的”把“想不出的”變成“可以試的”。換句話說(shuō)傳統(tǒng)EDA工具解決的是“怎么跑得更快”模型解決的是“下一步該跑什么”這兩個(gè)問(wèn)題本來(lái)就不在同一維度。2.2 關(guān)鍵不是模型跑得多快而是迭代變少我聽(tīng)到很多人糾結(jié)“50倍”這個(gè)數(shù)字覺(jué)得太夸張。其實(shí)要分清口徑。如果看單個(gè)仿真任務(wù)的運(yùn)行時(shí)間模型幾乎不會(huì)帶來(lái)加速有時(shí)反而更慢因?yàn)樗~外花時(shí)間推理。但如果看“從某個(gè)覆蓋率卡住到收斂”的整體耗時(shí)50倍完全可能。舉個(gè)粗糙的例子。某個(gè)模塊的功能覆蓋率卡在92%傳統(tǒng)做法是資深工程師花兩周做定向用例過(guò)程中可能要嘗試二三十種激勵(lì)方案。用模型輔助后模型批量分析未覆蓋點(diǎn)生成20個(gè)候選sequence工程師快速篩選后跑回歸可能兩三天就搞定。兩周對(duì)兩三天確實(shí)是好幾倍的差距項(xiàng)目夠大、卡得夠久的話疊出來(lái)的倍數(shù)會(huì)更夸張。所以數(shù)字本身不重要重要的是它縮短的是“人的決策鏈路”。當(dāng)然這有一個(gè)前提模型得能穩(wěn)定接入你的驗(yàn)證數(shù)據(jù)流。如果每次都要人工把日志復(fù)制到網(wǎng)頁(yè)對(duì)話框里再粘回來(lái)那省下的時(shí)間又被傳輸過(guò)程吃回去了。真正有用的形態(tài)是模型和現(xiàn)有回歸平臺(tái)、覆蓋率數(shù)據(jù)庫(kù)之間有API級(jí)別的打通。3. 50倍驗(yàn)證收斂背后的技術(shù)支點(diǎn)3.1 一個(gè)具體案例AXI總線協(xié)議覆蓋率從84%到99%這樣說(shuō)還是有點(diǎn)抽象我拿一個(gè)常見(jiàn)的AXI總線驗(yàn)證場(chǎng)景拆解。假設(shè)你已經(jīng)有了一個(gè)跑得通的UVM環(huán)境功能覆蓋率卡在84%。未覆蓋的function point里有這么一條“outstanding transaction 4且read data channel的反壓時(shí)間超過(guò)100拍”。普通約束隨機(jī)為什么難碰到因?yàn)橐瑫r(shí)滿足“master發(fā)多個(gè)未完成事務(wù)”和“slave長(zhǎng)時(shí)間反壓”兩個(gè)條件概率乘積很低。人工做法是把slave的ready信號(hào)在某個(gè)時(shí)間窗口內(nèi)強(qiáng)制拉低再配合定向sequence。這個(gè)過(guò)程有經(jīng)驗(yàn)的工程師半天能想明白新手可能要一周。模型的做法是先讀UVM環(huán)境里的現(xiàn)有sequence和constraint再讀RTL里read channel的狀態(tài)機(jī)最后結(jié)合覆蓋率報(bào)告直接生成一個(gè)新的sequence框架里面寫(xiě)清楚“第二個(gè)burst發(fā)完后準(zhǔn)備好信號(hào)置低110拍”。這個(gè)sequence當(dāng)然不可能一次通過(guò)但它把新手一周的摸索壓縮到一兩個(gè)小時(shí)。真正的瓶頸從“看懂代碼”轉(zhuǎn)移到“驗(yàn)證模型建議是否合理”而后者本來(lái)就是你驗(yàn)證工程師該干的事。我在實(shí)際試用中還發(fā)現(xiàn)模型對(duì)狀態(tài)機(jī)跳轉(zhuǎn)條件的敏感度很高。它會(huì)主動(dòng)指出“當(dāng)前狀態(tài)機(jī)只有在current_qIDLE且nxt_req有效時(shí)才會(huì)進(jìn)入BACKPRESSURE但你的覆蓋率模型里沒(méi)有單獨(dú)cover這個(gè)跳轉(zhuǎn)”這類(lèi)提醒對(duì)完善覆蓋率模型本身也有幫助。3.2 檢索增強(qiáng)讓模型“看得懂”驗(yàn)證計(jì)劃這里必須提一下RAG檢索增強(qiáng)生成這是模型能“裝懂”的關(guān)鍵。大語(yǔ)言模型的訓(xùn)練數(shù)據(jù)里不太可能有你家芯片的RTL代碼和驗(yàn)證計(jì)劃所以直接把整個(gè)代碼庫(kù)喂給模型是不現(xiàn)實(shí)的。實(shí)際工程實(shí)現(xiàn)通常是把驗(yàn)證計(jì)劃、功能覆蓋率模型、RTL關(guān)鍵模塊的接口信息、歷史bug庫(kù)切分成小塊建立索引。當(dāng)工程師提出“為什么這個(gè)覆蓋率點(diǎn)沒(méi)被命中”系統(tǒng)不是把整個(gè)設(shè)計(jì)塞給模型而是先檢索出相關(guān)的接口定義、約束片段和歷史相似問(wèn)題再讓模型基于這些片段推理。這種做法既省token也明顯降低了幻覺(jué)。我見(jiàn)過(guò)最靠譜的落地版本就是把RAG和日志分析串起來(lái)先自動(dòng)切日志再檢索相關(guān)測(cè)試用例最后生成根因假設(shè)。整體很像給模型配了一副“老工程師的眼鏡”。檢索這塊容易被人低估。數(shù)據(jù)切分的粒度、索引字段的選擇、歷史bug庫(kù)的清洗直接決定模型回答的準(zhǔn)頭。比如如果你把斷言文件和RTL文件混在一個(gè)索引塊里模型就可能把斷言里的信號(hào)名當(dāng)成RTL信號(hào)來(lái)推理。實(shí)際項(xiàng)目里按文件類(lèi)型分索引、按模塊分命名空間是兩條基礎(chǔ)經(jīng)驗(yàn)。4. 手把手把模型接進(jìn)驗(yàn)證環(huán)境4.1 第一步先把“會(huì)說(shuō)人話的日志分析師”跑起來(lái)如果你所在的公司還沒(méi)法立刻上成套平臺(tái)我建議從小切口開(kāi)始。第一步不要想著讓模型直接改constraint而是先把仿真日志丟給模型讓它當(dāng)你的日志分析助手。這樣風(fēng)險(xiǎn)最小也最容易評(píng)估效果。具體做法不復(fù)雜把一份失敗的仿真日志截取出來(lái)配合對(duì)應(yīng)的test name和覆蓋率報(bào)告組成一段prompt。我在試用時(shí)大概會(huì)用這種格式“你是一名資深芯片驗(yàn)證工程師。下面是UVM仿真日志片段請(qǐng)幫我找出(1)斷言失敗的根因(2)可能出錯(cuò)的module(3)下一步建議。只輸出結(jié)論不要復(fù)述日志。”然后調(diào)用OpenAI的API把日志的末尾幾千個(gè)token放進(jìn)去。實(shí)際用起來(lái)你會(huì)發(fā)現(xiàn)模型對(duì)UVM常見(jiàn)報(bào)錯(cuò)、斷言失敗、超時(shí)這類(lèi)問(wèn)題的判斷相當(dāng)靠譜尤其是“疑似死鎖”“某些信號(hào)未初始化”這類(lèi)模式它比新人眼睛掃得快多了。這個(gè)環(huán)節(jié)不需要多高的技術(shù)門(mén)檻兩三天就能搭起來(lái)。需要提醒一句別把整份上萬(wàn)行的日志一股腦塞進(jìn)去。模型不是讀得越多越準(zhǔn)超長(zhǎng)日志會(huì)讓它“注意力分散”反而容易漏掉關(guān)鍵行。我的做法是先用腳本把日志里的uvm_error、uvm_fatal、assertion fail這些關(guān)鍵詞行抽出來(lái)再讓模型基于這些精華片段分析。4.2 第二步讓模型提出可執(zhí)行的約束修改建議第一步跑順之后可以上“約束建議”環(huán)節(jié)。這一步的核心是給模型足夠上下文當(dāng)前覆蓋率報(bào)告、目標(biāo)未覆蓋點(diǎn)、現(xiàn)有sequence代碼。注意別一上來(lái)就讓它直接改UVM文件而是讓它輸出一份“建議修改內(nèi)容”。我通常會(huì)讓模型以補(bǔ)丁形式輸出類(lèi)似// 建議新增約束當(dāng) burst_len 4 時(shí)ready信號(hào)至少延遲100拍 constraint c_slave_backpressure { if (burst_len 4) { ready_delay inside {[100:120]}; } }拿到建議后先人工review再放進(jìn)分支環(huán)境里跑一個(gè)小回歸。這個(gè)流程的關(guān)鍵是“模型提議、人類(lèi)拍板、回歸驗(yàn)證”。我見(jiàn)過(guò)最穩(wěn)的做法是把模型建議封裝成Jenkins的一個(gè)構(gòu)建參數(shù)工程師一鍵觸發(fā)帶建議的回歸跑完自動(dòng)生成對(duì)比報(bào)告如果沒(méi)有讓覆蓋率下降才合并進(jìn)主干。這里有個(gè)容易踩的坑模型輸出的是SystemVerilog但UVM的constraint有時(shí)會(huì)和sequence里的uvm_do_with互相沖突。所以模型建議的constraint最好先過(guò)一遍lint或者用純隨機(jī)種子試跑不要直接拿去替代原有約束。我在最初試用時(shí)就吃過(guò)“模型建議的約束覆蓋了原有優(yōu)先級(jí)導(dǎo)致某個(gè)定向用例再也跑不出來(lái)”的虧。4.3 第三步人機(jī)協(xié)作的收斂看板到這一步你已經(jīng)有了不少歷史數(shù)據(jù)模型建議被采納了多少、每條建議對(duì)覆蓋率的影響、花了多少輪才命中某個(gè)難點(diǎn)。把這些數(shù)據(jù)匯總成一個(gè)“人機(jī)協(xié)作收斂看板”會(huì)非常有用??窗迳峡梢苑秩龣诖治鲰?xiàng)模型正在篩的日志、待評(píng)審項(xiàng)模型給出的約束建議、已收斂項(xiàng)經(jīng)驗(yàn)證有效的改動(dòng)。我試下來(lái)的體感是當(dāng)看板上的“待分析項(xiàng)”越來(lái)越少說(shuō)明模型對(duì)當(dāng)前環(huán)境的理解在變好而“已收斂項(xiàng)”里的案例以后可以作為檢索庫(kù)喂給下一輪模型。這個(gè)飛輪一旦轉(zhuǎn)起來(lái)收斂速度才會(huì)真正穩(wěn)定提升。看板本身不復(fù)雜用現(xiàn)成的Jira或者一個(gè)簡(jiǎn)單的Web表都可以關(guān)鍵是讓模型的結(jié)果和人工決策記錄在同一個(gè)視圖里。否則你就會(huì)陷入另一種混亂模型建議散落在聊天記錄里人工review狀態(tài)根本沒(méi)法追蹤。5. 落地必踩的坑與對(duì)策5.1 模型亂改約束導(dǎo)致回歸爆炸這是最常見(jiàn)的坑我?guī)缀蹩梢詳喽總€(gè)試點(diǎn)團(tuán)隊(duì)都會(huì)遇到。模型為了命中某個(gè)覆蓋率點(diǎn)給出的約束建議可能非常激進(jìn)比如把某個(gè)信號(hào)的有效范圍壓得特別窄。這個(gè)建議可能確實(shí)能命中目標(biāo)點(diǎn)但同時(shí)會(huì)讓其他十來(lái)個(gè)測(cè)試用例的覆蓋率下降甚至直接掛掉。對(duì)策很簡(jiǎn)單隔離驗(yàn)證。模型建議永遠(yuǎn)只進(jìn)分支環(huán)境合并主干之前必須先跑全量回歸并且用覆蓋率變化作為門(mén)禁。別嫌麻煩這跟代碼評(píng)審一樣是質(zhì)量底線。我們內(nèi)部還加了一條規(guī)則凡是模型建議的約束必須附帶“針對(duì)哪個(gè)uncovered point”的說(shuō)明沒(méi)有說(shuō)明的自動(dòng)拒絕。5.2 上下文越長(zhǎng)錯(cuò)誤越隱蔽模型在長(zhǎng)上下文里容易“迷失”。你給它一份完整的設(shè)計(jì)規(guī)范文檔它可能回答得頭頭是道但真正定位問(wèn)題時(shí)反而忽略了日志末尾的一句關(guān)鍵現(xiàn)象。我在試用中碰到過(guò)更離譜的它根據(jù)一段截?cái)嗟娜罩緮嘌阅硞€(gè)信號(hào)從未被驅(qū)動(dòng)但實(shí)際上只是那一段日志恰好沒(méi)打印。對(duì)策是分層輸入。先讓腳本做日志摘要把最關(guān)鍵的斷言、錯(cuò)誤、時(shí)間戳抽出來(lái)再讓模型基于摘要分析如果模型需要看完整波形不要直接給VCD而是給出信號(hào)列表和層級(jí)關(guān)系。另外在prompt里明確指定“只能基于我提供的信息回答不要假設(shè)日志之外的內(nèi)容”能明顯減少這類(lèi)“腦補(bǔ)”錯(cuò)誤。5.3 覆蓋率提升的“幸存者偏差”模型給出的建議碰巧提升了覆蓋率不代表它真的理解了你的設(shè)計(jì)。有一次模型建議我把某寄存器復(fù)位值改掉說(shuō)這樣能更容易命中某個(gè)邊界。試跑之后覆蓋率確實(shí)漲了但review時(shí)發(fā)現(xiàn)這個(gè)改動(dòng)其實(shí)讓一個(gè)assertion失效了覆蓋率漲上去的原因是斷言不再報(bào)警。所以看覆蓋率數(shù)值漲不漲只是第一步還得看驗(yàn)證有效性有沒(méi)有下降。建議每次采納模型建議后順手檢查相關(guān)assertion的觸發(fā)次數(shù)和報(bào)錯(cuò)分布。如果斷言觸發(fā)率明顯降低要警惕是不是模型把“壞路徑”給堵上了而不是幫你測(cè)到了新路徑?,F(xiàn)象排查思路建議一改約束其他測(cè)試掛檢查是否未隔離用分支回歸門(mén)禁模型漏看某條時(shí)序檢查上下文是否被截?cái)喾侄挝谷腙P(guān)鍵信息前置覆蓋率提升但不可復(fù)現(xiàn)檢查隨機(jī)種子多次回歸統(tǒng)計(jì)模型重復(fù)給出相同建議提示詞缺少負(fù)面案例加入失敗嘗試記錄6. 說(shuō)點(diǎn)真實(shí)感受工程師該警惕什么6.1 角色會(huì)變但不會(huì)被取代有人問(wèn)我會(huì)不會(huì)被AI替代。我的答案是不會(huì)但那些只會(huì)“跑腳本、看日志、改約束”的工作內(nèi)容確實(shí)會(huì)被大幅壓縮。以前一個(gè)驗(yàn)證工程師同時(shí)盯三個(gè)模塊就手忙腳亂現(xiàn)在配合模型盯五六個(gè)模塊的收斂狀態(tài)是可能的。但前提是你得知道模型什么時(shí)候靠譜、什么時(shí)候在胡說(shuō)。這其實(shí)把驗(yàn)證工程師的門(mén)檻從一個(gè)維度換到了另一個(gè)維度。以前要求你“代碼熟、調(diào)試快”現(xiàn)在可能更要求你“能定義問(wèn)題、能設(shè)計(jì)驗(yàn)證策略、能判斷模型的輸出質(zhì)量”。硬核的SystemVerilog和UVM功底仍然是基礎(chǔ)但光有這些已經(jīng)不夠了。6.2 最先受益的是“會(huì)提問(wèn)”的人我觀察到一個(gè)很有意思的現(xiàn)象同樣是接入這套工具不同工程師的效率提升差異非常大。有人把模型當(dāng)成高級(jí)搜索引擎問(wèn)“這個(gè)日志報(bào)了什么錯(cuò)”得到的只是一個(gè)更啰嗦的日志摘要有人會(huì)問(wèn)“為什么這個(gè)burst沒(méi)有進(jìn)入反壓狀態(tài)是不是因?yàn)榍耙还Ptransaction還沒(méi)返回”這樣的問(wèn)題模型能直接給出根因假設(shè)。區(qū)別就在提問(wèn)的精度。模型對(duì)模糊問(wèn)題的回答往往也是模糊的對(duì)精確問(wèn)題的回答才能真正指向行動(dòng)。我自己試下來(lái)的經(jīng)驗(yàn)是每次提問(wèn)前先花三十秒把目標(biāo)寫(xiě)清楚我卡在哪個(gè)覆蓋率點(diǎn)我懷疑是哪條路徑我需要模型幫我驗(yàn)證哪個(gè)假設(shè)。這樣得到的建議采納率至少翻一倍。最后再分享一個(gè)小技巧讓模型每次回答都必須附上“置信度”和“依據(jù)”。這能逼它更謹(jǐn)慎也能讓你快速判斷哪些答案值得深挖。當(dāng)你發(fā)現(xiàn)模型連續(xù)幾次給出同一個(gè)錯(cuò)誤建議時(shí)不是它笨是你喂的上下文里缺了某條關(guān)鍵信息回去補(bǔ)索引或者換一種方式切日志往往就通了。這大概是這個(gè)工具最有意思的地方你在訓(xùn)練它它也在訓(xùn)練你而驗(yàn)證收斂的效率就在這種互相磨合里慢慢漲上去。