Menu

Verilog bitwise- und Reduktions-Operatoren

Die Bit-Level-Operatoren in Verilog - bitweises AND/OR/XOR, die Invertierungsformen und die Reduktionsoperatoren, die einen ganzen Vektor auf ein einziges Bit kollabieren.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Zwei Rollen für dasselbe Symbol

&, |, ^ und ihre invertierten Geschwister tauchen in zwei verschiedenen Formen auf:

  • Binäre Form (zwei Operanden): a & b - bitweise Operation zwischen gleich breiten Vektoren.
  • Unäre Form (ein Operand): &a - Reduktion über alle Bits von a zu einem einzelnen Bit.

Der Compiler unterscheidet sie durch Zählen der Operanden. Die Namenskonvention: "die bitwise-Operatoren" für die binäre Form und "die Reduktions-Operatoren" für die unäre Form.

Bitwise: Ein Bit nach dem anderen

Der volle Satz:

OperatorNameErgebnisbit an Position N
a & bANDa[N] AND b[N]
a | bORa[N] OR b[N]
a ^ bXORa[N] XOR b[N]
a ~& bNANDNOT (a[N] AND b[N])
a ~| bNORNOT (a[N] OR b[N])
a ~^ bXNORNOT (a[N] XOR b[N])
~aNOTNOT a[N]

Beachte: ~&, ~|, ~^ werden mit Tilde zuerst und Operator danach geschrieben. Sie sind ein einzelnes Token; dazwischen darf kein Leerzeichen sein.

Sind die beiden Operanden unterschiedlich breit, wird der schmalere links mit Nullen erweitert. Willst du Vorzeichen-Erweiterung, nutze explizit signed-Operanden mit $signed().

Reduktion: Von vielen Bits zu einem

Die unären Formen derselben Operatoren kollabieren einen Vektor auf ein einzelnes Bit:

Was die einzelnen bedeuten:

  • &data liefert 1, wenn alle Bits von data 1 sind, sonst 0. Nützlich für "ist das nur Einsen?"-Checks.
  • |data liefert 1, wenn irgendein Bit von data 1 ist, sonst 0. Nützlich für "ist das ungleich Null?"-Checks.
  • ^data liefert die Parität - XOR aller Bits. 1, wenn ungerade Anzahl Einsen, 0, wenn gerade.
  • ~&data, ~|data, ~^data sind die Inversen der obigen.

Du siehst sie überall in echtem Code:

wire empty       = ~|fifo_count;       // leer gdw count Null ist
wire all_ones    = &mask;              // alle Bits gesetzt
wire parity_bit  = ^data;              // Parität eines Bytes
wire any_request = |request_vector;    // gibt es irgendeine Anfrage?

Die Reduktionsformen sind knapp und synthetisieren zu offensichtlichen Gatter-Bäumen: & reduziert auf ein Multi-Input-AND-Gatter, | auf ein Multi-Input-OR, ^ auf einen XOR-Baum (was in Hardware auch der Paritätsgenerator ist).

Übliche Muster

Bits setzen und löschen

wire [7:0] data;
wire [7:0] mask = 8'b0000_1000;

wire [7:0] set     = data | mask;     // erzwingt Bit 3 auf 1
wire [7:0] cleared = data & ~mask;    // erzwingt Bit 3 auf 0
wire [7:0] toggled = data ^ mask;     // dreht Bit 3 um
wire [7:0] tested  = data & mask;     // Null, wenn Bit 3 war 0, sonst ungleich Null

Das sind dieselben Bit-Manipulations-Idiome wie in C. Sie synthetisieren zu Operationen mit einem Gatter.

Prüfen, ob ein Wert nur aus Einsen besteht

wire is_max = &counter;       // 1, wenn jedes Bit von counter 1 ist

Ein Reduktions-AND mit einem Gatter, verglichen mit counter == 8'hFF (was ebenfalls funktioniert; Synthesizer erzeugen meist identische Hardware).

Ein Paritätsbit erzeugen

Erkennen, ob irgendein aktives Signal vorliegt

wire any_pending = |request_vector;

Ist request_vector breit (etwa 64 Anfrager), kollabiert das Reduktions-OR es zu einem einzelnen Signal, das du in einen Priority Encoder oder Arbiter füttern kannst.

Shift-Operatoren

Während wir bei Bit-Operatoren sind, die Shifts:

  • a << N schiebt a um N Bitpositionen nach links und füllt rechts mit Nullen.
  • a >> N schiebt a um N Bitpositionen nach rechts und füllt links mit Nullen.
  • a <<< N arithmetischer Linksshift (wie << für Unsigned).
  • a >>> N arithmetischer Rechtsshift - füllt mit dem Vorzeichenbit, wenn a signed ist.

Shifts um eine konstante Zweierpotenz sind in Hardware kostenlos (nur Umverdrahtung). Shifts um eine Laufzeit-Variable erzeugen einen Barrel-Shifter, der größer, aber immer noch günstig ist.

Wie es weitergeht

Du hast jetzt jeden Operator gesehen, der einen Einzelwert liefert. Das nächste Doc - Konkatenation und Replikation - behandelt die {}- und {N{...}}-Syntax, die breitere Vektoren aus Teilen baut und die du ständig brauchst, wenn du Module unterschiedlicher Breite verbindest.

Häufig gestellte Fragen

Was sind bitweise Operatoren in Verilog?

Bitweise Operatoren verknüpfen zwei gleich breite Vektoren positionsweise. a & b AND-verknüpft Bit 0 von a mit Bit 0 von b, Bit 1 mit Bit 1 usw. und liefert einen Vektor derselben Breite wie die Eingänge. Die volle Menge ist & (AND), | (OR), ^ (XOR), ~ (NOT) und die Invertierungsformen ~&, ~|, ~^ (NAND, NOR, XNOR).

Was ist ein Reduktionsoperator in Verilog?

Ein Reduktionsoperator ist eine unäre Form eines bitweisen Operators, die einen ganzen Vektor auf ein einzelnes Bit kollabiert. &data liefert 1 nur, wenn jedes Bit von data 1 ist. |data liefert 1, wenn irgendein Bit 1 ist. ^data liefert das XOR aller Bits - die Parität. Die Reduktionsformen haben keinen Operanden links, nur rechts.

Was ist der Unterschied zwischen & und && in Verilog?

& ist bitweises AND - es paart Bits positionsweise, und das Ergebnis hat dieselbe Breite wie die Operanden. && ist logisches AND - es behandelt jeden Operanden als Boolean (Null vs Nicht-Null) und liefert ein 1-Bit-Ergebnis. 4'b1100 & 4'b0011 ist 4'b0000; 4'b1100 && 4'b0011 ist 1.

Wie berechnet man Parität in Verilog?

Nutze den Reduktions-XOR-Operator: parity = ^data. Er XOR't jedes Bit von data zusammen. Für einen 8-Bit-Vektor ist das data[7] ^ data[6] ^ ... ^ data[0]. Das Ergebnis ist 1, wenn eine ungerade Anzahl an Bits gesetzt ist, 0, wenn gerade. Invertieren mit ~^ ergibt gerade Parität.

Was macht ~ in Verilog?

~ ist bitweises NOT - es invertiert jedes Bit seines Operanden. ~4'b1100 ist 4'b0011. Nicht mit ! (logisches NOT) verwechseln, das den Operanden auf ein 1-Bit-Boolean kollabiert und das invertiert. !4'b1100 ist 1'b0 (der Operand ist ungleich Null, der invertierte Wahrheitswert ergibt 0).

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S