習(xí):從核心概念到搭建最小驗(yàn)證環(huán)境)
在驗(yàn)證領(lǐng)域從 SystemVerilog 逐步過(guò)渡到 UVM 的過(guò)程中很多人都會(huì)被組件劃分、phase 機(jī)制、config_db 傳參這些抽象概念繞暈。網(wǎng)上資料不少但要么是官方手冊(cè)的翻譯腔要么是一堆代碼片段缺少上下文。最近我在用 Codex 輔助學(xué)習(xí)和搭建 UVM 驗(yàn)證環(huán)境發(fā)現(xiàn)只要提問(wèn)方式得當(dāng)它能把概念講解、代碼生成、報(bào)錯(cuò)分析、面試刷題全部串起來(lái)非常適合驗(yàn)證方向的新人也適合想快速搭建驗(yàn)證環(huán)境的在職工程師。本文會(huì)從 Codex 安裝開(kāi)始介紹如何通過(guò)提示詞學(xué)習(xí) UVM 核心概念再帶你使用 Codex 一步步搭建一個(gè)最小可用的 UVM 加法器驗(yàn)證環(huán)境最后補(bǔ)充寄存器模型學(xué)習(xí)、常見(jiàn)報(bào)錯(cuò)排查和工程落地建議。閱讀本文不需要你已經(jīng)掌握 UVM 全貌只需要有最基本的 SystemVerilog 語(yǔ)法基礎(chǔ)以及一點(diǎn)命令行操作經(jīng)驗(yàn)。1. 為什么要用 Codex 學(xué) UVM驗(yàn)證學(xué)習(xí)的新思路1.1 UVM 學(xué)習(xí)的典型痛點(diǎn)UVM 的全稱(chēng)是 Universal Verification Methodology即通用驗(yàn)證方法學(xué)。它并不是一種新的編程語(yǔ)言而是建立在 SystemVerilog 之上的一套類(lèi)庫(kù)和編程規(guī)范用于搭建可重用、可擴(kuò)展的驗(yàn)證環(huán)境。它把驗(yàn)證環(huán)境抽象成一棵組件樹(shù)并通過(guò) factory 機(jī)制、phase 機(jī)制、config_db 機(jī)制、sequence 機(jī)制等解決驗(yàn)證環(huán)境中的對(duì)象創(chuàng)建、執(zhí)行順序、配置傳遞和激勵(lì)生成問(wèn)題。新手學(xué)習(xí) UVM 時(shí)通常會(huì)遇到幾個(gè)明顯的坎。第一組件數(shù)量多driver、monitor、sequencer、agent、scoreboard、env、test 之間關(guān)系復(fù)雜直接看完整代碼很容易迷失方向。第二UVM 中有大量宏和回調(diào)方法比如uvm_component_utils、uvm_object_utils、build_phase、connect_phase、run_phase如果不理解底層邏輯代碼只能靠記憶去抄。第三驗(yàn)證環(huán)境的運(yùn)行依賴(lài) EDA 仿真器比如 ModelSim、QuestaSim、VCS很多入門(mén)者沒(méi)有現(xiàn)成的 license 或環(huán)境導(dǎo)致學(xué)習(xí)成本變高。這些痛點(diǎn)的本質(zhì)是UVM 不只是一個(gè)代碼庫(kù)更是一套“驗(yàn)證思維”。閱讀文檔只能知道組件有哪些但很難理解組件之間如何協(xié)作。如果有一個(gè)工具能隨時(shí)解釋概念、生成示例代碼、幫忙排查報(bào)錯(cuò)學(xué)習(xí)效率會(huì)提升很多。Codex 恰好可以承擔(dān)這個(gè)角色。1.2 Codex 在驗(yàn)證學(xué)習(xí)中的價(jià)值Codex 是 OpenAI 推出的 AI 編程助手可以在終端中通過(guò)自然語(yǔ)言與其交互。它不只是簡(jiǎn)單的代碼補(bǔ)全工具還可以理解項(xiàng)目上下文完成從代碼生成、代碼解釋、報(bào)錯(cuò)分析到重構(gòu)優(yōu)化的完整任務(wù)。對(duì)于學(xué)習(xí) UVM 來(lái)說(shuō)Codex 可以在以下幾個(gè)方面提供幫助概念講解用通俗語(yǔ)言解釋 UVM 的 phase 機(jī)制、factory 機(jī)制、config_db 機(jī)制等。代碼生成根據(jù)你給出的驗(yàn)證需求生成 transaction、sequence、driver、scoreboard 等組件代碼。代碼解釋把一段網(wǎng)上下載的 UVM 代碼逐行注釋幫助理解組件協(xié)作方式。報(bào)錯(cuò)排查把仿真器報(bào)錯(cuò)貼給 Codex讓它分析原因并給出修復(fù)方案。面試練習(xí)讓 Codex 扮演面試官針對(duì) UVM 方法學(xué)提問(wèn)幫你查漏補(bǔ)缺。學(xué)習(xí)規(guī)劃讓它制定一套從 SystemVerilog 到 UVM 再到驗(yàn)證項(xiàng)目的學(xué)習(xí)路線(xiàn)。不過(guò)需要明確一點(diǎn)Codex 可以幫你生成代碼但不能替代你思考。UVM 的工程落地最終還是要靠驗(yàn)證工程師自己理解場(chǎng)景、設(shè)計(jì)驗(yàn)證方案、檢查覆蓋率。把 Codex 當(dāng)作一個(gè)隨叫隨到的“結(jié)對(duì)工程師”而不是“答案生成器”是使用它的正確姿勢(shì)。1.3 本文適用讀者與學(xué)習(xí)目標(biāo)本文面向以下讀者正在學(xué)習(xí)芯片驗(yàn)證、FPGA 驗(yàn)證希望入門(mén) UVM 的學(xué)生已經(jīng)有 SystemVerilog 基礎(chǔ)但還沒(méi)有完整搭建過(guò) UVM 環(huán)境的工程師以及在實(shí)際項(xiàng)目中使用 UVM但想借助 AI 工具提高編碼和排錯(cuò)效率的驗(yàn)證工程師。讀完本文后你應(yīng)該能夠完成這些事在自己的電腦上安裝并配置 Codex用自然語(yǔ)言向 Codex 提問(wèn)學(xué)習(xí) UVM 核心概念讓 Codex 分步生成一個(gè)最小 UVM 驗(yàn)證環(huán)境理解 UVM 各組件的職責(zé)和連接方式用 Codex 輔助學(xué)習(xí)寄存器模型 RAL并應(yīng)付常見(jiàn) UVM 面試問(wèn)題。2. 環(huán)境準(zhǔn)備安裝 Codex 命令行工具2.1 安裝前置條件Codex CLI 是一個(gè)命令行工具主要面向開(kāi)發(fā)者。安裝前需要確認(rèn)你的電腦具備以下條件操作系統(tǒng)Windows、macOS 或 Linux 均可不同系統(tǒng)下的安裝步驟稍有差異。Node.js 環(huán)境Codex CLI 通過(guò) npm 分發(fā)需要安裝 Node.js 和 npm。建議使用較新的 LTS 版本版本太老可能導(dǎo)致安裝失敗或運(yùn)行異常。網(wǎng)絡(luò)環(huán)境Codex 需要聯(lián)網(wǎng)訪(fǎng)問(wèn)模型服務(wù)請(qǐng)確保你的網(wǎng)絡(luò)環(huán)境能夠正常訪(fǎng)問(wèn) Codex 使用的 API。如果使用的是公司網(wǎng)絡(luò)還需要確認(rèn)網(wǎng)絡(luò)策略是否允許訪(fǎng)問(wèn)相關(guān)域名。具體版本沒(méi)有統(tǒng)一標(biāo)準(zhǔn)因?yàn)?Codex 更新很快本文以常見(jiàn)環(huán)境為例重點(diǎn)演示配置思路。你在操作時(shí)可以根據(jù)本機(jī)環(huán)境靈活調(diào)整。2.2 安裝 Codex CLI最直接的安裝方式是通過(guò) npm 全局安裝。打開(kāi)終端執(zhí)行下面的命令npm install -g openai/codex安裝完成后驗(yàn)證是否安裝成功codex --version如果終端能輸出版本號(hào)說(shuō)明 Codex CLI 已經(jīng)安裝成功。如果提示command not found可能是 npm 的全局 bin 目錄沒(méi)有加入系統(tǒng) PATH。你可以通過(guò)下面的命令查看 npm 全局安裝路徑npm prefix -g然后把輸出目錄中的 bin 子目錄加入系統(tǒng) PATH再重新打開(kāi)終端測(cè)試。除了 npm 方式Codex 官方也可能會(huì)提供其他安裝方式比如通過(guò) Homebrew 等包管理器安裝。具體以官方 Readme 或項(xiàng)目主頁(yè)的安裝說(shuō)明為準(zhǔn)。安裝過(guò)程如果遇到權(quán)限問(wèn)題可以檢查 npm 全局目錄是否有寫(xiě)權(quán)限必要時(shí)使用sudo或給當(dāng)前用戶(hù)授權(quán)。2.3 登錄與模型配置安裝完成之后第一次使用需要登錄。在終端執(zhí)行codex login命令會(huì)引導(dǎo)你完成賬號(hào)授權(quán)登錄。登錄成功后Codex 就可以調(diào)用模型服務(wù)來(lái)處理你的提問(wèn)和代碼任務(wù)。如果你希望使用 DeepSeek 等兼容 OpenAI 接口的模型服務(wù)Codex 也支持通過(guò)配置文件自定義模型供應(yīng)商。不同版本的配置字段略有差異建議先查看官方倉(cāng)庫(kù)的 config 示例。整體思路是在配置中聲明模型供應(yīng)商的 base_url、API Key 環(huán)境變量、模型名稱(chēng)并在全局 model 中指定。下面是一個(gè)結(jié)構(gòu)示意不是某個(gè)版本的完整配置使用時(shí)請(qǐng)以官方文檔為準(zhǔn)# ~/.codex/config.toml 結(jié)構(gòu)示意 model deepseek/deepseek-chat [model_providers.deepseek] name DeepSeek base_url https://api.deepseek.com/v1 env_key DEEPSEEK_API_KEY wire_api chat配置完成后需要在環(huán)境變量中設(shè)置對(duì)應(yīng)的 API Key例如export DEEPSEEK_API_KEY你的密鑰然后重新啟動(dòng) Codex就能使用你指定的模型服務(wù)了。這里需要特別提醒不同模型的能力差異很大UVM 相關(guān)代碼生成任務(wù)建議選擇推理能力較強(qiáng)的模型否則生成的代碼可能在 API 細(xì)節(jié)上出錯(cuò)。2.4 第一次運(yùn)行 Codex安裝和登錄完成后可以通過(guò)交互模式啟動(dòng) Codexcodex進(jìn)入交互模式后你可以直接輸入自然語(yǔ)言問(wèn)題。例如用通俗的語(yǔ)言解釋 UVM 中的 phase 機(jī)制Codex 會(huì)返回一段解釋。如果你只需要一次性輸出結(jié)果也可以直接作為命令行參數(shù)傳入codex 什么是 UVM這種方式適合快速測(cè)試交互模式則更適合深入學(xué)習(xí)、連續(xù)追問(wèn)和多文件代碼生成。退出方式一般是在交互界面輸入 exit 或使用快捷鍵具體以你當(dāng)前版本的提示為準(zhǔn)。3. 先學(xué)會(huì)提問(wèn)如何用 Codex 學(xué)習(xí) UVM 核心概念3.1 讓 Codex 用通俗語(yǔ)言解釋 UVM 架構(gòu)很多教程一上來(lái)就給出 UVM 類(lèi)圖新手容易產(chǎn)生“每個(gè)字都認(rèn)識(shí)但連起來(lái)看不懂”的感覺(jué)。這時(shí)可以讓 Codex 換一種表達(dá)方式用比喻來(lái)解釋??梢赃@樣提問(wèn)請(qǐng)用大白話(huà)解釋 UVM 的驗(yàn)證環(huán)境結(jié)構(gòu)。把 driver、monitor、scoreboard、agent、env、test 之間的關(guān)系講清楚可以用現(xiàn)實(shí)中的比喻不要直接貼代碼。Codex 通常會(huì)給出類(lèi)似這樣的解釋思路test 是整個(gè)比賽的策劃env 是比賽場(chǎng)地agent 是場(chǎng)地中的一個(gè)工作小組driver 負(fù)責(zé)把指令發(fā)給選手monitor 負(fù)責(zé)記錄成績(jī)scoreboard 負(fù)責(zé)檢查成績(jī)是否合格。這種類(lèi)比雖然不完全嚴(yán)謹(jǐn)?shù)珜?duì)入門(mén)理解很有幫助。在此基礎(chǔ)上你可以繼續(xù)追問(wèn)更深入的問(wèn)題比如“UVM 為什么使用樹(shù)形結(jié)構(gòu)”“factory 機(jī)制解決什么問(wèn)題”“config_db 是如何從上往下傳遞配置的”。通過(guò)連續(xù)提問(wèn)把抽象概念拆成一個(gè)個(gè)具體問(wèn)題比一次性閱讀大段文檔要輕松很多。3.2 讓 Codex 對(duì)比 UVM 與普通 SystemVerilog 驗(yàn)證很多從 SystemVerilog 驗(yàn)證轉(zhuǎn)向 UVM 的人會(huì)疑惑為什么不用簡(jiǎn)單的initial塊和 task 完成激勵(lì)為什么要引入這么多類(lèi)你可以讓 Codex 做一個(gè)對(duì)比總結(jié)。比如這樣提問(wèn)傳統(tǒng) SystemVerilog 驗(yàn)證方式和 UVM 驗(yàn)證方式有什么區(qū)別請(qǐng)從可重用性、隨機(jī)激勵(lì)、覆蓋率收集、組件劃分、擴(kuò)展性幾個(gè)角度對(duì)比。通過(guò)學(xué)習(xí)對(duì)比輸出你會(huì)發(fā)現(xiàn) UVM 的核心價(jià)值在于重用和標(biāo)準(zhǔn)化。傳統(tǒng)方式的測(cè)試代碼往往和具體 DUT 強(qiáng)耦合換一個(gè)項(xiàng)目就要重新寫(xiě)而 UVM 將驗(yàn)證環(huán)境拆分為多個(gè)標(biāo)準(zhǔn)化組件組件之間通過(guò) TLM 端口和 sequence 機(jī)制交互換項(xiàng)目時(shí)只需要重新配置參數(shù)和封裝特定的 BFM很多組件可以直接復(fù)用。3.3 讓 Codex 拆解一個(gè) UVM 類(lèi)閱讀開(kāi)源 UVM 代碼時(shí)最常見(jiàn)的困惑是不知道一個(gè)類(lèi)從繼承到注冊(cè)再到 phase 回調(diào)的完整流程。遇到這種情況可以把代碼粘給 Codex讓它逐行注釋。例如你可以粘貼一段uvm_driver的代碼然后提問(wèn)請(qǐng)逐行解釋這段 UVM driver 代碼。重點(diǎn)說(shuō)明類(lèi)繼承關(guān)系、uvm_component_utils 的作用、build_phase 中 uvm_config_db 的用法、run_phase 中封裝的握手邏輯。這種方式非常有效。Codex 會(huì)把代碼中隱含的 UVM 規(guī)范逐條拆出來(lái)比如“通過(guò)uvm_config_db獲取 virtual interface”“通過(guò)seq_item_port.get_next_item向 sequencer 請(qǐng)求事務(wù)”“通過(guò)item_done通知 sequencer 事務(wù)處理完畢”。這些內(nèi)容如果只看代碼確實(shí)不容易總結(jié)清楚。3.4 讓 Codex 出題自測(cè)并整理高頻面試題學(xué)習(xí) UVM 不只是為了寫(xiě)代碼很多人在求職或轉(zhuǎn)崗時(shí)還需要通過(guò)面試。你可以讓 Codex 扮演面試官考察自己的理解深度。例如你現(xiàn)在是一名芯片驗(yàn)證面試官請(qǐng)圍繞 UVM 方法學(xué)向我提問(wèn)考察范圍包括 phase 機(jī)制、factory 機(jī)制、sequence 機(jī)制、config_db 機(jī)制、寄存器模型。每次問(wèn)一個(gè)問(wèn)題等我回答后再給出評(píng)價(jià)和標(biāo)準(zhǔn)答案。這種模式非常適合自測(cè)。常見(jiàn)的 UVM 面試問(wèn)題包括UVM 的 phase 階段分哪幾類(lèi)run_phase 和 reset_phase 的區(qū)別是什么factory 的 override 怎么實(shí)現(xiàn)uvm_config_db的 get 和 set 參數(shù)分別代表什么sequence 和 sequencer 之間如何通信寄存器模型中的期望值、鏡像值和硬件實(shí)際值有什么區(qū)別你完全可以借助 Codex 把這些題目逐個(gè)過(guò)一遍。4. 實(shí)戰(zhàn)讓 Codex 幫你搭建一個(gè)最小 UVM 驗(yàn)證環(huán)境4.1 明確需求描述驗(yàn)證目標(biāo)學(xué)概念只是第一步真正理解 UVM 還需要?jiǎng)邮执罱ㄒ粋€(gè)最小驗(yàn)證環(huán)境。這里我選擇最簡(jiǎn)單的加法器作為 DUT目標(biāo)是驗(yàn)證一個(gè) 8 位加法器的功能是否正確。先給出待測(cè)設(shè)計(jì)。文件路徑rtl/adder.svmodule adder #(parameter WIDTH 8) ( input logic [WIDTH-1:0] a, input logic [WIDTH-1:0] b, output logic [WIDTH-1:0] sum ); assign sum a b; endmodule這個(gè)模塊很簡(jiǎn)單輸入a和b輸出sum。驗(yàn)證環(huán)境要做的事情是隨機(jī)產(chǎn)生 8 位輸入驅(qū)動(dòng)到 DUT同時(shí)讓參考模型計(jì)算預(yù)期結(jié)果然后比較 DUT 輸出和預(yù)期結(jié)果。向 Codex 描述需求時(shí)可以這樣寫(xiě)請(qǐng)幫我搭建一個(gè)最小 UVM 驗(yàn)證環(huán)境DUT 是一個(gè) 8 位加法器輸入 a、b輸出 sum。 要求包含以下組件 1. transaction 類(lèi)包含隨機(jī)輸入 a、b 和輸出 sum 2. sequence 類(lèi)產(chǎn)生 10 個(gè)隨機(jī)激勵(lì) 3. driver從 sequencer 接收事務(wù)并驅(qū)動(dòng)到接口 4. monitor采樣接口信號(hào)并發(fā)送給 scoreboard 5. scoreboard比較 DUT 輸出與預(yù)期結(jié)果 6. agent、env、test 和頂層 tb。 請(qǐng)分文件生成代碼每個(gè)文件標(biāo)注路徑。接下來(lái)幾節(jié)給出的代碼是讓 Codex 生成后按教學(xué)需要整理的結(jié)果。你可以把這段描述作為自己的提問(wèn)模板然后結(jié)合 Codex 的實(shí)際輸出調(diào)整。4.2 生成事務(wù)類(lèi)與序列先創(chuàng)建接口文件。文件路徑tb/adder_if.svinterface adder_if(input logic clk); logic [7:0] a; logic [7:0] b; logic [7:0] sum; endinterface接口在驗(yàn)證環(huán)境中用于連接 DUT 和驗(yàn)證組件。driver會(huì)驅(qū)動(dòng)a和bmonitor會(huì)采樣a、b和sum。接下來(lái)是事務(wù)類(lèi)。文件路徑tb/adder_transaction.svclass adder_transaction extends uvm_sequence_item; rand bit [7:0] a; rand bit [7:0] b; bit [7:0] sum; uvm_object_utils_begin(adder_transaction) uvm_field_int(a, UVM_ALL_ON) uvm_field_int(b, UVM_ALL_ON) uvm_field_int(sum, UVM_ALL_ON) uvm_object_utils_end function new(string name adder_transaction); super.new(name); endfunction endclass事務(wù)類(lèi)繼承自u(píng)vm_sequence_item它描述的是驗(yàn)證環(huán)境中流動(dòng)的一筆“數(shù)據(jù)”。這里把輸入a、b設(shè)置為rand這樣 sequence 可以隨機(jī)化它們。uvm_field_int宏會(huì)把字段自動(dòng)注冊(cè)到 factory 的復(fù)制、比較、打印等方法中方便后續(xù)使用。然后是序列。文件路徑tb/adder_sequence.svclass adder_sequence extends uvm_sequence #(adder_transaction); uvm_object_utils(adder_sequence) function new(string name adder_sequence); super.new(name); endfunction task body(); repeat (10) begin req adder_transaction::type_id::create(req); start_item(req); assert(req.randomize()); finish_item(req); end endtask endclassadder_sequence繼承自u(píng)vm_sequence #(adder_transaction)它負(fù)責(zé)產(chǎn)生事務(wù)。body任務(wù)里循環(huán) 10 次每次創(chuàng)建事務(wù)、隨機(jī)化后通過(guò)start_item和finish_item發(fā)送給 sequencer。start_item會(huì)等待 sequencer 仲裁finish_item表示事務(wù)已經(jīng)交給 driver。4.3 生成驅(qū)動(dòng)器與監(jiān)視器驅(qū)動(dòng)器負(fù)責(zé)把事務(wù)數(shù)據(jù)驅(qū)動(dòng)到 DUT 接口。文件路徑tb/adder_driver.svclass adder_driver extends uvm_driver #(adder_transaction); uvm_component_utils(adder_driver) virtual adder_if vif; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); if (!uvm_config_db#(virtual adder_if)::get(this, , vif, vif)) uvm_fatal(NOVIF, virtual interface not found) endfunction task run_phase(uvm_phase phase); forever begin seq_item_port.get_next_item(req); vif.a req.a; vif.b req.b; (posedge vif.clk); seq_item_port.item_done(); end endtask endclassdriver 是驗(yàn)證環(huán)境中的“執(zhí)行者”。它通過(guò)uvm_config_db獲取 virtual interface然后在run_phase中不斷從 sequencer 取事務(wù)把數(shù)據(jù)放到接口上。這里的item_done是通知 sequencer 當(dāng)前事務(wù)已經(jīng)處理完成可以發(fā)送下一筆。監(jiān)視器負(fù)責(zé)采樣接口數(shù)據(jù)。文件路徑tb/adder_monitor.svclass adder_monitor extends uvm_monitor #(adder_transaction); uvm_component_utils(adder_monitor) virtual adder_if vif; uvm_analysis_port #(adder_transaction) mon_ap; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); if (!uvm_config_db#(virtual adder_if)::get(this, , vif, vif)) uvm_fatal(NOVIF, virtual interface not found) mon_ap new(mon_ap, this); endfunction task run_phase(uvm_phase phase); adder_transaction tr; forever begin (posedge vif.clk); tr adder_transaction::type_id::create(tr); tr.a vif.a; tr.b vif.b; tr.sum vif.sum; mon_ap.write(tr); end endtask endclassmonitor 是驗(yàn)證環(huán)境中的“觀(guān)察者”。它在每個(gè)時(shí)鐘上升沿采樣接口信號(hào)把采樣結(jié)果封裝成事務(wù)對(duì)象并通過(guò)uvm_analysis_port廣播出去。scoreboard 可以訂閱這個(gè)端口從而拿到真實(shí)輸出進(jìn)行比對(duì)。4.4 生成代理、驗(yàn)證環(huán)境、測(cè)試與頂層agent 把 driver、monitor 和 sequencer 封裝在一起。文件路徑tb/adder_agent.svclass adder_agent extends uvm_agent; uvm_component_utils(adder_agent) adder_driver drv; adder_monitor mon; uvm_sequencer #(adder_transaction) sqr; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); drv adder_driver::type_id::create(drv, this); mon adder_monitor::type_id::create(mon, this); sqr uvm_sequencer#(adder_transaction)::type_id::create(sqr, this); endfunction function void connect_phase(uvm_phase phase); super.connect_phase(phase); drv.seq_item_port.connect(sqr.seq_item_export); endfunction endclassagent 是驗(yàn)證環(huán)境中的可重用單元它把同一組 driver、monitor、sequencer 打包方便上層 env 直接使用。connect_phase 里把 driver 的seq_item_port和 sequencer 的seq_item_export連接起來(lái)構(gòu)成 sequence 到 driver 的數(shù)據(jù)通路。scoreboard 用于結(jié)果比對(duì)。文件路徑tb/adder_scoreboard.svclass adder_scoreboard extends uvm_scoreboard; uvm_component_utils(adder_scoreboard) uvm_analysis_imp #(adder_transaction, adder_scoreboard) mon_imp; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); mon_imp new(mon_imp, this); endfunction function void write(adder_transaction tr); bit [7:0] expect_sum; expect_sum tr.a tr.b; if (tr.sum ! expect_sum) begin uvm_error(SCOREBOARD, $sformatf(Mismatch: a%0d b%0d expect%0d actual%0d, tr.a, tr.b, expect_sum, tr.sum)) end else begin uvm_info(SCOREBOARD, $sformatf(Pass: a%0d b%0d sum%0d, tr.a, tr.b, tr.sum), UVM_MEDIUM) end endfunction endclassscoreboard 通過(guò)實(shí)現(xiàn)write方法接收 monitor 發(fā)來(lái)的事務(wù)對(duì)象。這里使用uvm_analysis_imp建立了一個(gè) analysis 端口實(shí)際理解時(shí)可以把它看作一個(gè)可以接收廣播數(shù)據(jù)的“收件箱”。write方法里計(jì)算預(yù)期值并與 DUT 輸出比較。env 用于裝配 agent 和 scoreboard。文件路徑tb/adder_env.svclass adder_env extends uvm_env; uvm_component_utils(adder_env) adder_agent agent; adder_scoreboard scb; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); agent adder_agent::type_id::create(agent, this); scb adder_scoreboard::type_id::create(scb, this); endfunction function void connect_phase(uvm_phase phase); super.connect_phase(phase); agent.mon.mon_ap.connect(scb.mon_imp); endfunction endclassenv 是驗(yàn)證環(huán)境的容器負(fù)責(zé)創(chuàng)建 agent 和 scoreboard并連接它們的端口。這一步體現(xiàn)了 UVM 樹(shù)形結(jié)構(gòu)的優(yōu)勢(shì)上層組件只需要關(guān)注組件的實(shí)例化和連接不需要關(guān)心內(nèi)部實(shí)現(xiàn)。test 是驗(yàn)證用例的入口。文件路徑tb/adder_test.svclass adder_test extends uvm_test; uvm_component_utils(adder_test) adder_env env; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); env adder_env::type_id::create(env, this); endfunction task run_phase(uvm_phase phase); adder_sequence seq; phase.raise_objection(this); seq adder_sequence::type_id::create(seq); assert(seq.randomize()); seq.start(env.agent.sqr); phase.drop_objection(this