Chapitre 12 — Machines à états finis
Objectif — Finalité du chapitre Modéliser des systèmes séquentiels complexes par des machines de Moore ou de Mealy, appliquer une méthode de conception rigoureuse, choisir un style VHDL et valider plusieurs contrôleurs par simulation. |
Objectifs pédagogiques
À la fin de ce chapitre, l’étudiant devra être capable de :
- définir les états, transitions, entrées, sorties et état initial d’une machine ;
- distinguer une machine de Moore d’une machine de Mealy ;
- construire un diagramme d’états et une table de transition ;
- décomposer une machine en registre d’état, logique de transition et logique de sortie ;
- écrire des machines à un, deux ou trois processus ;
- choisir un codage binaire, one-hot ou Gray ;
- éviter les latches et transitions non définies ;
- synchroniser les entrées externes avant leur utilisation ;
- simuler les transitions, sorties et situations invalides ;
- concevoir un détecteur de séquence, un feu de circulation, une porte automatique et un distributeur.
Prérequis
- processus combinatoires et cadencés ;
- bascules, registres, compteurs et ticks ;
- instructions if et case ;
- types énumérés et signaux ;
- bancs de test et assertions.
Organisation du chapitre
Section | Contenu | Compétence principale |
|---|---|---|
| 12.1 | Définition d’une machine à états | Identifier les éléments d’un automate |
| 12.2 | Machine de Moore | Produire les sorties à partir de l’état |
| 12.3 | Machine de Mealy | Combiner état et entrées dans les sorties |
| 12.4 | Méthode de conception | Passer du cahier des charges au VHDL |
| 12.5 | Styles de description | Organiser les processus |
| 12.6 | Codage des états | Choisir une représentation matérielle |
| TP 9 | Conception de machines | Mettre en œuvre quatre contrôleurs |
Concept clé — Structure générale Une machine à états finis associe un registre d’état à une logique combinatoire. Le registre mémorise l’état courant ; la logique calcule l’état suivant et les sorties. |
12.1 Définition d’une machine à états
Une machine à états finis, ou FSM (Finite State Machine), est un modèle de commande dont le comportement dépend d’un nombre fini de situations mémorisées appelées états. Elle évolue d’un état à un autre au rythme d’une horloge.
12.1.1 État
Un état résume l’histoire utile du système. Il représente une situation dans laquelle les mêmes règles de transition et de sortie s’appliquent.
Exemple de système | États possibles |
|---|---|
| Feu de circulation | VERT, ORANGE, ROUGE |
| Porte automatique | FERMEE, OUVERTURE, OUVERTE, FERMETURE |
| Distributeur | CREDIT_0, CREDIT_1, CREDIT_2, DISTRIBUTION |
| Récepteur série | ATTENTE, START, DONNEES, STOP |
12.1.2 Transition
Une transition est un passage d’un état courant vers un état suivant. Elle est déclenchée par une condition sur les entrées, un temporisateur ou un événement interne.
| Transition conceptuelle | Diagramme textuel |
| ETAT_A -- condition --> ETAT_B |
12.1.3 Entrée
Une entrée est une information observée par la machine : bouton, capteur, bit série, tick de temporisation, crédit inséré ou résultat d’un comparateur.
12.1.4 Sortie
Une sortie commande le système : moteur, feu, signal de validation, impulsion de distribution, alarme ou autorisation.
12.1.5 État initial
L’état initial est l’état imposé au démarrage ou par le reset. Il doit placer le système dans une situation sûre et déterministe.
| Registre d’état avec reset | VHDL |
| process(clk, reset) begin if reset = '1' then etat_courant <= ATTENTE; elsif rising_edge(clk) then etat_courant <= etat_suivant; end if; end process; |
12.1.6 Modèle matériel
Bloc | Rôle |
|---|---|
| Registre d’état | Mémorise l’état courant au front d’horloge. |
| Logique de transition | Calcule l’état suivant à partir de l’état courant et des entrées. |
| Logique de sortie | Calcule les sorties selon le modèle Moore ou Mealy. |
| Reset | Force l’état initial. |
12.1.7 Représentation par diagramme
Un diagramme d’états utilise des cercles ou rectangles pour les états et des flèches pour les transitions. Les conditions sont écrites sur les flèches. Pour une machine de Moore, les sorties peuvent être indiquées à l’intérieur de l’état.
| Exemple simplifié | Diagramme textuel |
| [ATTENTE / pret=1] | | start=1 v [TRAITEMENT / pret=0] | | fini=1 v [ATTENTE / pret=1] |
12.1.8 Table de transition
État courant | Entrées | État suivant | Sorties |
|---|---|---|---|
| ATTENTE | start=0 | ATTENTE | pret=1 |
| ATTENTE | start=1 | TRAITEMENT | pret=1 |
| TRAITEMENT | fini=0 | TRAITEMENT | pret=0 |
| TRAITEMENT | fini=1 | ATTENTE | pret=0 |
12.1.9 Finie ne signifie pas petite
Le nombre d’états est fini, mais peut être important. Une bonne méthode cherche à limiter les états aux situations réellement distinctes et à factoriser les comportements identiques.
12.1.10 Machine déterministe
Pour chaque combinaison état courant/entrées, l’état suivant doit être défini sans ambiguïté. Une machine déterministe ne possède qu’une transition applicable à la fois.
Bonne pratique — Complétude Dans une description combinatoire de FSM, définir une valeur par défaut pour l’état suivant et pour toutes les sorties afin d’éviter les latches et les situations non couvertes. |
12.2 Machine de Moore
Dans une machine de Moore, les sorties dépendent uniquement de l’état courant. Elles ne changent normalement qu’après la mise à jour du registre d’état.
12.2.1 Principe
| Relation de Moore | Modèle |
| etat_suivant = F(etat_courant, entrees) sorties = G(etat_courant) |
12.2.2 Conséquences
- sorties stables entre deux changements d’état ;
- faible sensibilité aux variations instantanées des entrées ;
- latence possible d’un cycle pour certaines réactions ;
- diagrammes souvent simples à relire.
12.2.3 Exemple : commande start/done
| Diagramme de Moore | Diagramme textuel |
| [ATTENTE / busy=0, done=0] | start=1 v [ACTIF / busy=1, done=0] | fini=1 v [FIN / busy=0, done=1] | acquit=1 v [ATTENTE / busy=0, done=0] |
12.2.4 Table de transition
État | Condition | État suivant | busy | done |
|---|---|---|---|---|
| ATTENTE | start=0 | ATTENTE | 0 | 0 |
| ATTENTE | start=1 | ACTIF | 0 | 0 |
| ACTIF | fini=0 | ACTIF | 1 | 0 |
| ACTIF | fini=1 | FIN | 1 | 0 |
| FIN | acquit=0 | FIN | 0 | 1 |
| FIN | acquit=1 | ATTENTE | 0 | 1 |
12.2.5 Déclaration des états
| Type énuméré | VHDL |
| type etat_t is (ATTENTE, ACTIF, FIN); signal etat_courant : etat_t; signal etat_suivant : etat_t; |
12.2.6 Registre d’état
| Mémorisation synchrone | VHDL |
| registre_etat : process(clk, reset) begin if reset = '1' then etat_courant <= ATTENTE; elsif rising_edge(clk) then etat_courant <= etat_suivant; end if; end process; |
12.2.7 Logique de transition
| Transition Moore — Partie 1 | VHDL |
| logique_transition : process(all) begin etat_suivant <= etat_courant; case etat_courant is when ATTENTE => if start = '1' then etat_suivant <= ACTIF; end if; |
| Transition Moore — Partie 2 | VHDL |
| when ACTIF => if fini = '1' then etat_suivant <= FIN; end if; when FIN => if acquit = '1' then etat_suivant <= ATTENTE; end if; end case; end process; |
12.2.8 Logique de sortie
| Sorties de Moore | VHDL |
| logique_sortie : process(all) begin busy <= '0'; done <= '0'; case etat_courant is when ATTENTE => null; when ACTIF => busy <= '1'; when FIN => done <= '1'; end case; end process; |
12.2.9 Sorties concurrentes
| Alternative compacte | VHDL |
| busy <= '1' when etat_courant = ACTIF else '0'; done <= '1' when etat_courant = FIN else '0'; |
12.2.10 Chronologie
Instant | start | État courant | busy |
|---|---|---|---|
| Avant front | 1 | ATTENTE | 0 |
| Après front | 1 | ACTIF | 1 |
| Entre fronts | 0 ou 1 | ACTIF | 1 |
Caractéristique — Sortie Moore La sortie réagit au changement d’état enregistré. Une condition d’entrée ne modifie pas directement la sortie tant que le registre n’a pas changé. |
12.3 Machine de Mealy
Dans une machine de Mealy, les sorties dépendent de l’état courant et des entrées. Une sortie peut donc changer immédiatement après une variation d’entrée, sans attendre le front suivant.
12.3.1 Principe
| Relation de Mealy | Modèle |
| etat_suivant = F(etat_courant, entrees) sorties = G(etat_courant, entrees) |
12.3.2 Exemple de sortie immédiate
| Validation en Mealy | VHDL |
| valide <= '1' when etat_courant = ATTENTE and start = '1' else '0'; |
12.3.3 Diagramme de Mealy
Les sorties associées à une transition sont écrites sur la flèche sous la forme condition/sortie.
| Exemple | Diagramme textuel |
| [ATTENTE] -- start=1 / valide=1 --> [ACTIF] [ACTIF] -- fini=1 / done=1 --> [ATTENTE] |
12.3.4 Différences Moore/Mealy
Critère | Moore | Mealy |
|---|---|---|
| Dépendance des sorties | État courant | État courant + entrées |
| Réaction | Après transition d’état | Potentiellement immédiate |
| Nombre d’états | Parfois plus élevé | Souvent plus faible |
| Stabilité des sorties | Très bonne | Dépend de la stabilité des entrées |
| Lecture du diagramme | Sorties dans les états | Sorties sur les transitions |
12.3.5 Avantages de Mealy
- réponse rapide ;
- réduction possible du nombre d’états ;
- impulsions de sortie naturelles sur une transition ;
- description compacte de certains protocoles.
12.3.6 Inconvénients de Mealy
- sorties sensibles aux glitches des entrées ;
- chemins combinatoires directs entrée-sortie ;
- chronogrammes plus délicats ;
- nécessité de synchroniser et filtrer les entrées externes.
12.3.7 Exemple VHDL Mealy
| Sorties et transitions combinées | VHDL |
| process(all) begin etat_suivant <= etat_courant; impulsion <= '0'; case etat_courant is when ATTENTE => if entree = '1' then etat_suivant <= ACTIF; impulsion <= '1'; end if; when ACTIF => if entree = '0' then etat_suivant <= ATTENTE; end if; end case; end process; |
12.3.8 Enregistrement d’une sortie Mealy
Une sortie Mealy critique peut être enregistrée pour supprimer les glitches, au prix d’une latence supplémentaire.
| Sortie enregistrée | VHDL |
| process(clk, reset) begin if reset = '1' then sortie_reg <= '0'; elsif rising_edge(clk) then sortie_reg <= sortie_mealy; end if; end process; |
12.3.9 Choisir Moore ou Mealy
Besoin | Choix souvent adapté |
|---|---|
| Sorties stables commandant un actionneur | Moore |
| Impulsion immédiate sur une combinaison | Mealy |
| Entrées asynchrones ou bruitées | Moore après synchronisation |
| Réduction du nombre d’états | Mealy |
| Lisibilité pédagogique | Moore |
Attention — Entrées synchrones Même une machine de Moore peut mal fonctionner si ses entrées violent les temps de setup/hold. Toute entrée provenant de l’extérieur du domaine d’horloge doit être synchronisée. |
12.4 Méthode de conception
Une FSM fiable résulte d’une démarche structurée. Le code VHDL ne doit être écrit qu’après clarification du comportement et des transitions.
12.4.1 Analyse du cahier des charges
- identifier les entrées, sorties et horloge ;
- préciser les niveaux actifs ;
- définir les temporisations en cycles ou ticks ;
- déterminer le comportement au reset ;
- traiter les erreurs et cas simultanés ;
- définir les priorités.
12.4.2 Identification des états
Créer un état lorsque le système doit mémoriser une situation différente. Deux situations peuvent partager le même état si elles produisent les mêmes sorties et les mêmes règles de transition.
12.4.3 Construction du diagramme
1. Placer l’état initial.
2. Ajouter les états fonctionnels.
3. Tracer toutes les transitions possibles.
4. Annoter les conditions.
5. Ajouter les sorties Moore ou Mealy.
6. Vérifier qu’aucun état n’est isolé.
12.4.4 Définition des transitions
Chaque état doit définir le comportement pour toutes les combinaisons d’entrées significatives. Une transition implicite de maintien peut être représentée par etat_suivant <= etat_courant.
12.4.5 Codage des états
Le type énuméré est recommandé dans le code RTL. Le choix physique du codage peut être laissé au synthétiseur ou guidé par des attributs.
| Type énuméré | VHDL |
| type etat_t is ( ATTENTE, INITIALISATION, TRAITEMENT, ERREUR, FIN ); |
12.4.6 Description du registre d’état
| Processus séquentiel | VHDL |
| process(clk, reset) begin if reset = '1' then etat_courant <= ATTENTE; elsif rising_edge(clk) then etat_courant <= etat_suivant; end if; end process; |
12.4.7 Logique de l’état suivant
| Patron combinatoire | VHDL |
| process(all) begin etat_suivant <= etat_courant; case etat_courant is when ATTENTE => -- transitions when INITIALISATION => -- transitions when TRAITEMENT => -- transitions when ERREUR => -- transitions when FIN => -- transitions end case; end process; |
12.4.8 Logique de sortie
| Valeurs par défaut | VHDL |
| process(all) begin sortie_a <= '0'; sortie_b <= '0'; alarme <= '0'; case etat_courant is when ATTENTE => sortie_a <= '1'; when ERREUR => alarme <= '1'; when others => null; end case; end process; |
12.4.9 Simulation
- appliquer le reset ;
- tester chaque transition ;
- tester les boucles de maintien ;
- tester les entrées simultanées ;
- vérifier les sorties dans chaque état ;
- tester les états invalides si un codage explicite est utilisé ;
- utiliser des assertions.
12.4.10 Assertions d’état
| Vérification fonctionnelle | VHDL |
| assert not (ouvrir = '1' and fermer = '1') report "Commandes ouvrir et fermer simultanees" severity error; |
12.4.11 Temporisations
Une durée est généralement convertie en nombre de ticks. Un compteur interne déclenche ensuite une transition.
| Transition après temporisation | VHDL |
| if tick = '1' then if temporisateur = DUREE-1 then temporisateur <= 0; etat_suivant <= ETAT_SUIVANT; else temporisateur <= temporisateur + 1; end if; end if; |
12.4.12 Séparation commande/données
La FSM doit piloter des signaux de contrôle tandis que les registres de données et opérateurs effectuent les calculs. Cette séparation facilite la réutilisation et le test.
12.4.13 Gestion d’un état illégal
| Récupération sûre | VHDL |
| when others => etat_suivant <= ATTENTE; |
Avec un type énuméré, tous les états déclarés doivent être traités. Le synthétiseur peut cependant produire des codes physiques inutilisés ; les options de récupération dépendent de l’outil.
12.4.14 Checklist de conception
- État initial sûr et explicite.
- Toutes les transitions sont couvertes.
- Sorties définies dans tous les chemins.
- Aucune entrée asynchrone utilisée directement.
- Temporisations exprimées en ticks synchrones.
- Priorités documentées.
- Banc de test couvrant les scénarios normaux et défauts.
12.5 Styles de description
Une même machine peut être décrite avec un, deux ou trois processus. Le choix influence l’organisation du code, pas nécessairement le matériel final.
12.5.1 Machine à un processus
Le registre d’état, les transitions et les sorties enregistrées sont regroupés dans un processus cadencé.
| Patron à un processus — Partie 1 | VHDL |
| process(clk, reset) begin if reset = '1' then etat_courant <= ATTENTE; sortie <= '0'; elsif rising_edge(clk) then case etat_courant is when ATTENTE => sortie <= '0'; if start = '1' then etat_courant <= ACTIF; end if; |
| Patron à un processus — Partie 2 | VHDL |
| when ACTIF => sortie <= '1'; if fini = '1' then etat_courant <= ATTENTE; end if; end case; end if; end process; |
- sorties naturellement enregistrées ;
- code compact ;
- état suivant moins visible ;
- attention aux sorties conservées si elles ne sont pas affectées dans une branche.
12.5.2 Machine à deux processus
Un processus mémorise l’état ; un processus combinatoire calcule l’état suivant et les sorties.
| Processus 1 : registre | VHDL |
| process(clk, reset) begin if reset = '1' then etat_courant <= ATTENTE; elsif rising_edge(clk) then etat_courant <= etat_suivant; end if; end process; |
| Processus 2 : transition et sorties | VHDL |
| process(all) begin etat_suivant <= etat_courant; sortie <= '0'; case etat_courant is when ATTENTE => if start = '1' then etat_suivant <= ACTIF; end if; when ACTIF => sortie <= '1'; if fini = '1' then etat_suivant <= ATTENTE; end if; end case; end process; |
12.5.3 Machine à trois processus
Le registre, la logique de transition et la logique de sortie sont séparés.
| Processus de transition | VHDL |
| process(all) begin etat_suivant <= etat_courant; case etat_courant is when ATTENTE => if start = '1' then etat_suivant <= ACTIF; end if; when ACTIF => if fini = '1' then etat_suivant <= ATTENTE; end if; end case; end process; |
| Processus de sortie | VHDL |
| process(all) begin sortie <= '0'; case etat_courant is when ACTIF => sortie <= '1'; when others => null; end case; end process; |
12.5.4 Comparaison
Critère | Un processus | Deux processus | Trois processus |
|---|---|---|---|
| Compacité | Très forte | Bonne | Moyenne |
| Lisibilité état suivant | Faible | Bonne | Très bonne |
| Séparation sorties | Faible | Moyenne | Forte |
| Sorties enregistrées | Naturelles | À ajouter si nécessaire | À ajouter si nécessaire |
| Risque de latch combinatoire | Faible | À contrôler | À contrôler |
| Usage pédagogique | Moyen | Très bon | Très bon |
12.5.5 Choix pratique
- deux processus : compromis fréquent pour les FSM RTL ;
- trois processus : séparation claire des sorties Moore ;
- un processus : contrôleurs compacts avec sorties enregistrées ;
- respecter les conventions de l’équipe et de l’outil.
12.5.6 Sensibilité
Les processus combinatoires utilisent process(all) en VHDL-2008. Le registre d’état utilise clk et les resets asynchrones uniquement.
12.5.7 Valeurs par défaut
| Prévention des latches | VHDL |
| process(all) begin etat_suivant <= etat_courant; sortie_1 <= '0'; sortie_2 <= '0'; -- case / if end process; |
12.5.8 Sorties enregistrées
Une sortie peut être générée combinatoirement puis enregistrée dans un processus séparé. Cette option stabilise les interfaces mais ajoute un cycle de latence.
12.6 Codage des états
Le codage associe une valeur binaire à chaque état. Avec un type énuméré, le synthétiseur choisit souvent automatiquement la représentation.
12.6.1 Codage binaire
Le codage binaire utilise le nombre minimal de bascules : ceil(log2(nombre d’états)).
Nombre d’états | Bits minimaux |
|---|---|
| 2 | 1 |
| 3 à 4 | 2 |
| 5 à 8 | 3 |
| 9 à 16 | 4 |
12.6.2 Exemple binaire
| Codage explicite | VHDL |
| constant ATTENTE : std_logic_vector(1 downto 0) := "00"; constant ACTIF : std_logic_vector(1 downto 0) := "01"; constant FIN : std_logic_vector(1 downto 0) := "10"; |
- peu de bascules ;
- logique de décodage parfois plus complexe ;
- codes inutilisés possibles.
12.6.3 Codage one-hot
Chaque état possède une bascule dédiée. Un seul bit vaut 1 à la fois.
| Exemple one-hot | Codage |
| ATTENTE = "001" ACTIF = "010" FIN = "100" |
- plus de bascules ;
- décodage simple ;
- souvent performant dans les FPGA riches en registres ;
- détection possible des codes zéro-hot ou multi-hot.
12.6.4 Codage Gray
Deux états successifs sont choisis de façon à ne différer que par un bit, lorsque le graphe de transitions le permet.
| Exemple Gray | Codage |
| E0 = "00" E1 = "01" E2 = "11" E3 = "10" |
- réduit les commutations simultanées ;
- utile dans certains compteurs et traversées de domaines ;
- ne garantit pas un bit de différence pour un graphe arbitraire.
12.6.5 Attribut de codage
Certains outils acceptent un attribut enum_encoding. Sa prise en charge et sa syntaxe peuvent dépendre du synthétiseur.
| Exemple indicatif | VHDL |
| type etat_t is (ATTENTE, ACTIF, FIN); attribute enum_encoding : string; attribute enum_encoding of etat_t : type is "001 010 100"; |
Attention — Portabilité Les attributs de synthèse sont souvent spécifiques aux outils. Le comportement fonctionnel ne doit pas dépendre d’un codage particulier sauf nécessité démontrée. |
12.6.6 Comparaison
Critère | Binaire | One-hot | Gray |
|---|---|---|---|
| Bascules | Minimum | Une par état | Minimum ou proche |
| Décodage | Modéré | Simple | Modéré |
| Commutations | Plusieurs bits possibles | Deux bits typiquement | Un bit sur transitions prévues |
| FPGA | Bon généraliste | Souvent rapide | Cas ciblés |
| Lisibilité physique | Moyenne | Bonne | Moyenne |
12.6.7 Choix du codage
- laisser le synthétiseur choisir pour commencer ;
- mesurer fréquence, surface et consommation ;
- utiliser one-hot si le chemin critique bénéficie d’un décodage simple ;
- utiliser Gray pour une séquence appropriée ;
- documenter tout codage imposé.
12.6.8 États sûrs
Des options de synthèse peuvent ajouter une récupération depuis les codes illégaux. Elles augmentent parfois la logique et doivent être validées par simulation post-synthèse ou analyse appropriée.
Méthode synthétique de développement
1. Reformuler le cahier des charges sous forme de scénarios.
2. Lister les entrées, sorties et temporisations.
3. Identifier les états nécessaires.
4. Dessiner le diagramme.
5. Construire la table de transition.
6. Choisir Moore ou Mealy.
7. Choisir le style de processus.
8. Écrire le registre d’état.
9. Écrire les transitions et sorties avec valeurs par défaut.
10. Créer un banc de test couvrant tous les arcs.
11. Examiner le schéma RTL et les rapports de synthèse.
Erreurs fréquentes
Erreur | Conséquence | Correction |
|---|---|---|
| État suivant non initialisé | Latch combinatoire | Maintien par défaut |
| Sortie non affectée | Latch ou valeur conservée | Valeurs par défaut |
| Entrée asynchrone directe | Métastabilité | Synchroniseur |
| Transition manquante | Blocage ou comportement implicite | Table complète |
| Sortie Mealy bruitée | Glitches | Filtrage ou enregistrement |
| Compteur non remis à zéro lors d’un changement d’état | Durée incorrecte | Réinitialiser selon état |
| Reset vers un état dangereux | Actionneur activé au démarrage | État initial sûr |
Travaux pratiques
TP 9 — Conception de machines à états
1. Objectifs du TP
- concevoir un détecteur de séquence binaire ;
- concevoir un feu de circulation temporisé ;
- concevoir le contrôleur d’une porte automatique ;
- concevoir un distributeur acceptant des pièces de £1 et £2 ;
- comparer Moore et Mealy ;
- utiliser des assertions et chronogrammes.
2. Organisation proposée
| Arborescence | Arborescence |
| tp9_machines_etats/ ├── src/ │ ├── detecteur_1011_moore.vhd │ ├── detecteur_1011_mealy.vhd │ ├── feu_tricolore.vhd │ ├── controleur_porte.vhd │ └── distributeur.vhd └── sim/ ├── tb_detecteur_1011.vhd ├── tb_feu_tricolore.vhd ├── tb_controleur_porte.vhd └── tb_distributeur.vhd |
3. Partie A — Détecteur de séquence 1011
Le détecteur reçoit un bit par cycle et active detection lorsqu’il reconnaît 1011. Les occurrences peuvent se chevaucher.
| États Moore | Définition |
| S0 : aucun préfixe reconnu S1 : préfixe "1" S2 : préfixe "10" S3 : préfixe "101" S4 : séquence "1011" reconnue |
| Diagramme textuel Moore | Transitions |
| S0 --1--> S1 ; S0 --0--> S0 S1 --0--> S2 ; S1 --1--> S1 S2 --1--> S3 ; S2 --0--> S0 S3 --1--> S4 ; S3 --0--> S2 S4 --1--> S1 ; S4 --0--> S2 Sortie detection=1 uniquement en S4 |
| detecteur_1011_moore.vhd — Entité | VHDL |
| library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity detecteur_1011_moore is port ( clk : in std_logic; reset : in std_logic; bit_entree: in std_logic; detection : out std_logic ); end entity detecteur_1011_moore; |
| Moore — Registre et types | VHDL |
| architecture rtl of detecteur_1011_moore is type etat_t is (S0, S1, S2, S3, S4); signal etat_courant, etat_suivant : etat_t; begin process(clk, reset) begin if reset = '1' then etat_courant <= S0; elsif rising_edge(clk) then etat_courant <= etat_suivant; end if; end process; |
| Moore — Transitions, partie 1 | VHDL |
| process(all) begin etat_suivant <= etat_courant; case etat_courant is when S0 => if bit_entree = '1' then etat_suivant <= S1; end if; when S1 => if bit_entree = '0' then etat_suivant <= S2; else etat_suivant <= S1; end if; |
| Moore — Transitions, partie 2A | VHDL |
| when S2 => if bit_entree = '1' then etat_suivant <= S3; else etat_suivant <= S0; end if; when S3 => if bit_entree = '1' then etat_suivant <= S4; else etat_suivant <= S2; end if; |
| Moore — Transitions, partie 2B | VHDL |
| when S4 => if bit_entree = '1' then etat_suivant <= S1; else etat_suivant <= S2; end if; end case; end process; detection <= '1' when etat_courant = S4 else '0'; end architecture rtl; |
4. Version Mealy du détecteur
La version Mealy peut utiliser seulement quatre états. La sortie est activée sur la transition depuis S3 lorsque bit_entree vaut 1.
| Mealy — Sortie sur transition | VHDL |
| process(all) begin etat_suivant <= etat_courant; detection <= '0'; case etat_courant is when S0 => if bit_entree = '1' then etat_suivant <= S1; end if; when S1 => if bit_entree = '0' then etat_suivant <= S2; end if; when S2 => if bit_entree = '1' then etat_suivant <= S3; else etat_suivant <= S0; end if; when S3 => if bit_entree = '1' then detection <= '1'; etat_suivant <= S1; else etat_suivant <= S2; end if; end case; end process; |
5. Banc de test du détecteur
| Séquence de test | VHDL |
| constant MOT : std_logic_vector(15 downto 0) := "0010110101101011"; for i in MOT'range loop bit_entree <= MOT(i); wait until rising_edge(clk); wait for 1 ns; -- Observer et compter les impulsions detection. end loop; |
| Assertion d’impulsion | VHDL |
| if detection = '1' then nb_detections := nb_detections + 1; end if; assert nb_detections = 3 report "Nombre de sequences detectees incorrect" severity error; |
6. Partie B — Feu de circulation
Le feu suit VERT pendant 5 ticks, ORANGE pendant 2 ticks et ROUGE pendant 5 ticks. Les sorties sont de Moore.
| Diagramme | Diagramme textuel |
| VERT --5 ticks--> ORANGE ORANGE --2 ticks--> ROUGE ROUGE --5 ticks--> VERT |
| feu_tricolore.vhd — Entité | VHDL |
| entity feu_tricolore is generic ( DUREE_VERT : positive := 5; DUREE_ORANGE : positive := 2; DUREE_ROUGE : positive := 5 ); port ( clk, reset, tick : in std_logic; feu_vert, feu_orange, feu_rouge : out std_logic ); end entity feu_tricolore; |
| Feu — Registre et temporisateur | VHDL |
| architecture rtl of feu_tricolore is type etat_t is (VERT, ORANGE, ROUGE); signal etat_courant, etat_suivant : etat_t; signal temps : natural range 0 to DUREE_VERT + DUREE_ORANGE + DUREE_ROUGE; begin process(clk, reset) begin if reset = '1' then etat_courant <= ROUGE; temps <= 0; elsif rising_edge(clk) then etat_courant <= etat_suivant; if etat_suivant /= etat_courant then temps <= 0; elsif tick = '1' then temps <= temps + 1; end if; end if; end process; |
| Feu — Transitions | VHDL |
| process(all) begin etat_suivant <= etat_courant; case etat_courant is when VERT => if tick = '1' and temps = DUREE_VERT-1 then etat_suivant <= ORANGE; end if; when ORANGE => if tick = '1' and temps = DUREE_ORANGE-1 then etat_suivant <= ROUGE; end if; when ROUGE => if tick = '1' and temps = DUREE_ROUGE-1 then etat_suivant <= VERT; end if; end case; end process; |
| Feu — Sorties | VHDL |
| feu_vert <= '1' when etat_courant = VERT else '0'; feu_orange <= '1' when etat_courant = ORANGE else '0'; feu_rouge <= '1' when etat_courant = ROUGE else '0'; end architecture rtl; |
Amélioration — Dimension du temporisateur Dans un code générique complet, la plage du temporisateur doit être dimensionnée à partir de la plus grande durée. On peut utiliser une constante MAX_DUREE calculée par une fonction. |
7. Partie C — Contrôleur d’une porte automatique
La porte s’ouvre lorsqu’une présence est détectée, reste ouverte tant que la zone est occupée, puis se ferme. Un obstacle pendant la fermeture provoque une réouverture.
| États de la porte | États |
| FERMEE OUVERTURE OUVERTE FERMETURE DEFAUT |
| Table de transitions | Règles |
| FERMEE + presence -> OUVERTURE OUVERTURE + fin_ouverture -> OUVERTE OUVERTE + absence -> FERMETURE FERMETURE + obstacle -> OUVERTURE FERMETURE + fin_fermeture -> FERMEE Tout état + arret_urgence -> DEFAUT DEFAUT + reset -> FERMEE |
| controleur_porte.vhd — Sorties Moore | VHDL |
| process(all) begin moteur_ouvrir <= '0'; moteur_fermer <= '0'; alarme <= '0'; case etat_courant is when OUVERTURE => moteur_ouvrir <= '1'; when FERMETURE => moteur_fermer <= '1'; when DEFAUT => alarme <= '1'; when others => null; end case; end process; |
| Porte — Logique de transition, partie 1 | VHDL |
| process(all) begin etat_suivant <= etat_courant; if arret_urgence = '1' then etat_suivant <= DEFAUT; else case etat_courant is when FERMEE => if presence = '1' then etat_suivant <= OUVERTURE; end if; when OUVERTURE => if fin_ouverture = '1' then etat_suivant <= OUVERTE; end if; |
| Porte — Logique de transition, partie 2 | VHDL |
| when OUVERTE => if presence = '0' then etat_suivant <= FERMETURE; end if; when FERMETURE => if obstacle = '1' then etat_suivant <= OUVERTURE; elsif fin_fermeture = '1' then etat_suivant <= FERMEE; end if; when DEFAUT => null; end case; end if; end process; |
| Assertion de sécurité | VHDL |
| assert not (moteur_ouvrir = '1' and moteur_fermer = '1') report "Commandes moteur contradictoires" severity failure; |
8. Partie D — Distributeur
Le produit coûte £3. Le distributeur accepte une pièce de £1 ou £2 par cycle. Il délivre le produit lorsque le crédit atteint au moins £3 et rend £1 si le crédit total atteint £4.
| États du crédit | États Moore |
| C0 : crédit £0 C1 : crédit £1 C2 : crédit £2 DISTRIBUE : produit délivré, aucune monnaie DISTRIBUE_MONNAIE : produit délivré + retour £1 |
| distributeur.vhd — Interface | VHDL |
| entity distributeur is port ( clk, reset : in std_logic; piece_1 : in std_logic; piece_2 : in std_logic; distribuer : out std_logic; monnaie_1 : out std_logic ); end entity distributeur; |
| Distributeur — Transitions, partie 1 | VHDL |
| process(all) begin etat_suivant <= etat_courant; case etat_courant is when C0 => if piece_2 = '1' then etat_suivant <= C2; elsif piece_1 = '1' then etat_suivant <= C1; end if; when C1 => if piece_2 = '1' then etat_suivant <= DISTRIBUE; elsif piece_1 = '1' then etat_suivant <= C2; end if; |
| Distributeur — Transitions, partie 2 | VHDL |
| when C2 => if piece_2 = '1' then etat_suivant <= DISTRIBUE_MONNAIE; elsif piece_1 = '1' then etat_suivant <= DISTRIBUE; end if; when DISTRIBUE | DISTRIBUE_MONNAIE => etat_suivant <= C0; end case; end process; |
| Distributeur — Sorties Moore | VHDL |
| distribuer <= '1' when etat_courant = DISTRIBUE or etat_courant = DISTRIBUE_MONNAIE else '0'; monnaie_1 <= '1' when etat_courant = DISTRIBUE_MONNAIE else '0'; |
Cas limite — Pièces simultanées Le cahier des charges doit préciser le comportement si piece_1 et piece_2 valent 1 simultanément. Dans cet exemple, piece_2 est prioritaire. Un vrai système utiliserait un validateur de pièces produisant un code exclusif. |
9. Banc de test du distributeur
| Scénario £1 + £2 | VHDL |
| piece_1 <= '1'; wait until rising_edge(clk); piece_1 <= '0'; piece_2 <= '1'; wait until rising_edge(clk); piece_2 <= '0'; wait for 1 ns; assert distribuer = '1' and monnaie_1 = '0' report "Distribution £3 incorrecte" severity error; wait until rising_edge(clk); wait for 1 ns; assert distribuer = '0' severity error; |
| Scénario £2 + £2 | VHDL |
| piece_2 <= '1'; wait until rising_edge(clk); piece_2 <= '0'; piece_2 <= '1'; wait until rising_edge(clk); piece_2 <= '0'; wait for 1 ns; assert distribuer = '1' and monnaie_1 = '1' report "Monnaie £1 attendue" severity error; wait until rising_edge(clk); wait for 1 ns; assert distribuer = '0' severity error; |
10. Comparaison Moore/Mealy
Critère | Détecteur Moore | Détecteur Mealy |
|---|---|---|
| Nombre d’états | 5 | 4 |
| Moment de detection | Après entrée en S4 | Sur transition depuis S3 |
| Dépendance directe entrée-sortie | Non | Oui |
| Risque de glitch | Plus faible | Plus élevé |
| Latence | Souvent un cycle supplémentaire | Réaction immédiate |
11. Compilation avec GHDL
| Compilation | Terminal |
| ghdl -a --std=08 src/detecteur_1011_moore.vhd ghdl -a --std=08 src/detecteur_1011_mealy.vhd ghdl -a --std=08 src/feu_tricolore.vhd ghdl -a --std=08 src/controleur_porte.vhd ghdl -a --std=08 src/distributeur.vhd |
| Simulation | Terminal |
| ghdl -a --std=08 sim/tb_detecteur_1011.vhd ghdl -e --std=08 tb_detecteur_1011 ghdl -r --std=08 tb_detecteur_1011 --vcd=tb_detecteur_1011.vcd gtkwave tb_detecteur_1011.vcd |
12. Observations demandées
- Afficher l’état courant dans le chronogramme si le simulateur le permet.
- Vérifier les séquences qui se chevauchent.
- Mesurer la latence Moore/Mealy.
- Vérifier les durées des feux.
- Tester un obstacle pendant la fermeture.
- Tester l’arrêt d’urgence.
- Tester toutes les combinaisons de pièces.
- Vérifier qu’aucune sortie contradictoire n’est active.
13. Tableau de résultats
Machine | Scénario | Résultat attendu | Observé | Conforme |
|---|---|---|---|---|
| Détecteur | Entrée 1011 | Une détection | ||
| Détecteur | Séquences chevauchées | Détections correctes | ||
| Feu | 5/2/5 ticks | VERT/ORANGE/ROUGE | ||
| Porte | Obstacle en fermeture | Réouverture | ||
| Porte | Arrêt urgence | DEFAUT | ||
| Distributeur | £1 + £2 | Produit, pas de monnaie | ||
| Distributeur | £2 + £2 | Produit + £1 |
14. Questions d’analyse
1. Pourquoi le détecteur Moore nécessite-t-il un état supplémentaire ?
2. Comment le chevauchement de séquences est-il conservé ?
3. Pourquoi les sorties du feu sont-elles adaptées à Moore ?
4. Comment dimensionner le temporisateur du feu ?
5. Pourquoi l’obstacle est-il prioritaire sur fin_fermeture ?
6. Quel état initial est le plus sûr pour le feu et la porte ?
7. Comment gérer deux pièces simultanées ?
8. Quelle sortie Mealy pourrait être enregistrée ?
9. Quel codage d’états choisir sur un FPGA ?
10. Comment prouver que tous les arcs du diagramme ont été testés ?
15. Extensions proposées
- Détecter une séquence paramétrable.
- Ajouter un feu piéton avec bouton.
- Ajouter une durée minimale de porte ouverte.
- Ajouter un capteur de panne moteur.
- Ajouter plusieurs produits et prix.
- Créer une machine de remboursement.
- Comparer codage binaire et one-hot après synthèse.
- Implanter une des machines sur carte FPGA.
16. Barème indicatif
Critère | Points |
|---|---|
| Détecteur Moore | 3 |
| Détecteur Mealy et comparaison | 3 |
| Feu de circulation | 3 |
| Porte automatique | 3 |
| Distributeur | 3 |
| Bancs de test et assertions | 3 |
| Analyse et qualité du compte rendu | 2 |
| Total | 20 |
Synthèse du chapitre
Notion | Résumé |
|---|---|
| État | Situation mémorisée du système. |
| Transition | Passage conditionnel vers un autre état. |
| Moore | Sorties dépendant uniquement de l’état. |
| Mealy | Sorties dépendant de l’état et des entrées. |
| Registre d’état | Mémorise l’état au front d’horloge. |
| Logique de transition | Calcule l’état suivant. |
| Un processus | FSM compacte, sorties souvent enregistrées. |
| Deux processus | Registre + logique combinatoire. |
| Trois processus | Registre + transition + sorties séparées. |
| Binaire | Codage compact en bascules. |
| One-hot | Une bascule par état. |
| Gray | Un bit change entre états successifs prévus. |
Autoévaluation
1. De quoi dépend une sortie Moore ?
Réponse : Uniquement de l’état courant.
2. De quoi dépend une sortie Mealy ?
Réponse : De l’état courant et des entrées.
3. Quel bloc mémorise l’état ?
Réponse : Le registre d’état.
4. Pourquoi initialiser etat_suivant ?
Réponse : Pour définir le maintien et éviter un latch.
5. Quel style sépare le mieux les sorties ?
Réponse : Le style à trois processus.
6. Combien de bits binaires pour cinq états ?
Réponse : Trois bits.
7. Combien de bascules one-hot pour cinq états ?
Réponse : Cinq bascules.
8. Où apparaissent les sorties dans un diagramme Mealy ?
Réponse : Sur les transitions.
9. Pourquoi synchroniser une entrée externe ?
Réponse : Pour réduire le risque de métastabilité.
10. Que doit couvrir le banc de test ?
Réponse : Tous les états, transitions et cas limites.
Exercice de consolidation
Concevoir une FSM Moore commandant une pompe. La pompe démarre sur demande si le niveau est suffisant, s’arrête lorsque la demande disparaît et passe en alarme si le niveau devient trop bas.
| Correction proposée — États et transitions | VHDL |
| type etat_t is (ARRET, MARCHE, ALARME); case etat_courant is when ARRET => if niveau_bas = '1' then etat_suivant <= ALARME; elsif demande = '1' then etat_suivant <= MARCHE; end if; when MARCHE => if niveau_bas = '1' then etat_suivant <= ALARME; elsif demande = '0' then etat_suivant <= ARRET; end if; when ALARME => if acquit = '1' and niveau_bas = '0' then etat_suivant <= ARRET; end if; end case; |
| Correction proposée — Sorties | VHDL |
| pompe <= '1' when etat_courant = MARCHE else '0'; alarme <= '1' when etat_courant = ALARME else '0'; |