Verilog intègre directement la notion de front montant ou descendant
dans la syntaxe des listes de sensibilité.
Si votre module possède une entrée horloge clk_i
, l’exécution
d’un processus sur front montant de clk_i
s’écrira :
always @ (posedge clk_i)
instruction séquentielle ou bloc
De même le mot-clé negedge
est utilisé pour déclencher un processus
sur front descendant.
Comme en VHDL, on pourra traduire les différentes variantes de bascules et de registres.
always @ (posedge clk_i)
q <= d;
enable_i
active au niveau haut :always @ (posedge clk_i)
if (enable_i)
q <= d;
reset_i
active au niveau haut :always @ (posedge clk_i)
if (reset_i)
q <= 0;
else
q <= d;
reset_i
active au niveau haut :always @ (posedge clk_i, posedge reset_i)
if (reset_i)
q <= 0;
else
q <= d;
reset_i
active au niveau haut, et autorisation d’écriture sur une entrée
enable_i
active au niveau haut :always @ (posedge clk_i)
if (reset_i)
q <= 0;
else if (enable_i)
q <= d;
reset_i
active au niveau haut, et autorisation d’écriture sur une entrée
enable_i
active au niveau haut :always @ (posedge clk_i, posedge reset_i)
if (reset_i)
q <= 0;
else if (enable_i)
q <= d;
Comme en VHDL, à l’exception de la réinitialisation asynchrone, seule l’horloge apparaît dans la liste de sensibilité.
initial
Contrairement à VHDL, qui permet d’indiquer la valeur initiale des signaux
directement dans leur déclaration, Verilog fournit à cet effet une
instruction initial
qui est exécutée au démarrage du système,
et indépendamment de l’existence d’un signal reset_i
:
initial
instruction séquentielle ou bloc
Cette instruction est traitée différemment selon les outils de développement utilisés et selon la technologie de circuit visée :
initial
est exécutée au démarrage de la simulation.initial
ne
correspond à rien physiquement. Elle sera ignorée par les outils de synthèse,
et les bascules D de votre circuit auront des valeurs inconnues au démarrage.
Dans ce cas, il faut prévoir une entrée de réinitialisation reset_i
et
gérer l’initialisation dans chaque processus synchrone.initial
peut être utilisée
pour affecter une autre valeur.La description des compteurs s’appuie sur les instructions présentées
précédemment.
Voici un exemple de compteur modulo 10 utilisant un processus pour mettre
à jour le signal counter_mod_10_reg
sur fronts d’horloge, et une affectation
concurrente pour calculer la valeur suivante counter_mod_10_next
:
reg [3:0] counter_mod_10_reg;
wire [3:0] counter_mod_10_next;
always @ (posedge clk_i, posedge reset_i)
if (reset_i)
counter_mod_10_reg <= 0;
else if (enable_i)
counter_mod_10_reg <= counter_mod_10_next;
assign counter_mod_10_next = counter_mod_10_reg == 9 ? 0 : counter_mod_10_reg + 1;
Comme en VHDL, on peut regrouper dans le même processus le calcul de la valeur suivante et la mémorisation :
reg [3:0] counter_mod_10_reg;
always @ (posedge clk_i, posedge reset_i)
if (reset_i)
counter_mod_10_reg <= 0;
else if (enable_i) begin
if (counter_mod_10_reg == 9)
counter_mod_10_reg <= 0;
else
counter_mod_10_reg <= counter_mod_10_reg + 1;
end
Les opérations arithmétiques sur des vecteurs de taille
se font modulo .
Par exemple, le résultat de l’addition 4'b1111 + 1
est 4'b0000
.
Cela permet de simplifier l’écriture des compteurs lorsque leur modulo est une
puissance de deux.
Ci-dessous, le signal counter_mod_16_reg
compte de 0 à 15 et revient
à zéro automatiquement :
reg [3:0] counter_mod_16_reg;
always @ (posedge clk_i, posedge reset_i)
if (reset_i)
counter_mod_16_reg <= 0;
else if (enable_i)
counter_mod_16_reg <= counter_mod_16_reg + 1;
Verilog ne permet pas de définir des types énumérés. Les états d’une machine à états doivent être représentés par des valeurs explicites de votre choix. On peut les déclarer sous la forme de constantes pour améliorer la lisibilité :
localparam STOPPED = 0;
localparam PLAYING = 1;
localparam PAUSED = 2;
reg [1:0] state_reg;
always @ (posedge clk_i, posedge reset_i)
if (reset_i)
state_reg <= STOPPED;
else
case (state_reg)
STOPPED:
if (btn_play_i)
state_reg <= PLAYING;
PLAYING:
if (btn_play_i)
state_reg <= PAUSED;
else if (btn_stop_i)
state_reg <= STOPPED;
PAUSED:
if (btn_play_i)
state_reg <= PLAYING;
else if (btn_stop_i)
state_reg <= STOPPED;
default:
state_reg <= STOPPED;
endcase