SystemVerilog

**SystemVerilog** 是一種在現代積體電路（尤其是超大型積體電路）的設計及驗證流程中，由 Verilog 發展而來的硬體描述、硬體驗證統一語言，前一部分基本上是 2005 年版 Verilog 的擴充，而後一部分功能驗證特性則是一門物件導向程式設計語言。物件導向特性很好地彌補了傳統 Verilog 在晶片驗證領域的缺陷，改善了代碼可重用性，同時可以讓驗證工程師在比暫存器傳輸級更高的抽象級別，以事務而非單個訊號作為監測物件，這些都大大提高了驗證平台搭建的效率。

SystemVerilog 已經被採納為電氣電子工程師學會 1800-2009 標準，並獲得了主流電子設計自動化工具供應商的支援。雖無任一個仿真系統能聲稱自己完全支援 SystemVerilog 語言參考手冊（Language Reference Manual, LRM）裡介紹的所有語言結構，要改善測試平台的互操作性相當困難，但推進跨平台相容性的研究開發工作已在進行中。若干種驗證方法學相繼出現，以預定義類的形式對測試平台模組進行標準化，如今最新基於 SystemVerilog 的驗證方法學為通用驗證方法學。此方法學主要包括開放原始碼的類別館以及支援可重用測試平台、開發驗證矽智財的偏好設定格式。許多第三方提供商則開始推出基於 SystemVerilog 的驗證矽智財。

## 發展歷史

SystemVerilog 的歷史可以追溯到 2002 年，當時一個被稱為「Superlog」的語言被捐贈給 Accellera 公司（Verilog 的主要支持者）。而 Synopsys 公司捐贈的 OpenVera 後來發展成為 SystemVerilog 中硬體驗證語言子集。2005 年，SystemVerilog 獲批成為電氣電子工程師學會 1800-2005 標準。當時 Verilog 作為電氣電子工程師學會 1364-2005 標準尚獨立存在。2009 年，SystemVerilog 與的 Verilog 進行了合併，成為了新的電氣電子工程師學會 1800-2009 標準。現在的最新標準是電氣電子工程師學會 1800-2017 標準。

## 設計特性

對於電路設計工程師來說，SystemVerilog 中有大部分內容繼承自 Verilog，但是也提供了一些增強或者改進的特性。下面的章節主要講述 SystemVerilog 的這些特性。

### 新的資料類型

#### 邏輯型變數

SystemVerilog 定義了一種新的邏輯型（`logic`）變數。和 Verilog 中變數的聲明類似，以下代碼描述了一個 32 位元的邏輯型變數：

在傳統的 Verilog 中，變數主要分為線網型（`wire`）和暫存器型（`reg`）兩大類型。只有暫存器型變數才能夠在過程代碼塊中被賦值，而線網型變數只能在過程代碼塊之外被連續賦值。暫存器型變數的過程賦值和線網型變數的連續賦值使用了完全不同的語句結構。在 Verilog 中，二者的區分比較微妙，以至於有些專業的工程師也在設計中混淆二者。由於 `always` 過程代碼塊不僅可以描述序向邏輯電路，還可以通過將所有暫存器型的輸入變數添加到敏感列表來實現純組合邏輯電路，因此「暫存器型」這個帶有序向邏輯意義的術語本身也令人誤會。

SystemVerilog 增強了暫存器型變數的功能，它可以像 Verilog 中線網型變數一樣由線網（如邏輯閘等模組的輸出）驅動（這樣的線網驅動暫存器的方式在 Verilog 中是不允許的）。這種增強的變數類型被命名為「邏輯型」，從而避免「暫存器型」在字面上給人帶來的誤會。在大多數情況中，SystemVerilog 中的 `logic` 可以替代 Verilog 中的 `reg` 和 `wire`，但是如果某個某個變數具有多個驅動源，那麼就不能使用 `logic`，而要使用嚴格的 `wire` 來定義它。

