Altifigence Academy

24 / 37 · Thực hành

Thực hành: testbench tự báo lỗi

Tách DUT, kích thích, tham chiếu và kiểm tra để thử reset, enable và quay vòng không tranh chấp.

Tách triển khai và bộ kiểm tra

Testbench tạo kích thích, tính kỳ vọng và báo khác biệt. Đây là mã mô phỏng, không phải mạch tổng hợp. Lưu modulo_tick từ bài tham số trong modulo_tick.sv và testbench đầy đủ này trong tb.sv. Reset đồng bộ ưu tiên; không enable thì count giữ, pulse xóa; enable thì đếm modulo N, pulse=1 chỉ khi quay vòng. Dùng tham chiếu số nguyên, không đọc trạng thái nội bộ.

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

Tránh tranh chấp tại cạnh hoạt động

Task đổi đầu vào ở cạnh xuống, nửa chu kỳ trước bắt, và so sau cập nhật không chặn của cạnh lên. #1 là độ trễ quan sát giảng dạy với timescale và clock 10ns, không phân tích vật lý clock-to-Q, setup hay hold. Môi trường tái sử dụng có thể dùng clocking blocks hoặc kỷ luật vùng sự kiện. Reset đầu làm DUT xác định; khởi tạo tham chiếu không khởi tạo DUT. !== báo X/Z khi kỳ vọng xác định.

Biên dịch với top rõ

Trong shell có Icarus:

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

Biên dịch riêng với -P tb.N=1,-P tb.N=2,-P tb.N=5,-P tb.N=8. Tài liệu Icarus chính thức mô tả ngôn ngữ và top. Ghi phiên bản vì hỗ trợ SystemVerilog khác nhau.

Cố ý gây thất bại

Đổi so sánh để quay vòng sớm một cạnh hoặc bỏ xóa pulse mặc định. Một tình huống phải lỗi với mã thoát khác zero trước timeout. Sau đó khôi phục mã đúng. PASS không phát hiện biến đổi lỗi liên quan là bằng chứng yếu. Ghi hash, N, lệnh, trạng thái, PASS và sai khác đầu tiên. Không gọi thử cục bộ là chạy DDS:#delay và initial của testbench tổng quát không tự tương đương giao diện thực hành hạn chế một clock.

Lựa chọn áp dụng cho trình duyệt này. Có thể đổi ở chân trang bất cứ lúc nào.