Menu

Verilog Vektoren und Arrays: Mehrbittige Signale erklärt

Wie du mehrbittige Signale mit [7:0] deklarierst, in Slices zerlegst, kombinierst und der Unterschied zwischen einem packed-Vektor und einem Memory-Array.

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

Eine Leitung vs viele

Bisher war jedes Signal, das wir gesehen haben, ein Bit breit. Echte Designs sehen fast nie so aus - Adressen sind 16 oder 32 Bit, Datenbusse 8 oder 64, RGB-Pixel 24. Verilog gibt dir einen einzigen Mechanismus, jedes Signal mehrbittig zu machen: Bereich in eckigen Klammern hinzufügen.

wire [7:0] data;       // 8-Bit-wire, Bit 7 ist MSB, Bit 0 ist LSB
reg  [15:0] address;   // 16-Bit-reg
output reg [31:0] result; // 32-Bit-Modul-Ausgang

Die Zahlen in den Klammern sind die Bit-Positionen des höchst- und niedrigstwertigen Bits. [7:0] heißt "dieses Signal hat Bits von 7 hinab bis 0", was 8 Bit insgesamt sind. Die erste Zahl ist der High-Index. Die zweite der Low.

Du wirst gelegentlich [0:7] sehen - gleiche Bitanzahl, andere Endianness fürs Slicen. Die [high:low]-Form ist die überwiegende Industrie-Konvention; bleib dabei, außer du hast einen starken Grund dagegen.

Ein durchgearbeitetes Beispiel: Ein 8-Bit-Addierer

Jedes + addiert die beiden 8-Bit-Vektoren und liefert ein 9-Bit-Ergebnis. Die Zahlen-Literale wie 8'd10 heißen "ein 8-Bit-breiter Dezimalwert von 10" - wir behandeln sie in Zahlen-Literale.

Slicen: Bits herauspicken

Sobald du einen Vektor hast, kannst du einzelne Bits oder zusammenhängende Bereiche herausziehen:

Lass dich nicht von der force-Zeile der Testbench irritieren - wir brauchen nur einen Weg, einen Wert zu injizieren, um das Slicing zu demonstrieren. Interessant sind die Slices selbst.

Ein paar Regeln:

  • Die Slice-Richtung muss zur Deklaration passen. Hast du [7:0] deklariert, slice mit [high:low]. Die Richtung umzudrehen ist ein Syntaxfehler.
  • Außerhalb des Bereichs slicen ergibt in der Simulation x (unknown). Das Synthese-Tool warnt oder bricht ab.
  • Bit-Auswahl ist null-basiert auf dem Index, den du geschrieben hast - data[0] ist das Bit namens 0, was (bei einer [7:0]-Deklaration) das LSB ist.

Variable-Basis-Slices: +: und -:

Ein häufiger Bedarf: "Gib mir 8 Bit ab Bit N." Du kannst data[N+7:N] nicht direkt schreiben, weil Verilog beide Enden des Bereichs als Konstanten verlangt. Die Syntax, die das löst:

data[base +: width]   // width Bits ab `base`, AUFWÄRTS
data[base -: width]   // width Bits ab `base`, ABWÄRTS

Die Breite ist konstant (wir wählen je 8 Bit), aber die Basis kann ein Laufzeit-Ausdruck sein. Genau das brauchst du für byteadressierbare Speicher, Schieberegister-Taps und so weiter.

Arrays: Ein Schritt jenseits von Vektoren

Ein Vektor ist ein einzelnes mehrbittiges Signal. Ein Array ist eine Sammlung von Vektoren, unabhängig indizierbar:

reg [31:0] mem [0:1023];

Diese Deklaration hat zwei Bereiche, und die beiden bedeuten Unterschiedliches:

  • [31:0] ist die packed-Dimension - die Breite jedes einzelnen Worts.
  • [0:1023] ist die unpacked-Dimension - wie viele Wörter es gibt.

Also ist mem 1024 separate 32-Bit-Register. Du sprichst eines mit einem einzelnen Index an:

mem[5] = 32'hCAFE_BABE;       // Wort 5 schreiben
data   = mem[address];        // das Wort bei `address` lesen

Das ist ein winziger Speicher, der Quadrate hält. Echte Designs nutzen dasselbe Muster für Register-Files, Lookup-Tabellen, FIFOs und jeden On-Chip-Speicher, der größer als ein einzelner Vektor ist.

