58 / 63 · Konzept
FIFO-/Speicherprüfplan und unabhängiges Scoreboard
Zeigerunabhängige Queue-Referenz mit Grenzen, Reset, valid und uninitialisiertem Lesen verbinden.
Lektionen sind frei lesbar. Schreibe dich ein, um deinen Fortschritt zu speichern.
Der Prüfer soll anders aufgebaut sein als das DUT
Ein Prüfer vergleicht Vertragserwartungen mit dem DUT. Kopierte FIFO-ZeigerFIFO Warteschlange, die zuerst eingefügte Daten zuerst ausgibt. Voll-/Leerzustände und Regeln gleichzeitigen Lesens/Schreibens gehören zum Vertrag. Mehr erfahren rptr, wptr können denselben Fehler erneut erzeugen. Ein unabhängiges ScoreboardScoreboard Referenzzustand einer Prüfumgebung zum geordneten Vergleich erwarteter und tatsächlicher Daten. Wird unabhängig berechnet statt aus internen DUT-Zuständen kopiert. speichert nur die logische Reihenfolge in einer SystemVerilog-Queue: angenommenes push hängt an, angenommenes pop nimmt vorn weg.
Planen Sie Kreuzkombinationen aus empty/mittel/full und keine/push/pop/beide Anforderungen. Ergänzen Sie wiederholten Umlauf, fortlaufende pops und Reset bei vorhandenen Daten. Erfassen Sie die Abdeckung und bewahren Sie Seed und Fehlereingaben zur Reproduktion auf.
Erwartete Annahmen werden aus der alten Queuegröße berechnet, nicht aus DUT-full oder -occupancy.
Entfernen Sie zuerst den alten Head, dann hängen Sie neue Daten an. So bleibt bei gleichzeitigen Anforderungen an full der richtige alte Wert erhalten. Vergleichen Sie dout nur bei erwartetem .
Vollständige Testbench
Diese Testbench wird mit fifo4 aus der vorigen Lektion kompiliert. Sie nutzt Verzögerungen und Queues als Verifikationscode. Eingaben wechseln an fallenden Flanken; eine Pikosekunde nach der steigenden werden die nonblocking-AktualisierungenNonblocking Sequenzielle RTL-Zuweisung mit <=. Nach Auswertung der rechten Seite wird die Aktualisierung geplant, sodass Register derselben Flanke den alten Zustand verwenden. Mehr erfahren verglichen.
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
endmoduleDie erste Flanke mit rst=1 leert DUT und Modell. === vergleicht streng einschließlich X. Bei valid=0 wird uninitialisiertes dout ignoriert; X in valid selbst lässt den Test scheitern. Die letzten vier pops prüfen alle Restdaten. PASS ist die Meldung nach tatsächlicher Ausführung aller erfolgreichen Assertions; der abgedruckte Code allein bedeutet keinen bereits ausgeführten Test.
Vor Einfügen von B0 wird der alte Head A0 als Erwartung gesichert. Verglichen wird logische Datenreihenfolge statt physischer Plätze oder Zeiger.
- Bisherige Queue: [A0, A1, A2, A3]
- Erwarteter pop-Wert: Den bisherigen Kopf A0 aufbewahren
- push anwenden: [A1, A2, A3, B0]
- Antwort vergleichen: Bei valid=1 gilt dout=A0
Das Scoreboard an Grenzfällen prüfen
Bei [A0, A1, A2, A3] wird ein bloßes push EE wegen der Größe 4 verworfen. Die nächste gleichzeitige Anforderung sichert expected=A0 und hängt B0 zu [A1, A2, A3, B0] an. Liefert das DUT sofort B0, schlägt die Datenassertion fehl. Bei empty und beiden gilt expect_pop=0, expect_push=1: nur speichern, kein Datenvergleich. Reset ignoriert beide, leert die Queue und verlangt valid=0.
Für Speicher gelten dieselben Prinzipien: Referenzarray plus initialized-Tabelle; read-first-Erwartung vor der Referenzschreibaktualisierung erfassen. Bei Registerdatei-BypassRegister Speichert einen Zustand aus mehreren Bits. Die synchronen Register dieses Kurses übernehmen festgelegte Eingaben an Taktflanken. Mehr erfahren wählen Sie bei Kollision zuerst wr_data und schreiben danach die Referenz. Legen Sie fest, ob uninitialisiertes Lesen verboten oder als unbestimmt erlaubt ist; erfinden Sie keine 0 als Sollwert. Adressspeicher brauchen einen eigenen Prüfer.
Injizieren Sie einzeln Fehler wie neue Daten bei full-pop, Zählererhöhung bei gleichzeitiger Annahme oder valid bei empty-pop: Die entsprechenden Prüfungen müssen scheitern. Zusammen mit Grenzfall-Coverage deckt dies Lücken im Test auf. RAM-Abbildung und Timing benötigen eigene Synthese-/Timing-Verifikation.
Selbst ausprobieren
Ein falsches Scoreboard hängt push zuerst an und entscheidet pop anhand der neuen Größe. Was geht bei empty mit beiden schief? Wann muss bei full der Erwartungswert gesichert werden? Ist dout=0 nach jedem Reset eine richtige Prüfung?
Erklärung lesen
Es erlaubt fälschlich sofortiges pop des neuen Eintrags: expect_pop=1. Annahme muss vom Zustand vor der Flanke abhängen, also nur push und valid=0. Bei full zuerst den alten Head sichern und entfernen, dann hinten anfügen. Reset setzt dout nicht auf 0; prüfen Sie valid=0 und leere Queue/occupancy. Datenvergleich erfolgt bei expect_pop=1, valid wird unabhängig verglichen, damit dauerhaftes valid=0 nicht verborgen bleibt.