Altifigence Academy

24 / 37 · 實作

實驗:會自行報告失敗的測試平台

分開 DUT、刺激、參考模型和判定,在無競爭的觀察時刻檢查 reset、enable 與迴繞。

分開實現和檢查器

測試平台提供刺激、計算期望並報告不匹配,是模擬程式碼而非合成電路。把參數課的 modulo_tick 存為 modulo_tick.sv,以下完整測試平台存為 tb.sv。契約是同步 reset 優先,禁用時保持 count 並清 pulse,有致能時模 N 增加,只在迴繞時 pulse=1。參考用整數 count,不讀 DUT 內部狀態。

SystemVerilog
`timescale 1ns/1ps
module tb #(parameter integer N = 5);
  localparam integer CW = (N <= 1) ? 1 : $clog2(N);
  logic clk = 1'b0;
  logic rst = 1'b0;
  logic enable = 1'b0;
  wire [CW-1:0] count;
  wire pulse;
  integer expected_count = 0;
  logic expected_pulse = 1'b0;
  integer checks = 0;
  modulo_tick #(.N(N)) dut (
    .clk(clk), .rst(rst), .enable(enable),
    .count(count), .pulse(pulse)
  );
  always #5 clk = ~clk;

  task automatic step(input logic reset_value, enable_value);
    begin
      @(negedge clk);
      rst = reset_value;
      enable = enable_value;
      if (reset_value) begin
        expected_count = 0;
        expected_pulse = 1'b0;
      end else begin
        expected_pulse = 1'b0;
        if (enable_value) begin
          expected_count = expected_count + 1;
          if (expected_count == N) begin
            expected_count = 0;
            expected_pulse = 1'b1;
          end
        end
      end
      @(posedge clk);
      #1;
      if (count !== CW'(expected_count) || pulse !== expected_pulse)
        $fatal(1, "Mismatch check=%0d count=%0d expected=%0d pulse=%b expected=%b",
          checks, count, expected_count, pulse, expected_pulse);
      checks = checks + 1;
    end
  endtask

  initial begin
    if (N < 1) $fatal(1, "N must be positive");
    step(1'b1, 1'b1);
    repeat (N-1) step(1'b0, 1'b1);
    step(1'b0, 1'b0);
    step(1'b0, 1'b1);
    step(1'b0, 1'b0);
    repeat (2*N+1) step(1'b0, 1'b1);
    step(1'b1, 1'b1);
    step(1'b0, 1'b0);
    $display("PASS N=%0d checks=%0d", N, checks);
    $finish;
  end
  initial begin
    #10000;
    $fatal(1, "Timeout");
  end
endmodule

避免有效時脈邊緣競爭

task 在下降緣驅動,比捕獲早半個時脈,在下一上升緣的非阻塞更新後比較。#1 是已宣告 timescale 與 10ns 時脈的教學觀察延遲,不是物理 clock-to-Q、setup 或 hold 分析。可重用生產驗證可採用 clocking block 或嚴格事件區域規則。首個 reset 讓 DUT 狀態已知;初始化參考不等於初始化 DUT。!== 會把意外 X/Z 與已知期望的比較報告為不匹配。

指定 top,編譯和執行

在安裝 Icarus Verilog 的 shell 中執行:

text
iverilog -g2012 -s tb -o sim.vvp modulo_tick.sv tb.sv
vvp sim.vvp

分別用 -P tb.N=1、-P tb.N=2、-P tb.N=5、-P tb.N=8 編譯配置矩陣。Icarus 官方命令列文件解釋語言模式和 top 選擇。不同模擬器支援範圍不同,應記錄實際版本。

讓檢查器故意失敗

修改終止比較,讓 DUT 提前一拍迴繞,或去掉預設 pulse 清除。至少一個場景必須在 timeout 前以非零狀態失敗,隨後恢復正確原始碼。無法檢測相關變異的 PASS 證據很弱。記錄原始碼雜湊、N、命令、退出狀態、PASS 和故意失敗的首個不匹配。不得把這個本地測試標為 DDS 執行;通用測試平台的 #delay/initial 與產品限制的單時脈實驗不同。

此選擇適用於本瀏覽器,隨時可從頁尾變更。