58 / 63 · Concetto
Piano di verifica FIFO/memorie e scoreboard indipendente
Costruire un riferimento queue indipendente dai puntatori e pianificare confini, reset, valid e letture non inizializzate.
Le lezioni sono gratuite. Iscriviti per salvare i progressi.
Il verificatore deve differire dal DUT
Il verificatore confronta il contratto atteso col DUT. Copiare rptr, wptr della FIFOFIFO Coda che estrae prima i dati inseriti prima. Pieno, vuoto e regole di lettura/scrittura simultanee fanno parte del contratto. Approfondisci può riprodurre lo stesso errore. Uno scoreboardScoreboard Stato di riferimento che confronta in ordine dati attesi e reali. Si calcola indipendentemente senza copiare lo stato interno dell’implementazione. indipendente conserva solo l'ordine logico in una queue SystemVerilog: push accettato aggiunge in fondo, pop accettato estrae davanti.
Pianificate incroci empty/intermedio/full con nessuna/solo push/solo pop/entrambe le richieste. Aggiungete wrap ripetuti, pop continui e reset con dati presenti. Registrate copertura, seed e ingressi di guasto per riprodurre i casi.
Le accettazioni attese si ricavano dalla vecchia dimensione della queue, non da full o occupancy del DUT.
Estraete prima la vecchia testa, poi accodate il nuovo dato: così il caso pieno simultaneo conserva la risposta corretta. Confrontate dout solo con atteso.
Testbench completo
Il testbench si compila insieme a fifo4 della lezione precedente. È codice di verifica con ritardi e queue. Gli ingressi cambiano al fronte di discesa; un picosecondo dopo la salita si confrontano gli aggiornamenti nonblockingNonblocking Assegnazione RTL sequenziale con <=. Valuta il membro destro e pianifica l’aggiornamento, permettendo ai registri dello stesso fronte di usare lo stato precedente. Approfondisci.
module tb_fifo4;
timeunit 1ns;
timeprecision 1ps;
typedef logic [7:0] word_t;
logic clk=0, rst=1, push=0, pop=0;
word_t din=0, dout;
logic dout_valid, full, empty;
logic [2:0] occupancy;
word_t model[$], expected;
bit expect_pop, expect_push;
fifo4 dut (.*);
always #5ns clk = ~clk;
always @(posedge clk) begin
if (rst) begin
model.delete();
expect_pop = 0;
end else begin
expect_pop = pop && (model.size() != 0);
expect_push = push && ((model.size() < 4) || expect_pop);
if (expect_pop) expected = model.pop_front();
if (expect_push) model.push_back(din);
end
#1ps;
assert (dout_valid === expect_pop)
else $fatal(1, "valid mismatch");
if (expect_pop)
assert (dout === expected)
else $fatal(1, "data mismatch");
assert (int'(occupancy) === model.size())
else $fatal(1, "count mismatch");
assert (empty === (model.size() == 0))
else $fatal(1, "empty mismatch");
assert (full === (model.size() == 4))
else $fatal(1, "full mismatch");
end
task automatic step(input bit r, p, o, input word_t d);
@(negedge clk);
rst=r; push=p; pop=o; din=d;
endtask
initial begin
step(0,0,1,0);
step(0,1,1,8'hA0);
for (int i=1; i<4; i++)
step(0,1,0,word_t'(160+i));
step(0,1,0,8'hEE);
step(0,1,1,8'hB0);
repeat (5) step(0,0,1,0);
repeat (3) begin
for (int i=0; i<4; i++) step(0,1,0,word_t'(i));
repeat (4) step(0,0,1,0);
end
step(0,1,0,8'h5A);
step(1,1,1,8'hFF);
step(0,0,1,0);
repeat (100)
step(0,bit'($urandom_range(1,0)),bit'($urandom_range(1,0)),
word_t'($urandom));
repeat (4) step(0,0,1,0);
@(negedge clk);
$display("PASS");
$finish;
end
endmoduleIl primo fronte con rst=1 svuota DUT e modello. === confronta rigorosamente anche X. Con valid=0 non si confronta dout non inizializzato, ma un valore X su valid fa fallire il controllo. Gli ultimi quattro pop verificano i dati rimasti. PASS è il messaggio dopo esecuzione reale e superamento di tutte le assertion; il codice mostrato da solo non indica una prova già eseguita.
Prima di inserire B0 si conserva la vecchia testa A0 come valore atteso. Si confronta l'ordine logico dei dati, non puntatori o posizioni fisiche.
- Coda precedente: [A0, A1, A2, A3]
- Valore atteso da pop: Conservare la precedente testa A0
- Applicare push: [A1, A2, A3, B0]
- Confrontare la risposta: Con valid=1, dout=A0
Controllare lo scoreboard ai confini
Con [A0, A1, A2, A3], un solo push EE viene scartato perché la dimensione è 4. La richiesta simultanea successiva salva expected=A0 e aggiunge B0, dando [A1, A2, A3, B0]. Se il DUT emette subito B0, l'assertion dati fallisce. A vuoto, entrambe danno expect_pop=0, expect_push=1: si salva senza confronto d'uscita. Reset ignora entrambe, svuota la queue e verifica valid=0.
Per le memorie vale lo stesso principio: array di riferimento e tabella initialized; per read-first, atteso prima dell'aggiornamento di scrittura. Nel bypass del file di registriRegistro Memorizza uno stato di più bit. I registri sincroni del corso acquisiscono gli ingressi specificati al fronte di clock. Approfondisci, selezionate prima wr_data in collisione e poi aggiornate l'array. Dichiarate se vietare letture non inizializzate o ammettere risposte indeterminate; non inventate 0 come atteso. Le memorie indirizzate richiedono un verificatore separato.
Iniettate singolarmente difetti come dato nuovo nel pop a pieno, incremento con doppia accettazione o valid nel pop a vuoto: i controlli corrispondenti devono fallire. Insieme alla coverage dei confini, ciò trova lacune nei test. Mappatura RAM e timing richiedono verifiche specifiche di sintesi e temporizzazione.
Prova tu
Uno scoreboard inserisce prima push e decide pop dalla dimensione aggiornata. Quale errore a vuoto con entrambe? Quando salvare l’atteso a pieno? È corretto verificare sempre dout=0 dopo reset?
Leggi la spiegazione
Permette erroneamente pop immediato del nuovo elemento: expect_pop=1. Il contratto usa lo stato precedente: solo push e valid=0. A pieno salvate e rimuovete prima la vecchia testa, poi aggiungete in fondo. Reset non azzera dout: verificate valid=0 e queue/occupancy vuote. Confrontate dati con expect_pop=1 e valid separatamente, per rilevare anche un valid sempre a 0.