Menu

Verilog Modul-Ports: input, output und inout erklärt

Wie du Modul-Ports deklarierst - input, output und inout - die ANSI-Port-Liste und wann ein output wire und wann reg sein sollte.

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

Die Schnittstelle eines Moduls

Die Port-Liste eines Moduls ist seine Schnittstelle - alles, was die Außenwelt sehen und anfassen kann. Innerhalb des Moduls berechnet der Body Ausgänge aus Eingängen. Die Ports sind die Leitungen, die die Grenze überqueren.

Die moderne ANSI-Deklaration packt Richtung, Typ und Breite direkt in die Port-Liste:

module my_module(
    input  wire        clk,
    input  wire        reset,
    input  wire [7:0]  data_in,
    output reg  [7:0]  data_out,
    output wire        valid
);
    // body
endmodule

Das ist die ganze Form. Jeder Port hat:

  • Eine Richtung: input, output oder inout.
  • Einen Typ: wire oder reg (oder logic in SystemVerilog).
  • Eine Breite: ein Bereich wie [7:0], oder einzelbittig, wenn weggelassen.
  • Einen Namen: den Bezeichner, den du im Body verwendest.

Die drei Richtungen

input - von außen getrieben

Eingänge sind immer wire. Der Treiber liegt außerhalb des Moduls - entweder ein Signal eines übergeordneten Moduls oder ein reg der Testbench. Innerhalb dieses Moduls kannst du Eingänge in Ausdrücken lesen, ihnen aber nie zuweisen:

module reader(input wire [7:0] data);
    initial $display("data = %h", data);
endmodule

data = ... innerhalb des Moduls zu schreiben, wäre ein Fehler.

output - von innen getrieben

Outputs werden von etwas innerhalb dieses Moduls getrieben. Sie können entweder wire sein (getrieben von assign oder vom Output eines Submoduls) oder reg (getrieben aus always/initial).

module driver(
    input  wire       a,
    input  wire       b,
    input  wire       clk,
    output wire       y,    // wire - durch assign getrieben
    output reg        q     // reg  - durch always getrieben
);
    assign y = a & b;       // OK, weil y ein wire ist

    always @(posedge clk)
        q <= a;             // OK, weil q ein reg ist
endmodule

Versuchst du, y innerhalb des always-Blocks zuzuweisen oder q mit einem assign zu treiben, gibt's einen Compile-Fehler. Die Wahl des Schlüsselworts muss zum Treiber passen.

inout - bidirektional

inout-Ports sind Leitungen, die abwechselnd vom Modul oder von dem getrieben werden können, was extern angeschlossen ist. Sie tauchen an Chip-Grenzen auf - I²C-SDA-Leitungen, bidirektionale GPIO-Pins, geteilte Datenbusse. Innerhalb des Moduls steuerst du die Richtung mit einem Tri-State-Muster:

module bidir_pin(
    input  wire data_out,
    input  wire output_enable,
    output wire data_in,
    inout  wire pin
);
    assign pin     = output_enable ? data_out : 1'bz;
    assign data_in = pin;
endmodule

pin ist die geteilte Leitung. Wenn output_enable high ist, treibt das Modul pin auf data_out. Wenn low, gibt es den Pin in High-Impedance (z) frei, damit ein externer Treiber ihn benutzen kann. data_in beobachtet immer das, was gerade am Pin liegt.

inout ist in reiner Internlogik selten. Wenn du einen Speichercontroller, einen CPU-Kern oder eine Bildverarbeitungs-Pipeline baust, brauchst du es vielleicht nie. Es ist ein Feature für den I/O-Ring an Chip-Grenzen.

Einzelbittige vs. mehrbittige Ports

Der Bereich ist optional - lass ihn weg für einen Einzelbit-Port:

input wire valid,         // 1 Bit
input wire [7:0] data,    // 8 Bits
input wire [31:0] addr,   // 32 Bits

Du kannst Parameter für Breiten verwenden, so funktionieren parametrierte Module:

