通用验证方法学

通用驗證方法學（英語：Universal Verification Methodology, UVM）是一個以SystemVerilog類庫為主體的驗證平台開發框架，驗證工程師可以利用其可重用組件構建具有標準化層次結構和接口的功能驗證環境。它是第一個由電子設計自動化領域三巨頭（Cadence、Synopsys和Mentor Graphics）聯合支持的驗證方法學，其最新版本為1.2版。

概述

最原始、最簡陋的Verilog測試平台通常會做以下幾件事情：第一，在測試平台模塊中例化被測設計；第二，創建若干變量（通常是reg類型），將它們連接到被測設計的輸入埠，並在過程代碼塊（通常是initial塊）中的不同時間點對它們進行賦值，使這些變量充當被測設計的輸入激勵；第三，採集被測設計輸出埠的信號，或者直接採集被測設計的內部信號；第四，在測試平台模塊內建立一些功能模塊，將採集到的信號與根據之前設計規範預測的參考數值進行對比，然後輸出一些信息以方便故障的排除。
這樣的驗證模式對於簡單的被測設計尚可，但是如果被測設計的複雜程度較高，這樣的測試平台將會變得十分臃腫，而且不利於工程師維護和重用。例如，如果驗證人員想在原有輸入激勵基礎上添加一系列新的測試序列，則很可能會牽一髮而動全身，影響測試平台的其他部分。工程師需要將驗證平台的不同組分，例如輸入激勵、輸出採集、記分板對比等不同部分相互隔離。在超大規模集成電路已經是主流的今天，Verilog結構化的編程方式使代碼的復用成為了一個嚴重的難題。
雖然SystemVerilog的物件導向編程特性提供了解決了上述問題的可能，但是仍然存在一些問題。工程師有了更靈活的語言，但是怎麼用這種語言來搭建驗證平台卻是沒有明確規範的，因而不同人搭建的驗證平台在結構上會有差異。最明顯的是，不同工程師對於驗證平台功能的劃分可能不一樣，即使採用同樣的劃分，其中同類模塊對外的接口（方法和數據成員）也沒有統一的標準。這在一定程度上阻礙了大型驗證平台之間的協作性、擴展性（假設某公司的兩個團隊分別負責驗證平台的輸入激勵部分和輸出信號比較部分，卻各自使用了非標準化的事務接口，其結果是他們將耗費大量的時間對各自的代碼進行修改，這將大大延緩晶片的上市時間）。驗證方法學提供了一套基於SystemVerilog的類庫，驗證工程師以其中預定義的類作為起點，就可以建立起具有標準結構的驗證平台。
由於行業競爭的關係，歷史上不同廠商曾推出了數種略有差異的驗證方法學。使用不同驗證方法學的驗證平台之間的互操作性仍有一定的障礙。為了進行實現驗證方法學的標準化，早在2009年12月，Accellera（電子設計自動化行業的一個致力於標準化的組織）內部就通過投票，決定以之前的開放驗證方法學2.1.1版為基礎，構建一個新的功能驗證方法學。在此之前，不同的電子設計自動化廠商相繼推出了自己的驗證方法學，例如開放驗證方法學就是Cadence和Mentor Graphics合作推出的。這種情況就造成了不同驗證方法學之間的協同工作需要工程師額外的精力。2011年2月21日，Accelera通過了通用驗證方法學的1.0版，並得到了三大廠商的共同支持。目前最新版本為1.2版。

頂層模塊和測試類之間的關聯

上面簡歷的這個頂層模塊（非物件導向部分）不屬於測試類所在的類、對象層次結構之中，一般使用常規的Verilog或SystemVerilog模塊（module）來構建。這種結構不具備物件導向特性，它和測試類（物件導向部分）的聯繫是通過以下兩步建立的。

run_test()方法

首先，當頂層模塊執行run_test()方法（這是個類庫自帶的方法，調用者無需關心其具體定義）時，通用驗證方法學引擎會在後台執行一系列操作來建立測試環境。驗證人員在啟動類似Synopsys VCS之類的仿真工具之前需要制定測試名稱，仿真工具執行到run_test()方法時會去查找名稱與之相同的測試類（由uvm_test類繼承），找到之後會創建這個測試類的一個對象（在整個物件導向部分，這個對象的實例化由通用驗證方法學引擎而非用戶完成，且該實例名稱為uvm_test_top），然後根據人為的實例化語句來逐層創建測試類中的環境類、代理類、驅動器類等的對象層次結構）。這些對象所屬的類都是從通用驗證方法學預定義的基類繼承而來，驗證人員需要覆蓋一些特定名稱的方法，通用驗證方法學的引擎在執行仿真時會自動調用這些方法，來達到驅動被測設計、採樣所需信號的目的

接口

接口（interface）是連接驗證平台頂層模塊（非物件導向部分）和測試類（物件導向部分）的橋樑（參見匯流排功能模型）。
頂層模塊還必須將所用的接口在工廠，即配置資料庫（uvm_config_db，詳見本條目後面相關章節）里註冊（執行set靜態方法），然後測試所在的物件導向部分可以在工廠里將其取出（執行get靜態方法）。這是因為，頂層模塊並不在測試部分的類屬層次關係之中，因此頂層模塊與測試之間的關聯必須使用這樣的特殊的方式建立起來。在配置資料庫中註冊的接口相當於一個大的全局變量，聯繫著整個驗證平台的非物件導向硬體描述語言部分（被測設計實例）和物件導向硬體驗證語言部分（真正測試部分各種類的實例，具有物件導向編程的若干層次）。
測試類獲得這個接口之後，會負責將它在測試類這一端連接到測試類內部的相關組件（如驅動器、監視器等）。頂層模塊的被測設計和測試類不直接通過信號名稱匹配相連（類似Verilog中的埠連接），而是分別只對接口內的信號進行讀寫。

