Maîtriser les Boucles For en Verilog : Construire une Logique Matérielle Réutilisable
Une boucle for est la boucle la plus utilisée dans le logiciel, mais elle est principalement utilisée pour répliquer la logique matérielle en Verilog. L'idée derrière une boucle for est d'itérer un ensemble d'instructions données dans la boucle aussi longtemps que la condition donnée est vraie. Cela ressemble beaucoup à la boucle while, mais est davantage utilisé dans un contexte où un itérateur est disponible et où la condition dépend de la valeur de cet itérateur.
Syntaxe
for (<condition_initiale>; <condition>; <affectation_pas>) begin
// Instructions
end
Le mot-clé for est utilisé pour spécifier ce type de boucle et comporte trois parties :
- Condition initiale pour spécifier les valeurs initiales des signaux
- Une vérification pour évaluer si la condition donnée est vraie
- Mise à jour de la variable de contrôle pour l'itération suivante
La condition initiale et les mises à jour de la variable de contrôle sont incluses dans la boucle for et ne sont pas requises d'être spécifiées séparément contrairement à une boucle while. Une boucle while est plus polyvalente et est principalement utilisée seulement lorsque les instructions données doivent être répétées aussi longtemps qu'une condition donnée. Cependant, la boucle for a typiquement un début et une fin définis contrôlés par la variable de pas.
Voici un exemple simple qui illustre l'utilisation d'une boucle for.
module my_design;
integer i;
initial begin
// Notez que l'opérateur ++ n'existe pas en Verilog !
for (i = 0; i < 10; i = i + 1) begin
$display ("Boucle actuelle #%0d ", i);
end
end
endmodule
Journal de Simulation
ncsim> run Current loop#0 Current loop#1 Current loop#2 Current loop#3 Current loop#4 Current loop#5 Current loop#6 Current loop#7 Current loop#8 Current loop#9 ncsim: *W,RNQUIE: Simulation is complete.
Exemple de Conception
Examinons comment un registre à décalage gauche 8 bits peut être implémenté en Verilog sans boucle for puis comparons-le avec le code utilisant une boucle for pour apprécier l'utilité d'une structure de boucle.
module lshift_reg (
input clk, // Entrée d'horloge
input rstn, // Reset actif bas
input [7:0] load_val, // Valeur de chargement
input load_en, // Activation de chargement
output reg [7:0] op // Valeur de sortie du registre
);
// Au front montant d'horloge, si reset est bas mettre la sortie à 0
// Si reset est haut, charger la nouvelle valeur dans op si load_en=1
// Si reset est haut, et load_en=0 décaler le registre vers la gauche
always @ (posedge clk) begin
if (!rstn) begin
op <= 0;
end else begin
if (load_en) begin
op <= load_val;
end else begin
op[0] <= op[7];
op[1] <= op[0];
op[2] <= op[1];
op[3] <= op[2];
op[4] <= op[3];
op[5] <= op[4];
op[6] <= op[5];
op[7] <= op[6];
end
end
end
endmodule
Le même comportement peut être implémenté en utilisant une boucle for qui réduira le code et le rendra évolutif pour différentes largeurs de registre. Si la largeur du registre est rendue paramètre Verilog, le module de conception deviendra évolutif et le même paramètre peut être utilisé à l'intérieur de la boucle for.
module lshift_reg (
input clk, // Entrée d'horloge
input rstn, // Reset actif bas
input [7:0] load_val, // Valeur de chargement
input load_en, // Activation de chargement
output reg [7:0] op // Valeur de sortie du registre
);
integer i;
// Au front montant d'horloge, si reset est bas mettre la sortie à 0
// Si reset est haut, charger la nouvelle valeur dans op si load_en=1
// Si reset est haut, et load_en=0 décaler le registre vers la gauche
always @ (posedge clk) begin
if (!rstn) begin
op <= 0;
end else begin
// Si load_en est 1, charger la valeur dans op
// sinon continuer à décaler pour chaque horloge
if (load_en) begin
op <= load_val;
end else begin
for (i = 0; i < 8; i = i + 1) begin
op[i+1] <= op[i];
end
op[0] <= op[7];
end
end
end
endmodule
Banc de Test
Le code du banc de test est montré ci-dessous et instancie la conception.
module tb;
reg clk;
reg rstn;
reg [7:0] load_val;
reg load_en;
wire [7:0] op;
// Configuration de l'horloge DUT
always #10 clk = ~clk;
// Instanciation de la conception
lshift_reg u0 (
.clk(clk),
.rstn (rstn),
.load_val (load_val),
.load_en (load_en),
.op (op)
);
initial begin
// 1. Initialiser les variables du banc de test
clk <= 0;
rstn <= 0;
load_val <= 8'h01;
load_en <= 0;
// 2. Appliquer le reset à la conception
repeat (2) @ (posedge clk);
rstn <= 1;
repeat (5) @ (posedge clk);
// 3. Mettre load_en pour 1 cycle d'horloge afin que load_val soit chargé
load_en <= 1;
repeat(1) @ (posedge clk);
load_en <= 0;
// 4. Laisser la conception tourner pendant 20 cycles d'horloge puis finir
repeat (20) @ (posedge clk);
$finish;
end
endmodule
Verilog
- Verilog basique : concevoir votre première porte ET
- Maîtriser les boucles For en C# : Syntaxe, flux et exemples pratiques
- Programme Java pour identifier les nombres d'Armstrong avec une boucle for
- Maîtriser Verilog : Tutoriel complet pour la conception de circuits numériques
- Maîtriser la concaténation Verilog : Guide pratique
- Comprendre les affectations Verilog : Types, Syntaxe et Bonnes Pratiques
- Verilog Blocking vs Non-Blocking : Différences Clés Expliquées
- Maîtriser les Fonctions Verilog pour une Conception RTL Efficace
- Comprendre les Tasks Verilog : Fonctions vs Tasks, Syntaxe et Utilisation