Verilog Scheduling Semantics verstehen: Timing, Events und Ausführungsreihenfolge
Verilog-Design und Testbench haben typischerweise viele Codezeilen, die aus always- oder initial-Blöcken, kontinuierlichen Zuweisungen und anderen prozeduralen Anweisungen bestehen, die zu unterschiedlichen Zeiten im Verlauf einer Simulation aktiv werden.
Jede Wertänderung eines Signals im Verilog-Modell wird als Update-Event betrachtet. Und Prozesse wie always- und assign-Blöcke, die empfindlich auf diese Update-Events sind, werden in beliebiger Reihenfolge ausgewertet und dies wird als Evaluation-Event bezeichnet. Da diese Events zu unterschiedlichen Zeiten eintreten können, werden sie besser verwaltet und ihre korrekte Ausführungsreihenfolge durch Einplanung in Event-Queues sichergestellt, die nach Simulationszeit angeordnet sind.
module tb;
reg a, b, c;
wire d;
// 'always' ist ein Prozess, der ausgewertet wird, wenn entweder 'a' oder 'b' aktualisiert wird.
// Wenn 'a' oder 'b' seinen Wert ändert, nennt man das ein 'Update-Event'.
// Wenn der 'always'-Block aufgrund einer Änderung in 'a' oder 'b' getriggert wird,
// nennt man das ein Evaluation-Event
always @ (a or b) begin
c = a & b;
end
// Hier ist 'assign' ein Prozess, der ausgewertet wird, wenn entweder 'a' oder 'b' oder 'c'
// aktualisiert wird
assign d = a | b ^ c;
endmodule
Event-Queue
Ein Simulationsschritt kann in vier verschiedene Regionen segmentiert werden. Eine aktive Event-Queue ist lediglich eine Menge von Prozessen, die zur aktuellen Zeit ausgeführt werden müssen, was dazu führen kann, dass weitere Prozesse in die aktive oder andere Event-Queues eingeplant werden. Events können zu beliebigen Regionen hinzugefügt werden, aber immer nur aus der aktiven Region entfernt werden.
- Aktive Events treten zur aktuellen Simulationszeit auf und können in beliebiger Reihenfolge verarbeitet werden.
- Inaktive Events treten zur aktuellen Simulationszeit auf, werden aber nach der Verarbeitung aller aktiven Events verarbeitet.
- Nonblocking Assign Events, die zuvor ausgewertet wurden, werden nach der Verarbeitung aller aktiven und inaktiven Events zugewiesen.
- Monitor Events werden nach der Verarbeitung aller aktiven, inaktiven und Non-Blocking-Zuweisungen verarbeitet.
Wenn alle Events in der aktiven Queue für den aktuellen Zeitschritt ausgeführt wurden, schreitet der Simulator die Zeit zum nächsten Zeitschritt fort und führt dessen aktive Queue aus.
module tb;
reg x, y, z;
initial begin
#1 x = 1; y = 1;
#1 z = 0;
end
endmodule
Die Simulation startet zur Zeit 0, und die erste Anweisung wird eingeplant, um ausgeführt zu werden, wenn die Simulationszeit 1 Zeiteinheit erreicht, woraufhin x und y auf 1 zugewiesen werden. Dies ist die aktive Queue für die aktuelle Zeit, die 1 Zeiteinheit beträgt. Der Simulator plant dann die nächste Anweisung nach 1 weiterer Zeiteinheit ein, woraufhin z auf 0 zugewiesen wird.
Was macht die Simulation nicht-deterministisch?
Es können Race Conditions während der Simulation auftreten, die zu unterschiedlichen Ausgängen für dasselbe Design und denselben Testbench führen. Einer der Gründe für nicht-deterministisches Verhalten ist, dass aktive Events aus der Queue entfernt und in beliebiger Reihenfolge verarbeitet werden können.
Verilog
- Verilog meistern: Komplettes Tutorial für digitales Schaltungsdesign
- Verilog Concatenation meistern: Praktischer Leitfaden
- Verilog Assignments verstehen: Typen, Syntax und Best Practices
- Verilog Blocking vs. Non-Blocking: Wichtige Unterschiede erklärt
- Verilog Functions meistern für effizientes RTL-Design
- Verilog Tasks verstehen: Functions vs. Tasks, Syntax und Verwendung
- Verilog Clock Generator: Design & Implementierungsleitfaden
- Verilog Math Functions meistern für effizientes Hardware-Design
- Verilog $timeformat meistern: Präzision und Anzeigesteuerung
- Verilog Timescales an jedem Scope verstehen und ausgeben