虛接口

接口是在頂層模塊被實例化，並與被測設計實例進行連接的。理論上，測試類部分的成分，例如驅動器、監視器，也需要實例化一個接口，並通過配置資料庫與頂層模塊中的接口實例進行匹配。測試類中的這個接口在實例化時，必須使用關鍵字virtual關鍵字進行聲明。將配置資料庫中的接口取出，並賦值給此虛接口，就可以將測試類和頂層模塊聯繫起來。

測試類

由測試基類uvm_test繼承。
整個驗證平台中除去頂層模塊、被測設計之外的物件導向部分，其頂級類被稱為測試類。測試類通常負責實例化一個環境、一個序列，並調用序列實例的start(sequencer)方法來啟動一個環境實例的代理實例的序列產生器。

環境類

由環境基類uvm_env繼承。
記分板實例、訂閱者實例（如功能覆蓋統計模塊）也在環境中被創建，它們通常不直接讀寫那個與頂層模塊直接相連的接口。與那個接口發生直接關係的驅動器、監視器都由環境實例內的代理實例包裹。通過使用通信接口，事務包由代理生成，傳輸給記分板和覆蓋統計模塊。

代理類

由代理基類uvm_agent繼承。

序列發生器類

由序列發生器基類uvm_sequencer繼承。這一繼承是參數化繼承，需要指定與其相關的序列項目類的名稱。
序列發生器不需要定義數據成員和方法。一旦高層次的測試中創建了一個序列實例，然後在測試類實例中執行了類似sequence.start(env.agent.sequencer)這樣的開啟方法，序列發生器實例就在後台將連串的數據包發送出去（開發人員無需關注數據包是怎麼發送出去的，這些操作由uvm_sequencer這個基類中定義的方法來完成）。開發人員只需要在驅動器類中調用其基類成員之一的seq_item_port通訊埠的get_next_item(sequence)方法，驅動器就能獲得數據包。

驅動器類

由驅動器基類uvm_driver繼承。這一繼承是參數化繼承，需要指定與其相關的序列項目類的名稱。
驅動器是代理中直接與被測設計發生作用的部分。它本身並不知道如何產生激勵信號，它只是調用get_next_item(sequence)方法，從序列發生器接收的一系列數據包，然後將包中對應的信號通過賦值施加到整個測試平台的公共匯流排接口上，從而間接地給被測設計提供了所需的輸入激勵。

監視器類

由監視器基類uvm_monitor繼承。
監視器是一個被動的模塊，通過接口和被測設計中的信號相連。獲得要監測的數據包（或者單獨的信號）之後，監視器只負責將這些信息通過通訊埠發送出去，至於誰來接收這些信息則由其他模塊類關心。通常的做法是，在監視器類里聲明分析埠uvm_analysis_port類的實例，調用該實例的write方法將獲取的信息放置到分析埠上。這相當於監視器向外界「廣播」內容，然後由對此感興趣的模塊（訂閱者）負責接收。

記分板類

由記分板基類uvm_scoreboard繼承。
記分板不直接與被測設計發生互動，而是通過通訊埠，從監視器那裡獲取後者提供的事務（數據包）。記分板的run_phase()方法（任務）通常會提取出數據包中的信號，然後將它們與預設的參考模型進行對比，從而驗證被測設計的功能是否與預期相同。如果不同，驗證人員可以選擇在螢幕上顯示提示或警告，或者直接中斷仿真的運行。

訂閱者類

由訂閱者基類uvm_subscriber繼承。這一繼承是參數化繼承，需要指定與其相關的序列項目類的名稱。
覆蓋統計模塊通常是一個訂閱者。

序列類

由序列基類uvm_sequence繼承。。這一繼承是參數化繼承，需要指定與其相關的序列項目類的名稱。
序列類不需要定義任何與phase有關的方法，開發人員只需要覆寫task body()方法（任務）。此方法內部一般會調用`uvm_do(sequence)方法宏，其結果是使用定義好的序列項目來輸出一系列事務序列（一連串事務包，或數據包），這些事務序列將有驅動器接收，進而施加給被測設計。如果序列項目類的數據成員被聲明為隨機變量（例如使用rand），隨機化方法randomize()會在調用`uvm_do生成數據包時被隱式地調用。

序列項目類

由序列項目基類uvm_sequence_item繼承。
序列項目定義了了數據包每一幀包含哪些數據成員，這些數據成員可以被聲明為SystemVerilog的隨機變量類型（rand或randc）。通常不需要在這個類中定義任何方法。這個類的實例會作為序列類的`uvm_do(sequence_item)方法的參數，自動進行數據的隨機化（前面這個方法宏內嵌了randomize()這樣的隨機化方法，這些都在後台由驗證方法學引擎控制運行），進一步產生連串的數據包。

配置資料庫

前面提到了在頂層模塊中實例化和使用的接口可以通過配置資料庫（uvm_config_db）傳遞給測試類。配置資料庫本身是個參數化的類。配置資料庫的使用方法通常為調用其靜態方法而非實例化，最常用的兩個靜態方法分別為set()（存）和get()（取）。和實例方法使用.（點號）來連接實例名和實例方法名來調用不同，靜態方法使用::（雙冒號），類的作用域操作符）來連接類名和靜態方法名來調用。