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

Verilog Blocking vs. Non-Blocking: Wichtige Unterschiede erklärt

Blocking Assignments

Blocking-Zuweisungen verwenden das Symbol = und werden in einem prozeduralen Block nacheinander ausgeführt. Dies verhindert jedoch nicht die Ausführung von Anweisungen, die in einem parallelen Block laufen.

module tb;
  reg [7:0] a, b, c, d, e;
  initial begin
    a = 8'hDA;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    b = 8'hF1;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    c = 8'h30;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
  end
  initial begin
    d = 8'hAA;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
    e = 8'h55;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
  end
endmodule

Beachten Sie, dass es zwei initial-Blöcke gibt, die parallel ausgeführt werden, wenn die Simulation startet. Anweisungen werden in jedem Block sequenziell ausgeführt und beide Blöcke enden zur Zeit 0ns. Genauer gesagt: Variable a wird zuerst zugewiesen, gefolgt von der Display-Anweisung, dann allen anderen Anweisungen. Dies ist in der Ausgabe sichtbar, wo Variable b und c im ersten $display noch 8'hxx sind. Dies liegt daran, dass die Zuweisungen an b und c noch nicht ausgeführt wurden, als der erste $display aufgerufen wird.

Simulationslog:

ncsim> run
[0] a=0xda b=0xx c=0xx
[0] a=0xda b=0xf1 c=0xx
[0] a=0xda b=0xf1 c=0x30
[0] d=0xaa e=0xx
[0] d=0xaa e=0x55
ncsim: *W,RNQUIE: Simulation is complete.

Im nächsten Beispiel fügen wir ein paar Delays in dieselbe Anweisungsmenge ein, um zu sehen, wie es sich verhält.

module tb;
  reg [7:0] a, b, c, d, e;
  initial begin
    a = 8'hDA;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    #10 b = 8'hF1;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    c = 8'h30;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
  end
  initial begin
    #5 d = 8'hAA;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
    #5 e = 8'h55;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
  end
endmodule

Simulationslog:

ncsim> run
[0] a=0xda b=0xx c=0xx
[5] d=0xaa e=0xx
[10] a=0xda b=0xf1 c=0xx
[10] a=0xda b=0xf1 c=0x30
[10] d=0xaa e=0x55
ncsim: *W,RNQUIE: Simulation is complete.

Non-Blocking Assignments

Non-blocking-Zuweisungen erlauben es, Zuweisungen zu planen, ohne die Ausführung nachfolgender Anweisungen zu blockieren, und werden durch das Symbol <= spezifiziert. Interessanterweise wird dasselbe Symbol als relationaler Operator in Ausdrücken und als Zuweisungsoperator im Kontext einer Non-Blocking-Zuweisung verwendet. Wenn wir das erste Beispiel von oben nehmen und alle =-Symbole durch den Non-Blocking-Zuweisungsoperator <= ersetzen, sehen wir Unterschiede in der Ausgabe.

module tb;
  reg [7:0] a, b, c, d, e;
  initial begin
    a <= 8'hDA;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    b <= 8'hF1;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    c <= 8'h30;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
  end
  initial begin
    d <= 8'hAA;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
    e <= 8'h55;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
  end
endmodule

Man sieht, dass alle $display-Anweisungen 'h'x ausgaben. Der Grund für dieses Verhalten liegt in der Art, wie Non-Blocking-Zuweisungen ausgeführt werden. Die RHS jeder Non-Blocking-Anweisung eines bestimmten Zeitschritts wird erfasst, und es wird zur nächsten Anweisung übergegangen. Der erfasste RHS-Wert wird der LHS-Variable erst am Ende des Zeitschritts zugewiesen.

Simulationslog:

ncsim> run
[0] a=0xx b=0xx c=0xx
[0] a=0xx b=0xx c=0xx
[0] a=0xx b=0xx c=0xx
[0] d=0xx e=0xx
[0] d=0xx e=0xx
ncsim: *W,RNQUIE: Simulation is complete.

Wenn wir den Ausführungsfluss des obigen Beispiels aufschlüsseln, erhalten wir etwa Folgendes:

|__ Spawn Block1: initial
| |___ Zeit #0ns: a <= 8'DA, non-blocking, also RHS-Wert (8'hDA) merken und nächsten Schritt ausführen
| |___ Zeit #0ns: $display() ist blocking, also diese Anweisung ausführen: Aber a hat noch keine neuen Werte, also a=8'hx
| |___ Zeit #0ns: b <= 8'F1, non-blocking, also RHS-Wert (8'hF1) merken und nächsten Schritt ausführen
| |___ Zeit #0ns: $display() ist blocking, ausführen. Aber b hat noch keine neuen Werte, also b=8'hx
| |___ Zeit #0ns: c <= 8'30, non-blocking, also RHS-Wert (8'h30) merken und nächsten Schritt ausführen
| |___ Zeit #0ns: $display() ist blocking, ausführen. Aber c hat noch keine neuen Werte, also c=8'hx
| |___ Ende des Zeitschritts und initial-Block, erfasste Werte in Variablen a, b, c zuweisen
|__ Spawn Block2: initial
| |___ Zeit #0ns: d <= 8'AA, non-blocking, also RHS-Wert (8'hAA) merken und nächsten Schritt ausführen
| |___ Zeit #0ns: $display() ist blocking, ausführen: Aber d hat noch keine neuen Werte, also d=8'hx
| |___ Zeit #0ns: e <= 8'55, non-blocking, also RHS-Wert (8'h55) merken und nächsten Schritt ausführen
| |___ Zeit #0ns: $display() ist blocking, ausführen. Aber e hat noch keine neuen Werte, also e=8'hx
| |___ Ende des Zeitschritts und initial-Block, erfasste Werte in Variablen d und e zuweisen
|__ Ende der Simulation bei #0ns

