Altifigence Academy

24 / 37 · 実習

実習:自分で失敗を報告するテストベンチ

DUT・刺激・参照モデル・判定を分け、reset・enable・wrapを競合のない時点で検査します。

実装と検査器を分けます

テストベンチは刺激を供給し、期待動作を計算して不一致を報告するシミュレーションコードです。合成対象ではありません。パラメータの授業のmodulo_tickをmodulo_tick.sv、次の完全なコードをtb.svとして保存します。同期resetが優先し、無効エッジではcount保持・pulse解除、有効エッジではmodulo N増加・wrap時だけpulse=1です。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は立下りエッジで入力を設定し、次の立上りエッジのnonblocking更新後に比較します。#1はtimescaleと10nsクロックを指定した教材用観測遅延で、物理的clock-to-Q・setup・hold解析ではありません。再利用環境ではclocking blockなどイベント領域の規律も使えます。最初のresetがDUTを既知にします。参照値初期化はDUT初期化ではありません。!==は既知の期待値に対するX/Zを不一致として検出します。

topを明示してコンパイル・実行します

Icarus Verilogを導入したシェルで実行します。

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

別々のコンパイルに-P tb.N=1,2,5,8を指定して設定行列を検査します。Icarus公式コマンド文書は言語モードとtop選択を説明します。シミュレータごとに対応範囲が異なるため、実際のバージョンを記録します。

意図的に失敗させます

DUTを一エッジ早くwrapさせるか、pulseの既定解除を除去します。少なくとも一条件でtimeout前に非ゼロ終了の失敗を報告する必要があります。後で正常ソースに戻します。関連する変更を検出できない検査器のPASSは弱い証拠です。

ソースハッシュ・N・命令・終了状態・PASSと意図的失敗の不一致を記録します。このローカルテストをDDS実行と表示してはいけません。汎用テストベンチの遅延・initialと、制限された単一クロック製品実習は別です。

選択はこのブラウザに適用されます。フッターからいつでも変更できます。