Menu

Boucles for en Verilog : déroulées à la compilation

En quoi les boucles for de Verilog diffèrent de leurs cousines logicielles - elles sont déroulées par le synthétiseur en matériel parallèle, pas exécutées itérativement au runtime.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

La sosie logicielle

La boucle for de Verilog est une copie de celle de C :

for (i = 0; i < 8; i = i + 1) begin
    // corps
end

Les mêmes trois parties : initialiseur, condition, incrément. Le corps se ré-exécute tant que la condition tient.

Dans un testbench, ça se comporte exactement comme tu t'y attendrais du logiciel. Le simulateur parcourt chaque itération à son tour :

Quatre itérations, quatre lignes de sortie. Aucune surprise.

La surprise vient quand tu mets une boucle for dans du code synthétisable.

Le déroulement

Une boucle for dans un bloc always synthétisable ne devient pas une boucle runtime dans le matériel. Le synthétiseur la déroule au moment de l'élaboration - il étend la boucle en N copies du corps, où N est le compteur d'itérations :

Ça ressemble à une boucle. En simulation, le simulateur boucle effectivement à travers huit itérations. En synthèse, la boucle est déroulée en huit checks parallèles de data[0] à data[7], tous arrivant en même temps. Le synthétiseur voit :

count = 0;
if (data[0]) count = count + 1;
if (data[1]) count = count + 1;
if (data[2]) count = count + 1;
...
if (data[7]) count = count + 1;

…puis transforme la séquence en un arbre d'additionneurs. Le comportement runtime est « regarde les 8 bits d'un coup et compte combien valent 1 », en un seul balayage combinatoire.

L'implication : une boucle for en Verilog synthétisable n'est pas gratuite. Une boucle à 64 itérations devient 64 copies du corps en matériel. Si le corps est complexe, tu viens de construire un gros bloc combinatoire. Utilise des boucles quand N est petit (poignée à quelques dizaines). Pour des comptes plus grands, tu veux généralement un compteur cadencé et une machine à états.

Bornes constantes requises

Le synthétiseur ne peut dérouler la boucle que s'il connaît N à l'élaboration. Ça veut dire que les bornes de boucle doivent être constantes :

// Marche - borne constante
for (i = 0; i < 8; i = i + 1) ...

// Marche - borne est un paramètre
for (i = 0; i < WIDTH; i = i + 1) ...

// Ne se synthétise pas - borne dépend d'un signal runtime
for (i = 0; i < dynamic_count; i = i + 1) ...

La dernière forme peut toujours marcher en simulation, mais le synthétiseur la rejettera. Si tu as vraiment besoin d'une boucle au compte runtime, tu la construis avec une machine à états cadencée et un registre compteur - le matériel n'a pas de boucles à compte de tours variable comme le logiciel.

generate for vs for procédural

Une construction séparée mais reliée est generate for, qui utilise un genvar et vit en dehors des blocs always :

genvar i;
generate
    for (i = 0; i < 8; i = i + 1) begin : g
        bit_inverter inv(.x(in[i]), .y(out[i]));
    end
endgenerate

Ça crée 8 instances de bit_inverter (couvert dans Instantiation de module). C'est structurel - tu dis « fais 8 copies de ce sous-module » - pas comportemental.

