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 与产品限制的单时钟实验不同。

你的选择适用于此浏览器,可随时在页脚更改。