Leçon 10 sur 22

Chapitre 10 — Horloge, bascules et registres

Objectif — Finalité du chapitre

Comprendre le rôle de l’horloge dans les systèmes synchrones, décrire des bascules D et différents types de registres, puis maîtriser les resets, validations et opérations de décalage en VHDL.

Objectifs pédagogiques

À la fin de ce chapitre, l’étudiant devra être capable de :

  • définir une horloge, sa période, sa fréquence et son rapport cyclique ;
  • distinguer front montant et front descendant ;
  • utiliser rising_edge et falling_edge ;
  • reconnaître les anciennes formes de détection de front ;
  • décrire une bascule D simple ;
  • ajouter une validation, une initialisation et un reset ;
  • distinguer reset synchrone et reset asynchrone ;
  • identifier l’ordre de priorité des commandes ;
  • concevoir un registre parallèle ;
  • concevoir un registre avec validation ;
  • concevoir un registre à décalage gauche ou droite ;
  • combiner chargement parallèle, maintien et décalage ;
  • simuler puis valider les circuits sur une carte FPGA.

Prérequis

  • processus VHDL et listes de sensibilité ;
  • instruction if et détection de front ;
  • types std_logic et std_logic_vector ;
  • affectations de signaux ;
  • principes de synthèse et de simulation.

Organisation du chapitre

Section

Contenu

Compétence principale

10.1Signaux synchronesCaractériser une horloge
10.2Détection de frontÉcrire un processus cadencé correct
10.3Bascule DMémoriser un bit
10.4Reset synchrone et asynchroneDéfinir une initialisation fiable
10.5RegistresMémoriser et déplacer des mots binaires
TP 7Bascules et registresSimuler et valider sur FPGA

 

Concept clé — Principe central

Dans un système synchrone, les changements d’état sont coordonnés par les fronts d’une horloge. Entre deux fronts actifs, les registres conservent leur valeur.

 

10.1 Signaux synchrones

Un système synchrone utilise un signal périodique appelé horloge pour coordonner les transferts de données et les changements d’état. Les bascules et registres observent généralement un front précis de cette horloge.

10.1.1 Notion d’horloge

Une horloge est un signal logique alternant entre un niveau bas et un niveau haut. Elle sert de référence temporelle commune aux éléments séquentiels.

Génération d’une horloge dans un banc de test  |  VHDL
constant PERIODE_CLK : time := 20 ns;

clk <= not clk after PERIODE_CLK / 2;

 

Attention — Simulation uniquement

Une horloge est généralement fournie par un oscillateur externe ou une ressource dédiée du FPGA. La construction avec after est utilisée dans les bancs de test, pas pour créer une horloge matérielle synthétisable.

 

10.1.2 Période

La période T est la durée séparant deux instants identiques consécutifs du signal, par exemple deux fronts montants successifs.

Période T

Interprétation

20 nsUn front montant toutes les 20 ns
10 nsCycle deux fois plus rapide qu’une période de 20 ns
1 µsUn million de cycles par seconde
1 msMille cycles par seconde

 

10.1.3 Fréquence

La fréquence f est l’inverse de la période : f = 1 / T.

Période

Fréquence

20 ns50 MHz
10 ns100 MHz
8 ns125 MHz
1 µs1 MHz
1 ms1 kHz

 

Repère — Unités

1 MHz correspond à un million de cycles par seconde. 1 ns correspond à 10⁻9 seconde. Lors des calculs, convertir toutes les grandeurs dans des unités cohérentes.

 

10.1.4 Front montant

Un front montant est la transition du niveau bas vers le niveau haut. De nombreux registres FPGA sont déclenchés sur ce front.

Détection d’un front montant  |  VHDL
if rising_edge(clk) then
    q <= d;
end if;

 

10.1.5 Front descendant

Un front descendant est la transition du niveau haut vers le niveau bas. Il peut être utilisé dans certaines interfaces ou architectures, mais il est recommandé de conserver un seul type de front dans un domaine d’horloge.

Détection d’un front descendant  |  VHDL
if falling_edge(clk) then
    q <= d;
end if;

 

10.1.6 Rapport cyclique

Le rapport cyclique est le pourcentage de la période pendant lequel l’horloge reste au niveau haut.

Temps haut

Période

Rapport cyclique

10 ns20 ns50 %
6 ns20 ns30 %
15 ns20 ns75 %

 

Un rapport cyclique de 50 % est fréquent, mais certains circuits n’exigent qu’un front propre et des contraintes temporelles respectées.

10.1.7 Chronologie simplifiée

Instant

clk

Événement

0 ns0État initial
10 ns1Front montant
20 ns0Front descendant
30 ns1Front montant suivant
40 ns0Front descendant suivant

 

10.1.8 Domaine d’horloge

Un domaine d’horloge regroupe les registres commandés par la même horloge ou par des horloges considérées comme synchrones. Les échanges entre domaines différents exigent des techniques spécifiques de synchronisation.

  • Une horloge principale simplifie la conception.
  • Les horloges dérivées par logique combinatoire sont déconseillées.
  • Les signaux d’activation sont souvent préférables à la création de nouvelles horloges.
  • Les ressources d’horloge dédiées du FPGA doivent être utilisées.

