Kombinatorische Schaltungen in Verilog beschreiben: Bedingte Operatoren & Always-Blöcke
Dieser Artikel erklärt, wie man kombinatorische Logik in Verilog modelliert, wobei der bedingte Operator für Truth-Table-Implementierung und der mächtige "always"-Block für prägnantes Design behandelt werden.
In diesem Leitfaden gehen wir die Schlüsseltechniken zur Beschreibung kombinatorischer Schaltungen in Verilog durch. Zunächst revisieren wir die Continuous-Assignment-Syntax mit dem assign-Keyword, dann führen wir den bedingten Operator (?:) als prägnante Möglichkeit ein, Multiplexer-Logik auszudrücken. Schließlich zeigen wir, wie der always-Block eine noch klarere, prozedurale Beschreibung bieten kann.
Zuvor haben wir das assign-Keyword für Continuous Assignments behandelt. Diese Anweisungen bleiben aktiv und erlauben uns, eine Gate-Level-Beschreibung einer Schaltung zu erhalten. Zum Beispiel modelliert der folgende Code ein AND-Gatter:
assign out1 = a & b;
Verilogs bedingter Operator ermöglicht eine einzelne Assignment, die ihren Wert basierend auf einer Bedingung ändert. Die Syntax lautet:
assign [signal_name] = [conditional_expression] ? [value_if_true] : [value_if_false];
Der conditional_expression wird zuerst evaluiert. Wenn er wahr ist, wird value_if_true zu signal_name zugewiesen; andernfalls wird value_if_false verwendet. Zum Beispiel:
assign out1 = (sel) ? (a & b) : (a | b);
Wenn sel wahr ist, treibt das AND von a und b out1 an; andernfalls wird das OR von a und b gewählt. Diese einzelne Zeile implementiert einen 2-zu-1-Multiplexer.
Da sich der bedingte Operator wie ein if-Statement in traditioneller Programmierung verhält, ermöglicht er eine abstraktere Darstellung kombinatorischer Logik. Durch Verschachtelung des Operators können Sie komplexe Strukturen aufbauen, wie in Beispiel 1 illustriert.
Beispiel 1: Verschachtelte bedingte Operatoren
Unten ist ein 4-zu-2-Prioritätsencoder, implementiert mit verschachtelten bedingten Operatoren. Die Wahrheitstabelle ist in Abbildung 1 gezeigt.

Der Verilog-Code ist:
module Prio_4_to_2 ( input wire [3:0] x, output wire [1:0] y, output wire v ); assign y = x[3] ? 2'b11 : x[2] ? 2'b10 : x[1] ? 2'b01 : 2'b00; assign v = ( x[3] | x[2] | x[1] | x[0] ) ? 1'b1 : 1'b0; endmodule
Zeilen 7-10 zeigen den verschachtelten bedingten Operator. Jede Bedingung wird sequenziell evaluiert, was früheren Begriffen höhere Priorität gibt – perfekt für Prioritätslogik. Das finale assign für v verwendet ein bitweises OR, um anzuzeigen, ob irgendein Eingang high ist.
Simulationsergebnisse von Xilinx ISE bestätigen das Verhalten (Abbildung 2).

Abbildung 2. Xilinx ISE Simulation des Prioritätsencoders.
Es ist essenziell zu beachten, dass der bedingte Ausdruck in Reihenfolge evaluiert wird, bis eine wahre Bedingung gefunden wird; der entsprechende Wert wird dann zugewiesen. Folglich ist dieses Konstrukt am besten für Prioritätsnetzwerke (Abbildung 3) geeignet als für balancierte Multiplexer (Abbildung 4).

Abbildung 3. Ein Prioritätsnetzwerk.

Abbildung 4. Ein n-zu-1-Multiplexer ohne Eingangspriorität.
In einem früheren Artikel haben wir VHDL-Concurrent-Assignments diskutiert; die Konzepte übertragen sich ähnlich auf Verilog.
Verilog-Prozedurale Statements
Während assign und bedingte Operatoren für viele Designs ausreichen, bietet der always-Block einen ausdrucksstärkeren, prozeduralen Ansatz. Innerhalb eines always-Blocks werden Statements sequenziell ausgeführt und können High-Level-Konstrukte wie if und case enthalten, die dem natürlichen Fluss menschlichen Denkens entsprechen.
Beispiel 2 demonstriert einen grundlegenden always-Block, der ein einfaches AND-Gatter implementiert.
Beispiel 2: "Always"-Block-Statements
Die vereinfachte Syntax eines always-Blocks ist:
always @(sensitivity_list) begin sequential_statements; end
Die sensitivity_list spezifiziert, wann der Block re-evaluiert werden soll. Für eine rein kombinatorische Schaltung müssen alle Eingangssignale in dieser Liste erscheinen.
Betrachten Sie die Schaltung in Abbildung 5, wo sich der Output ändert, wann immer a oder b toggelt.

Abbildung 5. Schaltung_1
Der folgende always-Block implementiert die AND-Operation mit einer blocking Assignment:
always @(a, b) begin out1 = a & b; end
Blocking Assignments (=) aktualisieren die linke Seite sofort, während non-blocking Assignments (<=) das Update bis zum Ende des Blocks verzögern. Für kombinatorische Logik ist es am sichersten, blocking Assignments zu verwenden, um unbeabsichtigte Race Conditions zu vermeiden.
Da ein prozeduraler Block keinen wire treiben kann, muss der Output als reg deklariert werden, was ein Speicherelement inferieren kann oder nicht. Das vollständige Modul ist unten gezeigt:
module Circuit_1 ( input wire a, input wire b, output reg out1 ); always @(a, b) begin out1 = a & b; end endmodule
Zusammenfassend deckte dieser Artikel den bedingten Operator für kompakte Truth-Table-Logik, verschachtelte Operatoren für Prioritätskodierung und den prozeduralen always-Block für klarere kombinatorische Beschreibungen ab. Zukünftige Posts werden die Verwendung von always für sequentielle Logik untersuchen.
Eingebettet
- Verilog Grundlagen: Ihr erstes AND-Gate designen
- Grundlagen von Gleichstromkreisen: Gleichstrom und zentrale elektrische Konzepte verstehen
- Wechselstromkreise verstehen: Einsteiger-Leitfaden
- Vierstellige 7-Segment-Anzeige mit einem einzelnen Binär-Encoder designen
- Steuerschaltungen: Grundlagen, Anwendungen und Best Practices
- C# Operatoren – Umfassender Leitfaden zu Operatoren in C#
- C# Ternärer Operator: Knapper Leitfaden zu bedingten Ausdrücken
- Verilog meistern: Komplettes Tutorial für digitales Schaltungsdesign
- Verilog Concatenation meistern: Praktischer Leitfaden
- Verilog `ifdef: Bedingte Kompilierung erklärt