Logique séquentielle

La logique séquentielle introduit une mémoire d’état : la sortie dépend non seulement des entrées actuelles, mais aussi de l’historique. L’élément de base est la bascule D (flip-flop D).

La bascule D

Une bascule D capture la valeur de son entrée d sur le front montant de l’horloge et la présente sur sa sortie q jusqu’au prochain front.

bascule_d.v — bascule D avec reset asynchrone actif bas
module bascule_d (
    input  wire clk,    // horloge
    input  wire rst_n,  // reset asynchrone actif bas
    input  wire d,      // donnée
    output reg  q       // sortie mémorisée
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)  q <= 1'b0;   // reset : remise à zéro immédiate
        else         q <= d;       // capture sur front montant
    end
endmodule
Reset synchrone vs asynchrone

Type de reset

Déclenchement

Syntaxe Verilog

Asynchrone (recommandé Xilinx)

Dès que rst_n passe bas, indépendamment de l’horloge

always @(posedge clk or negedge rst_n)

Synchrone

Seulement sur le prochain front montant de l’horloge

always @(posedge clk) + if (!rst_n)

Compteur n bits

Un compteur est un registre auto-incrémenté. Avec \(n\) bits, il compte de \(0\) à \(2^n - 1\) puis déborde naturellement vers \(0\).

compteur 4 bits (0 à 15, débordement automatique)
module counter4 (
    input  wire       clk, rst_n,
    output reg  [3:0] count
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) count <= 4'd0;
        else        count <= count + 1'b1;
    end
endmodule

Le bit count[3] (MSB) vaut 1 pour les valeurs 8 à 15 et 0 pour les valeurs 0 à 7 — il bascule donc toutes les 8 périodes d’horloge, réalisant naturellement une division par 16 avec un rapport cyclique de 50 %.

Compteur avec remise à zéro conditionnelle

Pour un rapport de division quelconque \(N\), on remet le compteur à zéro dès qu’il atteint \(N/2 - 1\) (pour un signal symétrique) :

Principe du compteur à remise à zéro (extrait de freq_divider.v)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        count   <= 0;
        clk_out <= 1'b0;
    end
    else if (enable) begin           // n'avance que si enable actif
        if (count == (N/2) - 1) begin
            clk_out <= ~clk_out;     // inversion à mi-période
            count   <= 0;
        end
        else
            count <= count + 1'b1;
    end
end

Double registre de synchronisation

Lorsqu’un signal provient d’un domaine d’horloge différent (ou d’une logique asynchrone comme notre comparateur ADC), il faut le resynchroniser pour éviter la métastabilité — un état indéfini où la bascule ne sait pas si elle doit basculer à 0 ou à 1.

La solution standard est le double registre (two-FF synchronizer) :

Synchroniseur à deux bascules
reg sig_d1, sig_d2;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        sig_d1 <= 1'b0;
        sig_d2 <= 1'b0;
    end
    else begin
        sig_d1 <= sig_in;   // 1re bascule : peut être métastable
        sig_d2 <= sig_d1;   // 2e bascule : probabilité de métastabilité ≈ 0
    end
end

Ce double registre est aussi le cœur du détecteur de front montant décrit à la section suivante.

See also

Détecteur de front montant pour l’utilisation concrète du double registre dans la détection de front montant du signal analogique numérisé.