Als Nächstes verwenden wir das zweite Beispiel und ersetzen alle Blocking-Anweisungen durch Non-Blocking.

module tb;
  reg [7:0] a, b, c, d, e;
  initial begin
    a <= 8'hDA;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    #10 b <= 8'hF1;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
    c <= 8'h30;
    $display ("[%0t] a=0x%0h b=0x%0h c=0x%0h", $time, a, b, c);
  end
  initial begin
    #5 d <= 8'hAA;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
    #5 e <= 8'h55;
    $display ("[%0t] d=0x%0h e=0x%0h", $time, d, e);
  end
endmodule

Auch hier sehen wir, dass die Ausgabe anders ist als zuvor.

Simulationslog:

ncsim> run
[0] a=0xx b=0xx c=0xx
[5] d=0xx e=0xx
[10] a=0xda b=0xx c=0xx
[10] a=0xda b=0xx c=0xx
[10] d=0xaa e=0xx
ncsim: *W,RNQUIE: Simulation is complete.

Wenn wir den Ausführungsfluss aufschlüsseln, erhalten wir etwa Folgendes:

|__ Spawn Block1 bei #0ns: initial
| |___ Zeit #0ns: a <= 8'DA, non-blocking, also RHS-Wert (8'hDA) merken und nächsten Schritt ausführen
| |___ Zeit #0ns: $display() ist blocking, ausführen: Aber a hat noch keine neuen Werte, also a=8'hx
| |___ Ende des Zeitschritts: Erfassten Wert der Variable a zuweisen, a ist jetzt 8'hDA
| |___ Warten bis Zeit um 10 Zeiteinheiten auf #10ns fortschreitet
| | |___ Zeit #10ns: b <= 8'F1, non-blocking, also RHS-Wert (8'hF1) merken und nächsten Schritt ausführen
| |___ Zeit #10ns: $display() ist blocking, ausführen. Aber b hat noch keine neuen Werte, also b=8'hx
| |___ Zeit #10ns: c <= 8'30, non-blocking, also RHS-Wert (8'h30) merken und nächsten Schritt ausführen
| |___ Zeit #10ns: $display() ist blocking, ausführen. Aber c hat noch keine neuen Werte, also c=8'hx
| |___ Ende des Zeitschritts und initial-Block, erfasste Werte in Variablen b, c zuweisen
|__ Spawn Block2 bei #0ns: initial
| |___ Warten bis Zeit um 5 Zeiteinheiten auf #5ns fortschreitet
| | |___ Zeit #5ns: d <= 8'AA, non-blocking, also RHS-Wert (8'hAA) merken und nächsten Schritt ausführen
| |___ Zeit #5ns: $display() ist blocking, ausführen: Aber d hat noch keine neuen Werte, also d=8'hx
| |___ Ende des Zeitschritts: Erfassten Wert der Variable d zuweisen, d ist jetzt 8'hAA
| |___ Warten bis Zeit um 5 Zeiteinheiten auf #5ns fortschreitet
| | |___ Zeit #10ns: e <= 8'55, non-blocking, also RHS-Wert (8'h55) merken und nächsten Schritt ausführen
| |___ Zeit #10ns: $display() ist blocking, ausführen. Aber e hat noch keine neuen Werte, also e=8'hx
| |___ Ende des Zeitschritts und initial-Block, erfasste Werte der Variable e zuweisen, e ist jetzt 8'h55
|__ Ende der Simulation bei #10ns

Verilog

  1. Verilog meistern: Komplettes Tutorial für digitales Schaltungsdesign
  2. Verilog Concatenation meistern: Praktischer Leitfaden
  3. Verilog Functions meistern für effizientes RTL-Design
  4. Verilog Tasks verstehen: Functions vs. Tasks, Syntax und Verwendung
  5. Verilog Clock Generator: Design & Implementierungsleitfaden
  6. Verilog Math Functions meistern für effizientes Hardware-Design
  7. Verilog $timeformat meistern: Präzision und Anzeigesteuerung
  8. Verilog Timescales an jedem Scope verstehen und ausgeben
  9. Datei-E/A in Verilog meistern: Öffnen, Lesen, Schreiben und Schließen
  10. Verilog für Einsteiger: Hello-World-Beispiel