全解析:數(shù)字IC驗(yàn)證筆試面試實(shí)戰(zhàn)指南)
簡介思朗科技2022年提前批數(shù)字IC驗(yàn)證筆試題的完整復(fù)盤資料圍繞異步FIFO的UVM驗(yàn)證環(huán)境搭建與驗(yàn)證展開。資源面向2023屆及后續(xù)目標(biāo)IC驗(yàn)證崗位的求職者尤其適合希望鞏固UVM方法學(xué)、練習(xí)覆蓋率收集與錯(cuò)誤定位的在校生或初級(jí)工程師。壓縮包為7z格式共193個(gè)文件大小約5.13MB。其中包含7個(gè)SystemVerilog源碼文件對(duì)應(yīng)輸入驅(qū)動(dòng)、監(jiān)測、驅(qū)動(dòng)器、sequencer、agent等UVM組件、5個(gè)Verilog設(shè)計(jì)文件以及大量覆蓋率收集后生成的HTML/PNG/JS/CSS報(bào)告文件方便對(duì)照驗(yàn)證結(jié)果查看功能覆蓋率與代碼覆蓋率。當(dāng)前已有6214人學(xué)習(xí)下載可見該題目在IC驗(yàn)證求職圈中具有較高參考價(jià)值。資料不僅給出可運(yùn)行的UVM環(huán)境源碼還通過Questa Sim仿真后的覆蓋率報(bào)告、日志及UCDB數(shù)據(jù)庫完整呈現(xiàn)了從激勵(lì)發(fā)送、端口監(jiān)測到覆蓋率收斂的驗(yàn)證流程能幫助讀者理解異步FIFO驗(yàn)證的關(guān)鍵點(diǎn)和筆試題的答題思路。 今年數(shù)字IC驗(yàn)證崗的筆試面試有一個(gè)鐵打的組合UVM、異步FIFO、八股。無論你投的是芯片設(shè)計(jì)公司、IP公司還是驗(yàn)證服務(wù)團(tuán)隊(duì)這三樣?xùn)|西幾乎輪流出現(xiàn)在筆試題和面試官的追問里。異步FIFO既能考設(shè)計(jì)又能考驗(yàn)證還能順帶看你對(duì)跨時(shí)鐘域的理解UVM則幾乎是驗(yàn)證工程師的通用語言不問phase機(jī)制和寄存器模型基本說不過去。這篇文章就圍繞這三塊把我備考時(shí)整理的高頻考點(diǎn)、異步FIFO驗(yàn)證環(huán)境的搭建思路、以及筆試中容易踩的坑一次性擺出來適合正在準(zhǔn)備數(shù)字IC驗(yàn)證崗位面試的同學(xué)也適合剛?cè)胄邢胙a(bǔ)全知識(shí)框架的工程師。1. 筆試面試總覽驗(yàn)證崗到底在考什么1.1 驗(yàn)證崗的核心技能地圖數(shù)字IC驗(yàn)證的日常工作說白了就是三件事理解設(shè)計(jì)規(guī)格、搭建驗(yàn)證環(huán)境、把bug撈出來。筆試面試圍繞的也是這三件事但表達(dá)方式變成了UVM機(jī)制、斷言、覆蓋率、以及異步FIFO這類典型模塊的驗(yàn)證方案。我見過不少同學(xué)把大量精力花在背八股上結(jié)果面試官隨口一問“你為什么要在這個(gè)場景用virtual sequence”就卡殼。八股只能幫你進(jìn)門真正拉開差距的是你能不能把機(jī)制和場景對(duì)應(yīng)起來。技能地圖大概可以分成四層第一層是SystemVerilog語法和硬件思維第二層是UVM框架的組件結(jié)構(gòu)與phase機(jī)制第三層是跨時(shí)鐘域、復(fù)位、低功耗等通用知識(shí)的驗(yàn)證方法第四層才是具體的項(xiàng)目實(shí)戰(zhàn)比如異步FIFO、串口、I2C、AHB總線協(xié)議的驗(yàn)證環(huán)境搭建。筆試通常覆蓋第一層到第三層面試則會(huì)追著第四層問細(xì)節(jié)。1.2 異步FIFO為什么是必考題異步FIFO幾乎是一個(gè)完美的考察載體。它同時(shí)牽涉三塊硬知識(shí)跨時(shí)鐘域同步、格雷碼編碼、空滿判斷。設(shè)計(jì)端可以考你“多一比特”的指針比較法怎么寫驗(yàn)證端可以考你“兩個(gè)driver分別驅(qū)動(dòng)讀寫時(shí)鐘域怎么做”筆試還能考你“突發(fā)寫入時(shí)FIFO深度怎么算”。串口模塊里也常常用到小深度的異步FIFO做收發(fā)緩沖所以面試官還會(huì)順手問“異步FIFO深度一般選多大為什么”。我以前覺得異步FIFO很簡單不就是讀指針寫指針加格雷碼嘛。后來自己動(dòng)手搭驗(yàn)證環(huán)境才發(fā)現(xiàn)真正的坑全在邊界條件復(fù)位釋放瞬間的空滿標(biāo)志、同步器延遲導(dǎo)致的保守空滿、以及scoreboard比對(duì)時(shí)讀寫側(cè)時(shí)間差的處理。這些問題理解透了筆試面試基本就穩(wěn)了。2. UVM核心機(jī)制速覽面試八股里最值得深挖的四個(gè)點(diǎn)2.1 phase機(jī)制為什么環(huán)境能跑起來又能跑得完UVM的phase機(jī)制是面試必問但很多人只背了名字。build_phase自頂向下執(zhí)行connect_phase自底向上執(zhí)行run_phase是唯一消耗仿真時(shí)間的phase。這里的關(guān)鍵不是背誦而是理解為什么這樣設(shè)計(jì)。build_phase要自頂向下是因?yàn)楦附M件要先new子組件子組件才能接著build自己的內(nèi)容connect_phase要自底向上是因?yàn)橹挥兴薪M件的build都完成port和export才能安全連接。run_phase里真正坑人的是objection機(jī)制。很多人寫測試用例時(shí)只記得在sequence里調(diào)用start忘記在test里raise_objection仿真直接跑零時(shí)間退出或者出現(xiàn)“run phase就結(jié)束了但sequence還沒執(zhí)行完”的詭異現(xiàn)象。我自己的習(xí)慣是在test的run_phase里先raise_objection等所有sequence跑完再drop_objection并且用uvm_info把關(guān)鍵節(jié)點(diǎn)的objection計(jì)數(shù)打出來。如果某個(gè)用例異常提前結(jié)束第一件事就是查objection計(jì)數(shù)是不是提前歸零了。關(guān)于phase還有幾個(gè)容易被追問的點(diǎn)reset/configure/main等run_time phase和run_phase的關(guān)系以及UVM 1.2之后deprecated的uvm_sequence_item宏改成什么了。這些細(xì)節(jié)有時(shí)候比機(jī)制本身更能體現(xiàn)你是否真的用過UVM。2.2 寄存器模型鏡像值mirror value到底怎么維護(hù)寄存器模型里有一個(gè)概念叫鏡像值mirror value它代表軟件視角下寄存器的當(dāng)前硬件值。很多人忽略這個(gè)概念但面試官特別喜歡追問“如果你用寄存器模型寫了一個(gè)寄存器再讀回來為什么值不對(duì)”答案往往出在鏡像值的預(yù)期值上。寫入操作通過reg.write()完成寄存器模型會(huì)自動(dòng)更新鏡像值但如果硬件在寫之后又改變了寄存器的值而你沒有調(diào)用reg.mirror()或重新read模型里的鏡像值就和硬件不一致。反過來如果你只對(duì)寄存器做了reg.update()它會(huì)比較鏡像值和當(dāng)前期望值有差異才發(fā)起寫操作。理解了這些你自然能回答“為什么要用mirror機(jī)制來檢查硬件是否正確更新了寄存器”這類問題。構(gòu)造用例時(shí)我通常會(huì)在測試結(jié)束前對(duì)關(guān)鍵控制寄存器做一次mirror比對(duì)先讀硬件值再和期望值比較不一致就報(bào)FAIL。這個(gè)操作比單純打印寄存器值可靠得多因?yàn)殓R像值機(jī)制會(huì)自動(dòng)幫你完成一致性檢查。2.3 最終pass/fail醒目顯示的關(guān)鍵代碼有些同學(xué)問我能不能在仿真結(jié)束的時(shí)候打印一行特別醒目的PASS或者FAIL。當(dāng)然可以。UVM里最樸素也最好用的方式是在test的report_phase里根據(jù)錯(cuò)誤計(jì)數(shù)打印一個(gè)占滿屏幕的橫幅。我的實(shí)現(xiàn)大概是這樣的function void report_phase(uvm_phase phase); super.report_phase(phase); if (uvm_report_server::get_server().get_severity_count(UVM_ERROR) 0) begin $display(\n); $display( **** TEST PASSED ****); $display(\n); end else begin $display(\n); $display( ###### TEST FAILED ######); $display(\n); end endfunction這個(gè)寫法有幾個(gè)好處第一不需要額外引入任何宏隨便一個(gè)test都能用第二在仿真日志里搜索PASS或FAIL非常快回歸大量用例時(shí)掃一眼就知道結(jié)果第三因?yàn)橛昧藆vm_report_server的計(jì)數(shù)它能準(zhǔn)確反映整個(gè)UVM環(huán)境里的所有error包括sequence里的uvm_error和driver里的uvm_fatal。如果你用腳本跑回歸還可以在同一個(gè)位置把最終的pass/fail狀態(tài)寫入一個(gè)文本文件方便CI系統(tǒng)解析。我個(gè)人習(xí)慣把$display和文件寫入同時(shí)做這樣既能在波形里看到又能讓回歸腳本穩(wěn)定判據(jù)。2.4 sequence與sequencer握手的常見細(xì)節(jié)關(guān)于sequence機(jī)制面試官常問的問題集中在start一個(gè)sequence發(fā)生了什么以及item_done和finish_item的關(guān)系。實(shí)際上執(zhí)行一個(gè)sequence item時(shí)sequence調(diào)用start_item會(huì)先請(qǐng)求sequencer授權(quán)拿到授權(quán)后finish_item把item交給driverdriver側(cè)的seq_item_port.get_next_item()拿到item后驅(qū)動(dòng)到DUT最后調(diào)用item_done通知sequence。很多人不知道的是finish_item會(huì)阻塞sequence直到driver調(diào)用item_done或get()這是流控的關(guān)鍵。如果你在sequence里發(fā)了item但driver沒有及時(shí)getsequence會(huì)阻塞在那里整個(gè)用例就像“卡住”一樣。遇到這種現(xiàn)象先檢查driver的run_phase是否在正常工作再看seq_item_port的連接是否沒連上。3. 異步FIFO設(shè)計(jì)驗(yàn)證實(shí)戰(zhàn)從RTL到UVM環(huán)境3.1 設(shè)計(jì)要點(diǎn)格雷碼、兩級(jí)同步器與空滿判斷異步FIFO的經(jīng)典實(shí)現(xiàn)有幾個(gè)繞不開的點(diǎn)。寫指針和讀指針各自在本地時(shí)鐘域遞增但跨時(shí)鐘域比較時(shí)不能直接用二進(jìn)制指針因?yàn)槎辔恍盘?hào)同時(shí)變化時(shí)可能出現(xiàn)采樣到中間態(tài)的風(fēng)險(xiǎn)。格雷碼的優(yōu)勢(shì)在于相鄰兩個(gè)值只有一位變化跨時(shí)鐘域采樣時(shí)頂多采到“舊值”或“新值”不會(huì)出現(xiàn)錯(cuò)誤的新值。這就是為什么面試官總問“為什么要用格雷碼”??諠M判斷的標(biāo)準(zhǔn)做法是“最高位不同其余位相同”判滿“完全相等”判空。也就是說比較指針時(shí)把指針位寬擴(kuò)展一位寫指針比讀指針多跑一整圈時(shí)判滿。要注意的是寫側(cè)看到的滿信號(hào)是用同步到寫時(shí)鐘域的讀指針格雷碼比較出來的因?yàn)橥狡饔醒舆t這個(gè)滿信號(hào)實(shí)際上是一個(gè)保守的滿信號(hào)。換句話說FIFO真實(shí)滿了之后寫側(cè)可能要過幾個(gè)周期才能看到滿標(biāo)志但這不影響正確性因?yàn)閷憘?cè)在滿標(biāo)志拉高之前寫入的數(shù)據(jù)量一定小于FIFO深度不會(huì)造成覆蓋。設(shè)計(jì)里還有一個(gè)細(xì)節(jié)同步器打兩拍是在FIFO外部由RTL完成驗(yàn)證環(huán)境里不需要也不能去模擬同步器的行為只需要給足時(shí)間讓同步器收斂通常用時(shí)鐘沿對(duì)齊斷言或延時(shí)檢查來保證。3.2 UVM驗(yàn)證環(huán)境搭建思路異步FIFO的DUT有兩個(gè)時(shí)鐘域?qū)憘?cè)有寫時(shí)鐘、寫使能、寫數(shù)據(jù)讀側(cè)有讀時(shí)鐘、讀使能、讀數(shù)據(jù)外加復(fù)位和空滿標(biāo)志。這種結(jié)構(gòu)最自然的驗(yàn)證環(huán)境是搭兩個(gè)agent寫agent和讀agent各自包含driver和monitor然后通過virtual sequencer在頂層協(xié)調(diào)兩個(gè)agent同時(shí)發(fā)激勵(lì)。我見過不少新手把讀寫driver合并成一個(gè)導(dǎo)致讀寫激勵(lì)互相牽制后來為了模擬并發(fā)讀寫又給代碼加一堆分支邏輯極難維護(hù)。正確的做法是兩個(gè)driver完全獨(dú)立各自只負(fù)責(zé)自己時(shí)鐘域的信號(hào)。要構(gòu)造“幾乎同時(shí)的讀寫”可以用virtual sequence同時(shí)start兩個(gè)子sequence靠調(diào)度器的并行性來逼近真實(shí)時(shí)序。環(huán)境里核心的scoreboard用一個(gè)隊(duì)列來模擬FIFO行為寫側(cè)monitor收到有效寫時(shí)往隊(duì)列push數(shù)據(jù)讀側(cè)monitor收到有效讀時(shí)從隊(duì)列pop數(shù)據(jù)并和DUT輸出比對(duì)。因?yàn)閷懽x共用同一個(gè)隊(duì)列天然就避免了跨時(shí)鐘域比對(duì)的時(shí)間差問題。最后覆蓋率主要收集寫滿、讀空、同時(shí)讀寫、back-to-back突發(fā)、指針回繞等關(guān)鍵場景的覆蓋率。3.3 異步FIFO時(shí)序圖和典型用例設(shè)計(jì)筆試和面試常用的異步FIFO時(shí)序圖關(guān)注點(diǎn)是寫時(shí)鐘域產(chǎn)生寫數(shù)據(jù)寫使能拉高在寫時(shí)鐘上升沿采樣寫入讀時(shí)鐘域相同。空滿標(biāo)志的變化滯后于實(shí)際空滿狀態(tài)因?yàn)橥狡餍枰獌蓚€(gè)周期。面試官有時(shí)會(huì)畫一條寫指針和讀指針的關(guān)系曲線讓你標(biāo)出滿標(biāo)志實(shí)際拉高的位置。我的典型用例設(shè)計(jì)大概分這么幾組用例組場景檢查點(diǎn)基礎(chǔ)讀寫復(fù)位后先寫后讀讀出數(shù)據(jù)與寫入一致連續(xù)寫突發(fā)持續(xù)寫入超過FIFO深度滿標(biāo)志拉高寫入不覆蓋連續(xù)讀突發(fā)持續(xù)讀空空標(biāo)志拉高同時(shí)讀寫讀寫速率不同交替進(jìn)行scoreboard隊(duì)列始終一致背靠背寫滿后立刻讀空再寫滿指針回繞正確復(fù)位干擾寫讀過程中隨機(jī)復(fù)位標(biāo)志位復(fù)位后恢復(fù)無X態(tài)3.4 常見斷言與比對(duì)策略異步FIFO驗(yàn)證里最重要的斷言是寫滿時(shí)不能繼續(xù)寫讀空時(shí)不能繼續(xù)讀。這兩個(gè)斷言直接對(duì)應(yīng)FIFO設(shè)計(jì)的兩條安全底線我會(huì)在寫agent和讀agent的monitor里寫成immediate assertion一旦違反馬上報(bào)error。另一個(gè)容易漏的檢查是“復(fù)位后的空標(biāo)志必須在復(fù)位釋放后有限周期內(nèi)拉高”。異步FIFO復(fù)位后讀指針和寫指針都?xì)w零空標(biāo)志理論上立即有效但由于復(fù)位信號(hào)跨時(shí)鐘域的存在需要檢查兩個(gè)時(shí)鐘域各自的復(fù)位釋放是否干凈。我在一個(gè)項(xiàng)目里遇到過復(fù)位釋放順序不對(duì)導(dǎo)致的空標(biāo)志不定態(tài)后來加了一條斷言專門檢查空標(biāo)志在復(fù)位釋放后5個(gè)讀時(shí)鐘周期內(nèi)穩(wěn)定為1。scoreboard比對(duì)方面除了隊(duì)列比對(duì)我還會(huì)對(duì)FIFO的滿標(biāo)志和空標(biāo)志做“允許延遲”的時(shí)序檢查。因?yàn)樽x側(cè)看到的空標(biāo)志滯后于真實(shí)狀態(tài)scoreboard需要留出同步器延遲窗口不能要求即時(shí)相等否則會(huì)產(chǎn)生大量偽錯(cuò)。4. 筆試題目實(shí)錄與排查技巧4.1 一道必背的計(jì)算題FIFO深度怎么算筆試?yán)镒畛3霈F(xiàn)的題型是給定寫時(shí)鐘頻率、讀時(shí)鐘頻率和突發(fā)長度算FIFO最小深度。我給你一個(gè)我實(shí)際考到過的變體。寫時(shí)鐘100MHz讀時(shí)鐘80MHz寫側(cè)每200個(gè)寫時(shí)鐘周期連續(xù)寫入160個(gè)數(shù)據(jù)讀側(cè)以每200個(gè)讀時(shí)鐘周期讀出80個(gè)數(shù)據(jù)的恒定速率讀取問FIFO最小深度是多少。先把時(shí)間單位統(tǒng)一到寫時(shí)鐘周期。讀時(shí)鐘80MHz即寫時(shí)鐘周期10ns讀時(shí)鐘周期12.5ns。200個(gè)寫時(shí)鐘周期是2000ns這個(gè)時(shí)間段內(nèi)讀側(cè)能讀出的數(shù)據(jù)量為2000/12.5160個(gè)周期但讀側(cè)每200個(gè)讀周期只讀80個(gè)所以實(shí)際讀出80個(gè)數(shù)據(jù)這里要注意題目說的是“每200個(gè)讀時(shí)鐘周期讀出80個(gè)”折算到2000ns就是160個(gè)讀周期讀出64個(gè)數(shù)據(jù)。我算了一下突發(fā)期間寫入160讀出64積壓96個(gè)突發(fā)結(jié)束后的200個(gè)寫周期內(nèi)不再寫入讀側(cè)繼續(xù)讀可以把積壓逐漸清空。所以最小深度至少是96。出于同步器延遲和裕量考慮實(shí)際選擇128比較穩(wěn)妥。這道題的陷阱在于不能簡單比較讀寫平均速率而要算突發(fā)窗口內(nèi)的最大積壓。平均速率對(duì)比只能判斷“長期來看會(huì)不會(huì)溢出”無法回答“短期內(nèi)需要多大緩沖”。4.2 面試追問如果FIFO深度不是2的冪怎么辦格雷碼指針法天然要求FIFO深度是2的冪因?yàn)橹挥形粚挒镹時(shí)格雷碼才能覆蓋完整的0到2^N-1循環(huán)。如果深度不是2的冪比如10那就要考慮兩種處理方式一是把深度向上取整到16代價(jià)是浪費(fèi)6個(gè)存儲(chǔ)單元二是自定義非2冪次地址編碼但空滿判斷邏輯會(huì)變得復(fù)雜跨時(shí)鐘域安全性需要額外分析。大多數(shù)串口和以太網(wǎng)模塊里的異步FIFO深度是2的冪比如16或32這符合設(shè)計(jì)慣例。面試?yán)镉龅椒?冪次深度的題目先回答“會(huì)優(yōu)先向上取整到2的冪”再補(bǔ)一句“如果必須精確深度需要重新設(shè)計(jì)指針編碼和空滿判斷”基本就能過關(guān)。4.3 真機(jī)調(diào)試問題記錄最后分享一個(gè)我實(shí)際踩過的坑。有一次跑異步FIFO的UVM環(huán)境用例跑到一半就報(bào)“FATALobjection count is zero”但波形上看數(shù)據(jù)明明還在傳輸。排查后發(fā)現(xiàn)問題出在我的寫sequence里用了#delay來模擬時(shí)序間隔而讀sequence已經(jīng)提前跑完了所有item并drop了objection。因?yàn)閁VM的run_phase結(jié)束條件是所有objection都?xì)w零所以即使寫側(cè)還有掛起的延時(shí)任務(wù)環(huán)境也會(huì)被強(qiáng)制關(guān)閉。解決辦法有兩個(gè)一是在test的run_phase里維持一個(gè)總objection直到整個(gè)測試計(jì)劃完成再drop二是確保所有sequence在時(shí)間軸上同步退出。我現(xiàn)在更傾向于第一種簡單可靠而且方便控制整個(gè)test的生命周期。這類問題不會(huì)出現(xiàn)在教科書上但實(shí)際工程里幾乎一定會(huì)遇到提前知道能省下大量調(diào)試時(shí)間。異步FIFO看著小但把它的設(shè)計(jì)、驗(yàn)證、筆試計(jì)算全部吃透幾乎就能覆蓋數(shù)字IC驗(yàn)證崗一半以上的面試知識(shí)點(diǎn)。如果你還在準(zhǔn)備階段我建議你先自己動(dòng)手搭一個(gè)最小UVM環(huán)境跑通異步FIFO的讀寫用例再逐步加上scoreboard和覆蓋率這個(gè)過程比背任何八股都有用。本文還有配套的精品資源點(diǎn)擊獲取