Was "Zeit" in Verilog bedeutet
Verilog hat keinen eingebauten Begriff von Sekunden. Der Simulator rückt "Zeiteinheiten" - beliebige ganzzahlige Ticks - vor, und dein Code nutzt #N, um N davon zu warten. Die `timescale-Direktive bildet diese Ticks auf echte Zeit ab.
`timescale 1ns / 1ps
module test;
initial begin
$display("t = %0t", $time); // 0
#5;
$display("t = %0t", $time); // 5 ns
#1.5;
$display("t = %0t", $time); // 6500 ps (oder 6,5 ns)
$finish;
end
endmodule
Zwei Parameter:
- Einheit (erste Zahl): was
#1bedeutet.1nssagt, ein Tick ist eine Nanosekunde. - Präzision (zweite Zahl): wie fein die Simulation Zeit innerhalb dieser Einheit verfolgt.
1pssagt, gebrochene Delays werden auf Pikosekunden gerundet.
Die Präzision darf nicht gröber als die Einheit sein (1ps / 1ns ist illegal). Übliche Wahl:
1ns / 1ps- der De-facto-Standard. Alles in Nanosekunden, Sub-Nanosekunden-Präzision für Gatter-Delays.1ps / 1ps- wenn extrem schnelle Schaltungen modelliert werden oder jedes Delay sub-nanosekundig ist.1us / 1ns- für langsame, Embedded-Simulationen (UART-Byte-Zeiten, langsame Protokolle).
Wo es hingehört
`timescale ist eine Compiler-Direktive, kein Modul-Konstrukt. Sie steht ganz oben in einer Datei, vor jedem module:
`timescale 1ns / 1ps
module foo(...);
// ...
endmodule
Sein Scope ist "ab hier in der Kompilierreihenfolge, bis zum nächsten `timescale oder Ende der Kompilierung". Das hat eine subtile Implikation: Eine Datei ohne explizites `timescale erbt das, was die vorher kompilierte Datei deklarierte, was von der Reihenfolge abhängt, in der der Compiler die Dateien liest. Vermeide die Überraschung: Schreibe `timescale an die Spitze jeder Datei.
Der Browser-Editor in diesen Docs setzt eine Default-Timescale für dich (üblicherweise 1ns / 1ps), deshalb funktionierten die Beispiele in früheren Docs ohne Deklaration. In einem echten Projekt wärst du explizit.
#delay in der Praxis
Nach `timescale 1ns / 1ps:
#5 // warte 5 ns
#100 // warte 100 ns
#1.5 // warte 1,5 ns (Präzision erlaubt es)
#0.001 // warte 1 ps (gerade noch über der Präzision)
#0 // Null-Delay; nützlich zum Ordnen von Events zur selben Zeit
Innerhalb eines initial- oder always-Blocks blockiert #N den prozeduralen Fluss für N Zeiteinheiten. Der Simulator pausiert diesen Block (andere nebenläufige Blöcke laufen weiter) und setzt nach der Verzögerung fort.
Du kannst einer Zuweisung ein Delay voranstellen:
#10 a = 1; // warte 10 ns, dann zuweisen
data <= #2 new_value; // plane die non-blocking-Zuweisung 2 ns von jetzt
Die erste Form ist Testbench-Standard. Die zweite (delayed non-blocking) wird in Gate-Level-Simulationen genutzt, um Propagations-Delays zu modellieren.
Einen Takt erzeugen
Das klassische Muster:
`timescale 1ns / 1ps
module test;
reg clk = 0;
always #5 clk = ~clk;
// ...
endmodule
Mit Timescale 1ns / 1ps ist #5 5 ns. Der Takt schaltet alle 5 ns um, ergibt eine 10-ns-Periode - ein 100-MHz-Takt. Um die Frequenz zu ändern, ändere das Delay:
| Halb-Periode | Periode | Frequenz |
|---|---|---|
#1 | 2 ns | 500 MHz |
#2.5 | 5 ns | 200 MHz |
#5 | 10 ns | 100 MHz |
#10 | 20 ns | 50 MHz |
#25 | 50 ns | 20 MHz |
#50 | 100 ns | 10 MHz |
Willst du eine gebrochene Halb-Periode (#2.5), muss deine Präzision das unterstützen - 1ps-Präzision schafft alles bis 0,001 ns, also ist jede vernünftige Frequenz okay.
Timescales über Dateien hinweg mischen
Ein echtes Design hat viele Dateien, und sie können unterschiedliche Timescales deklarieren. Der Simulator nutzt jeweils die eigene Timescale der Datei, um die Delays in ihr zu interpretieren. Sagt module_a.v `timescale 1ns / 1ps und nutzt #5, sind das 5 ns. Sagt module_b.v `timescale 1us / 1ns und nutzt #5, sind das 5 µs.
Das ist meist unsichtbar, weil der Simulator unabhängig davon eine globale Zeitachse präsentiert - aber es heißt, dasselbe #N in zwei Dateien kann sehr unterschiedliche Dinge bedeuten. Der Fix: Eine Timescale wählen (Industriestandard ist 1ns / 1ps) und sie an die Spitze jeder Datei setzen. Nicht mischen.
Delays sind nicht synthetisierbar
Wichtig: #delay existiert nur für Simulation. Das Synthese-Tool liest:
// In synthetisierbarem RTL - FALSCH
always @(posedge clk) begin
out <= #2 in;
end
… und ignoriert entweder das #2 (die meisten Tools) oder weist das Konstrukt ab (strengere Linter). Das Timing echter Hardware wird vom Takt und der Gatter-Propagation bestimmt - beides für den Quelltext unsichtbar.
Die Regel: # nur in Testbenches. Synthetisierbares RTL hat keine #-Delays. Findest du dich dabei, ein Delay in synthetisierbarem Code zu wollen, willst du eigentlich einen Counter, der am Takt herunterzählt - so "wartet" echte Hardware.
$time vs $realtime
Zwei Wege, die aktuelle Simulationszeit zu lesen:
$timeliefert einen 64-Bit-Integer in der Einheit der aktuellen Timescale-Einheit.$realtimeliefert einrealin der Einheit der aktuellen Timescale-Einheit, aber mit voller Präzision.
Für Testbench-Logging reicht $time fast immer. Greife nur dann zu $realtime, wenn du in Print-Anweisungen Sub-Tick-Präzision brauchst.
Praktische Tipps
- Deklariere
`timescaleimmer oben in jeder Datei.1ns / 1psist der sichere Default. - Nutze
#delaynur in Testbenches. Behandle die Abwesenheit in synthetisierbarem Code als statische Regel. - Passe Taktperioden zur Zielfrequenz. Simulierst du ein 50-MHz-Design, nimm eine 20-ns-Periode - nicht passende Perioden können timing-empfindliche Bugs verdecken.
- Für zyklenbasierten Stimulus nimm
@(posedge clk)statt#. Das ist robust gegen Änderungen der Taktperiode.
Wie es weitergeht
Du hast jetzt jedes Doc dieser Verilog-Tutorials gesehen. Von den Grundlagen der Sprache (wire vs reg, Module, Operatoren) über prozedurale Blöcke und Kontrollfluss bis hin zu synchronem Design und Automaten - und schließlich das Testbench-Werkzeug, das beweist, dass alles funktioniert. Zeit, etwas zu bauen - der Playground neben diesen Docs ist derselbe Simulator, den wir die ganze Zeit benutzt haben, bereit für jedes Modul, das du skizzierst.
Häufig gestellte Fragen
Was bedeutet `timescale 1ns / 1ps in Verilog?
Es sagt dem Simulator: 'eine Zeiteinheit in dieser Datei ist eine Nanosekunde, und Zeit wird mit Pikosekunden-Präzision verfolgt.' Nach dieser Direktive wartet #5 5 ns, #1.5 wartet 1,5 ns (auf Pikosekunden gerundet), und $time wird in Nanosekunden ausgegeben. Die erste Zahl ist die Einheit; die zweite die Präzision.
Brauche ich `timescale in jeder Verilog-Datei?
Best Practice: ja. Der Scope der Direktive endet beim nächsten \timescaleoder am Ende der Kompilierung, sodass Dateien ohne sie das erben, was die zuletzt kompilierte Datei deklarierte. Das macht Timing nicht-deterministisch über Builds hinweg. Schreibe`timescale 1ns / 1ps` oben in jede Quelldatei - das ist die häufigste Konvention - und du wirst nie überrascht.
Was bedeutet #5 in Verilog?
#5 rückt die Simulationszeit um 5 Zeiteinheiten vor. Die Einheit kommt von der aktiven \timescale-Direktive. Mit `timescale 1ns / 1psist#55 Nanosekunden. Mit`timescale 1us / 1nsist#55 Mikrosekunden. Die Zahl kann gebrochen sein -#1.5` funktioniert, wenn deine Präzision feiner als die Einheit ist.
Ist #delay in Verilog synthetisierbar?
Nein. #delay beeinflusst nur die Simulation - das Synthese-Tool ignoriert oder weist es ab. Das Timing echter Hardware kommt vom Taktsignal und der Gatter-Propagationsverzögerung, nicht aus #-Anweisungen. Nutze # frei in Testbenches; schreib es nie in synthetisierbarem RTL.