Wie der Name schon sagt, ermöglichen nicht blockierende Zuweisungen die gleichzeitige Ausführung, während blockierende Zuweisungen sequenziell ausgeführt werden.
Nehmen Sie zum Beispiel Nandlands Erklärung:
In C: „Die zweite Zeile darf erst ausgeführt werden, wenn die erste Zeile vollständig ist.“ Dies wird als Beispiel oder Analogie zum Blockieren von Anweisungen in HDL verwendet.
Er verwendet dann ein Beispiel von 3 nicht blockierenden vs. 3 blockierenden Anweisungen innerhalb eines Always-Blocks, sagt jedoch, dass es 3 Taktzyklen dauern wird, bis das nicht blockierende Beispiel die dritte Anweisung ausführt, während die blockierenden Zuweisungen ihren Wert „sofort“ an das nächste Register übertragen .
always @(posedge i_clock)
begin
r_Test_1 <= 1'b1;
r_Test_2 <= r_Test_1;
r_Test_3 <= r_Test_2;
end
// versus:
always @(posedge i_clock)
begin
r_Test_1 = 1'b1;
r_Test_2 = r_Test_1;
r_Test_3 = r_Test_2;
end
Es scheint mir, als sollten ihre Namen ausgetauscht werden. Wo ist mein Denkfehler? Warum die Zuweisungen in der sequentiellen Logik nicht blockierend nennen , wenn sequentielle Anweisungen offensichtlich die Ausführung nachfolgender Anweisungen blockieren , da es sich um SEQUENTIAL-Anweisungen handelt?
Nicht die Aufgabenstellung wird „blockiert“, sondern die Auswertung der Aussagen innerhalb des Prozesses.
Zunächst einmal werden in beiden Fällen alle Anweisungen bei jedem Taktzyklus ausgewertet. Aber wie in einem Kommentar erwähnt, dauert es bei einer nicht blockierenden Zuweisung drei Taktzyklen, bevor der Wert zum letzten Register gelangt.
Bei einer nicht blockierenden Zuweisung können die drei Anweisungen gleichzeitig (z. B. in Hardware) oder in beliebiger Reihenfolge ausgeführt werden und erzeugen immer das gleiche Ergebnis. Die Bewertung einer Aussage „blockiert“ nicht die Bewertung der anderen.
Bei der blockierenden Zuweisung müssen die Zuweisungen genau wie im C-Code in der Reihenfolge ausgeführt werden, in der sie erscheinen. Jede Anweisung "blockiert" die Ausführung der nachfolgenden Anweisungen.
Warum erscheint die Zuweisung „nicht blockierend“ in Verilog wie eine Fehlbezeichnung?
Weil es eine falsche Bezeichnung ist .
Der Begriff Non-Blocking wurde als logisches Gegenstück zur früheren Fehlbezeichnung Blockierung geschaffen .
Bessere Begriffe für Blockierung und Nichtblockierung wären geordnete Auswertung und ungeordnete Auswertung oder Serienauswertung und parallele Auswertung .
Aber dann gibt es eine grausame Wendung: Die geordnete Auswertung wird als Parallelschaltung synthetisiert, während die ungeordnete Auswertung als Reihenschaltung synthetisiert wird.
Fehlbezeichnung „blockieren“. | „Non-Blocking“-Antonym-Fehlbezeichnung |
---|---|
Geordnete Auswertung (Quellcode-Reihenfolge) | Ungeordnete Auswertung (Reihenfolge bestimmt durch Simulator) |
Reihenauswertung (Quellcode-Reihenfolge) | Parallele Auswertung (Reihenfolge bestimmt durch Simulator) |
Parallele Synthese | Seriensynthese |
Hier ist ein Verilog-Beispiel, das ich mit Quartus synthetisiert habe.
module BlockingNonBlocking
(
input wire clock,
input wire data,
output reg R1,
output reg R2,
output reg R3,
output reg R4,
output reg R5,
output reg R6
);
// "Blocking" misnomer
// Ordered evaluation (source-code order)
// Series evaluation (source-code order)
// Parallel synthesis
always @(posedge clock)
begin
R1 = data;
R2 = R1;
R3 = R2;
end
// "Non-Blocking" antonym misnomer
// Unordered evaluation (order determined by simulator)
// Parallel evaluation (order determined by simulator)
// Series synthesis
always @(posedge clock)
begin
R4 <= data;
R5 <= R4;
R6 <= R5;
end
endmodule
Abbildung 1 – Blockierende versus nicht-blockierende Synthese.
Wie man sieht, blockieren beide Varianten (im wahrsten Sinne des Wortes) das data
Signal bis zur positiven Flanke von clock
, was bedeutet, dass beides sequentielle Schaltungen sind, aber R1, R2 und R3 parallel sind, während R4, R5 und R6 in sind Serie.
Die Begriffe Blockieren und Nicht-Blockieren haben mehr mit der Semantik der Ausführung von Simulationsprozessen zu tun als mit der Synthese. Leider ist Block auch ein Homonym für eine zusammenhängende Gruppierung oder einen zusammenhängenden Bereich (ein begin
/ end
-Block von Anweisungen).
Sowohl blockierende als auch nicht blockierende Zuweisungen sind prozedurale Anweisungen, die im Rahmen eines begin/end
Prozesses sequentiell ausgeführt werden. Beide Anweisungen werten den Ausdruck auf der rechten Seite aus, wenn sie auftreten, aber der Unterschied zwischen ihnen wird besser mit Verzögerungen innerhalb der Zuweisung angezeigt:
initial begin
#10
b = #5 a;
c = #5 b;
end
initial begin
#10
b <= #5 a;
c <= #5 b;
end
Beide initial
Prozesse beginnen zum Zeitpunkt 0 und verzögern sich dann um 10 Zeiteinheiten. Beide Zuweisungsanweisungen werten den Wert von a
zum Zeitpunkt 10 aus. Aber die erste blockierende Zuweisung setzt den Prozess für 5 Zeiteinheiten aus, aktualisiert sich nicht b
bis zum Zeitpunkt 15 und beginnt nicht mit der Ausführung der zweiten blockierenden Zuweisung bis zum Zeitpunkt 15. Sie unterbricht auch den initial
Prozess und wird erst c
zum Zeitpunkt 20 aktualisiert, wenn der erste initial
Prozess endet.
Die erste nicht blockierende Zuweisung im zweiten initial
Prozess plant und aktualisiert zum b
Zeitpunkt 15, setzt den Prozess jedoch nicht aus. Die zweite nicht blockierende Zuweisung wird also b
zum Zeitpunkt 10 ausgewertet, was ihr "alter" Wert ist. Es plant eine Aktualisierung mit c
dem alten Wert von b
zum Zeitpunkt 15. Der zweite initial
Prozess endet zum Zeitpunkt 10.
Übrigens sehen Sie selten blockierende Zuweisungen mit Verzögerungen innerhalb der Zuweisung. Es ist ein Überbleibsel aus dem sehr frühen Verilog, bevor nicht-blockierende Zuweisungen (von mir) in die Sprache eingeführt wurden.
Matte
Andreas
DonFusili
user_1818839
Mitu Raj
Onkel Dino