Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Industrial programming >> Verilog

Verilog Delay Control verstehen: Timing-Techniken und Best Practices

Es gibt zwei Arten von Timing-Kontrollen in Verilog: Delay- und Event-Ausdrücke. Die Delay-Kontrolle ist lediglich eine Möglichkeit, eine Verzögerung zwischen dem Zeitpunkt hinzuzufügen, zu dem der Simulator die Anweisung trifft, und dem Zeitpunkt, zu dem er sie tatsächlich ausführt. Der Event-Ausdruck erlaubt es, die Anweisung so lange zu verzögern, bis das Eintreten eines Simulationsereignisses eintritt, was eine Wertänderung auf einem Net oder einer Variable (implizites Ereignis) oder ein explizit benanntes Ereignis sein kann, das in einer anderen Prozedur ausgelöst wird.

Die Simulationszeit kann durch eine der folgenden Methoden vorangetrieben werden.

Gatter und Nets, die mit internen Delays modelliert wurden, treiben die Simulationszeit ebenfalls voran.

Delay Control

Wenn der Delay-Ausdruck zu einem unbekannten oder High-Impedance-Wert ausgewertet wird, wird er als Null-Delay interpretiert. Wenn er zu einem negativen Wert ausgewertet wird, wird er als 2-Komplement-vorzeichenlose Ganzzahl derselben Größe wie eine Time-Variable interpretiert.

