Verilog-module-instanties
Zoals we in een vorig artikel zagen, worden grotere en complexere ontwerpen gebouwd door meerdere modules op een hiërarchische manier te integreren. Modules kunnen worden geïnstantieerd binnen andere modules en poorten van deze instanties kan worden verbonden met andere signalen in de oudermodule.
Deze poortverbindingen kunnen worden gedaan via een geordende lijst of op naam.
Poortverbinding volgens geordende lijst
Een methode om de verbinding te maken tussen de poortuitdrukkingen die in een module-instantiatie worden vermeld met de signalen in de bovenliggende module is door de geordende lijst .
mijndesign is een module
geïnstantieerd met de naam d0 in een andere module genaamd tb_top. Poorten worden aangesloten in een bepaalde volgorde die wordt bepaald door de positie van die poort in de poortlijst van de moduledeclaratie. Zo is b in de testbench verbonden met y van het ontwerp, simpelweg omdat beide op de tweede positie in de lijst met poorten staan.
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
Volgorde van poorten in de ontwerpmodule moet bekend zijn voor een correcte aansluiting.
Dit is erg onhandig omdat de volgorde kan veranderen als er een nieuwe poort aan de lijst wordt toegevoegd of als het aantal poorten in het ontwerp erg groot is.
Poortverbinding op naam
Een betere manier om poorten aan te sluiten is door poorten aan beide zijden expliciet te koppelen met hun poortnaam .
De punt .
geeft aan dat de poortnaam na de punt bij het ontwerp hoort. De signaalnaam waarop de ontwerppoort moet worden aangesloten, staat hierna tussen haakjes ( )
.
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
Het wordt aanbevolen om elke poortverbinding in een aparte regel te coderen, zodat een compilatiefoutbericht correct verwijst naar het regelnummer waar de fout is opgetreden. Dit is veel gemakkelijker te debuggen en op te lossen dan niet te weten welke poort de fout heeft veroorzaakt als ze allemaal in dezelfde regel hadden gestaan.
Omdat deze verbindingen bij naam worden gemaakt, is de volgorde waarin ze verschijnen niet relevant. Poortverbindingen met meerdere module-instanties zijn niet toegestaan.
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
Niet-verbonden/zwevende poorten
Poorten die niet zijn aangesloten op een draad in de instantiërende module, hebben een hoge impedantie.
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
Voorbeeld
Laten we het voorbeeld van het schuifregister nemen dat we eerder hadden gezien, en sommige poorten niet aangesloten laten.
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
Merk op dat de uitgangen van de instanties u1 en u2 niet zijn aangesloten in het RTL-schema dat na synthese is verkregen. Omdat de invoer d naar instanties u2 en u3 nu verbonden zijn met netten die nergens door worden aangedreven, is deze geaard.
In simulaties worden dergelijke niet-verbonden poorten aangeduid als hoge impedantie ('hZ), meestal weergegeven in golfvormen als een oranje lijn die verticaal in het midden is uitgelijnd.
Alle poortdeclaraties worden impliciet gedeclareerd als wire
en dus is de poortrichting in dat geval voldoende. Maar output
poorten die waarden moeten opslaan, moeten worden gedeclareerd als reg
gegevenstype en kan worden gebruikt in een procedureel blok zoals always
en initial
alleen.
Poorten van het type input
of inout
kan niet worden gedeclareerd als reg
omdat ze continu van buitenaf worden aangestuurd en geen waarden moeten opslaan, maar de veranderingen in de externe signalen zo snel mogelijk moeten weerspiegelen. Het is volkomen legaal om twee poorten met verschillende vectorgroottes aan te sluiten, maar de poort met een lagere vectorgrootte prevaleert en de resterende bits van de andere poort met een grotere breedte worden genegeerd.
// 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