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.
Bài học miễn phí. Đăng ký để lưu tiến độ học tậ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ộ.
`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
endmoduleTrá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:
iverilog -g2012 -s tb -o sim.vvp modulo_tick.sv tb.sv
vvp sim.vvpBiê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.