Verilog Modul-Instanziierung meistern: Best Practices für hierarchisches Design
Komplexe Designs entstehen durch hierarchische Integration mehrerer Module. Module werden in anderen Modulen instanziiert; Ports der Instanzen werden mit Signalen im Parent-Modul verbunden.
Zwei Verbindungsmethoden: Geordnete Liste (Ordered List) und Benannte Verbindung (Named Connection).
Port Connection by Ordered List
Verbindung basiert auf Position in der Port-Liste der Modul-Deklaration.
module mydesign (input x, y, z, output o); endmodule
module tb_top;
wire [1:0] a; wire b, c;
mydesign d0 (a[0], b, a[1], c);
// a[0]→x (Pos1), b→y (Pos2), a[1]→z (Pos3), c→o (Pos4)
endmodule
Port Connection by Name (Empfohlen)
Explizite Verknüpfung über Port-Namen. Punkt . kennzeichnet Design-Port, Signalname in Klammern () für Parent-Modul.
module design_top;
wire [1:0] a; wire b, c;
mydesign d0 (
.x (a[0]),
.y (b),
.z (a[1]),
.o (c)
);
endmodule
Best Practice: Jede Port-Verbindung in eigener Zeile → Compiler-Fehlerzeile zeigt genaues Problem. Reihenfolge egal. Mehrfache Verbindungen desselben Ports illegal.
mydesign d0 (
.x (a[0]), .z (a[1]), .y (a[1]), .x (b), // Illegal: x doppelt verbunden
.o (c)
);
Unverbundene / Floating Ports
Nicht verbundene Ports → High-Impedance (Z).
module design_top;
mydesign d0 (
// x (Input) nicht verbunden → a[0] = Z
.y (a[1]), .z (a[1]),
.o () // o hat Wert in mydesign, aber nicht verbunden → c = Z
);
endmodule
Beispiel: Shift-Register mit Floating Outputs
module shift_reg (input d, clk, rstn, output q);
wire [2:0] q_net;
dff u0 (.d(d), .clk(clk), .rstn(rstn), .q(q_net[0]));
dff u1 (.d(q_net[0]), .clk(clk), .rstn(rstn), .q()); // q floating
dff u2 (.d(q_net[1]), .clk(clk), .rstn(rstn), .q()); // q floating
dff u3 (.d(q_net[2]), .clk(clk), .rstn(rstn), .q(q));
endmodule
RTL-Schema: Outputs von u1/u2 unconnected. Inputs d von u2/u3 an undriven Nets → Grounded. Simulation: Unconnected Ports = High-Z (Waveform: orangene vertikale Linie).
Port-Typ-Regeln
- Alle Ports implizit
wire→ Richtung reicht. outputPorts, die Werte speichern müssen →regTyp, nutzbar inalways/initial.input/inoutnicht alsregdeklarierbar (werden extern getrieben, sollen Änderungen sofort reflektieren).- Verschiedene Vektorbreiten verbindbar → kleinere Breite dominiert, höhere Bits ignoriert.
// Case 1: Inputs default wire
module des0_1 (input wire clk); // wire optional
module des0_2 (input clk); // default wire
// Case 2: Inputs NICHT als reg
module des1 (input reg clk); // Illegal!
// Case 3: Unterschiedliche Port-Breiten
module des2 (output [3:0] data);
module des3 (input [7:0] data);
module top;
wire [7:0] net;
des2 u0 (.data(net)); // obere 4 Bits von net undriven
des3 u1 (.data(net));
endmodule
// Case 4: Output NICHT an reg im Parent
module top_0;
reg [3:0] data_reg;
des2 (.data(data_reg)); // Illegal: output port an reg Signal
endmodule
Verilog
- Verilog meistern: Komplettes Tutorial für digitales Schaltungsdesign
- Verilog Concatenation meistern: Praktischer Leitfaden
- Verilog Essentials: Kurzer Überblick
- Verilog Assignments verstehen: Typen, Syntax und Best Practices
- Verilog Blocking vs. Non-Blocking: Wichtige Unterschiede erklärt
- Verilog Functions meistern für effizientes RTL-Design
- Verilog Tasks verstehen: Functions vs. Tasks, Syntax und Verwendung
- Verilogs hierarchischen Referenz-Gültigkeitsbereich meistern: Namenskonflikte in Modulen und Blöcken vermeiden
- Verilog Clock Generator: Design & Implementierungsleitfaden
- Verilog Math Functions meistern für effizientes Hardware-Design