`timescale 1ns/1ps
module tb;
  reg [3:0] a, b;
  initial begin
    {a, b} <= 0;
    $display ("T=%0t a=%0d b=%0d", $realtime, a, b);
    #10; a <= $random;
    $display ("T=%0t a=%0d b=%0d", $realtime, a, b);
    #10 b <= $random;
    $display ("T=%0t a=%0d b=%0d", $realtime, a, b);
    #(a) $display ("T=%0t After a delay of a=%0d units", $realtime, a);
    #(a+b) $display ("T=%0t After a delay of a=%0d + b=%0d = %0d units", $realtime, a, b, a+b);
    #((a+b)*10ps) $display ("T=%0t After a delay of %0d * 10ps", $realtime, a+b);
    #(b-a) $display ("T=%0t Expr evaluates to a negative delay", $realtime);
    #('h10) $display ("T=%0t Delay in hex", $realtime);
    a = 'hX; #(a) $display ("T=%0t Delay is unknown, taken as zero a=%h", $realtime, a);
    a = 'hZ; #(a) $display ("T=%0t Delay is in high impedance, taken as zero a=%h", $realtime, a);
    #1ps $display ("T=%0t Delay of 10ps", $realtime);
  end
endmodule

Beachten Sie, dass die Präzision des Timescale in 1ps liegt und daher $realtime erforderlich ist, um den Präzisionswert für die Anweisung mit dem Delay-Ausdruck (a+b)*10ps anzuzeigen.

Simulationslog:

xcelium> run
T=0 a=x b=x
T=10000 a=0 b=0
T=20000 a=4 b=0
T=24000 After a delay of a=4 units
T=29000 After a delay of a=4 + b=1 = 5 units
T=29050 After a delay of 5 * 10ps
T=42050 Expr evaluates to a negative delay
T=58050 Delay in hex
T=58050 Delay is unknown, taken as zero a=x
T=58050 Delay is in high impedance, taken as zero a=z
T=58051 Delay of 10ps
xmsim: *W,RNQUIE: Simulation is complete.

Event Control

Wertänderungen auf Nets und Variablen können als Synchronisationsereignis verwendet werden, um die Ausführung anderer prozeduraler Anweisungen auszulösen, und sind ein implizites Ereignis. Das Ereignis kann auch auf der Änderungsrichtung basieren, wie z. B. in Richtung 0, was es zu einem negedge macht, und eine Änderung in Richtung 1 macht es zu einem posedge.

Ein Übergang vom selben Zustand in denselben Zustand wird nicht als Edge betrachtet. Ein Edge-Ereignis wie posedge oder negedge kann nur am LSB eines Vektor-Signals oder einer Variable detektiert werden. Wenn ein Ausdruck zum selben Ergebnis ausgewertet wird, kann er nicht als Ereignis betrachtet werden.

module tb;
  reg a, b;
  initial begin
    a <= 0;
    #10 a <= 1;
    #10 b <= 1;
    #10 a <= 0;
    #15 a <= 1;
  end
  
  // Einen weiteren prozeduralen Block starten, der auf ein Update von
  // Signalen wartet, die im obigen prozeduralen Block gemacht wurden
  initial begin
    @(posedge a);
    $display ("T=%0t Posedge of a detected for 0->1", $time);
    @(posedge b);
    $display ("T=%0t Posedge of b detected for X->1", $time);
  end
  
  initial begin
    @(posedge (a + b))
    $display ("T=%0t Posedge of a+b", $time);
    @(a)
    $display ("T=%0t Change in a found", $time);
  end
endmodule

Simulationslog:

ncsim> run
T=10 Posedge of a detected for 0->1
T=20 Posedge of b detected for X->1
T=30 Posedge of a+b
T=45 Change in a found
ncsim: *W,RNQUIE: Simulation is complete.

Benannte Events (Named Events)

Das Schlüsselwort event kann verwendet werden, um ein benanntes Event zu deklarieren, das explizit ausgelöst werden kann. Ein event kann keine Daten halten, hat keine Zeitdauer und kann zu jedem bestimmten Zeitpunkt eintreten. Ein benanntes Event wird durch den ->-Operator ausgelöst, indem er vor dem benannten Event-Handle präfixiert wird. Ein benanntes Event kann mit dem oben beschriebenen @-Operator erwartet werden.

module tb;
  event a_event;
  event b_event[5];
  
  initial begin
    #20 -> a_event;
    #30; ->a_event;
    #50 ->a_event;
    #10 ->b_event[3];
  end
  
  always @ (a_event)
    $display ("T=%0t [always] a_event is triggered", $time);
    
  initial begin
    #25; @(a_event) $display ("T=%0t [initial] a_event is triggered", $time);
    #10 @(b_event[3]) $display ("T=%0t [initial] b_event is triggered", $time);
  end
endmodule

Benannte Events können verwendet werden, um zwei oder mehr parallel laufende Prozesse zu synchronisieren. Zum Beispiel werden der always-Block und der zweite initial-Block durch a_event synchronisiert. Events können als Arrays deklariert werden, wie im Fall von b_event, das ein Array der Größe 5 ist und der Index 3 für Trigger- und Wartezwecke verwendet wird.

Simulationslog:

ncsim> run
T=20 [always] a_event is triggered
T=50 [always] a_event is triggered
T=50 [initial] a_event is triggered
T=100 [always] a_event is triggered
T=110 [initial] b_event is triggered
ncsim: *W,RNQUIE: Simulation is complete.

Event-OR-Operator

or-Operator kann verwendet werden, um zu warten, bis eines der aufgelisteten Events in einem Ausdruck ausgelöst wird. Der Komma-Operator , kann ebenfalls anstelle des or-Operators verwendet werden.

module tb;
  reg a, b;
  initial begin
    $monitor ("T=%0t a=%0d b=%0d", $time, a, b);
    {a, b} <= 0;
    #10 a <= 1;
    #5 b <= 1;
    #5 b <= 0;
  end
  
  // "or" zwischen Events verwenden
  always @ (posedge a or posedge b)
    $display ("T=%0t posedge of a or b found", $time);
  
  // Komma zwischen Events verwenden
  always @ (posedge a, negedge b)
    $display ("T=%0t posedge of a or negedge of b found", $time);
  
  always @ (a, b)
    $display ("T=%0t Any change on a or b", $time);
endmodule

Simulationslog:

ncsim> run
T=0 posedge of a or negedge of b found
T=0 Any change on a or b
T=0 a=0 b=0
T=10 posedge of a or b found
T=10 posedge of a or negedge of b found
T=10 Any change on a or b
T=10 a=1 b=0
T=15 posedge of a or b found
T=15 Any change on a or b
T=15 a=1 b=1
T=20 posedge of a or negedge of b found
T=20 Any change on a or b
T=20 a=1 b=0
ncsim: *W,RNQUIE: Simulation is complete.

Implizite Event-Ausdrucksliste

module tb;
  reg a, b, c, d;
  reg x, y;
  
  // Event-Ausdruck/Sensitivitätsliste wird von allen
  // Signalen innerhalb von () nach @ Operator gebildet, in diesem Fall a, b, c oder d
  always @ (a, b, c, d) begin
    x = a | b;
    y = c ^ d;
  end
  
  initial begin
    $monitor ("T=%0t a=%0b b=%0b c=%0b d=%0b x=%0b y=%0b", $time, a, b, c, d, x, y);
    {a, b, c, d} <= 0;
    #10 {a, b, c, d} <= $random;
    #10 {a, b, c, d} <= $random;
    #10 {a, b, c, d} <= $random;
  end
endmodule

Simulationslog:

ncsim> run
T=0 a=0 b=0 c=0 d=0 x=0 y=0
T=10 a=0 b=1 c=0 d=0 x=1 y=0
T=20 a=0 b=0 c=0 d=1 x=0 y=1
T=30 a=1 b=0 c=0 d=1 x=1 y=1
ncsim: *W,RNQUIE: Simulation is complete.

Wenn der Benutzer beschließt, ein neues Signal e hinzuzufügen und den Inversen in z zu erfassen, muss besondere Sorgfalt darauf verwendet werden, e auch in die Sensitivitätsliste aufzunehmen.

module tb;
  reg a, b, c, d, e;
  reg x, y, z;
  
  // "e" auch in Sensitivitätsliste hinzufügen
  always @ (a, b, c, d, e) begin
    x = a | b;
    y = c ^ d;
    z = ~e;
  end
  
  initial begin
    $monitor ("T=%0t a=%0b b=%0b c=%0b d=%0b e=%0b x=%0b y=%0b z=%0b", $time, a, b, c, d, e, x, y, z);
    {a, b, c, d, e} <= 0;
    #10 {a, b, c, d, e} <= $random;
    #10 {a, b, c, d, e} <= $random;
    #10 {a, b, c, d, e} <= $random;
  end
endmodule

Simulationslog:

ncsim> run
T=0 a=0 b=0 c=0 d=0 e=0 x=0 y=0 z=1
T=10 a=0 b=0 c=1 d=0 e=0 x=0 y=1 z=1
T=20 a=0 b=0 c=0 d=0 e=1 x=0 y=0 z=0
T=30 a=0 b=1 c=0 d=0 e=1 x=1 y=0 z=0
ncsim: *W,RNQUIE: Simulation is complete.

Verilog erlaubt nun, die Sensitivitätsliste durch * zu ersetzen, was eine praktische Abkürzung ist, die diese Probleme beseitigt, indem alle Nets und Variablen hinzugefügt werden, die von der Anweisung gelesen werden, wie unten gezeigt.

module tb;
  reg a, b, c, d, e;
  reg x, y, z;
  
  // @* oder @(*) verwenden
  always @ * begin
    x = a | b;
    y = c ^ d;
    z = ~e;
  end
  
  initial begin
    $monitor ("T=%0t a=%0b b=%0b c=%0b d=%0b e=%0b x=%0b y=%0b z=%0b", $time, a, b, c, d, e, x, y, z);
    {a, b, c, d, e} <= 0;
    #10 {a, b, c, d, e} <= $random;
    #10 {a, b, c, d, e} <= $random;
    #10 {a, b, c, d, e} <= $random;
  end
endmodule

Simulationslog:

ncsim> run
T=0 a=0 b=0 c=0 d=0 e=0 x=0 y=0 z=1
T=10 a=0 b=0 c=1 d=0 e=0 x=0 y=1 z=1
T=20 a=0 b=0 c=0 d=0 e=1 x=0 y=0 z=0
T=30 a=0 b=1 c=0 d=0 e=1 x=1 y=0 z=0
ncsim: *W,RNQUIE: Simulation is complete.

Level-Sensitive Event Control

wait erreicht werden. Dies ist eine level-sensitive Steuerung.

Die wait-Anweisung wertet eine Bedingung aus, und wenn sie falsch ist, bleiben die nachfolgenden prozeduralen Anweisungen blockiert, bis die Bedingung wahr wird.

module tb;
  reg [3:0] ctr;
  reg clk;
  initial begin
    {ctr, clk} <= 0;
    wait (ctr);
    $display ("T=%0t Counter reached non-zero value 0x%0h", $time, ctr);
    wait (ctr == 4)
    $display ("T=%0t Counter reached 0x%0h", $time, ctr);
    $finish;
  end
  
  always #10 clk = ~clk;
  always @ (posedge clk) ctr <= ctr + 1;
endmodule

Simulationslog:

ncsim> run
T=10 Counter reached non-zero value 0x1
T=70 Counter reached 0x4
T=90 Counter reached 0x5
T=170 Counter reached 0x9
Simulation complete via $finish(1) at time 170 NS + 1

Verilog

  1. Verilog meistern: Komplettes Tutorial für digitales Schaltungsdesign
  2. Verilog Concatenation meistern: Praktischer Leitfaden
  3. Verilog Assignments verstehen: Typen, Syntax und Best Practices
  4. Verilog Blocking vs. Non-Blocking: Wichtige Unterschiede erklärt
  5. Verilog Control Flow meistern: IF-ELSE, Case, Loops und mehr
  6. Verilog Functions meistern für effizientes RTL-Design
  7. Verilog Tasks verstehen: Functions vs. Tasks, Syntax und Verwendung
  8. Inter- und Intra-Assignment Delays in Verilog verstehen
  9. Gate Delays in Verilog verstehen: Genaues Timing für zuverlässige Digitaldesigns
  10. Verilog Clock Generator: Design & Implementierungsleitfaden