Distinction rapide :

  • for procédural (à l'intérieur de always) - déroule des instructions dans un seul bloc comportemental.
  • generate for (à l'extérieur de always) - réplique des constructions structurelles entières : instances, instructions assign, blocs nommés.

Utilise celui qui correspond à ce que tu réplique.

Quand for brille : opérations vectorielles

Les boucles sont à leur meilleur quand tu fais la même opération sur chaque bit d'un vecteur. Population count, parité, inversion d'octets, génération de table de lookup :

32 itérations, chacune faisant une assignation de bit - beaucoup plus lisible que d'écrire 32 assignations wire à la main. Le synthétiseur déroule proprement.

while, repeat, forever

Au-delà de for, Verilog a trois autres constructions de boucle - surtout pour les testbenches :

// Tourne jusqu'à ce qu'une condition échoue
while (~done) begin
    @(posedge clk);
    cycles = cycles + 1;
end

// Tourne N fois - plus simple que for quand tu n'as pas besoin d'un compteur
repeat (8) @(posedge clk);

// Tourne pour toujours - générateurs d'horloge, boucles de monitoring
always #5 clk = ~clk;
forever begin
    @(posedge clk);
    $display("count=%0d", count);
end

while, repeat et forever ne sont synthétisables que dans des cas étroits (notamment repeat avec un compte constant et un corps cadencé). Dans les testbenches ce sont des outils utiles ; dans le RTL synthétisable préfère un for compté plus une machine à états explicite.

for procédural dans les testbenches

Dans un testbench, les boucles for se comportent comme le logiciel. Utilise-les librement :

Les boucles imbriquées balayent chaque combinaison de deux entrées 2 bits. Le simulateur exécute les itérations séquentiellement. Pas de soucis de déroulement - les testbenches ne se synthétisent pas.

Erreurs courantes

Utiliser une boucle for dans du code synthétisable avec une borne non constante. Le synthétiseur la rejettera. Si la borne est runtime, construis un compteur et une machine à états.

Oublier que le corps de la boucle devient du matériel parallèle. Une boucle à 64 itérations avec un multiplicateur dans le corps fait 64 multiplicateurs parallèles - probablement pas ce que tu veux. Pour les datapaths larges, construis un seul multiplicateur et alimente-le séquentiellement.

Mélanger integer i et un reg nommé i. Les deux sont des portées différentes ; l'entier l'emporte dans la boucle. Choisis des noms clairs pour éviter la confusion.

La suite

Tu as maintenant chaque construction procédurale que Verilog offre. Le prochain chapitre rassemble tout ça en motifs que les concepteurs de circuits numériques utilisent vraiment en production : Logique cadencée - flip-flops, registres et pipelines - et Machines à états finis - l'idiome standard pour tout contrôleur ayant plusieurs modes de fonctionnement.

Questions fréquentes

Comment fonctionnent les boucles for en Verilog ?

Syntaxiquement elles ressemblent à C : for (i = 0; i < N; i = i + 1) statement;. Mais pour le code synthétisable, la boucle est déroulée au moment de l'élaboration - le synthétiseur l'étend en N copies du corps. Pas de compteur de boucle au runtime et pas de boucle dans le matériel. Pour les testbenches, les boucles for se comportent comme leurs cousines logicielles parce que le simulateur peut les parcourir séquentiellement.

Une boucle for est-elle synthétisable en Verilog ?

Oui, mais seulement quand les bornes de boucle sont des constantes connues à l'élaboration. Le synthétiseur déroule la boucle en N copies parallèles du corps. Si les bornes dépendent d'un signal runtime, la boucle n'est pas synthétisable - tu dois la convertir en design séquentiel cadencé.

Quelle est la différence entre for et generate for en Verilog ?

Une boucle for à l'intérieur d'un bloc always est une construction procédurale qui se synthétise par déroulement. Une boucle generate for (avec genvar) est une construction explicite à l'élaboration qui crée du matériel structurel - plusieurs instances de modules, plusieurs wires, plusieurs instructions assign. Utilise for à l'intérieur des blocs procéduraux ; utilise generate for à l'extérieur pour répliquer de la structure.

Verilog a-t-il une boucle while ?

Oui - while (condition) statement;. Elle n'est synthétisable que quand le synthétiseur peut prouver que la boucle se termine avec un nombre d'itérations borné. En pratique c'est rare, donc while apparaît surtout dans les testbenches et le code simulation uniquement. Pour l'itération synthétisable, utilise une boucle for comptée à la place.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER