Décrire des circuits séquentiels

Bascules et registres

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;
always @ (posedge clk_i)
    if (enable_i)
        q <= d;
always @ (posedge clk_i)
    if (reset_i)
        q <= 0;
    else
        q <= d;
always @ (posedge clk_i, posedge reset_i)
    if (reset_i)
        q <= 0;
    else
        q <= d;
always @ (posedge clk_i)
    if (reset_i)
        q <= 0;
    else if (enable_i)
        q <= d;
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é.

L’instruction 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 :

Compteurs

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 NN se font modulo 2N2^N. 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;

Machines à états

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