--- name: dv-format description: Generates TESTBED.sv and PATTERN.sv for SystemVerilog verification. TESTBED owns FSDB dump and gate-level SDF annotation; PATTERN owns sim-based stimulus, drive_reset, checks, and in-file SVA. Applies design-format to all generated files. Use when the user calls /dv-format, asks to generate a testbench, TESTBED, or PATTERN, or when rewriting dv-style TB skeletons. --- # dv-format 產生或修改 testbench 時先套用 **`design-format`**。本檔只規定 **TESTBED / PATTERN 分工** 與 TB 語意。 **不套用** `rtl-constraint`(TB 本來就不可合成)。 呼叫 `/dv-format` 時:掃描 RTL → 一次問完 → 寫出接好線的骨架。**不替使用者寫完驗證內容。** 不產生 `CHECKER.sv`。 --- ## 分工 | 檔案 | 負責 | 不負責 | |---|---|---| | **TESTBED.sv** | 宣告 DUT 連線、instantiate PATTERN + DUT、**FSDB dump**、**gate-sim SDF** | clock、reset、stimulus、scoreboard | | **PATTERN.sv** | **Sim-based simulation**:clock、`drive_reset`、stimulus、check、watchdog、main flow;**SVA 寫在 PATTERN 裡** | `$fsdbDump*`、`$sdf_annotate`、`ifdef GATE`、獨立 `CHECKER.sv` | 兩邊接到 TESTBED 同一組 signal。PATTERN port 相對 DUT **方向反轉**: - DUT `input` → PATTERN `output`(驅動) - DUT `output` → PATTERN `input`(觀測) - clock / reset 由 PATTERN 產生,PATTERN 宣告為 `output` --- ## TESTBED ### FSDB Dump ```systemverilog initial begin $fsdbDumpfile("TESTBED.fsdb"); $fsdbDumpvars(0, TESTBED, "+mda"); end ``` 指定 scope、unlimited depth、展開多維陣列。不用 `"+all"`。 ### Gate-sim `ifdef GATE` 與其他區塊同層;分支內容再縮一層。SDF 路徑 `../02_SYN/Netlist/.sdf`,目標 DUT instance **`u_dut`**。 ```systemverilog //============================================================= // Sim Mode & SDF Annotate //============================================================= `ifdef GATE initial begin $display("======================================"); $display(" [INFO] GATE-LEVEL SIMULATION START "); $display("======================================"); $sdf_annotate("../02_SYN/Netlist/.sdf", u_dut, , ,"maximum"); end `else initial begin $display("======================================"); $display(" [INFO] BEHAVIORAL SIMULATION START "); $display("======================================"); end `endif ``` --- ## PATTERN(Sim-based) 用 procedural stimulus + `$fatal` check。不產獨立 `CHECKER.sv`;協定 / 穩定度等並行性質寫在 **PATTERN 底部的 SVA**。 ### Clock `localparam` 放 PATTERN **module 內**(不要在 `.sv` 散寫 `` `define ``)。半週期用 **`/ 2.0`**。 ```systemverilog localparam CLK_PERIOD = 10; localparam TIMEOUT = 1000000; always #(CLK_PERIOD / 2.0) clk = ~clk; ``` 多時脈:每個 clock 一個 `_PERIOD`,各寫一行 `always`。 ### drive_reset 唯一 reset 寫法。名稱固定 **`drive_reset`**。順序與使用者規格相同: 1. 把 PATTERN 驅動的 DUT input 設成 idle(`'0` / `1'b0`;有語意的欄位用協定 idle 值) 2. reset 先放到 **inactive**(active-low → `1'b1`) 3. **`force`** 所有 clock = `1'b0` 4. `#20` → reset **assert** 5. `#20` → reset **deassert** 6. **`release`** 所有 clock 7. `@(negedge )` 不要寫 `rst_n = 0; repeat(N) @(posedge clk); rst_n = 1;`。 ```systemverilog task automatic drive_reset(); in_valid = 1'b0; in_data = '0; rst_n = 1'b1; force clk = 1'b0; #20 rst_n = 1'b0; #20 rst_n = 1'b1; release clk; @(negedge clk); endtask ``` 多時脈:每個 clock 都 `force` / `release`,最後 `@(negedge <第一個 clock>)`。 active-high reset:inactive=`1'b0`,assert=`1'b1`,deassert=`1'b0`。 ### Stimulus 一律負緣送(gate-safe) 對 DUT 的驅動與取樣都在 **`@(negedge clk)`**,不要 `@(posedge clk)` 送訊號。 PATTERN 是零延遲 driver,沒有 `tcq`。posedge 送 → 翻轉時間 = 取樣邊緣 → GATE `$setuphold` violation → `X`。負緣送留半個 cycle 裕度。 ```systemverilog task automatic mem_write(input [`ADDR_W-1:0] a, input [`DW-1:0] d); addr_w = a; data_i = d; en_w = 1'b1; @(negedge clk); endtask ``` ### SVA(寫在 PATTERN,不另開 CHECKER) 格式對齊 [AXI4 PATTERN.sv](https://github.com/akira2963753/Pipelined-RV32-SoC/blob/main/AXI4/00_TESTBED/PATTERN.sv)。**固定骨架,不准亂換行、亂補空白。** 固定 5 行(第 2 行沒有 `disable iff` 時仍佔一行 clocking): ``` LABEL: assert property( @(posedge clk) disable iff(!rst_n) ) else $fatal(1, "[ERROR]: "); ``` | 項目 | 規定 | |---|---| | 縮排 | label / `)` / `else` = **4 spaces**;clocking 與 property = **8 spaces** | | 括號 | `assert property(`、`disable iff(!rst_n)`、`$fatal(`、`$stable(` 皆**零空格** | | 運算子 | `&&` 與 implication 前後各一格;逗號後一格、逗號前無空格 | | `)` | **單獨一行**,與 label 同層,不黏在 property 後面 | | `else` | 緊接 `)` 下一行,中間**不准空行** | | 條與條 | 兩條 assertion **之間空一行**;一條內部不准空行、不准 trailing space | | 取樣 | 一律 `@(posedge clk)`;有 reset 時 clocking **同一行**寫 `disable iff(!rst_n)` | | 換行 | property **盡量一行**。只有 `$stable({...})` / concat 超過約 100 字才在 `,` 後斷行,續行列仍 8 spaces,**不對齊 `{`** | | 錯誤字串 | `$fatal(1, "[ERROR]: ...")`;`[ERROR]:` 後一格再接英文 | ```systemverilog //============================================================= // SystemVerilog Assertion //============================================================= // Property Name: assert property(condition) else S_AW_STABLE: assert property( @(posedge clk) disable iff(!rst_n) AW_VALID && !AW_READY |=> $stable({AW_ID, AW_ADDR, AW_LEN, AW_SIZE}) ) else $fatal(1, "[ERROR]: AW informations must be stable after AW_VALID high & AW_READY low."); S_W_STABLE: assert property( @(posedge clk) disable iff(!rst_n) W_VALID && !W_READY |=> $stable({W_DATA, W_STRB, W_LAST}) ) else $fatal(1, "[ERROR]: W informations must be stable after W_VALID high & W_READY low."); CHECK_RESET_VALID_LOW: assert property( @(posedge clk) !rst_n |-> (!AW_VALID && !W_VALID && !B_VALID && !AR_VALID && !R_VALID) ) else $fatal(1, "[ERROR]: VALID signal asserted during reset"); ``` 長 list 才准這樣斷(逗號後換行,續行不 padding): ```systemverilog AW_VALID && !AW_READY |=> $stable({AW_ID, AW_ADDR, AW_LEN, AW_SIZE, AW_BURST, AW_LOCK, AW_CACHE, AW_PROT, AW_QOS}) ``` **禁止:** `assert property (`、`disable iff (!rst_n)`、property 與 `)` 同一行、`else` 與 `)` 中間空行、為對齊而補空白。 產生器**不預填**具體 property,只留區塊與格式註解。 ### Phase 追蹤 ```systemverilog typedef enum int {PHASE1, PHASE2, DONE} phase_type; phase_type veri_phase; veri_phase = PHASE1; $display("Phase 1 Pass."); veri_phase = DONE; ``` --- ## 產生器(`/dv-format`) **先掃描、再問完、後執行。** Phase 2 開始後不再問。 ### 前置 告知使用者 Phase 2 會多次讀寫,建議 **Shift+Tab** 開 Auto-Accept。確認後才進 Phase 0。 ### Phase 0(只讀) 1. `RTL_DIR`:偵測 `01_RTL`;沒有 → Phase 1 問。 2. `TB_DIR`:偵測 `00_TESTBED`;沒有 → Phase 1 問。 3. Glob `/**/*.{sv,v}`,Grep `^package` 排除 package,其餘 `SCAN_DESIGN_FILES`。 4. 解析 top port:`name` / `dir` / `packed` / `signed` / `unpacked`(ANSI 與 non-ANSI)。 5. clock:名稱含 `clk` / `clock`。reset:含 `rst` / `reset`;`_n` 結尾 → active-low。 記錄:`RTL_DIR`、`TB_DIR`、`TOP`、`PORTS[]`、`CLK_PORTS[]`、`RST_PORT`、`RST_ACTIVE_LOW`。 ### Phase 1(只問需要問的) - **Q1** `TB_DIR` 不存在:建 `00_TESTBED` / 其他名稱 / 當前目錄。 - **Q2** 多個 design 檔:選 top。1 個直接用;0 個則中止。 - **Q3** clock 與 period(預設 `10`;多時脈各自 `_PERIOD`)。 - **Q4** reset 名稱與 active-low / high(reset task 一律 `drive_reset`)。 - **Q5** banner:`Author: Marco `;`Project` 目錄名或手填;`YEAR` 當年。 - **Q6** 覆蓋:全部覆蓋 / 逐檔問 / 全部跳過。 ### Phase 2(寫檔) `mkdir` `TB_DIR`(若需要)。Read `resource/*.tpl`,套 **`design-format`** 後 Write。 占位符:`{{YEAR}}` `{{AUTHOR_NAME}}` `{{PROJECT}}` `{{AUTHOR}}` `{{TOP}}` **TESTBED.sv** - `{{DUT_SIGNAL_DECLS}}`:`logic` 宣告,沿用 packed / signed / unpacked,不對齊。 - `{{PATTERN_PORTMAP}}` / `{{DUT_PORTMAP}}`:`.name(name)`,最後一個不加逗號;兩 instance 同一組 signal。 **PATTERN.sv** - `{{CLK_LOCALPARAMS}}`:每個 clock 一行 `localparam _PERIOD = ;`(放在 module 內;`TIMEOUT` 已在 template) - `{{PATTERN_PORTS}}`:方向反轉;clk/rst 為 `output` - `{{CLK_GEN}}`:`always #(_PERIOD / 2.0) = ~;` - `{{RESET_BODY}}`:依 Q4 填 `drive_reset` 本體(init DUT input → force clk → #20 拉 reset → #20 放 → release → negedge) - 只填骨架:clock、`drive_reset`、`end_task`、watchdog、main flow 外框、SVA 區塊標題與格式註解。不預產生 `send_data` / `check_out`,不預填具體 assertion ``` 已產生以下檔案: ✓ 00_TESTBED/TESTBED.sv (Top: , Clocks: ) ✓ 00_TESTBED/PATTERN.sv (Reset: , drive_reset) 下一步:在 PATTERN.sv 填 sim-based stimulus / check / main flow。 ```