10.1.9 Temps de setup et de hold

La donnée doit être stable pendant une courte durée avant et après le front actif. Ces intervalles sont respectivement appelés temps de setup et temps de hold.

Contrainte

Signification

SetupLa donnée doit être stable avant le front actif.
HoldLa donnée doit rester stable après le front actif.
Clock-to-QDélai entre le front et la modification de la sortie de la bascule.
Chemin combinatoireDélai entre la sortie d’un registre et l’entrée du suivant.

 

Conception — Analyse temporelle

Le fonctionnement correct ne dépend pas seulement de la logique VHDL. Les contraintes d’horloge et l’analyse temporelle statique doivent confirmer que les chemins respectent la période demandée.

 

10.1.10 Horloge et simulation

Processus explicite de génération  |  VHDL
generation_clk : process
begin
    clk <= '0';
    wait for PERIODE_CLK / 2;

    clk <= '1';
    wait for PERIODE_CLK / 2;
end process;

 

Ce processus se répète indéfiniment, car il atteint end process puis recommence automatiquement.

10.2 Détection d’un front d’horloge

Un processus cadencé est réveillé par l’horloge, puis vérifie si l’événement correspond au front utilisé par le circuit.

10.2.1 Forme recommandée

Processus sur front montant  |  VHDL
process(clk)
begin
    if rising_edge(clk) then
        q <= d;
    end if;
end process;

 

La fonction rising_edge est définie dans IEEE.STD_LOGIC_1164. Elle vérifie une transition vers le niveau logique haut selon les règles du type std_logic.

10.2.2 Fonction rising_edge

  • convient aux signaux std_logic et types compatibles ;
  • gère correctement les transitions des niveaux faibles vers forts ;
  • est reconnue par les outils de synthèse ;
  • exprime clairement l’intention du concepteur.

10.2.3 Fonction falling_edge

Processus sur front descendant  |  VHDL
process(clk)
begin
    if falling_edge(clk) then
        q <= d;
    end if;
end process;

 

La fonction falling_edge détecte la transition vers le niveau logique bas.

10.2.4 Ancienne forme avec event

Ancienne détection du front montant  |  VHDL
if clk'event and clk = '1' then
    q <= d;
end if;

 

Cette forme a longtemps été utilisée. Elle vérifie qu’un événement s’est produit sur clk et que sa nouvelle valeur est 1.

10.2.5 Ancienne forme du front descendant

Ancienne détection du front descendant  |  VHDL
if clk'event and clk = '0' then
    q <= d;
end if;

 

10.2.6 Comparaison des formes

Forme

Lisibilité

Gestion de std_logic

Recommandation

rising_edge(clk)Très claireNormaliséeÀ privilégier
falling_edge(clk)Très claireNormaliséeÀ privilégier si nécessaire
clk'event and clk='1'Moins expressivePlus ancienneÀ reconnaître
clk='1' seulIncorrectNe détecte pas un frontÀ éviter

 

10.2.7 Erreur : tester seulement le niveau

Description incorrecte  |  VHDL
process(clk)
begin
    if clk = '1' then
        q <= d;
    end if;
end process;

 

Cette écriture ne décrit pas explicitement une bascule sur front. Elle peut être interprétée comme un comportement sensible au niveau haut ou être rejetée selon le contexte de synthèse.

10.2.8 Liste de sensibilité d’un processus cadencé

Type de reset

Liste de sensibilité

Aucun resetclk
Reset synchroneclk
Reset asynchroneclk, reset
Set asynchroneclk, set
Reset et set asynchronesclk, reset, set

 

10.2.9 Un seul front par processus

Un même registre ne doit généralement pas être mis à jour à la fois sur front montant et descendant dans un processus RTL standard.

Forme déconseillée pour une bascule classique  |  VHDL
if rising_edge(clk) then
    q <= d1;
elsif falling_edge(clk) then
    q <= d2;
end if;

 

Cas avancé — Ressources DDR

Les transferts sur les deux fronts existent dans certaines interfaces DDR, mais ils utilisent généralement des primitives dédiées du FPGA plutôt qu’une description RTL générique.

 

10.2.10 Exemple de banc de test

Horloge et stimuli  |  VHDL
constant PERIODE : time := 20 ns;

clk <= not clk after PERIODE / 2;

stimuli : process
begin
    d <= '0';
    wait for 15 ns;

    d <= '1';
    wait for 20 ns;

    d <= '0';
    wait;
end process;

 

L’observation du chronogramme montre que q ne change qu’aux fronts actifs, même lorsque d change entre deux fronts.

10.3 Bascule D

La bascule D mémorise un bit. Au front actif de l’horloge, elle copie l’entrée D vers la sortie Q, puis conserve cette valeur jusqu’au front suivant.

10.3.1 Fonctionnement

Événement

D

Q après l’événement

Aucun front actif0 ou 1Q conserve sa valeur
Front actif0Q devient 0
Front actif1Q devient 1

 

10.3.2 Description VHDL simple

Bascule D  |   VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity bascule_d is
    port (
        clk : in  std_logic;
        d   : in   std_logic;
        q   : out std_logic
    );
