轉譯輸出分析#
Veryl 不是直譯器,也不是綜合器——它是一個「轉譯到 SystemVerilog」的語言前端。veryl build 之後,veryl.toml 指定的輸出目錄裡會出現 .sv 檔案,那才是送進 Vivado、Vcs、Verilator 的東西。看懂轉譯輸出,是掌握 Veryl 的關鍵一步:你寫的是新語言,交付的是工業界通用的 SV。
if_reset 如何展開#
Veryl 的 always_ff (clk, rst) { if_reset { ... } else { ... } } 展開成 SV 的非同步/同步 reset 樣式,概念上對應:
always_ff @ (posedge clk or posedge rst) begin
if (rst) begin
in_vld <= 1'b0;
...
end else begin
if (bus_vld && bus_rdy) begin
in_vld <= 1'b1;
...
end
end
end
注意兩件事。第一,reset 型別(reset、reset_async_high、reset_async_low)決定展開時 sensitivity list 與極性,寫錯型別等於寫錯硬體,這是 Veryl 用型別系統取代口頭慣例的地方。第二,展開後的 SV 裡不會出現「忘記 reset」的暫存器——if_reset 在語法上強迫你宣告初始值,這正是 reset 遺漏這類經典 bug 在語言層面被消滅的例子。
let / var 的對應#
Veryl 的 let 是單一賦值:一個 let x: logic<32> = a * b; 轉成 SV 的 logic [31:0] x; assign x = a * b;(在 always_comb 內則是 blocking 賦值的臨時變數)。var 是可變訊號,可在多個 always 區塊驅動或在 always_ff 內更新,轉成對應的 reg/logic 宣告。這個區分讓「這是線還是狀態」在閱讀程式碼的第一眼就明確——SV 裡 logic 一個關鍵字身兼兩職的歷史包袱,在 Veryl 的語意層被拆開了。
位寬推導#
Veryl 會依運算元推導結果位寬:兩個 W 位數相乘得到 2W,相加得到 W+1,比較得到 1 位。轉譯出的 SV 裡可以看到明確的 [31:0] 這類範圍宣告。要驗證推導結果,最直接的方法就是打開 .sv 檔數位寬;veryl build 在位寬截斷發生時也會給出警告,提醒你顯式標註。
時脈分析概念:Fmax 與 critical path#
轉譯只是前端,決定設計能跑多快的是後端綜合。兩個基本量:
- Fmax(最高工作頻率): \(F_{max} = 1 / T_{clk,min}\) ,其中 \(T_{clk,min}\) 由暫存器到暫存器路徑的延遲決定,包含組合邏輯延遲、時脈歪斜、setup 時間。
- critical path(關鍵路徑):延遲最長的那條路徑。在我們的兩級流水線裡,stage1 的組合乘法器就是最可疑的關鍵路徑——16 位乘法在現代 FPGA 上約需一到兩個邏輯層,32 位就會明顯變長。
這正是流水線存在的理由:把長組合鏈切短,用暫存器分段,每一級變短,Fmax 就上升,代價是延遲(latency)增加與 bubble 造成的吞吐損失。如果 stage1 的乘法讓時脈收斂不了,工程師的下一步就是把乘法再切兩級,或改用管線化的乘法器 IP。
「零 overhead」如何驗證#
Veryl 宣稱轉譯不引入額外硬體。驗證方法很樸素:
- 手寫一段等價的 SV,與 Veryl 的輸出並排比對(diff 或看綜合後的電路圖)。
- 用同一個綜合腳本分別跑兩者,比較 LUT/FF 數與 Fmax——數字應該相同。
- 用
veryl doc或直接閱讀輸出,確認沒有多餘的中間層級、沒有自動插入的 mux 或暫存器。
這種「輸出即工業標準 SV、零隱藏成本」的路線,是 Veryl 與需要專用中間表示與專屬後端的語言(如 Chisel 的 FIRRTL)最根本的差異,我們在第 12 章會再回來比較。下一章,我們進入更大規模的實戰:AXI4-Lite。