跳轉到

07.2 embed 嵌入機制#

任何一個新的 HDL 都會面對同一個靈魂拷問:三十年累積下來的 SystemVerilog IP、供應商巨集、驗證環境,你打算怎麼辦?全數重寫不現實,完全隔絕則失去生態。Veryl 的答案是 embed 機制——不隔絕 SystemVerilog 生態,而是與之共存。

為什麼需要 embed#

現實的專案裡,你一定會遇到這些狀況:

  • 供應商提供的 hard IP wrapper 是 SystemVerilog 或 Verilog,無法重寫。
  • 某些工具專屬的合成指令(synthesis attribute、ifdef 巨集)在 Veryl 語法中沒有對應物。
  • 驗證程式碼需要借用 Python(cocotb)的能力。

Veryl 的選擇是把這些「非 Veryl 的程式碼」用明確的語法標記出來,讓它們與 Veryl 原始碼並存於同一個檔案,並參與同樣的 build 流程。這與軟體界 Rust 的立場高度相似:Rust 沒有企圖取代 C 生態,而是提供 FFI 與 C 相容 ABI,讓新舊程式碼能共存遷移。

embed (inline):內嵌 SystemVerilog#

最基本的用法是 inline embed,把一段 SystemVerilog 原封不動放進輸出:

embed (inline) {{{
    module legacy_checker (
        input wire clk,
        input wire [7:0] data
    );
        // 既有 IP 的 wrapper 或供應商程式碼
    endmodule
}}}

{{{ ... }}} 三層大括號之間的內容會原樣出現在 Veryl 轉譯出的 SystemVerilog 檔案中。這適合:

  • 包裝既有的 Verilog IP,使其在同一個編譯單元內可被參考。
  • 放置工具專屬的 pragma 或 ifdef 片段。
  • 寫一些尚未有 Veryl 對應語法的罕見結構(過渡期的逃生門)。

embed (cocotb):內嵌 Python 測試#

第二種形式是 cocotb embed,用來撰寫測試:

embed (cocotb) sv {{{
    // cocotb 相關的測試描述
}}}

#[test(counter_test)]

在這個形式中,測試程式以 cocotb 的慣例撰寫——Python coroutine 觀察與驅動 DUT 訊號——並以 #[test(testname)] 屬性把測試名稱標記在 Veryl 模組上。veryl test 在執行時會收集這些屬性,將對應的模組當成 DUT,串接 cocotb 執行測試。這讓「模組與它的測試」在原始碼裡緊鄰出現,閱讀與維護都是同一個位置。

以下概念性示意一個 cocotb 測試的樣貌(實際串接細節依工具版本而定,參考官方文件):

import cocotb

@cocotb.test()
async def counter_test(dut):
    await cocotb.triggers.ReadOnly()
    assert dut.value.value == 0

coroutine 風格讓「等一個時脈邊緣」「等一個條件成立」讀起來像連續敘事,而不是 Verilog 時代用 event 與 fork/join 拼出來的難懂結構。這是 Python 驗證文化(第 07.4 章詳述)的核心吸引力。

$sv namespace:引用外部 SystemVerilog 識別字#

當 Veryl 程式碼需要引用外部 SystemVerilog 世界中的識別字(module、function、參數等)時,可以使用 $sv namespace:

inst u_ext: $sv::legacy_core;

$sv:: 前綴告訴編譯器:這個名字定義在 SystemVerilog 一側,請照原樣產生參考,不要嘗試在 Veryl 的符號表中查找。這是兩個世界之間的橋樑:Veryl 模組可以 instantiate 外部 IP,外部 IP 也透過 embed 進到同一個編譯單元。精確的語法細節隨版本演進,使用時請以官方文件的最新說明為準。

與既有 IP、巨集共存的務實策略#

把 embed 機制放進遷移策略裡,可以看到一條務實的路線:

  • 新寫的模組全部用 Veryl,享受型別與位寬檢查。
  • 既有 IP 原封不動,透過 embed (inline) 或外部檔案參與編譯。
  • 需要供應商巨集的地方,直接 embed 原始 SV 片段,不做無意義的轉譯。
  • 隨時間推移,把 embed 區塊一塊一塊換成真正的 Veryl 程式碼。

這個策略的成本曲線是漸進的:每一個 embed 區塊都是一筆明確的技術債,看得見、數得出、可分期償還。

小結#

embed 機制體現了 Veryl 的設計立場:它不是要把 SystemVerilog 關在門外,而是把自己放進 SystemVerilog 的生態裡,做一個更好的前端語言。inline embed 處理設計側的共存,cocotb embed 處理驗證側的整合,$sv namespace 處理符號層的引用。下一章我們來看這些機制背後的執行引擎——Verilator。