end entity bascule_d;

architecture rtl of bascule_d is
begin
    process(clk)
    begin
        if rising_edge(clk) then
            q <= d;
        end if;
    end process;
end architecture rtl;

 

10.3.3 Interprétation matérielle

  • Le processus est sensible à clk.
  • La condition rising_edge décrit le front actif.
  • L’affectation q <= d infère une bascule D.
  • La sortie conserve sa valeur entre deux fronts.

10.3.4 Bascule avec activation

Une entrée enable contrôle le chargement. Lorsque enable vaut 0, la bascule conserve son état.

Bascule D avec enable  |  VHDL
process(clk)
begin
    if rising_edge(clk) then
        if enable = '1' then
            q <= d;
        end if;
    end if;
end process;

 

Front actif

enable

Action

Non0 ou 1Q conserve sa valeur
Oui0Q conserve sa valeur
Oui1Q reçoit D

 

10.3.5 Bascule avec initialisation

Une valeur initiale peut être indiquée lors de la déclaration d’un signal interne. De nombreux FPGA prennent en charge l’initialisation de registres lors de la configuration, mais la portabilité dépend de la cible et de l’outil.

Initialisation d’un signal interne  |  VHDL
architecture rtl of bascule_initialisee is
    signal q_i : std_logic := '0';
begin
    process(clk)
    begin
        if rising_edge(clk) then
            q_i <= d;
        end if;
    end process;

    q <= q_i;
end architecture rtl;

 

Distinction — Initialisation ou reset

Une initialisation à la configuration n’est pas toujours équivalente à un reset disponible pendant le fonctionnement. Un reset explicite est nécessaire lorsque le système doit pouvoir revenir à un état connu après le démarrage.

 

10.3.6 Bascule avec set

Set synchrone  |   VHDL
process(clk)
begin
    if rising_edge(clk) then
        if set = '1' then
            q <= '1';
        else
            q <= d;
        end if;
    end if;
end process;

 

10.3.7 Bascule avec reset et enable

Priorité reset puis enable  |  VHDL
process(clk)
begin
    if rising_edge(clk) then
        if reset = '1' then
            q <= '0';
        elsif enable = '1' then
            q <= d;
        end if;
    end if;
end process;

 

Le reset est prioritaire sur enable parce qu’il est testé en premier.

10.3.8 Bascule et métastabilité

Si D change trop près du front d’horloge, la bascule peut entrer temporairement dans un état métastable. Ce phénomène physique n’est pas représenté par une simulation RTL idéale.

Sécurité temporelle — Entrées asynchrones

Un bouton, un signal externe ou une donnée provenant d’un autre domaine d’horloge doit être synchronisé avant d’être utilisé par la logique séquentielle.

 

10.3.9 Deux bascules de synchronisation

Synchroniseur simplifié  |  VHDL
process(clk)
begin
    if rising_edge(clk) then
        sync_1 <= entree_async;
        sync_2 <= sync_1;
    end if;
end process;

entree_synchrone <= sync_2;

 

Cette structure réduit la probabilité que la métastabilité se propage, sans l’annuler mathématiquement.

10.3.10 Banc de test d’une bascule

Stimuli essentiels  |  VHDL
d <= '0';
wait until rising_edge(clk);

d <= '1';
wait until rising_edge(clk);

assert q = '1'
    report "La bascule n'a pas capture D"
    severity error;

 

10.4 Reset synchrone et asynchrone

Le reset place les registres dans un état connu. Il peut être pris en compte uniquement au front d’horloge ou agir immédiatement.

10.4.1 Reset synchrone

Le reset synchrone est testé à l’intérieur de la condition rising_edge. Il ne modifie la sortie qu’au front actif.

Reset synchrone actif à 1  |  VHDL
process(clk)
begin
    if rising_edge(clk) then
        if reset = '1' then
            q <= '0';
        else
            q <= d;
        end if;
    end if;
end process;

 

10.4.2 Reset asynchrone

Le reset asynchrone est testé avant le front d’horloge et apparaît dans la liste de sensibilité. Il agit immédiatement.

Reset asynchrone actif à 1  |  VHDL
process(clk, reset)
begin
    if reset = '1' then
        q <= '0';
    elsif rising_edge(clk) then
        q <= d;
    end if;
end process;

 

10.4.3 Reset actif à 0

Reset asynchrone bas  |   VHDL
process(clk, reset_n)
begin
    if reset_n = '0' then
        q <= '0';
    elsif rising_edge(clk) then
        q <= d;
    end if;
end process;

 

Le suffixe _n indique souvent qu’un signal est actif au niveau bas.

10.4.4 Ordre de priorité

Reset, chargement et enable  |  VHDL
process(clk, reset)
begin
    if reset = '1' then
        q <= (others => '0');
    elsif rising_edge(clk) then
        if load = '1' then
            q <= data_in;
        elsif enable = '1' then
            q <= q_suivant;
        end if;
    end if;
end process;

 

Priorité

Commande

Effet

1resetForce la valeur initiale
2loadCharge une donnée parallèle
3enableAutorise la mise à jour
4aucuneConserve la valeur

 

