第一個專案#
工具裝好了、編輯器配好了、設定檔看懂了——現在動手寫第一個 Veryl 專案。我們從 veryl new 開始,寫一個 Counter module,看它如何被轉譯成 SystemVerilog。
建立專案#
$ veryl new first_proj
這會產生一個最小專案骨架:
first_proj/
├── Veryl.toml
└── src/
└── lib.veryl
結構與 cargo new 產出的專案如出一轍:根目錄一個 Veryl.toml(上章介紹過),原始碼集中在 src/。打開 Veryl.toml 確認 [project] name = "first_proj",然後進入專案目錄開始編輯。
寫一個 Counter#
把 src/lib.veryl 改寫成一個帶參數寬度的計數器:
module Counter #(
param WIDTH: u32 = 8,
) (
port clk : input clock,
port rst : input reset,
port o_count: output logic<WIDTH>,
) {
var count: logic<WIDTH>;
always_ff (clk, rst) {
if_reset {
count = 0;
} else {
count = count + 1;
}
}
assign o_count = count;
}
幾個語法點值得停留。第一,param WIDTH: u32 = 8 是 module 參數,帶型別與預設值——注意所有參數與 port 都有顯式的型別,而且 logic<WIDTH> 的寬度可以是參數:位寬進入型別系統,這是 Veryl 的招牌特徵。第二,clk 的型別是 clock、rst 是 reset,不是普通的 logic:時脈與重置在型別層面就被區分,把資料訊號誤接上時脈 port 是編譯錯誤。第三,var count 宣告可變的內部訊號(若用 let 則是單一賦值),第四,always_ff (clk, rst) 描述時序邏輯,敏感列表由所用的 clock/reset 型別決定展開方式;if_reset 是重置分支的抽象寫法,具體展開成同步或非同步、high active 或 low active,由 Veryl.toml 的 reset_type 全域決定——你在原始碼裡完全不必寫 posedge rst_n 這類細節。第五,組合驅動用 assign o_count = count;,與 SV 的語意相同但型別檢查更嚴格。
轉譯:veryl build#
$ veryl build
Veryl 會做型別檢查,然後把整個專案轉譯成 SystemVerilog,輸出放在 target/ 目錄下(對應 cargo 的 target 慣例),同時產生 filelist。用編輯器打開 target/ 裡對應 Counter 的 .sv 檔案,你會看到大致如下的 SystemVerilog(細節依 Veryl 版本與 Veryl.toml 設定略有差異):
module Counter #(
parameter WIDTH = 8
) (
input var logic clk,
input var logic rst,
output var logic [WIDTH-1:0] o_count
);
logic [WIDTH-1:0] count;
always_ff @(posedge clk, negedge rst) begin
if (!rst) begin
count <= 0;
end else begin
count <= count + 1;
end
end
assign o_count = count;
endmodule
請仔細端詳這份輸出,因為它是 Veryl 哲學的具體呈現:這是一份人類會寫、也願意 review 的 SystemVerilog。if_reset { count = 0; } 被展開成 if (!rst) 加上非同步重置的敏感列表——這是 Veryl.toml 裡 reset_type 的全域決定;如果設定改為同步重置,展開會變成時脈分支內的 if,原始碼一行都不用改。logic<WIDTH> 對應成 [WIDTH-1:0]。轉譯是一對一的,沒有暴肥的中間碼,從 SV 讀回 Veryl 的心智映射毫不費力。這就是「零額外成本的可讀轉譯」:你可以把 target/ 的輸出直接交給任何模擬器、綜合器或公司既有流程,也可以在 code review 時讓不熟 Veryl 的同事直接讀 SV。
文件註解與更多觀察#
再補一個細節:Veryl 的文件註解用 ///,寫在 module 或 item 之前:
/// 8-bit free-running counter.
module Counter #(
veryl doc 會把這些註解收進產生的 HTML 文件(rustdoc 模式),而轉譯出的 SV 裡也會保留對應的註解——文件不會在轉譯的過程中消失。至於 let/var 的對應:var 轉成一般的 logic 訊號宣告,let 的單一賦值語意則由編譯器檢查後照常輸出,差異在編譯期的保證而非輸出的形態。
驗證與下一步#
$ veryl check
veryl check 做靜態檢查而不產生輸出,適合放進編輯器的儲存後鉤子與 CI。寫測試、跑模擬用 veryl test(後續章節專述);更新格式用 veryl fmt。到此你已經跑完 Veryl 的最小迴路:new → 編輯 → build → 檢查輸出。下一步,我們把這個迴路升級成有測試的迴路。
本章小結#
veryl new first_proj產生 Veryl.toml + src/ 的最小專案,結構比照 cargo。- Counter 範例展示 param、clock/reset 型別、
var/always_ff/if_reset/assign的基本語法。 veryl build轉譯出人類可讀的 SystemVerilog 到target/,if_reset 依 Veryl.toml 的 reset_type 全域展開。///文件註解會進入veryl doc輸出並保留在 SV 中。- 轉譯輸出可直接進任何 SystemVerilog 工具鏈——相容性零成本。