1.2 SystemVerilog的黃金年代與UVM的代價(2005-2017)#
一場三合一的合併#
2005 年 6 月,IEEE 發布 IEEE 1800-2005。這份標準的核心動作只有一句話:把三種東西合成一種語言。
- Verilog-2001(IEEE 1364-2001)——成熟、被產業完全接受的硬體描述基礎。
- C++ 語言的核心機制——類別、封裝(encapsulation)、繼承、多型、泛型、異常處理、隨機化與約束求解。
- PSL / OpenVera 的硬體斷言語言(e 語言)與 DPI——專為硬體設計的時間語意與形式化性質表達。
這三者的來源與動機各自獨立,卻在同一時間點被合併,因為它們共同回答了同一個問題:硬體設計已經變得比 Verilog 能表達的更複雜。
Accellera:從志願者組織到標準推手#
推動這場合併的是 Accellera。它於 1995 年成立,最初名為 Open Verilog International(OVI),任務是推廣 Verilog-2001 之前的一些擴充;後來改名 Accellera,轉型為推動 SystemVerilog 的中立組織。
Accellera 的重要性在於它代表了硬體語言標準化的新形態:由使用者聯盟先行、以實務程式碼為基礎、成熟後再交給 IEEE 認證。這與 Verilog 的路徑恰好相反(Verilog 是廠商先定,IEEE 後追認)。
2003 到 2005 年間,SystemVerilog 經歷了一次戲劇性的插曲:原本計畫在 2003 年發布的「Verilog-2005」被合併進 SystemVerilog,導致「Verilog 2005」這個版本編號從未存在。這是因為 IEEE 認為把 Verilog 的擴充與 SystemVerilog 的擴充分成兩份標準,會造成工具支援的分裂與使用者混淆。於是 1364 的版本停在 2001,而 1800 承擔了 Verilog 的所有內容加上新特性。
這個插曲有一個長遠影響:從 2005 年起,Verilog 與 SystemVerilog 之間就不再有「版本對應」了。今天的工具在選項上寫「Verilog-2001 / SystemVerilog」,而 SystemVerilog 是唯一的完整語言。
規格頁數:第一個訊號#
IEEE 1800-2005 的語言規格約 1100 頁;後續版本一路增長:1800-2009 約 1300 頁、1800-2012 約 1500 頁、1800-2017 約 1800 頁,加上相關的 IEEE 1800.2(UPF)、1800.2a 等,低功耗與多電壓的補充文件另外再加數百頁。
我們在第 0 章說過,頁數本身不是罪惡——C++ 的規格至今也超過一千頁,而 C++ 是一門成功的語言。但硬體語言的頁數有一個 C++ 沒有的對照組:Verilog 的規格只有約 400 頁,而 Verilog 支撐了整個半導體產業二十年。從 400 到 1800,功能增加了四倍多,同時整個產業的專案規模也增加了十倍。兩條曲線的乘積,就是工程師的負擔。
SystemVerilog 的核心新增#
一、類別與封裝:把資料與行為綁在一起#
Verilog 的世界觀是資料流與結構分離的:資料放在 wire / reg 裡,行為放在 always / module 裡,兩者靠「名字」連結。
SystemVerilog 引進了類別:
class Packet;
rand bit [7:0] addr;
rand bit [31:0] data;
int unsigned id;
function new(int unsigned id);
this.id = id;
endfunction
function bit is_valid();
return (addr inside {[0:255]});
endfunction
endclass
語法上是 C++,但設計意圖完全不同。Verilog 的 reg 只是「可被程序性賦值的變數」;SystemVerilog 的類別把屬性、行為、隨機性、約束綁成一個具有生命週期的物件。
為什麼硬體需要這件事?兩個原因:
- 驗證環境。UVM 的整個架構建立在類別之上——transaction、sequence、driver、monitor、scoreboard 全是類別。這是語言支援的最大受惠者。
- 參數化硬體建構。SystemVerilog 的類別也能用在硬體建模上(例如用類別寫一個可參數化的 AXI 介面模型)。
但這也是一把雙刃劍:一旦語言有了類別與多型,就有了繼承階層的深度、建構與析構的順序、句柄與物件的區別、虛函式派發。這些概念對硬體工程師(通常沒有 C++ 背景)來說是全新的負擔,而它們最終全都會出現在 Verilog→SystemVerilog 的遷移道路上。
二、介面與 modport:SystemVerilog 最重要的進步#
如果只能挑一項 SystemVerilog 的功能來說明它為什麼成功,那就是 interface。
問題:Verilog 的「一束訊號」#
用 Verilog 描述一個 SPI 從機介面:
module SpiSlave (
input wire clk,
input wire rst_n,
input wire cs_n,
input wire sclk,
input wire mosi,
output reg miso,
output wire [7:0] rx_data
);
每個模組都要重新宣告這五個訊號。若這是一個被 20 個模組共用的匯流排,就有 20 份重複宣告,改一個訊號名要改 20 個地方,而且沒有任何機制保證它們一致。
解法:介面把「一束訊號」變成「一個有型別的物件」#
interface spi_if #(parameter int WIDTH = 8) (input logic clk, input logic rst_n);
logic cs_n;
logic sclk;
logic mosi;
logic miso;
logic [WIDTH-1:0] rx_data;
// 從機觀點:cs_n, sclk, mosi 是輸入;miso, rx_data 是輸出
modport slave (
input clk, rst_n, cs_n, sclk, mosi,
output miso, rx_data
);
// 主機觀點:反向
modport master (
input clk, rst_n, miso, rx_data,
output cs_n, sclk, mosi
);
endinterface
用起來:
module SpiSlave (spi_if.slave bus) (
input logic clk,
input logic rst_n
);
// bus.cs_n, bus.sclk ... 直接可用
endmodule
module SpiMaster (spi_if.master bus) (
input logic clk,
input logic rst_n
);
endmodule
module Top (input logic clk, input logic rst_n);
spi_if #(8) bus (clk, rst_n);
SpiMaster u_master (.bus(bus));
SpiSlave u_slave (.bus(bus));
endmodule
interface 帶來的四個立即收益:
- 單一真相來源。訊號宣告只寫一次。
- 埠方向約束(modport)。
spi_if.slave這個型別宣告了「從這個角度只能看到這些方向」,編譯器可以檢查方向錯誤。 - 參數化。同一個
spi_if可以參數化成 8/16/32 位元。 - 連接語義清楚。
.bus(bus)是「把這個介面物件接上去」,不再是「手接 5 根線」。
這是模組間契約在硬體語言中第一次有了語言級的支持,直接解決了我們在第 1.1 節列出的 Verilog 缺陷三。
副作用:新的複雜度來源#
介面並非只有好處。它帶來了 Verilog 時代不存在的問題。
問題一:驅動衝突(driver conflict)與 tri 邏輯。
在 Verilog 中,wire 是單一驅動者(single-driver)語義:兩個 assign 驅動同一個 wire 是錯誤。當訊號被包進介面後,同一個介面訊號可能需要被多個模組驅動(例如多個 master 共用一條匯流排的仲裁邏輯),於是必須引入解析邏輯。
SystemVerilog 定義了四種邏輯值型別:
| 型別 | 驅動語意 |
|---|---|
logic | 單一驅動者(Verilog 的 wire 近似) |
tri | 多驅動者,強度解析(0 與 1 相遇得 x) |
wand / wor | 連線(wired-AND / wired-OR)解析 |
tri0 / tri1 | 預設值為 0 / 1 的多驅動者 |
Verilog 裡 wire 其實就是 tri 的別名,Verilog 的 wand/wor 也存在,但多數工程師從沒用過它們。SystemVerilog 把多驅動從罕見邊角提升為日常概念,代價是「這個訊號現在是誰在驅動、解析規則是什麼」變成每個設計者都要思考的問題。
問題二:介面與模組埠的組合爆炸。
一個模組可能接 5 個不同的介面,每個介面有 20 個訊號,modport 又有 3 種視角。型別參數與介面參數交錯之後,工具產生的錯誤訊息經常長得像這樣:
Error: Cannot bind port '.data' of type 'logic [31:0]' to
expression of type 'logic [15:0]' in instance 'u_bridge'.
其中一半的型別來自介面參數的推斷。使用者要靠心裡「展開」介面的參數才能理解。
問題三:always_comb 與介面訊號的敏感度計算。
always_comb 的敏感度清單由工具自動推導,包含「讀取到的所有訊號」。若讀到的是介面訊號,工具需要跨介面邊界做依賴分析。在大型設計中這不僅是正確性問題,也是效能問題。
三、泛型與參數化#
SystemVerilog 提供三種彼此獨立的參數化機制:
(一)模組參數的型別化
module fifo #(
parameter type DATA_T = logic [31:0],
parameter int DEPTH = 16
) (
input logic clk,
input logic rst_n,
input logic push,
input DATA_T din,
output logic full,
output logic empty,
output DATA_T dout
);
parameter type 讓參數不只是一個數字,而是可以是一個型別。這是 Verilog 的 parameter(只能傳整數或字串常數)的根本性擴充。
(二)類別的泛型參數
class stack #(type T = int);
local stack #(T) m_items [$];
...
endclass
但要注意:類別參數在編譯時是「靜態」的。stack #(int) 與 stack #(string) 是兩個完全不同的編譯期型別,各有自己的 vtable 佈局。當你有多種資料型別時,類別數量會呈現乘法膨脹。
(三)動態資料結構
| 結構 | 語法 | 用途 |
|---|---|---|
| 動態陣列 | bit [7:0] q[$]; q.push_back(x); | 驗證環境的佇列 |
| 關聯陣列 | int map[string]; map["a"] = 1; | 以任意鍵值索引 |
| 佇列 | q.push_front(x); q.pop_front(); | 雙端操作 |
| 開列陣列 | int q[$];([] 索引) | 稀疏陣列 |
關鍵限制:這些結構不能被硬體綜合。 它們是純驗證語言。這個界線在 SystemVerilog 中是明確的(硬體語法與驗證語法分離),但它的直接後果是:SystemVerilog 中有兩套並存的世界觀,語法交集很小,而工具必須同時支援兩套。 這是「工具子集」危機(第 1.3 節)的根源之一。
四、斷言與涵蓋:從「驗證」到「形式化」#
SystemVerilog 斷言(SystemVerilog Assertions, SVA)是這門語言裡最有深遠影響、也最被低估的部分。
為什麼需要 SVA#
傳統的驗證方式是「寫 testbench、跑模擬、看結果」。它有兩個致命缺陷:
- 覆蓋率無法窮舉。一個 \(n\) 輸入的設計有 \(2^n\) 種可能輸入組合,
for迴圈跑不完。 - 錯誤的發現是隨機的。你不能證明「沒有 bug」,只能證明「跑過的測試沒有抓到 bug」。
SVA 讓工程師可以用宣告式的方式寫出「這個性質必須永遠成立」,然後交給形式驗證工具用數學方法證明它。JasperGold、Questa Formal VC、Conformal 等工具因此在 2005 年之後迅速成長,成為 ASIC 流程的標準環節。
SVA 的時間語意#
SVA 的核心是「並行蕴含」——描述「在某個時間點發生的事件,會強制在另一個時間點發生什麼」。
| 運算子 | 名稱 | 語意 |
|---|---|---|
\|-> | 重疊蕴含(overlapped implication) | 若antecedent 在時間 \(t\) 成立,consequent 必須在同一時間槽的下一個 sampling 成立(即時間 \(t\) 結束前) |
\|=> | 非重疊蕴含(non-overlapped implication) | 若 antecedent 在時間 \(t\) 成立,consequent 必須在**下一個 sampling 時間 \(t + 1\) ** 成立 |
##n | 延遲 | 往後 \(n\) 個 sampling 事件 |
##[a:b] | 延遲範圍 | 往後 \(a\) 到 \(b\) 個 sampling 事件之間任一者 |
[*n] | 連續重複 | 連續 \(n\) 個時間槽 |
throughout | 貫穿 | 性質在整個區間持續成立 |
until / s_until | 直到 | 某性質在某區間內首次成立 |
##0 | 零延遲 | 同一時間槽(與 \|-> 組合用) |
\$rose / \$fell / \$stable | 邊緣偵測 | 訊號剛剛上升 / 下降 / 保持穩定 |
一個典型的握手正確性斷言:
// 要求:任何一次 request 之後,必須在 3 個週期內看到 ack
property p_req_ack;
@(posedge clk) disable iff (rst_n)
(req |-> ##[1:3] ack);
endproperty
assert property (p_req_ack) else $error("req 未被 ack");
一個典型的匯流排協定斷言:
// 要求:寫入位址必須對齊到 4 bytes
property p_addr_align;
@(posedge clk) disable iff (!rst_n)
(wr_en |-> (addr[1:0] == 2'b00));
endproperty
SVA 的代價#
SVA 是 expressive 的,但它的學習曲線極陡:
- 時間語意需要時間建模。property 的 sampling event、disable iff、以及多個 property 間的互動,形成一套獨立的時間邏輯系統。
- 語法密度高。
|-> ##[1:3]這種寫法對不熟悉 temporallogic 的工程師幾乎不可讀。 - 模擬與形式驗證的語意不完全一致。同一條 SVA 在模擬器裡是「抽樣檢查」,在形式驗證工具裡是「數學證明」;兩者的邊界情況處理可能不同(例如在
disable iff的競態時刻)。 - 工具支援分歧嚴重。不同工具支援的 SVA 子集、支援的 temporal operator 集合、支援的 sequencer 種類都不同。
五、DPI:連接 C 語言#
DPI(Direct Programming Interface)提供了一條從 SystemVerilog 呼叫 C 函數的路徑,語意上比 Verilog 的 PLI 簡單得多。
import "DPI-C" function int unsigned crc32(
input byte unsigned data[],
input int unsigned length
);
function int unsigned compute_crc(input bit [31:0] w);
byte unsigned buf[4];
buf[0] = w[7:0];
buf[1] = w[15:8];
buf[2] = w[23:16];
buf[3] = w[31:24];
return crc32(buf, 4);
endfunction
DPI 的價值在於:C 語言有所有硬體語言都缺的東西——成熟的演算法函式庫、成熟的物件導向、成熟的 OS 與檔案系統存取。在「硬體加速驗證」或「硬體加速演算法」這類場景(例如 crypto IP 的參考模型、或把軟體模型接進硬體做 co-simulation),DPI 是不可或缺的。
DPI 也解決了 Verilog-AMS 混模(AMS 與 Verilog 混在同一個模擬器裡)的痛點——C 模型相容性好得多。
六、隨機化與約束求解#
這是 SystemVerilog 對硬體驗證影響最深的一項功能。
class AxiReq;
rand bit [7:0] addr;
rand bit [31:0] data;
rand bit [3:0] burst_len;
rand bit [1:0] burst_size;
constraint c_addr_align {
addr[1:0] == 0;
}
constraint c_burst_size {
burst_size inside {[1:4]};
}
constraint c_len_size {
(burst_len * (1 << burst_size)) <= 256;
}
endclass
隨機化 + 約束求解把驗證從「窮舉」轉向「有方向的搜尋」。這是整個硬體驗證產業在 2005-2017 年間最大的進步來源。
排程(scheduling):當一個物件有隨機欄位之間存在相依時(例如 addr 依賴某個全域狀態),SystemVerilog 提供 solve ... before ... 排程指示,讓求解器決定求值順序。
隨機化的代價:約束求解器是一個複雜的軟體元件,求解時間隨約束數量呈指數成長。大型SoC 的隨機測試中,「隨機」意味著「每次跑的刺激序列都不同」,這使得重現 bug 變得困難——需要額外的 seed 管理機制。
UVM:驗證方法學的巔峰與代價#
為什麼需要 UVM#
2005 年之後,SystemVerilog 提供類別,但類別只是語言機制,不構成方法學。每家公司要自己決定:交易物件怎麼定義?激勵怎麼產生?觀測點在哪裡?預期值怎麼算?怎麼比對?
2007 年推出的 UVM(Universal Verification Methodology) 把這些問題的答案標準化。它的架構分層如下:
flowchart TD
T[uvm_test 測試] --> E[uvm_env 環境]
E --> A1[uvm_agent A]
E --> A2[uvm_agent B]
E --> S[uvm_scoreboard 記分板]
A1 --> DRV[uvm_driver 驅動器]
A1 --> MON[uvm_monitor 監視器]
A2 --> DRV2[uvm_driver]
A2 --> MON2[uvm_monitor]
DRV --> SEQ[uvm_sequence 序列]
DRV --> TLM[TLM 連線埠]
MON --> TLM
S --> TLM
TLM --> CFG[uvm_config_db 設定]
FAC[uvm_factory 工廠] --> T
FAC --> A1
FAC --> A2- transaction:代表一次匯流排交易的物件,攜帶欄位與限制。
- sequence:產生 transaction 的序列物件,含隨機與約束。
- driver:把 transaction 轉成匯流排上的訊號活動。
- monitor:被動觀察匯流排,把活動轉回 transaction。
- agent:把 driver + monitor 組成一個可重用的驗證元件。
- scoreboard:收集預期值與實際值並比對。
- environment:把 agent 與 scoreboard 組成一個 DUT 的驗證環境。
- factory:動態建立物件、支援覆寫。
uvm_config_db:以「路徑字串」為鍵的設定傳遞機制。
UVM 的代價#
UVM 是硬體驗證史上最大的軟體框架。它帶來的成功是顯著的:它讓驗證環境可重用、讓新人能透過標準框架學習驗證、讓跨專案的驗證資產可以累積。
但它的代價同樣顯著:
第一,類別階層深到令人眩暈。
一個驅動一個 AXI4 從機的 uvm_driver 衍生鏈可能是:
uvm_component
└─ uvm_driver
└─ axi_slave_driver
└─ my_project_axi_slave_driver (專案特定)
而一個 scoreboard 常常需要 uvm_scoreboard → uvm_subscriber → 自訂類別。三到四層的繼承加上 uvm_object / uvm_component 兩套基底類別的語意差異(前者有 reference semantics,後者有 phase 與 hierarchy),使得繼承的「坑」深到看不見底。
第二,一個測試的啟動成本極高。
要跑一個基本測試,UVM 需要:建立 uvm_test → 建立 uvm_env → 建立所有 agent → 建立所有 driver 與 monitor → 建立 scoreboard → 建立 uvm_phase 調度器 → 解析 phase 依賴 → 依序跑 build、connect、end_of_elaboration、start_of_simulation、run 等 phase。
啟動一個測試要建構數百甚至數千個物件,而這只是為了「跑一個簡單的讀寫」。對一個只需要跑 100 個測試向量的小 IP 來說,UVM 的啟動開銷可能比測試本身還大。
第三,scoreboard 的程式碼量常常超過 DUT。
一個中等的 AXI4 從機驗證環境,scoreboard 常見的寫法是手寫一堆 virtual sequence 與「把收到的資料存起來、比較時取出來」的邏輯。這些程式碼:
- 冗長且高度重複;
- 與 DUT 的 RTL 幾乎無關;
- 卻是專案裡最常出 bug 的地方(記分板本身的 bug 會產生「假失敗」,浪費大量除錯時間);
- 難以覆蓋邊界情況。
第四,UVM 把硬體專案變成了軟體專案。
這是最深層的代價。一個典型的 UVM 專案需要:
- 軟體工程師級的物件導向訓練;
- 建置系統(CMake / Makefile / Python)與相依性管理;
- 程式碼風格規範、靜態分析、單元測試;
- 開發者要能除錯一個多層繼承的物件圖。
用軟體語言的能力解決硬體驗證問題是一次典型的成功,因為隨機化與約束確實大幅提升了驗證效率。但把硬體專案變成軟體專案是一次典型的失敗,因為工具鏈複雜度、建置複雜度與人才需求都超過了硬體專案應有的比例。
第五,效能。
UVM 的物件建構與 phase 調度是純軟體開銷。在一個以數百萬個事件為單位的模擬中,UVM 的 monitor/scoreboard 每處理一個 transaction 都要做多次虛函式派發與物件操作。實際專案中,驗證環境的執行時間往往是 DUT 的 10 到 100 倍,而 DUT 本身可能只佔模擬時間的一小部分。
模擬器效能的隱形戰爭#
SystemVerilog 時代的隱形戰爭,不在語言,而在模擬速度。
事件式模擬的天花板#
Verilog/SystemVerilog 的事件式模擬是一種樂觀執行:只有在訊號值改變時才做工作。這個模型對「大部分時間靜止」的電路非常有效,但對現代 SoC 越來越不適用:
- 現代 CPU 的 pipeline 有數千個 in-flight 指令,每個 clock 都有大量狀態改變;
- 快取與記憶體子系統的行為高度非線性;
- 多核系統中數百個核同時活動;
- 開機(boot)序列牽涉到韌體的大量指令執行。
量級的體感:一個跑了 Linux 7.1 的完整開機流程模擬,可能需要數小時的模擬時間與數天的掛機時間。而一個 SoC 專案的完整回歸(regression)通常包含數千個測試。
cycle-based 模擬器的崛起#
正因為如此,Verilator(2011 年起)這類 cycle-based 模擬器(也稱 compiled simulator)崛起。Verilator 的做法是:
- 把 RTL 轉譯成 C++ 或 SystemC;
- 每次 clock 邊緣,整批評估所有邏輯;
- 不維護事件佇列。
代價是只能支援硬體可綜合的子集(沒有延遲 #、沒有競態、沒有 initial 區塊的即時語意、沒有完整四態)。收穫是模擬速度快一到兩個數量級,而且可以直接產出 C++ 測試平台(Google famously 用 Verilator 產生 verilated model 給 C++ 測試使用)。
Verilator 的成功不只是效能問題,更是「語言子集才是真實需求」這個事實的公開證明:整個產業的開發者最終選擇在一個子集裡工作。
額外負擔#
SystemVerilog 的模擬負擔還包括:
- 程式碼覆蓋收集。要達到 sign-off 要求的覆蓋率(line / branch / toggle / FSM state / functional coverage),工具需要插樁並在每個事件上更新計數器。這本身可能讓模擬變慢 1.5 到 3 倍。
- 交易紀錄(transaction logging)。把每個 transaction 寫成文字或二進位紀錄,供除錯與後分析使用。一個完整回歸可能產生 TB 級的紀錄檔案。
- DPI 呼叫的跨越邊界成本。每次 DPI 呼叫都有序列化與型別轉換開銷,若在回圈裡密集呼叫,會嚴重拖慢模擬。
- 隨機測試的不可預測執行時間。隨機測試的執行長度由 seed 決定,同一個測試在不同種子下可能快 10 倍或慢 10 倍,讓 CI 的時間估算變得困難。
文化層面的轉變#
技術變遷最終一定會反映在人才結構上。
2005 年之前,一位硬體工程師的典型技能組合是:數位電路、Verilog、合成與時序的直覺、可能的 C。2005 年之後,期望的技能組合變成:Verilog/SystemVerilog 之外,還要有物件導向、Python(驗證腳本)、可能的 C++(UVM 加速或 DPI)、建置系統、除錯大型物件圖的能力。
這造成三個後果:
- 學習曲線成為專案瓶頸。一個原本 3 個月可以上手 Verilog 的團隊,改用 SystemVerilog + UVM 後需要 12 到 18 個月才有生產力。
- 人才分層加劇。RTL 工程師與驗證工程師的技能分化越來越大,兩者的薪資差距與溝通成本都上升。
- 「會寫 RTL」不再是選拔指標。越來越多面試在問「你如何做驗證環境架構」。
同時,SystemVerilog 的廣泛採用也帶來了正面效果:它把硬體設計的工程標準拉高到與軟體相當的層次。版本控制、程式碼審查、靜態分析、持續整合、程式碼覆蓋率——這些軟體工程文化確實隨著 SystemVerilog 一起進入了硬體產業。這一點不應該被低估:它是 SystemVerilog 黃金年代最重要的正面遺產。
收束:SystemVerilog 解決了什麼,又製造了什麼#
我們把 1.1 節提出的 Verilog 四缺陷與 SystemVerilog 的對策並排:
| Verilog 的四缺陷 | SystemVerilog 的解方 | 引入的新代價 |
|---|---|---|
| 語法糖掩蓋語意 | always_comb / always_ff / always_latch 意圖標記 | 三者語意相近但不完全一致,語意負擔只是被重新分配 |
| 無嚴謹型別系統 | logic、enum、struct、二維陣列、parameter type | 硬體子集與驗證子集並存,型別推斷規則更複雜 |
| 無模組間契約 | interface 與 modport | 多驅動與 tri 解析規則成為新的日常概念 |
| 語意負擔落在設計者 | 斷言、隨機化、約束求解、UVM 方法學 | 語言規模膨脹、學習曲線、工具分歧 |
SystemVerilog 解決了 Verilog 的四個缺陷,但也製造了四個自己的缺陷:
- 語言規模膨脹:規格從 400 頁變成 1800 頁,超過多數工程師終生能精讀的量。
- 工具子集分化:沒有一家 EDA 工具支援完整的 SystemVerilog,於是工程師實際工作在「工具的交集」裡。
- 語意不可預測:類別、巨集、繼承、
x傳播、always家族的細微差別、多驅動解析,全部疊加在 Verilog 原有的隱藏規則之上。 - 驗證方法學的複雜度外溢:UVM 把驗證從「寫幾個 testbench」變成「寫一個框架」,框架本身的維護與除錯成為專案負擔。
這四個缺陷並不是 SystemVerilog 的設計者「沒想到」——他們想到了,而且標準裡有大量針對它們的規範。問題在於結構性的:只要語言要同時滿足「描述硬體」與「描述驗證環境」兩種本質迥異的需求,它的複雜度就會以乘積而不是加法的速度成長。
下一節(1.3)將把 2017 年之後這三場危機攤開:工具子集、語意不可預測、以及替代語言的挑戰。同時我們也會看到 Veryl 如何在 2022 年把這些危機收斂成一組設計目標。
下一節:第 1.3 節「複雜度危機:工具子集、語意不可預測與替代語言的挑戰(2017-2026)」