module bus #(
    parameter WIDTH = 32
)(
    input  wire [WIDTH-1:0] in,
    output wire [WIDTH-1:0] out
);
    assign out = in;
endmodule

ANSI- vs Verilog-1995-Stil

Gelegentlich siehst du älteren Code, der Port-Liste und Deklarationen trennt:

// Alter Verilog-1995-Stil - mach das NICHT in neuem Code
module foo(clk, data_in, data_out);
    input clk;
    input [7:0] data_in;
    output reg [7:0] data_out;
    // ...
endmodule

Die Port-Liste enthält nur Namen; jeder Port wird dann separat im Body deklariert. Das ist umständlich, anfällig für "in Port-Liste benannt, aber nie deklariert"-Fehler und doppelte Tipparbeit. Der ANSI-2001-Stil (der in diesen Docs durchgehend gezeigt wird) ersetzt beides:

module foo(
    input  wire       clk,
    input  wire [7:0] data_in,
    output reg  [7:0] data_out
);
    // ...
endmodule

Nimm den ANSI-Stil. Tools unterstützen ihn seit 2001.

Ein vollständiges Beispiel

Dieses eine Modul hat:

  • Einen Parameter (WIDTH).
  • Eingänge für Takt, Reset, Load-Enable, Daten und Shift-Enable.
  • Einen reg-Ausgang (data_out), getrieben in einem always-Block.
  • Einen wire-Ausgang (msb_out), getrieben durch eine kontinuierliche Zuweisung.
  • Eine vollständige ANSI-Deklaration, die Richtung, Typ und Breite jedes Ports direkt auflistet.

So ist fast jedes synthetisierbare Modul aufgebaut, das du schreiben wirst.

Wie es weitergeht

Das nächste Doc - Modul-Instanziierung - zeigt, wie du dieses Modul nimmst und in einem größeren Design einsetzt. Der Shifter, den du gerade geschrieben hast, ist allein nicht nützlich; er verdient sich seinen Lohn, wenn ihn etwas instanziiert und in ein System einbindet.

Häufig gestellte Fragen

Welche drei Port-Richtungen gibt es in Verilog?

input, output und inout. input wird von außen getrieben. output wird von innerhalb des Moduls getrieben. inout ist bidirektional - nützlich für Tri-State-Busse, bei denen das Modul denselben Pin sowohl treibt als auch liest. Die große Mehrheit interner Ports ist input oder output; inout taucht nur an Chip-Pins auf.

Was ist der Unterschied zwischen output wire und output reg?

output wire heißt, der Ausgang wird durch eine kontinuierliche Zuweisung oder durch den Ausgang eines Submoduls getrieben - alles außerhalb eines always-Blocks. output reg heißt, er wird aus einem prozeduralen Block (initial oder always) getrieben. Das Schlüsselwort entscheidet, ob du das Signal aus einem always heraus ansprechen kannst - nicht, ob die synthetisierte Hardware ein Flip-Flop enthält.

Was ist der ANSI-Stil für Verilog-Ports?

Der ANSI-Stil deklariert Richtung und Typ jedes Ports direkt in der Port-Liste: module foo(input wire [7:0] data, output reg [7:0] result);. Der ältere Verilog-1995-Stil führte in der Port-Liste nur Namen auf und re-deklarierte sie im Modul-Body. Nutze in neuem Code immer den ANSI-Stil - er ist kürzer, weniger fehleranfällig und überall modern Standard.

Kann ein Verilog-Modul mehrere Inputs und Outputs haben?

Ja - ein Modul kann beliebig viele Ports in jeder Richtungskombination haben. Trenne sie in der Port-Liste mit Kommas. Die Reihenfolge in der Port-Liste bestimmt die positionsbasierte Verbindungsreihenfolge bei der Instanziierung, aber du verwendest fast immer benannte Verbindungen (.port(signal)), um nicht auf die Reihenfolge angewiesen zu sein.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S