Packed vs Unpacked: Warum es wichtig ist

Die Trennung zwischen packed- und unpacked-Dimensionen taucht überall auf. Zu wissen, was was ist, spart viel Debugging:

  • Ein packed-Vektor ist ein Signal. Du kannst es als Zahl behandeln: data + 1 funktioniert, data == 32'h0 funktioniert, data[7:0] funktioniert.
  • Ein unpacked-Array sind viele Signale. Du kannst es nicht als Zahl behandeln: mem + 1 ist ein Syntaxfehler. Du musst erst ein bestimmtes Wort herausgreifen.

Mehrere packed-Dimensionen sind ebenfalls erlaubt:

reg [3:0][7:0] regs;   // 4 Bytes zusammengepackt zu einem 32-Bit-Signal

regs[0] ist ein Byte (das untere Byte). regs als Ganzes sind 32 Bit. SystemVerilog nutzt das stark.

Mehrere unpacked-Dimensionen erzeugen einen 2D-Speicher:

reg [31:0] frame [0:479][0:639];  // 480x640 mit 32-Bit-Pixeln

Ein einzelnes Pixel sprichst du mit frame[y][x] an. So sähe ein Bildpuffer in HDL aus.

Wie es weitergeht

Du kannst jetzt jedes Signal beliebiger Breite deklarieren und manipulieren. Das nächste Doc - Parameter - zeigt, wie du diese Breiten konfigurierbar machst, sodass dasselbe Modul in einer Instanz mit 8 Bit und in einer anderen mit 32 funktioniert. Danach behandeln wir die Regeln zum Schreiben literaler Zahlen (8'b1010_1100, 32'hDEAD_BEEF) und die x/z-Werte, die immer dann auftauchen, wenn etwas nicht getrieben wird.

Häufig gestellte Fragen

Was ist ein Vektor in Verilog?

Ein Vektor ist ein mehrbittiges Signal. Du deklarierst einen, indem du einem wire oder reg einen Bereich hinzufügst: wire [7:0] data ist ein 8-Bit-Wire. Die Zahlen in den Klammern sind die Bit-Positionen - in diesem Fall ist Bit 7 das höchstwertige und Bit 0 das niedrigstwertige. Du kannst einzelne Bits (data[3]) oder zusammenhängende Bereiche (data[7:4]) slicen.

Was bedeutet [7:0] in Verilog?

[7:0] deklariert einen Bereich von Bit 7 hinunter bis Bit 0, inklusive - ein 8-Bit-Signal mit Bit 7 als höchstwertigem Bit. Die erste Zahl ist der High-Index, die zweite ist der Low-Index. Du kannst auch [0:7] für Little-Endian-Indexierung schreiben, aber die [high:low]-Form ist die in der Industrie weit verbreitete Konvention.

Wie slict man Bits in Verilog?

Mit Klammer-Indizierung. data[3] wählt ein einzelnes Bit. data[7:4] wählt die obersten vier Bits als 4-Bit-Vektor. Der Slice muss dieselbe Richtung wie die Deklaration haben - wenn du [7:0] deklariert hast, slice mit [high:low]. SystemVerilog ergänzt zudem data[3 +: 4] für variable-Basis-Slices konstanter Breite.

Was ist der Unterschied zwischen einem packed und einem unpacked Array in Verilog?

Ein packed-Array ist ein einzelner zusammenhängender Bus - reg [31:0] word ist ein 32-Bit-Signal. Ein unpacked-Array (oder 'Memory') ist eine Sammlung unabhängiger Wörter - reg [31:0] mem [0:1023] sind 1024 separate 32-Bit-Register. Du kannst ein ganzes Wort eines unpacked-Arrays lesen oder schreiben, aber nicht auf dem Ganzen wie auf einem einzelnen Signal operieren.

Wie deklariert man Speicher in Verilog?

reg [31:0] mem [0:1023]; deklariert einen Speicher mit 1024 Einträgen, jeder 32 Bit breit. Der erste Satz Klammern ist die Wortbreite (packed); der zweite ist die Anzahl Wörter (unpacked). Ein Eintrag wird mit mem[address] adressiert, und du kannst einen Slice davon mit mem[address][7:0] lesen oder schreiben, sobald SystemVerilog-2005-Indizierung aktiviert ist.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S