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.1 | Signaux synchrones | Caractériser une horloge |
| 10.2 | Détection de front | Écrire un processus cadencé correct |
| 10.3 | Bascule D | Mémoriser un bit |
| 10.4 | Reset synchrone et asynchrone | Définir une initialisation fiable |
| 10.5 | Registres | Mémoriser et déplacer des mots binaires |
| TP 7 | Bascules et registres | Simuler 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 ns | Un front montant toutes les 20 ns |
| 10 ns | Cycle deux fois plus rapide qu’une période de 20 ns |
| 1 µs | Un million de cycles par seconde |
| 1 ms | Mille 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 ns | 50 MHz |
| 10 ns | 100 MHz |
| 8 ns | 125 MHz |
| 1 µs | 1 MHz |
| 1 ms | 1 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 ns | 20 ns | 50 % |
| 6 ns | 20 ns | 30 % |
| 15 ns | 20 ns | 75 % |
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 ns | 0 | État initial |
| 10 ns | 1 | Front montant |
| 20 ns | 0 | Front descendant |
| 30 ns | 1 | Front montant suivant |
| 40 ns | 0 | Front 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 |
|---|---|
| Setup | La donnée doit être stable avant le front actif. |
| Hold | La donnée doit rester stable après le front actif. |
| Clock-to-Q | Délai entre le front et la modification de la sortie de la bascule. |
| Chemin combinatoire | Dé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 claire | Normalisée | À privilégier |
| falling_edge(clk) | Très claire | Normalisée | À privilégier si nécessaire |
| clk'event and clk='1' | Moins expressive | Plus ancienne | À reconnaître |
| clk='1' seul | Incorrect | Ne 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 reset | clk |
| Reset synchrone | clk |
| Reset asynchrone | clk, reset |
| Set asynchrone | clk, set |
| Reset et set asynchrones | clk, 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 actif | 0 ou 1 | Q conserve sa valeur |
| Front actif | 0 | Q devient 0 |
| Front actif | 1 | Q 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 |
|---|---|---|
| Non | 0 ou 1 | Q conserve sa valeur |
| Oui | 0 | Q conserve sa valeur |
| Oui | 1 | Q 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 |
|---|---|---|
| 1 | reset | Force la valeur initiale |
| 2 | load | Charge une donnée parallèle |
| 3 | enable | Autorise la mise à jour |
| 4 | aucune | Conserve 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’action | Au front actif | Immédiatement |
| Liste de sensibilité | clk | clk, reset |
| Dépendance à l’horloge | Oui | Non pour l’activation |
| Risque à la désactivation | Faible si synchrone | Doit être synchronisée |
| Utilisation | Contrôle fonctionnel | Initialisation 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 |
|---|---|---|
| Initial | — | 00000000 |
| 1 | 1 | 00000001 |
| 2 | 0 | 00000010 |
| 3 | 1 | 00000101 |
| 4 | 1 | 00001011 |
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 simple | Bascules dans les blocs logiques |
| Registre avec enable | Clock enable dédié |
| Registre avec reset | Entrée reset/set dédiée ou logique |
| Long registre à décalage | Bascules ou ressource LUT/SRL selon FPGA |
| Registre très large | Bascules 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 event | Comportement de niveau, pas de front | Utiliser rising_edge |
| Ajouter d à la sensibilité d’une bascule | Simulation inutilement réveillée | Conserver clk et reset asynchrone |
| Oublier reset dans une sensibilité asynchrone | Simulation incorrecte | Ajouter reset |
| Créer une horloge par logique combinatoire | Glitches et skew | Utiliser enable ou ressources d’horloge |
| Changer un signal asynchrone directement | Métastabilité | Synchroniseur |
| Mauvaise priorité load/shift | Fonction incorrecte | Ordonner les tests selon le cahier des charges |
| Lire un port out avec un ancien standard | Erreur de compilation | Utiliser 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 D | D change entre deux fronts | Q inchangé | ||
| Bascule D reset | reset=1 | Q=0 immédiatement | ||
| Registre 8 bits | enable=1 | Q charge D | ||
| Registre 8 bits | enable=0 | Q conservé | ||
| Registre décalage | 8 impulsions | Mot série reçu | ||
| Carte FPGA | Reset puis décalages | LED 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 D | 2 |
| Bascule avec reset asynchrone | 3 |
| Registre 8 bits avec enable | 3 |
| Registre à décalage | 4 |
| Bancs de test et assertions | 3 |
| Validation sur carte FPGA | 2 |
| Analyse des chronogrammes | 2 |
| Qualité du code et du compte rendu | 1 |
| Total | 20 |
Synthèse du chapitre
Notion | Résumé |
|---|---|
| Horloge | Signal périodique coordonnant les changements d’état. |
| Période | Durée d’un cycle complet. |
| Fréquence | Nombre de cycles par seconde. |
| Front montant | Transition de 0 vers 1. |
| rising_edge | Forme recommandée de détection du front montant. |
| Bascule D | Mémorise D au front actif. |
| Enable | Autorise le chargement d’un registre. |
| Reset synchrone | Agit au front d’horloge. |
| Reset asynchrone | Agit immédiatement. |
| Registre | Ensemble de bascules mémorisant un mot. |
| Registre à décalage | Déplace les bits à chaque front autorisé. |
| Synchroniseur | Ré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. |