Warum erscheint die Zuweisung „nicht blockierend“ in Verilog wie eine Fehlbezeichnung?

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?

"Es dauert 3 Taktzyklen, bis das nicht blockierende Beispiel die dritte Anweisung ausführt" - ich glaube nicht, dass das die richtige Interpretation ist. Es dauert 3 Zyklen, bis der Wert an Test_3 weitergegeben wird, was nicht dasselbe ist.
Nun, wenn wir die 3. Anweisung als r_Test_3 <= r_Test_2; dann bin ich mir nicht sicher, warum Sie denken, dass dies eine fehlerhafte Interpretation ist, da es sicherlich 3 Taktflanken dauert, bis der Wert der ersten Anweisung an die letzte weitergegeben wird. Ergo wirken die Zwischenaussagen „blockierend“
@Andrew, denn wenn Sie den Wert von r_Test_1 auch in jedem Taktzyklus umschalten, ändert sich r_Test_3 in jedem Taktzyklus im stationären Zustand. "Es dauert 3 Taktzyklen, bis die dritte Anweisung ausgeführt wird" impliziert, dass dies unmöglich wäre.
Synthetisieren Sie beide und beachten Sie die maximale Taktrate. Sie werden feststellen, dass einer schneller getaktet werden kann als der andere.
Wenn Sie sich Sorgen wegen des Begriffs „Blockierung“ machen: In diesem speziellen Fall wird die Zuweisung von Test3 „blockiert“, bis Test2 ausgewertet wird, dessen Zuweisung blockiert ist, bis Test1 ausgewertet wird.
Äh, schon wieder diese Frage. Es scheint, als wäre dies einer der verwirrendsten Teile von Verilog. Ich rate Ihnen, ein Netzlisten-Anzeigetool zu verwenden, um das Blockdiagramm zu zeichnen, da es auf diese Weise einfacher zu verstehen ist.

Antworten (3)

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

Blockierende versus nicht-blockierende Synthese

Abbildung 1 – Blockierende versus nicht-blockierende Synthese.

Wie man sieht, blockieren beide Varianten (im wahrsten Sinne des Wortes) das dataSignal 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.

Beste Erklärung, die ich je zu diesem Thema gesehen habe, zumindest für mich.
wirklich fantastisch! Ich würde dies gerne zur akzeptierten Antwort machen, aber ich fühle mich schlecht, wenn ich sie von Dave nehme, da ich sie ihm bereits gegeben habe. Die visuelle Darstellung des synthetisierten Ergebnisses ist absolut aufschlussreich. Danke schön!

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/endProzesses 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 initialProzesse beginnen zum Zeitpunkt 0 und verzögern sich dann um 10 Zeiteinheiten. Beide Zuweisungsanweisungen werten den Wert von azum Zeitpunkt 10 aus. Aber die erste blockierende Zuweisung setzt den Prozess für 5 Zeiteinheiten aus, aktualisiert sich nicht bbis zum Zeitpunkt 15 und beginnt nicht mit der Ausführung der zweiten blockierenden Zuweisung bis zum Zeitpunkt 15. Sie unterbricht auch den initialProzess und wird erst czum Zeitpunkt 20 aktualisiert, wenn der erste initialProzess endet.

Die erste nicht blockierende Zuweisung im zweiten initialProzess plant und aktualisiert zum bZeitpunkt 15, setzt den Prozess jedoch nicht aus. Die zweite nicht blockierende Zuweisung wird also bzum Zeitpunkt 10 ausgewertet, was ihr "alter" Wert ist. Es plant eine Aktualisierung mit cdem alten Wert von bzum Zeitpunkt 15. Der zweite initialProzess 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.