10.4.5 Avantages du reset synchrone

  • reset traité comme une donnée synchrone ;
  • facilité d’analyse temporelle ;
  • moins sensible aux impulsions courtes asynchrones ;
  • utilisation possible des ressources de données des registres.

10.4.6 Limites du reset synchrone

  • nécessite une horloge active ;
  • ne réagit pas immédiatement ;
  • peut ajouter de la logique sur le chemin de données ;
  • doit être maintenu jusqu’à un front valide.

10.4.7 Avantages du reset asynchrone

  • action immédiate ;
  • indépendant de l’horloge ;
  • utile au démarrage ou lors d’un défaut critique ;
  • souvent directement pris en charge par les bascules FPGA.

10.4.8 Limites du reset asynchrone

  • désactivation proche d’un front pouvant créer des problèmes temporels ;
  • distribution du reset à travers le circuit ;
  • sensibilité aux glitches si le signal est mal conçu ;
  • contraintes de recovery et removal à respecter.

10.4.9 Comparaison

Critère

Reset synchrone

Reset asynchrone

Moment d’actionAu front actifImmédiatement
Liste de sensibilitéclkclk, reset
Dépendance à l’horlogeOuiNon pour l’activation
Risque à la désactivationFaible si synchroneDoit être synchronisée
UtilisationContrôle fonctionnelInitialisation ou sécurité

 

10.4.10 Activation asynchrone, relâchement synchrone

Une stratégie fréquente consiste à activer le reset immédiatement, puis à synchroniser sa désactivation dans chaque domaine d’horloge.

Architecture — Bonne pratique système

Le choix du reset dépend de l’architecture FPGA, des recommandations du fabricant, du nombre de domaines d’horloge et des exigences de sûreté. Un reset global n’est pas toujours nécessaire pour chaque registre.

 

10.4.11 Reset dans un banc de test

Séquence de reset  |  VHDL
reset <= '1';
wait for 3 * PERIODE_CLK;

reset <= '0';
wait until rising_edge(clk);

 

Maintenir le reset pendant plusieurs cycles simplifie l’observation et garantit un état stable avant les tests.

10.5 Registres

Un registre mémorise plusieurs bits en parallèle. Il est généralement constitué d’un ensemble de bascules D partageant la même horloge et les mêmes commandes.

10.5.1 Registre parallèle

Registre 8 bits  |   VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity registre8 is
    port (
        clk : in  std_logic;
        d   : in   std_logic_vector(7 downto 0);
        q   : out std_logic_vector(7 downto 0)
    );
end entity registre8;

architecture rtl of registre8 is
begin
    process(clk)
    begin
        if rising_edge(clk) then
            q <= d;
        end if;
    end process;
end architecture rtl;

 

10.5.2 Registre paramétrable

Registre sur N bits  |   VHDL
entity registre_n is
    generic (
        N : positive := 8
    );
    port (
        clk : in  std_logic;
        d   : in   std_logic_vector(N-1 downto 0);
        q   : out std_logic_vector(N-1 downto 0)
    );
end entity registre_n;

 

Architecture générique  |  VHDL
architecture rtl of registre_n is
begin
    process(clk)
    begin
        if rising_edge(clk) then
            q <= d;
        end if;
    end process;
end architecture rtl;

 

10.5.3 Registre avec validation

Chargement conditionnel  |  VHDL
process(clk)
begin
    if rising_edge(clk) then
        if enable = '1' then
            q <= d;
        end if;
    end if;
end process;

 

Lorsque enable vaut 0, le registre conserve sa valeur. Le synthétiseur peut utiliser l’entrée clock enable dédiée des bascules.

10.5.4 Registre avec reset asynchrone

Registre 8 bits réinitialisable  |  VHDL
process(clk, reset)
begin
    if reset = '1' then
        q <= (others => '0');
    elsif rising_edge(clk) then
        q <= d;
    end if;
end process;

 

10.5.5 Registre à décalage

Un registre à décalage déplace les bits à chaque front actif. Il peut réaliser une conversion série-parallèle ou parallèle-série.

10.5.6 Décalage à gauche

