Instanziierungen des Verilog-Moduls
Wie wir in einem früheren Artikel gesehen haben, werden größere und komplexe Designs erstellt, indem mehrere Module hierarchisch integriert werden. Module können instanziiert werden innerhalb anderer Module und Ports dieser Instanzen kann mit anderen Signalen innerhalb des übergeordneten Moduls verbunden werden.
Diese Portverbindungen können über eine geordnete Liste oder nach Namen erfolgen.
Portverbindung nach geordneter Liste
Eine Methode, um die Verbindung zwischen den Portausdrücken, die in einer Modulinstanziierung aufgeführt sind, mit den Signalen innerhalb des übergeordneten Moduls herzustellen, ist die geordnete Liste .
meindesign ist ein module
mit dem Namen d0 in einem anderen Modul namens tb_top instanziiert. Ports werden in einer bestimmten Reihenfolge verbunden, die durch die Position dieses Ports in der Portliste der Moduldeklaration bestimmt wird. Zum Beispiel ist b in der Testbench einfach mit y des Designs verbunden, weil beide an zweiter Stelle in der Liste der Ports stehen.
module mydesign ( input x, y, z, // x is at position 1, y at 2, x at 3 and
output o); // o is at position 4
endmodule
module tb_top;
wire [1:0] a;
wire b, c;
mydesign d0 (a[0], b, a[1], c); // a[0] is at position 1 so it is automatically connected to x
// b is at position 2 so it is automatically connected to y
// a[1] is at position 3 so it is connected to z
// c is at position 4, and hence connection is with o
endmodule
Die Reihenfolge der Ports im Designmodul sollte für eine korrekte Verbindung bekannt sein.
Dies ist sehr unpraktisch, da sich die Reihenfolge ändern kann, wenn ein neuer Port zur Liste hinzugefügt wird oder wenn die Anzahl der Ports im Design sehr groß ist.
Portverbindung nach Name
Ein besserer Weg, Ports zu verbinden, besteht darin, Ports auf beiden Seiten explizit mit ihrem Portnamen zu verknüpfen .
Der Punkt .
gibt an, dass der Anschlussname nach dem Punkt zum Design gehört. In Klammern ( )
steht als nächstes der Signalname, mit dem der Designport verbunden werden soll .
module design_top;
wire [1:0] a;
wire b, c;
mydesign d0 ( .x (a[0]), // signal "x" in mydesign should be connected to "a[0]" in this module (design_top)
.y (b), // signal "y" in mydesign should be connected to "b" in this module (design_top)
.z (a[1]),
.o (c));
endmodule
Es wird empfohlen, jede Portverbindung in einer separaten Zeile zu codieren, damit jede Kompilierungsfehlermeldung korrekt auf die Zeilennummer verweist, in der der Fehler aufgetreten ist. Dies ist viel einfacher zu debuggen und zu beheben als nicht zu wissen, welcher Port den Fehler verursacht hat, wenn sie alle in derselben Zeile gewesen wären.
Da diese Verbindungen namentlich hergestellt werden, ist die Reihenfolge, in der sie erscheinen, irrelevant. Mehrere Modulinstanz-Port-Verbindungen sind nicht zulässig.
module design_top;
mydesign d0 ( .x (a[0]),
.z (a[1]), // z at second position is okay because of explicit connection
.y (a[1]),
.x (b), // illegal - x is already connected to a[0]
.o (c));
endmodule
Nicht verbundene/Floating Ports
Ports, die im Instantiierungsmodul mit keinem Draht verbunden sind, haben einen hochohmigen Wert.
module design_top;
mydesign d0 ( // x is an input and not connected, hence a[0] will be Z
.y (a[1]),
.z (a[1]),
.o ()); // o has valid value in mydesign but since
// it is not connected to "c" in design_top, c will be Z
endmodule
Beispiel
Nehmen wir das Schieberegister-Beispiel, das wir zuvor gesehen haben, und lassen einige Ports unbeschaltet.
module shift_reg ( input d,
input clk,
input 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()); // Output q is left floating
dff u2 (.d(q_net[1]), .clk(clk), .rstn(rstn), .q()); // Output q is left floating
dff u3 (.d(q_net[2]), .clk(clk), .rstn(rstn), .q(q));
endmodule
Beachten Sie, dass die Ausgänge der Instanzen u1 und u2 in dem nach der Synthese erhaltenen RTL-Schema unverbunden bleiben. Da der Eingang d zu den Instanzen u2 und u3 nun mit Netzen verbunden ist, die von nichts angesteuert werden, ist er geerdet.
In Simulationen werden solche nicht angeschlossenen Ports als hohe Impedanz ('hZ) bezeichnet, die in Wellenformen typischerweise als orangefarbene Linie dargestellt wird, die vertikal in der Mitte ausgerichtet ist.
Alle Portdeklarationen werden implizit als wire
deklariert und daher ist die Portrichtung in diesem Fall ausreichend. Jedoch output
Ports, die Werte speichern müssen, sollten als reg
deklariert werden Datentyp und kann in einem Prozedurblock wie always
verwendet werden und initial
nur.
Ports vom Typ input
oder inout
kann nicht als reg
deklariert werden denn sie werden ständig von außen angesteuert und sollen keine Werte speichern, sondern die Änderungen der externen Signale so schnell wie möglich widerspiegeln. Es ist völlig legal, zwei Ports mit unterschiedlichen Vektorgrößen zu verbinden, aber der mit der kleineren Vektorgröße wird sich durchsetzen und die verbleibenden Bits des anderen Ports mit der größeren Breite werden ignoriert.
// Case #1 : Inputs are by default implicitly declared as type "wire"
module des0_1 (input wire clk ...); // wire need not be specified here
module des0_2 (input clk, ...); // By default clk is of type wire
// Case #2 : Inputs cannot be of type reg
module des1 (input reg clk, ...); // Illegal: inputs cannot be of type reg
// Case #3: Take two modules here with varying port widths
module des2 (output [3:0] data, ...); // A module declaration with 4-bit vector as output
module des3 (input [7:0] data, ...); // A module declaration with 8-bit vector as input
module top ( ... );
wire [7:0] net;
des2 u0 ( .data(net) ... ); // Upper 4-bits of net are undriven
des3 u1 ( .data(net) ... );
endmodule
// Case #4 : Outputs cannot be connected to reg in parent module
module top_0 ( ... );
reg [3:0] data_reg;
des2 ( .data(data) ...); // Illegal: data output port is connected to a reg type signal "data_reg"
endmodule
Verilog