Instanciations de modules Verilog
Comme nous l'avons vu dans un article précédent, les conceptions plus grandes et complexes sont construites en intégrant plusieurs modules de manière hiérarchique. Les modules peuvent être instanciés dans d'autres modules et ports de ces instances peut être connecté à d'autres signaux à l'intérieur du module parent.
Ces connexions de port peuvent se faire via une liste ordonnée ou par nom.
Connexion des ports par liste ordonnée
Une méthode pour établir la connexion entre les expressions de port répertoriées dans une instanciation de module avec les signaux à l'intérieur du module parent est par la liste ordonnée .
mondesign est un module
instancié avec le nom d0 dans un autre module appelé tb_top. Les ports sont connectés dans un certain ordre qui est déterminé par la position de ce port dans la liste des ports de la déclaration du module. Par exemple, b dans le testbench est connecté à y de la conception simplement parce que les deux sont à la deuxième position dans la liste des ports.
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
L'ordre des ports dans le module de conception doit être connu pour une connexion correcte.
Ceci est très gênant car l'ordre peut changer si un nouveau port est ajouté à la liste ou lorsque le nombre de ports dans la conception est très important.
Connexion de port par nom
Une meilleure façon de connecter les ports consiste à lier explicitement les ports des deux côtés à l'aide de leur nom de port .
Le point .
indique que le nom du port suivant le point appartient à la conception. Le nom du signal auquel le port de conception doit être connecté est donné ensuite entre parenthèses ( )
.
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
Il est recommandé de coder chaque connexion de port dans une ligne distincte afin que tout message d'erreur de compilation pointe correctement vers le numéro de ligne où l'erreur s'est produite. C'est beaucoup plus facile à déboguer et à résoudre que de ne pas savoir quel port a créé l'erreur s'ils avaient tous été sur la même ligne.
Étant donné que ces connexions sont établies par leur nom, l'ordre dans lequel elles apparaissent n'a pas d'importance. Les connexions de plusieurs ports d'instance de module ne sont pas autorisées.
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
Ports non connectés/flottants
Les ports qui ne sont connectés à aucun fil dans le module d'instanciation auront une valeur de haute impédance.
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
Exemple
Prenons l'exemple du registre à décalage que nous avions vu auparavant et laissons certains ports non connectés.
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
Notez que les sorties des instances u1 et u2 ne sont pas connectées dans le schéma RTL obtenu après synthèse. Étant donné que l'entrée d des instances u2 et u3 est maintenant connectée à des réseaux qui ne sont pilotés par rien, elle est mise à la terre.
Dans les simulations, ces ports non connectés seront désignés comme étant à haute impédance ('hZ), généralement affichés dans les formes d'onde sous la forme d'une ligne orange alignée verticalement au milieu.
Toutes les déclarations de port sont implicitement déclarées comme wire
et donc la direction du port est suffisante dans ce cas. Cependant output
les ports qui ont besoin de stocker des valeurs doivent être déclarés comme reg
type de données et peut être utilisé dans un bloc procédural comme always
et initial
uniquement.
Ports de type input
ou inout
ne peut pas être déclaré comme reg
car ils sont alimentés de l'extérieur en permanence et ne doivent pas stocker de valeurs, mais plutôt refléter les changements dans les signaux externes dès que possible. Il est parfaitement légal de connecter deux ports avec des tailles de vecteur différentes, mais celui avec une taille de vecteur inférieure prévaudra et les bits restants de l'autre port avec une largeur supérieure seront ignorés.
// 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