#### 多維壓縮陣列

這種結構將 Verilog 中與暫存器、記憶體相關的概念進行了合併和擴充。

在 Verilog 中，變數名稱左邊的索引被用來表示二進位變數的位寬，Verilog 規定它只能是一維的。而這個陣列名稱右邊的索參照來表示以這種位寬變數組成陣列的元素個數，因為陣列可以是一維陣列、二維陣列或者多維陣列，因此這個索引可以是任意整數。在 SystemVerilog 中，如果在變數名稱左邊指定了由高至低的位寬（如 8 位元訊號由 `[7:0` 表示），則稱之為「壓縮陣列」（packed array，有時也被譯為「合併陣列」）。壓縮陣列本身可以是多維的，即變數名稱左邊可以具有多維索引。如果在變數名稱右邊指定了陣列尺寸，則稱之為「非壓縮陣列」。下面用範例代碼表示了一個由二維壓縮陣列構成的一維非壓縮陣列：

在上面的例子裡，非壓縮陣列陣列 `my_pack` 具有 32 個元素（這裡用到了類似 C 語言的陣列元素個數表示方法，這裡也可以寫成 Verilog 中常見的 `[31:0]` 形式）。這個非壓縮陣列每一個元素本身又是壓縮陣列，即 2 個位寬為 3 的邏輯型變數，因此非壓縮陣列的每一個元素包含六位二進位數的資訊。A variable of packed array type maps 1:1 onto an integer arithmetic quantity.

#### 列舉

SystemVerilog 引入了列舉型變數，它使用一系列有實際字面意義的名稱來代表若干變數。如果不進行專門的資料類型轉換，一個列舉型變數不能直接賦值給另一個列舉型的變數。過去在 Verilog 中描述有限狀態機常常使用參數（關鍵字為 `parameter`），而在 SystemVerilog 中，使用列舉則更為方便。

上面的例子使用了 typedef 來建立了一個新的資料類型名稱，從而可以用它來建立一系列列舉資料。列舉類型的資料類型，為位寬為 3 的邏輯型變數。3 位二進位數能夠逐一指代六種顏色。使用代碼 `color_t my_color = GREEN;` 建立了一個新的 `color_t` 型變數，其值初始化為六種顏色中的綠色。系統函式 `$display` 的作用與 Verilog 相同，其參數是 `my_color` 所屬函式 `name()` 的返回值，即當前列舉值的 ASCII 值。

#### 其他新增的資料類型

除了基本的邏輯型變數（`logic`），SystemVerilog 正還提供了位元組型變數（`byte`，8 位元）、短整型變數（`shortint`，16 位元）、整型變數（`int`，32 位元）和長整型變數（`longint`64 位元）、位元型變數（`bit`，1 位，僅具有兩個邏輯狀態，和邏輯型資料（`logic`）缺少了未知邏輯（`x`）和高阻態（`z`）。使用兩態邏輯可以提高邏輯仿真速度）。

#### 結構體和聯合體

這兩種資料類型和 C 語言中的結構體和聯合體類似。在 SystemVerilog 中，與這兩種資料類型相關的增強特性為壓縮屬性（`packed`）和標籤屬性（`tagged`）。壓縮屬性使得 mapped 1:1 onto a packed array of bits，而標籤屬性允許跟蹤當前聯合體中實際被使用的成員。這些結構占據了連續的儲存空間。

### 條件、選擇語句的唯一性和優先性

當條件、選擇語句的路徑分支較為複雜時，設計人員稍不留意就可能造成代碼所描述的行為違背設計人員預計的優先級別，或者被判斷的表達式同時滿足多個分支條件，從而在仿真過程中產生無規律結果。