Décalage gauche avec entrée série  |  VHDL
process(clk, reset)
begin
    if reset = '1' then
        q <= (others => '0');
    elsif rising_edge(clk) then
        if enable = '1' then
            q <= q(q'high-1 downto 0)
                 & entree_serie;
        end if;
    end if;
end process;

 

Le bit q(q'high) est perdu. L’entrée série est insérée en position de poids faible.

10.5.7 Décalage à droite

Décalage droite avec entrée série  |  VHDL
process(clk, reset)
begin
    if reset = '1' then
        q <= (others => '0');
    elsif rising_edge(clk) then
        if enable = '1' then
            q <= entree_serie
                 & q(q'high downto 1);
        end if;
    end if;
end process;

 

Le bit q(0) est perdu. L’entrée série est insérée en position de poids fort.

10.5.8 Chargement parallèle

Registre avec load  |   VHDL
process(clk, reset)
begin
    if reset = '1' then
        q <= (others => '0');
    elsif rising_edge(clk) then
        if load = '1' then
            q <= data_in;
        end if;
    end if;
end process;

 

10.5.9 Registre universel

Un registre universel peut conserver sa valeur, charger un mot parallèle, décaler à gauche ou décaler à droite.

Commandes du registre universel  |  Convention
-- mode = "00" : maintien
-- mode = "01" : décalage à gauche
-- mode = "10" : décalage à droite
-- mode = "11" : chargement parallèle

 

Registre universel — Partie 1  |  VHDL
process(clk, reset)
begin
    if reset = '1' then
        q <= (others => '0');
    elsif rising_edge(clk) then
        case mode is
            when "00" =>
                null;

            when "01" =>
                q <= q(q'high-1 downto 0)
                     & serie_gauche;

 

Registre universel — Partie 2  |  VHDL
            when "10" =>
                q <= serie_droite
                     & q(q'high downto 1);

            when others =>
                q <= data_in;
        end case;
    end if;
end process;

 

10.5.10 Signal interne pour relire q

Pour une compatibilité maximale avec les anciennes versions de VHDL, on peut utiliser un signal interne plutôt que relire directement un port out.

Registre avec signal interne  |  VHDL
architecture rtl of registre_decalage is
    signal q_i : std_logic_vector(7 downto 0);
begin
    process(clk, reset)
    begin
        if reset = '1' then
            q_i <= (others => '0');
        elsif rising_edge(clk) then
            q_i <= q_i(6 downto 0) & entree_serie;
        end if;
    end process;

    q <= q_i;
end architecture rtl;

 

10.5.11 Conversion série-parallèle

Cycle

Entrée série

Contenu après décalage gauche

Initial00000000
1100000001
2000000010
3100000101
4100001011

 

10.5.12 Registre parallèle-série

Un mot est d’abord chargé en parallèle, puis ses bits sont présentés successivement à la sortie série lors des décalages.

Sortie série  |   VHDL
sortie_serie <= q_i(0);

process(clk, reset)
begin
    if reset = '1' then
        q_i <= (others => '0');
    elsif rising_edge(clk) then
        if load = '1' then
            q_i <= data_in;
        elsif shift = '1' then
            q_i <= '0' & q_i(q_i'high downto 1);
        end if;
    end if;
end process;

 

10.5.13 Utilisations

  • stockage temporaire ;
  • pipeline de traitement ;
  • synchronisation de signaux ;
  • conversion série/parallèle ;
  • retard numérique de plusieurs cycles ;
  • génération de séquences ;
  • interfaces SPI et UART ;
  • registres d’état et de commande.

10.5.14 Inférence de ressources FPGA

Description

Ressource possible

Registre simpleBascules dans les blocs logiques
Registre avec enableClock enable dédié
Registre avec resetEntrée reset/set dédiée ou logique
Long registre à décalageBascules ou ressource LUT/SRL selon FPGA
Registre très largeBascules ou mémoire selon usage

 

Bonne pratique — Horloge unique

Pour suspendre la mise à jour d’un registre, utiliser enable plutôt que de couper l’horloge avec une porte logique. Le clock gating manuel peut créer des glitches et perturber le réseau d’horloge.

 

Méthode de conception d’un circuit séquentiel simple

1. Identifier le front d’horloge actif.

2. Déterminer si un reset est nécessaire et choisir son type.

3. Définir l’ordre de priorité entre reset, chargement, enable et décalage.

4. Choisir la largeur des registres.

5. Écrire un seul processus cadencé par domaine d’horloge lorsque cela améliore la cohérence.

6. Utiliser rising_edge ou falling_edge.

7. Définir clairement les états de maintien.

8. Écrire un banc de test avec horloge et séquence de reset.

9. Tester les changements de données avant, pendant et après les fronts.

10. Vérifier le schéma RTL et les contraintes temporelles.

Checklist d’un processus cadencé

  • La liste de sensibilité contient-elle seulement clk et les commandes asynchrones ?
  • La détection utilise-t-elle rising_edge ou falling_edge ?
  • Le reset possède-t-il la priorité voulue ?
  • Les commandes sont-elles testées dans le bon ordre ?
  • La conservation de valeur est-elle volontaire ?
  • Les entrées asynchrones sont-elles synchronisées ?
  • L’horloge utilise-t-elle une broche et un réseau dédiés ?
  • Une contrainte de période est-elle définie dans le projet FPGA ?

Erreurs fréquentes

Erreur

Conséquence

Correction

Tester clk='1' sans eventComportement de niveau, pas de frontUtiliser rising_edge
Ajouter d à la sensibilité d’une basculeSimulation inutilement réveilléeConserver clk et reset asynchrone
Oublier reset dans une sensibilité asynchroneSimulation incorrecteAjouter reset
Créer une horloge par logique combinatoireGlitches et skewUtiliser enable ou ressources d’horloge
Changer un signal asynchrone directementMétastabilitéSynchroniseur
Mauvaise priorité load/shiftFonction incorrecteOrdonner les tests selon le cahier des charges
Lire un port out avec un ancien standardErreur de compilationUtiliser un signal interne

 

Travaux pratiques

TP 7 — Bascules et registres

1. Objectifs du TP

  • simuler une bascule D ;
  • ajouter un reset asynchrone ;
  • concevoir un registre 8 bits ;
  • concevoir un registre à décalage ;
  • vérifier les fronts d’horloge et les priorités ;
  • implanter les circuits sur une carte FPGA ;
  • commander les entrées par boutons et interrupteurs ;
  • observer les sorties sur des LED.

2. Organisation du projet

Arborescence proposée  |  Arborescence
tp7_bascules_registres/
├── src/
│   ├── bascule_d.vhd
│   ├── bascule_d_reset.vhd
│   ├── registre8.vhd
│   ├── registre_decalage8.vhd
│   └── top_fpga.vhd
├── sim/
│   ├── tb_bascule_d.vhd
│   ├── tb_bascule_d_reset.vhd
│   ├── tb_registre8.vhd
│   └── tb_registre_decalage8.vhd
└── constraints/
    └── carte.xdc_ou_qsf

 

3. Partie A — Bascule D

bascule_d.vhd  |   VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity bascule_d is
    port (
        clk : in  std_logic;
        d   : in   std_logic;
        q   : out std_logic
    );
end entity bascule_d;

architecture rtl of bascule_d is
begin
    process(clk)
    begin
        if rising_edge(clk) then
            q <= d;
        end if;
    end process;
end architecture rtl;

 

4. Banc de test de la bascule D

tb_bascule_d.vhd — Partie 1  |  VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use STD.ENV.ALL;

entity tb_bascule_d is
end entity tb_bascule_d;

architecture simulation of tb_bascule_d is
    constant PERIODE : time := 20 ns;

    signal clk : std_logic := '0';
    signal d   : std_logic := '0';
    signal q   : std_logic;
begin
    clk <= not clk after PERIODE / 2;

    DUT : entity work.bascule_d(rtl)
        port map (
            clk => clk,
            d   => d,
            q   => q
        );

 

tb_bascule_d.vhd — Partie 2  |  VHDL
    stimuli : process
    begin
        d <= '0';
        wait until rising_edge(clk);
        wait for 1 ns;
        assert q = '0' severity error;

        d <= '1';
        wait for 5 ns;

        -- Q ne doit changer qu'au front suivant.
        assert q = '0'
            report "Q a change entre deux fronts"
            severity error;

        wait until rising_edge(clk);
        wait for 1 ns;
        assert q = '1' severity error;

        report "Bascule D valide" severity note;
        stop;
        wait;
    end process;
end architecture simulation;

 

5. Partie B — Bascule D avec reset asynchrone

bascule_d_reset.vhd — Entité  |  VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity bascule_d_reset is
    port (
        clk   : in   std_logic;
        reset : in  std_logic;
        d     : in   std_logic;
        q     : out std_logic
    );
end entity bascule_d_reset;
bascule_d_reset.vhd — Architecture  |  VHDL
architecture rtl of bascule_d_reset is
begin
    process(clk, reset)
    begin
        if reset = '1' then
            q <= '0';
        elsif rising_edge(clk) then
            q <= d;
        end if;
    end process;
end architecture rtl;

 

6. Banc de test du reset asynchrone

tb_bascule_d_reset.vhd — Scénario  |  VHDL
reset <= '1';
d <= '1';
wait for 7 ns;

assert q = '0'
    report "Le reset asynchrone n'agit pas"
    severity error;

reset <= '0';
wait until rising_edge(clk);
wait for 1 ns;

assert q = '1'
    report "D n'a pas ete capture apres reset"
    severity error;

reset <= '1';
wait for 1 ns;

assert q = '0'
    report "Le reset doit agir sans attendre l'horloge"
    severity error;

 

7. Partie C — Registre 8 bits

registre8.vhd — Entité  |  VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity registre8 is
    port (
        clk    : in   std_logic;
        reset  : in   std_logic;
        enable : in  std_logic;
        d      : in   std_logic_vector(7 downto 0);
        q      : out std_logic_vector(7 downto 0)
    );
end entity registre8;
registre8.vhd — Architecture  |  VHDL
architecture rtl of registre8 is
begin
    process(clk, reset)
    begin
        if reset = '1' then
            q <= (others => '0');
        elsif rising_edge(clk) then
            if enable = '1' then
                q <= d;
            end if;
        end if;
    end process;
end architecture rtl;

 

8. Banc de test du registre 8 bits

tb_registre8.vhd — Tests  |  VHDL
reset <= '1';
enable <= '0';
d <= x"A5";
wait for 15 ns;

assert q = x"00" severity error;

reset <= '0';
enable <= '1';
wait until rising_edge(clk);
wait for 1 ns;

assert q = x"A5"
    report "Chargement du registre incorrect"
    severity error;

enable <= '0';
d <= x"3C";
wait until rising_edge(clk);
wait for 1 ns;

assert q = x"A5"
    report "Le registre doit conserver sa valeur"
    severity error;

 

9. Partie D — Registre à décalage 8 bits

registre_decalage8.vhd — Entité  |  VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity registre_decalage8 is
    port (
        clk          : in  std_logic;
        reset        : in   std_logic;
        enable       : in   std_logic;
        entree_serie : in  std_logic;
        q            : out std_logic_vector(7 downto 0)
    );
end entity registre_decalage8;

 

registre_decalage8.vhd — Architecture  |  VHDL
architecture rtl of registre_decalage8 is
    signal q_i : std_logic_vector(7 downto 0);
begin
    process(clk, reset)
    begin
        if reset = '1' then
            q_i <= (others => '0');
        elsif rising_edge(clk) then
            if enable = '1' then
                q_i <= q_i(6 downto 0)
                       & entree_serie;
            end if;
        end if;
    end process;

    q <= q_i;
end architecture rtl;

 

10. Banc de test du registre à décalage

Séquence binaire 10110010  |  VHDL
constant SEQUENCE : std_logic_vector(7 downto 0)
                    := "10110010";

for i in SEQUENCE'range loop
    entree_serie <= SEQUENCE(i);
    wait until rising_edge(clk);
    wait for 1 ns;
end loop;

assert q = SEQUENCE
    report "La sequence serie-parallele est incorrecte"
    severity error;

 

Vérification — Ordre des bits

Avec la boucle sur SEQUENCE'range = 7 downto 0 et un décalage vers la gauche, les bits sont injectés du poids fort vers le poids faible pour obtenir finalement le mot SEQUENCE.

 

11. Partie E — Niveau supérieur pour carte FPGA

L’exemple suivant associe les boutons et interrupteurs aux blocs du TP. Les noms exacts des ports doivent être adaptés à la carte.

top_fpga.vhd — Entité  |  VHDL
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity top_fpga is
    port (
        clk_carte : in  std_logic;
        bouton_reset : in std_logic;
        bouton_shift : in std_logic;
        switch_serie : in std_logic;
        leds : out std_logic_vector(7 downto 0)
    );
end entity top_fpga;

 

top_fpga.vhd — Instanciation  |  VHDL
architecture structurelle of top_fpga is
    signal shift_synch : std_logic;
begin
    -- Pour un prototype pédagogique, le bouton doit
    -- idéalement être synchronisé et anti-rebond.

    U_SHIFT : entity work.registre_decalage8(rtl)
        port map (
            clk          => clk_carte,
            reset        => bouton_reset,
            enable       => bouton_shift,
            entree_serie => switch_serie,
            q            => leds
        );
end architecture structurelle;

 

12. Attention aux boutons mécaniques

Un bouton mécanique produit plusieurs transitions rapides lors d’un appui. Il est également asynchrone par rapport à l’horloge du FPGA.

  • synchroniser le bouton avec deux bascules ;
  • ajouter un circuit anti-rebond ;
  • détecter une impulsion d’un seul cycle ;
  • ne pas utiliser directement un bouton comme horloge logique.

Carte FPGA — Validation progressive

Pour une première démonstration, un bouton peut servir d’enable sur l’horloge de la carte. Pour un fonctionnement fiable, il doit être synchronisé, filtré et transformé en impulsion.

 

13. Exemple de synchronisation du bouton

Synchroniseur à deux bascules  |  VHDL
process(clk_carte)
begin
    if rising_edge(clk_carte) then
        bouton_meta  <= bouton_shift;
        bouton_synch <= bouton_meta;
    end if;
end process;

 

14. Détection d’un appui

Détection de front du bouton synchronisé  |  VHDL
process(clk_carte)
begin
    if rising_edge(clk_carte) then
        bouton_prec <= bouton_synch;

        impulsion <= bouton_synch
                    and not bouton_prec;
    end if;
end process;

 

L’impulsion vaut 1 pendant un cycle lors du passage de 0 à 1, après synchronisation.

15. Contraintes de broches

Le fichier de contraintes associe les ports VHDL aux broches physiques et précise les standards électriques. La syntaxe dépend de l’outil et de la carte.

Exemple conceptuel XDC  |   Contraintes
set_property PACKAGE_PIN <PIN_CLK> [get_ports clk_carte]
set_property IOSTANDARD LVCMOS33 [get_ports clk_carte]

set_property PACKAGE_PIN <PIN_LED0> [get_ports {leds[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {leds[0]}]

create_clock -period 10.000   -name clk_carte   [get_ports clk_carte]

 

Important — Ne pas copier les broches sans vérifier

Les identifiants de broches, tensions et standards doivent provenir du manuel ou du fichier maître de contraintes de la carte utilisée.

 

16. Procédure de validation sur la carte

1. Sélectionner la carte ou le composant FPGA.

2. Ajouter les fichiers VHDL au projet.

3. Définir top_fpga comme entité supérieure.

4. Ajouter les contraintes de broches et d’horloge.

5. Lancer l’analyse, la synthèse, le placement et le routage.

6. Vérifier les avertissements et le rapport temporel.

7. Générer le fichier de configuration.

8. Programmer la carte.

9. Activer le reset.

10. Choisir le bit série avec l’interrupteur.

11. Produire des impulsions de décalage.

12. Observer le contenu du registre sur les LED.

17. Commandes GHDL

Compilation des blocs  |  Terminal
ghdl -a --std=08 src/bascule_d.vhd
ghdl -a --std=08 src/bascule_d_reset.vhd
ghdl -a --std=08 src/registre8.vhd
ghdl -a --std=08 src/registre_decalage8.vhd

 

Simulation d’un banc de test  |  Terminal
ghdl -a --std=08 sim/tb_registre_decalage8.vhd
ghdl -e --std=08 tb_registre_decalage8
ghdl -r --std=08 tb_registre_decalage8    --vcd=tb_registre_decalage8.vcd

gtkwave tb_registre_decalage8.vcd

 

18. Observations demandées

  • Vérifier que Q ne change qu’au front actif.
  • Vérifier l’action immédiate du reset asynchrone.
  • Vérifier le maintien lorsque enable vaut 0.
  • Observer la progression du registre à décalage.
  • Comparer les données avant et après chaque front.
  • Observer le reset et les LED sur la carte.
  • Comparer la simulation RTL et le comportement matériel.

19. Tableau de résultats

Circuit

Scénario

Résultat attendu

Résultat observé

Conforme

Bascule DD change entre deux frontsQ inchangé  
Bascule D resetreset=1Q=0 immédiatement  
Registre 8 bitsenable=1Q charge D  
Registre 8 bitsenable=0Q conservé  
Registre décalage8 impulsionsMot série reçu  
Carte FPGAReset puis décalagesLED conformes  

 

20. Questions d’analyse

1. Pourquoi une bascule D mémorise-t-elle la valeur uniquement au front actif ?

2. Quelle différence existe entre la période et la fréquence ?

3. Pourquoi rising_edge est-il préférable à clk'event and clk='1' ?

4. Pourquoi D ne figure-t-il pas dans la liste de sensibilité d’une bascule ?

5. Quelle différence fonctionnelle existe entre reset synchrone et asynchrone ?

6. Pourquoi le reset est-il généralement prioritaire sur enable ?

7. Comment un registre conserve-t-il sa valeur lorsque enable vaut 0 ?

8. Quelle est la direction du décalage dans q_i(6 downto 0) & entree_serie ?

9. Pourquoi un bouton ne doit-il pas être utilisé directement comme horloge ?

10. Quel est le rôle de la contrainte create_clock ?

21. Extensions proposées

  • Ajouter un reset synchrone au registre 8 bits.
  • Créer un registre universel.
  • Ajouter un chargement parallèle au registre à décalage.
  • Créer une sortie série.
  • Ajouter un anti-rebond pour les boutons.
  • Créer un registre paramétrable sur N bits.
  • Comparer décalage gauche et décalage droite.
  • Afficher le registre sur un afficheur sept segments.
  • Créer un pipeline de plusieurs registres.

22. Barème indicatif

Critère

Points

Bascule D2
Bascule avec reset asynchrone3
Registre 8 bits avec enable3
Registre à décalage4
Bancs de test et assertions3
Validation sur carte FPGA2
Analyse des chronogrammes2
Qualité du code et du compte rendu1
Total20

 

Synthèse du chapitre

Notion

Résumé

HorlogeSignal périodique coordonnant les changements d’état.
PériodeDurée d’un cycle complet.
FréquenceNombre de cycles par seconde.
Front montantTransition de 0 vers 1.
rising_edgeForme recommandée de détection du front montant.
Bascule DMémorise D au front actif.
EnableAutorise le chargement d’un registre.
Reset synchroneAgit au front d’horloge.
Reset asynchroneAgit immédiatement.
RegistreEnsemble de bascules mémorisant un mot.
Registre à décalageDéplace les bits à chaque front autorisé.
SynchroniseurRéduit le risque lié aux entrées asynchrones.

 

Autoévaluation

1. Quelle relation lie fréquence et période ?

Réponse : f = 1/T.

2. Quelle fonction détecte un front montant ?

Réponse : rising_edge(clk).

3. Quelle valeur capture une bascule D ?

Réponse : La valeur de D au front actif.

4. Un reset synchrone agit-il sans horloge ?

Réponse : Non.

5. Un reset asynchrone doit-il apparaître dans la sensibilité ?

Réponse : Oui.

6. Que fait un registre lorsque enable vaut 0 ?

Réponse : Il conserve sa valeur.

7. Que réalise q(6 downto 0) & entree_serie ?

Réponse : Un décalage à gauche avec insertion en bit 0.

8. Pourquoi synchroniser un bouton ?

Réponse : Parce qu’il est asynchrone et peut provoquer de la métastabilité.

9. Pourquoi éviter une horloge créée par une porte logique ?

Réponse : Elle peut produire glitches et skew.

10. Quel fichier associe les ports aux broches FPGA ?

Réponse : Le fichier de contraintes.

Exercice de consolidation

Concevoir un registre 4 bits avec reset synchrone, chargement parallèle prioritaire et décalage à droite autorisé par enable.

Correction proposée  |  VHDL
process(clk)
begin
    if rising_edge(clk) then
        if reset = '1' then
            q <= (others => '0');
        elsif load = '1' then
            q <= data_in;
        elsif enable = '1' then
            q <= entree_serie & q(3 downto 1);
        end if;
    end if;
end process;

 

Suite du cours — Transition vers la suite

Après les bascules et registres, le cours peut aborder les compteurs, diviseurs de fréquence et temporisateurs, qui combinent registres et opérations arithmétiques synchrones.