Le temps logiciel vs le temps matériel
Dans un programme, le temps avance une instruction à la fois. Le CPU termine la ligne 1, puis exécute la ligne 2. Si tu veux que deux choses se passent en même temps, tu utilises des threads, de l'async, ou une deuxième machine.
Dans le matériel, tout se passe en même temps. Un circuit ne prend pas son tour. L'additionneur additionne en permanence, le multiplexeur sélectionne en permanence, le flip-flop surveille l'horloge en permanence. Il n'y a pas de compteur de programme. Il n'y a pas de « ligne en cours ».
Verilog doit décrire ce monde en texte. La façon dont il s'y prend est la source de toutes les confusions dans ce chapitre.
Deux couches de concurrence
Quand tu lis un module Verilog, tu regardes deux choses différentes en même temps :
- La description statique du circuit. Wires, registres, instances de portes, instances de sous-modules, assignations continues. Tout ça existe simultanément. L'ordre dans le fichier n'a pas d'importance.
- Les blocs procéduraux -
initialetalways- qui ressemblent à de petits programmes que le simulateur déroule. À l'intérieur de l'un de ces blocs, les instructions s'exécutent dans un certain ordre. Mais plusieurs blocsalwayspeuvent être actifs en même temps, chacun dans son propre fil de temps simulé.
module example(input wire a, input wire b, output wire y, output wire z);
assign y = a & b; // existe à tout instant
assign z = a | b; // existe aussi à tout instant, en parallèle
always @(posedge a) begin
// un autre réacteur « always-on » qui se réveille
// à chaque front montant de `a`
end
endmodule
Les deux lignes assign ne forment pas une séquence. Elles décrivent deux morceaux de logique combinatoire que l'outil de synthèse peut placer côte à côte. Le bloc always est une troisième chose qui se passe en parallèle.
Ce que « signal » veut dire
En logiciel, une variable retient une valeur jusqu'à ce que tu la changes. En Verilog, un signal retient une valeur en permanence - et à chaque instant elle dépend de ce qui le pilote.
Un wire est piloté depuis l'extérieur (un assign, le port de sortie d'un sous-module, une connexion inout). Un reg est piloté depuis l'intérieur d'un bloc procédural. Les deux ont une valeur à tout instant. Il n'existe rien qui ressemble à « non initialisé » au sens où C l'entend - les signaux sont soit pilotés à une valeur définie, soit à l'inconnu spécial x, soit à la haute impédance z. On couvre les deux derniers dans Valeurs X et Z.
Les horloges changent tout
Dès que tu introduis une horloge, le temps commence à compter. Un flip-flop est un minuscule morceau de matériel qui capture la valeur de son entrée sur le front montant (ou descendant) d'une horloge et la maintient jusqu'au front suivant. C'est l'horloge qui te permet de construire des compteurs, des machines à états, des pipelines - tout ce qui a de la mémoire.
Remarque q <= d plutôt que q = d. C'est une assignation non-blocking - le pilier de la logique cadencée. Elle dit « au prochain front d'horloge, planifie que q devienne ce que d est maintenant ». On creuse les règles dans Blocking vs Non-blocking ; pour l'instant, retiens que l'assignation ne fait pas semblant d'être une instruction logicielle.
RTL : le modèle mental Register Transfer
La majorité du Verilog synthétisable est écrite dans un style appelé Register Transfer Level, ou RTL. L'idée est simple :
- Décide quel état ton circuit a besoin de tenir (les registres).
- Pour chaque registre, décris deux choses : ce qui le reset, et la logique combinatoire qui calcule sa prochaine valeur.
- Connecte les sorties de la logique combinatoire aux entrées des registres et tu as un circuit fonctionnel.
always @(posedge clk) begin
if (reset) state <= IDLE;
else state <= next_state;
end
always @(*) begin
case (state)
IDLE: next_state = start ? RUNNING : IDLE;
RUNNING: next_state = done ? IDLE : RUNNING;
default: next_state = IDLE;
endcase
end
C'est une machine à deux états. Le premier bloc always est cadencé - c'est un flip-flop. Le second est purement combinatoire - c'est juste une équation. Presque toutes les machines à états, compteurs et pipelines que tu écriras suivent cette forme.
Les habitudes qui te bloquent
Si tu viens du logiciel, voici une courte liste d'habitudes à laisser de côté :
- « Les variables se mettent à jour quand je les assigne. » Pas sur un front d'horloge - une assignation non-blocking planifie la mise à jour pour la fin du pas de temps.
- « Les instructions s'exécutent du haut vers le bas. » En dehors des blocs procéduraux, non. À l'intérieur d'un bloc cadencé, plus ou moins - mais blocking vs non-blocking change le sens de « dans l'ordre ».
- « J'alloue ça quand j'en aurai besoin. » Le matériel n'alloue pas. Chaque registre et chaque porte doit exister au moment de la synthèse. La taille de chaque vecteur est fixe.
- « Cette boucle est rapide - ce n'est qu'une opération. » Une boucle
foren Verilog synthétisable est déroulée en matériel parallèle. Une boucle de 64 itérations devient 64 copies du corps, pas une instruction CPU qui tourne 64 fois.
Tu n'apprends pas à écrire un programme. Tu apprends à décrire un circuit. L'instinct de lire du haut vers le bas est exactement le mauvais et il faut un certain temps pour le rééduquer.
La suite
Les prochains documents te guident à travers l'installation d'une toolchain locale (optionnel - l'éditeur en ligne suffit), puis l'écriture de ton premier module from scratch. On reviendra sur le contraste matériel-vs-logiciel chaque fois que quelque chose paraîtra bizarre, parce que la majorité des parties « bizarres » ont la même cause racine : ce n'est pas du logiciel.
Questions fréquentes
Quelle est la différence entre matériel et logiciel en termes Verilog ?
Le logiciel est une séquence d'instructions exécutées par un CPU, l'une après l'autre. Le matériel - ce que Verilog décrit - est un réseau de portes et de wires qui portent tous des signaux en même temps. Un fichier Verilog décrit ce réseau. Le simulateur imite le comportement parallèle ; un outil de synthèse le transforme en silicium réel.
Le code Verilog s'exécute-t-il du haut vers le bas comme en C ?
Non - et le traiter comme tel est l'erreur la plus courante chez les débutants. Les instructions au niveau supérieur (assigns, instances de modules, blocs always) « existent » toutes en même temps. Ce n'est qu'à l'intérieur des blocs procéduraux - initial et always - qu'il se passe quelque chose qui ressemble à de l'exécution séquentielle, et encore, les assignations non-blocking brisent cette illusion.
Que veut dire « concurrent » en Verilog ?
Ça veut dire que plusieurs instructions décrivent des parties d'un circuit qui fonctionnent toutes en même temps. Deux instructions assign dans le même module ne sont pas « ligne 1 puis ligne 2 » - ce sont deux morceaux de matériel qui tournent en parallèle, réagissant chacun à leurs entrées en permanence.
Qu'est-ce que le RTL design ?
RTL veut dire Register Transfer Level. C'est un style d'écriture Verilog où tu décris le circuit comme un ensemble de registres (flip-flops) et la logique combinatoire qui calcule leur prochaine valeur. La majorité du Verilog synthétisable est en RTL. Le niveau au-dessus est le comportemental ; celui en dessous est le niveau portes.