為此，SystemVerilog 增強了條件、選擇語句的功能，允許設計人員為這分支流程的執行設定特別的約束。在多級條件、選擇語句中使用關鍵字 `unique`，可以限定有且只有一個分支可能被執行到，否則將產生一個警告。而關鍵字 `priority` 則指出某些分支路徑具有更高的優先級。過去，在傳統的 Verilog 中，要實現類似的功能，設計人員需要在可綜合代碼中附帶一些特殊的注釋（例如： `// synopsys full_case parallel_case`）來通知邏輯綜合工具產生正確的分支邏輯電路。不過，注釋並非 SystemVerilog 代碼的正式組成部分，它們只是在邏輯綜合過程被特定的工具讀取，而不嚴謹的注釋很可能造成綜合後電路與綜合前仿真結果不同的情況。

### 過程代碼

Verilog 中的過程代碼可以描述序向邏輯電路，也可以描述組合邏輯電路，這一點容易造成概念的混淆，如果代碼不嚴謹，邏輯綜合很可能推斷出閂鎖，從而產生不符合預期的硬體模型。SystemVerilog 除了繼續支援原來 Verilog 中的老式過程結構 `always`、`initial`，還在原有 `always` 基礎上針對組合邏輯電路、正反器、閂鎖設計了專用的 `always` 結構。雖然它們顯得不夠通用，但是三類硬體模型的差異得到了明確地區分，避免使用老式 `always` 時容易出現的閂鎖推斷：

* `always_comb`：用於組合邏輯電路（相當於 Verilog 中對所有輸入變數電平敏感的 `always`，但 `always_comb` 無需手動列出所有輸入變數，系統會自動辨識）；
* `always_ff`：用於正反器及相關的序向邏輯電路（相當於 Verilog 中對某個或某幾個訊號有效跳變沿敏感、並帶有訊號儲存特性的 `always`）；
* `always_latch`：用於閂鎖級相關的序向邏輯電路（相當於 Verilog 中對某個或某幾個訊號電平敏感、並帶有訊號儲存特性的的 `always`）。

三種專用的 `always` 結構在使用時會檢查設計代碼是否符合對應硬體模型的特徵。如果設計人員在過程代碼中描述了與對應硬體不符合的行為（例如在 `always_latch` 的敏感列表中添加了定時器訊號的上升沿），那麼系統會發出警告。這是 SystemVerilog 種專用型過程結構的優越之處。

下面的例子使用 `always_comb` 來描述組合邏輯電路。在 SystemVerilog 中無需像 Verilog 中描述組合邏輯電路那樣寫出敏感列表，`always_comb` 會告訴邏輯綜合工具這是一個組合邏輯電路，因此系統會預設對所有輸入訊號的電平敏感。在表示組合邏輯電路的過程代碼中，一般使用阻塞賦值。

邏輯綜合工具會將 `always_ff` 推斷為同步序向邏輯，這裡需要寫明對什麼訊號的什麼邊緣（上升或者下降）敏感。在表示序向邏輯電路的過程代碼中，一般使用非阻塞賦值。

邏輯綜合工具還會將 `always_latch` 推斷為電平敏感的閂鎖電路，對輸入訊號的電平敏感，但是具有訊號儲存特性：

## 介面

對於小型的設計，Verilog 設計人員可以使用埠（port）來簡潔地描述模組與外部環境的連接情況。不過，在規模較大、抽象層次較多的設計中，處於樞紐地位的模組往往具有大量連線與外界的連通。為此，SystemVerilog 引入了介面（interface）的概念，這個概念一方面減少了大量需要聲明的埠名稱，另一方面，它還方便設計人員將某些相關訊號的通道作為一捆相對獨立的線網組，這樣就使複雜的設計更加簡單、明晰。另一個概念是 modport，它顯示了邏輯連接的方向。例如：

## 驗證特性

隨著積體電路整合規模的不斷提高，電路的複雜程度也越來越大。在這種情況下，設計驗證在整個設計流程中所占用的時間越來越高。SystemVerilog 在 Verilog 基礎上增加了許多專門針對驗證的特性，使其成為一種傑出的硬體驗證語言。下面所提到的驗證代碼通常是不可綜合的，它們的作用主要體現在測試平台的搭建過程中。

### 新的資料類型

SystemVerilog 引入了專門的字串型變數，用關鍵字 `string` 表示，例如：

除了在設計中使用靜態陣列，SystemVerilog 還提供了動態陣列、關聯陣列（associative array）和佇列（queues）：

動態陣列的行為和非壓縮陣列相似，不過它允許仿真在執行時動態分配元素個數（正如上面例子所示）。壓縮陣列部分的元素個數（以往稱之為「位寬」）必須在編譯的時候已知（通過由常數或常數表達式直接確定），而非壓縮陣列的動態大小則可以在程式執行時，由另一個執行中的程式變數進行初始化，這樣就可以在執行中根據所需改變陣列的大小。

### 類

SystemVerilog 為驗證代碼的編寫提供了物件導向程式設計的模型。

SystemVerilog 支援類的單一繼承，即不允許一個類繼承多個基本類。需要注意的是，雖然 SystemVerilog 里提供了與 Java 中名稱相同的「介面」概念，但是二者的實際含義卻大有不同，後者的介面能夠提供類似多繼承的功能。SystemVerilog 的類可以內建組態參數，這種類被稱為參數化的類，其功能與 C++ 的模板類似，不過 SystemVerilog 不支援模板特化和函式模板。SystemVerilog 的多型性和 C++ 類似，在子類中被覆蓋的同名方法在基本類中必須使用關鍵字 `virtual` 予以標識。SystemVerilog 里也有諸如 `local`、`protected` 等關鍵字來管理資料、方法成員的可見性。預設情況下，所有方法、資料都是對外公有的。類的範例由建構函式 `new` 來建立，而解構函式則無需驗證人員手動建立。如果某個物件沒有被任何控制代碼指向，系統會自動銷毀它。SystemVerilog 的類是構建諸如通用驗證方法學類別館結構的基礎。

### 含約束的隨機化

可以對定義在類或者其他語句塊中的整數型變數進行隨機化，從而實現輸入激勵的隨機化，大大降低了驗證人員專門定義輸入激勵的複雜程度。這時使用 SystemVerilog 構建隨機驗證平台的重要技術基礎。在類資料變數聲明前使用 `rand` 和 `randc` 這兩個關鍵字，可以讓系統得知這些變數在隨後被隨機化。`randc` 產生的亂數序列可以保證變數被再次賦值為同一數值之前，所有可能數值已經被遍歷，而聲明為 `rand` 的變數則在隨機化過程中沒有這一特性。

在上面這一例子中，資料成員 `fcs` 未被聲明為隨機變數，而其他幾個資料成員則被聲明為隨機變數。在這個類中，緊隨變數聲明的是兩個對隨機化進行約束的語句塊，用關鍵字 `constraint` 予以標識。例如第一個名為 `basic` 的約束要求資料成員 `payload[]`（動態陣列）的大小在 46 和 1500 之間（包含這兩個邊界值）。如果沒有專門指定約束條件，則變數在可能的取值範圍內的隨機化不受任何約束。約束塊內代碼的寫法有若干種，驗證人員可以設定更加複雜的約束關係，例如變數取得區間甲內某一數值的權重為某一定值，或者採用多個數學關係式來限定變數的隨機化取值。當然，這樣做的前提是數學上能夠找到數值來同時滿足這些約束。SystemVerilog 的解析器會儘量產生符合條件的亂數值，但是如果沒能夠成功，則會返回資訊告知驗證人員此隨機化過程失敗。

#### 隨機化方法

每一個 SystemVerilog 類都有隱含的三個與隨機化有關的方法，它們是 `pre_randomize`、`randomize` 和 `post_randomize`。其中，`randomize` 方法為整個隨機化過程中最重要的方法，驗證人員可以在過程代碼中使用該方法來啟動變數的隨機化過程。注意該方法的主體是事務物件本身（在通用驗證方法學中，事務一般是一個具有 `uvm_sequence_item` 類型或從它繼承而來的類型），因此需要用 `object.randomize()` 來呼叫該方法，每執行一次該方法，該物件所有的隨機變數將會得到滿足約束條件（如果有）的亂數值。如果隨機化失敗，例如沒能找到滿足工程師定義約束的數值，則該方法將返回 0 表示隨機化存在問題。另外兩個方法 `pre_randomize` 和 `post_randomize` 則可以被用來處理隨機化主過程之前、之後其他需要的事情。

#### 控制約束條件

此外，SystemVerilog 還提供了 `constraint_mode()` 和 `random_mode()` 這兩個方法來在過程代碼中控制隨機化，前者用於臨時開啟或關閉一個約束，而後者則用於臨時開啟或關閉某個變數的隨機化。此外還有 `randomize () with {constraint}` 方法可以在該方法被呼叫時將花括號內的約束附加到原有的約束條件之上。

### 斷言

與其他屬性規約語言類似，SystemVerilog 具有斷言這一概念。在整個晶片驗證流程中，斷言檢查器會自動檢查定義的屬性是否得到滿足，如果違背，則會給出警告。SystemVerilog 斷言由序列（`sequences`）和屬性（`properties`）兩部分組成。屬性可以是多個序列在時間上的組合。序列主要用布林表達式和時序運算子來描述。

這一簡單序列的意思是，訊號 `gnt` 會在訊號 `req` 為高電平一個時鐘周期後也為高電平，如果這一情況沒有發生，則斷言失敗。SystemVerilog 還提供其他一些時序運算子，例如重複、連續運算子。這些運算子可以讓驗證人員定義更加複雜的變數關係。在上面這個例子中，加入訊號 `req` 為低電平，則這個斷言永遠都是失敗的。我們可以使用蘊含運算子 `|=>` 來表示我們所需的情況。

上面這個例子顯示了蘊含（implication）運算子 `|=>` 的使用。它左邊的子句稱為先行算子（antecedent）而右邊的子句稱為後續算子（consequent）。這時，如果 `req` 未滿足高電平的要求，則後面的 `gnt` 無論是高電平還是低電平，整個斷言都預設為成功；但是如果 `req` 為高電平，則系統會根據 `gnt` 的邏輯值來決定斷言是否成功。除此之外，SystemVerilog 還支援斷言覆蓋。

### 功能覆蓋

在硬體驗證中，功能覆蓋是指驗證過程中對人工定義訊號事件的資料取樣和收集過程。功能覆蓋率在某種程度上反映了被測設計在所給輸入激勵下，其內部功能正確與否被檢測到的百分比。功能覆蓋率越高，一般代表測試越完備。注意功能覆蓋率和代碼覆蓋率不同，後者只是測量被測設計的所有代碼有多少在仿真過程中被執行過。功能覆蓋的目的是確保設計中的所有邊界情況都能夠被經歷。

SystemVerilog 覆蓋組（coverage group）內可以定義若干個倉（bins）來儲存相關變數取值在其範圍內的次數。交叉覆蓋（Cross-coverage）則可以進一步取得多個變數分別在某一範圍內統計資料。通過使用覆蓋組的 `sample` 方法，可以啟動該覆蓋率的統計。

For example:

在這一例子中，驗證工程師重點關注廣播和單播影格的分布以及負載大小。

### 同步化

一個複雜的測試平台往往是包含多個可重用驗證模組的環境，這些模組之間需要互相通信。Verilog 的事件（`event`）允許不同語句塊之間相互觸發，不過這在複雜測試平台的執行緒間通信比較繁瑣。為此，SystemVerilog 提供了兩種新的語言要素，信箱（`mailbox`）和旗語（`semaphore`）。信箱類似一個參數化的 FIFO（意味著其內容的類型是可定義的），可以將符合其類型的物件「裝入」和「取出」信箱。而旗語則限定了對同一資源的存取個數。

