Mots-clés : instanciation, generate, additionneur complet, accès hiérarchique
Référencer un autre module à l'intérieur d'un module et connecter ses ports s'appelle l'instanciation de module. L'instanciation de module établit la hiérarchie de la description. Les ports de signal peuvent être associés par position ou par nom, et les connexions de port doivent également suivre certaines règles.
Connexion de port par nom
Cette méthode connecte les ports du module à instancier avec des signaux externes par nom. L'ordre des ports est arbitraire et peut différer de l'ordre de déclaration des ports du module référencé, tant que les noms des ports correspondent aux signaux externes.
Voici un exemple d'instanciation d'un additionneur complet 1 bit :
Exemple
.Ai (a[0]),
.Bi (b[0]),
.Ci (c==1'b1 ? 1'b0 : 1'b1),
.So (so_bit0),
.Co (co_temp[0]));
Si certains ports de sortie n'ont pas besoin d'être connectés à l'extérieur, ils peuvent être laissés flottants ou même omis lors de l'instanciation. En général, les ports d'entrée ne peuvent pas être omis lors de l'instanciation, sinon une erreur de compilation se produira, tandis que les ports de sortie peuvent être omis lors de l'instanciation. Par exemple :
Exemple
full_adder1 u_adder0(
.Ai (a[0]),
.Bi (b[0]),
.Ci (c==1'b1 ? 1'b0 : 1'b1),
.So (so_bit0),
.Co ());
//port de sortie Co omis
full_adder1 u_adder0(
.Ai (a[0]),
.Bi (b[0]),
.Ci (c==1'b1 ? 1'b0 : 1'b1),
.So (so_bit0));
Connexion ordonnée des ports
Cette méthode fait correspondre et connecte les ports du module à instancier avec des signaux externes selon l'ordre des ports déclaré dans le module, et les positions doivent être strictement cohérentes. Par exemple, le code d'instanciation d'un additionneur complet 1 bit peut être modifié comme suit :
full_adder1 u_adder1(
a[1], b[1], co_temp[0], so_bit1, co_temp[1]);
Bien que ce code puisse occuper relativement moins d'espace à l'écriture, la lisibilité du code est réduite et le débogage devient plus difficile. Parfois, dans les grandes conceptions, il peut y avoir de nombreux ports, et l'ordre des signaux de port peut changer de temps en temps. Dans de tels cas, utiliser une connexion de ports ordonnée pour l'instanciation de module est manifestement peu pratique. Par conséquent, dans la pratique normale, il est recommandé d'utiliser une connexion de ports nommée pour l'instanciation de module.
Règles de connexion des ports
Port d'entrée
Lors de l'instanciation d'un module, depuis l'extérieur du module, les ports d'entrée peuvent être connectés à des variables de type wire ou reg. Cela diffère de la déclaration de module ; depuis l'intérieur du module, les ports d'entrée doivent être des variables de type wire.
Port de sortie
Lors de l'instanciation d'un module, depuis l'extérieur du module, les ports de sortie doivent être connectés à des variables de type wire. Cela diffère de la déclaration de module ; depuis l'intérieur du module, les ports de sortie peuvent être des variables de type wire ou reg.
Port inout
Lors de l'instanciation d'un module, depuis l'extérieur du module, les ports inout doivent être connectés à des variables de type wire. Cela est identique à la déclaration de module.
Port flottant
Lors de l'instanciation d'un module, si certains signaux n'ont pas besoin d'être connectés ou d'interagir avec des signaux externes, nous pouvons les laisser flottants, c'est-à-dire laisser vide la position d'instanciation du port, comme mentionné dans les exemples ci-dessus.
Lorsqu'un port de sortie est laissé flottant, nous pouvons même l'omettre lors de l'instanciation.
Lorsqu'un port d'entrée est laissé flottant, la fonction logique du signal flottant apparaît comme un état haute impédance (valeur logique z). Cependant, un port d'entrée flottant ne peut généralement pas être omis lors de l'instanciation, sinon une erreur de compilation se produira. Par exemple :
Exemple
full_adder4 u_adder4(
.a (a),
.b (b),
.c (),
.so (so),
.co (co));
Exemple
full_adder4 u_adder4(
.a (a),
.b (b),
.so (so),
.co (co));
En général, il est recommandé de ne pas laisser les ports d'entrée flottants ; lorsqu'il n'y a pas d'autre connexion externe, attribuez-leur une valeur constante. Par exemple :
Exemple
.a (a),
.b (b),
.c (1'b0),
.so (so),
.co (co));
Correspondance des largeurs de bits
Lorsque la largeur de bits d'un port d'instanciation ne correspond pas à celle du signal continu, le port sera mis en correspondance par alignement à droite ou troncature du nombre non signé.
Supposons que, dans le module full_adder4, les ports a et b aient tous deux une largeur de 4 bits. Le résultat de l'instanciation du code suivant provoquera :u_adder4.a = {2'bzz, a[1:0]}, u_adder4.b = b[3:0] 。
Exemple
.a (a[1:0]), //entrée a[3:0]
.b (b[5:0]), //entrée b[3:0]
.c (1'b0),
.so (so),
.co (co));
Types de signaux continus des ports
Les types de signaux connectés aux ports peuvent être : 1) des identificateurs, 2) des sélections de bits, 3) des sélections de parties, 4) des concaténations des types ci-dessus, 5) des expressions utilisées pour les ports d'entrée.
Bien sûr, les noms de signaux peuvent être identiques aux noms de ports, mais leurs significations sont différentes ; ils représentent respectivement des signaux dans 2 modules différents.
Utilisation de generate pour l'instanciation de modules
Lors de l'instanciation de plusieurs modules identiques, les instancier manuellement un par un est fastidieux. L'utilisation d'instructions generate pour instancier plusieurs modules de manière répétée peut grandement simplifier le processus de programmation.
Le code pour instancier de manière répétée quatre additionneurs complets 1-bit afin de former un additionneur complet 4-bit est le suivant :
Exemple
input [3:0] a , //additionneur1
input [3:0] b , //additionneur2
input c , //bit de retenue d'entrée
output [3:0] so , //résultat de l'addition
output co //bit de retenue de sortie
);
wire [3:0] co_temp ;
//Le premier module instancié a généralement un format différent et doit être instancié séparément
full_adder1 u_adder0(
.Ai (a[0]),
.Bi (b[0]),
.Ci (c==1'b1 ? 1'b1 : 1'b0),
.So (so[0]),
.Co (co_temp[0]));
genvar i ;
generate
for(i=1; i<=3; i=i+1) begin: adder_gen
full_adder1 u_adder(
.Ai (a[i]),
.Bi (b[i]),
.Ci (co_temp[i-1]), //Le débordement de l'additionneur complet précédent est la retenue d'entrée du suivant
.So (so[i]),
.Co (co_temp[i]));
end
endgenerate
assign co = co_temp[3] ;
endmodule
Le banc de test est le suivant :
Exemple
module test ;
reg [3:0] a ;
reg [3:0] b ;
//reg c ;
wire [3:0] so ;
wire co ;
//Commande simple
initial begin
a = 4'd5 ;
b = 4'd2 ;
#10 ;
a = 4'd10 ;
b = 4'd8 ;
end
full_adder4 u_adder4(
.a (a),
.b (b),
.c (1'b0), //Les ports peuvent être connectés à des constantes
.so (so),
.co (co));
initial begin
forever begin
#100;
if ($time >= 1000) $finish ;
end
end
endmodule // test
Les résultats de simulation sont les suivants. On peut voir que l'additionneur complet 4 bits fonctionne correctement :

Accès hiérarchique
Le nom de chaque module instancié, les variables de signal de chaque module, etc., sont tous définis à l'aide d'identifiants spécifiques. Dans toute la conception hiérarchique, chaque identifiant a une position et un nom uniques.
En Verilog, en utilisant une série de.symboles pour séparer et relier hiérarchiquement les identifiants de chaque module, les identifiants de toute la conception sont accessibles n'importe où en spécifiant le nom hiérarchique complet.
L'accès hiérarchique est le plus souvent observé en simulation.
Par exemple, avec la conception hiérarchique suivante, les signaux entre les cellules feuilles, les sous-modules et le module de niveau supérieur peuvent accéder les uns aux autres.
Exemple
a = top.u_m2.u_n3.c ;
//Accès aux signaux du module top dans le module u_n1
if (top.p == 'b0) a = 1'b1 ;
//Accès aux signaux du module u_n4 dans le module top
assign p = top.u_m2.u_n4.d ;

Dans les simulations des sections précédentes, l'accès hiérarchique a été effectué dans une certaine mesure. Par exemple"Affectation continue procédurale"section, les instructions suivantes ont été utilisées dans le module de test de stimulus de simulation de niveau supérieur :
wait (test.u_counter.cnt_temp == 4'd4) ;
Téléchargement du code source
Téléchargement