24 / 37 · Esercitazione
Laboratorio: un testbench che segnala i propri errori
Separa DUT, stimoli, modello di riferimento e controlli per reset, enable e ritorno senza race condition.
Le lezioni sono gratuite. Iscriviti per salvare i progressi.
Separare implementazione e verificatore
Il testbench fornisce stimoli, calcola attese e segnala differenze. È codice di simulazione, non circuito da sintetizzare. Salva modulo_tick della lezione parametri in modulo_tick.sv e questo banco completo in tb.sv. Reset sincrono vince; senza enable, count mantiene e pulse si azzera; abilitato incrementa modulo N e pulse è 1 solo al ritorno. Usa un modello di riferimento intero invece dello stato interno.
`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
endmoduleEvitare la competizione sul fronte attivo
La task cambia ingressi in discesa, mezzo ciclo prima della cattura, e confronta dopo aggiornamenti non bloccanti della salita. #1 è ritardo didattico d'osservazione con timescale e clock di 10ns, non analisi fisica di clock-to-Q, setup o hold. Ambienti riusabili possono utilizzare clocking blocks o disciplina delle regioni di eventi. Il primo reset rende noto il DUT; inizializzare il modello non lo inizializza. !== segnala X/Z contro aspettative note.
Compilare con top esplicito
In una shell con Icarus installato:
iverilog -g2012 -s tb -o sim.vvp modulo_tick.sv tb.sv
vvp sim.vvpCompila separatamente con -P tb.N=1,-P tb.N=2,-P tb.N=5,-P tb.N=8. La documentazione ufficiale Icarus spiega lingua e top. Registra versione, poiché il supporto SystemVerilog varia.
Provocare un errore
Modifica confronto per tornare un fronte prima o elimina l'azzeramento predefinito di pulse. Almeno uno scenario deve fallire con stato non zero prima del timeout. Ripristina poi sorgente corretta. Un PASS incapace di rilevare mutazioni rilevanti è prova debole. Registra hash, N, comandi, stati, PASS e prima divergenza. Un test locale non è un'esecuzione DDS:#delay e initial di banco generale non equivalgono automaticamente all'interfaccia limitata del laboratorio con un clock.