## 其他與傳統 Verilog 類似概念的比較

除了前面提到的特性，SystemVerilog 還在以下方面對傳統的 Verilog 進行了增強：

* 過程設定運算子（包括阻塞和非阻塞）能夠直接對陣列進行操作
* 埠（輸入、輸出、雙向）可以支援更多的資料類型，包括結構體、列舉、實數等
* For 迴圈內部可以自動定義變數，並為它添加了 `continue` 和 `break` 功能
* 在原有的 `while` 迴圈基礎上添加了 `do-while` 迴圈
* 可以使用關鍵字 `const` 來聲明常數
* 可以對整個陣列進行初始化
* 預處理器的字串宏的功能得到增強
* 除了原有的並行過程語句塊 `fork/join` 結構，還提供 `join_none` 和 `join_any` 兩種代碼塊結尾方式
* 任務的埠能夠被聲明為參照類型（`ref`），這使得任務能夠直接取得任務參數自身（參照傳遞），而不是一個臨時複製的數值（值傳遞）。因此，對輸入方向的形式參數的操作會直接改變對應的實際參數。
* 函式能夠被聲明為空類型 `void`，即不返回任何數值
* 參數（`parameters`）可以被聲明為任何類型，包括使用者使用 `typedef` 定義的新類型
* 提供 SystemVerilog DPI（即 SystemVerilog 直接編程介面）來連接以 C 語言、C++ 編寫的模組

## 注釋

## 參考文獻

### 參照

### 來源

* Project VeriPage. Project VeriPage. 1997-06-06 [2012-07-12]. （原始內容存檔於 2012-06-09）.
* McGrath, Dylan. IEEE approves SystemVerilog, revision of Verilog. EE Times. 2005-11-09 [2007-01-31]. （原始內容存檔於 2007-09-29）.
* Kumar, Puneet. System Verilog Tutorial. 2005-11-09 [2012-07-12]. （原始內容存檔於 2011-09-14）.
* Krishna, Gopi. SystemVerilog ,SVA,SV DPI Tutorials. 2005-11-09 [2020-09-27]. （原始內容存檔於 2020-09-03）.
* HDVL. More SystemVerilog Weblinks. [2012-07-12]. （原始內容存檔於 2012-02-20）.
* Sutherland, Stuart, Davidmann, Simon, Flake, Peter. SystemVerilog for Design Second Edition: A Guide to Using SystemVerilog for Hardware Design and Modeling. New York City, NY: Springer. [2012-07-12]. ISBN0-387-33399-1. （原始內容存檔於 2021-07-10）.
* SystemVerilog Assertions Handbook, 2nd Edition - http://SystemVerilog.us（頁面存檔備份，存於網際網路檔案館）
* A Pragmatic Approach to VMM Adoption - http://SystemVerilog.us（頁面存檔備份，存於網際網路檔案館）

## 外部連結

### IEEE 標準文獻

* 1800-2009 IEEE Standard for System Verilog-Unified Hardware Design, Specification, and Verification Language
* SystemVerilog 3.1a Language Reference Manual（頁面存檔備份，存於網際網路檔案館） - 2004 draft version, which is before IEEE 1800-2005 standard.

### 教程

* SystemVerilog Tutorial（頁面存檔備份，存於網際網路檔案館）

### 標準開發

* IEEE P1800（頁面存檔備份，存於網際網路檔案館） – Working group for SystemVerilog
* Sites used before IEEE 1800-2005
  * SystemVerilog official website（頁面存檔備份，存於網際網路檔案館）
  * SystemVerilog Technical Committees（頁面存檔備份，存於網際網路檔案館）

### 語言延伸

* Verilog AUTOs （頁面存檔備份，存於網際網路檔案館） - An open-source meta-comment system to simplify maintaining Verilog code.

## 參見

* Verilog
* 硬體驗證語言