Conception et implémentation des machines à états finis (FSM) en VHDL : Moore et Mealy.
Une machine à états mémorise l'étape courante d'une opération. Sa logique de transition choisit l'état suivant à partir de cet état et des entrées.
Séparer état et sorties
Une sortie Moore dépend de l'état ; une sortie Mealy dépend aussi des entrées :
Moore
Mealy
Sorties dépendent de
État uniquement
État + Entrées
Sorties
Changent avec l’état
Peuvent changer avec une entrée
Latence
Dépend du découpage et des registres
Dépend du découpage et des registres
Points à vérifier
Décodage et enregistrement des sorties
Chemins combinatoires et glitches
Le détecteur suivant reconnaît 101. Sa sortie devient active dans FOUND, puis il revient à IDLE. Il ignore l'entrée pendant ce retour et ne traite donc pas toutes les séquences qui se chevauchent.
État actuel
Entrée i_data
État suivant
Sortie o_found
IDLE
0
IDLE
0
IDLE
1
GOT_1
0
GOT_1
1
GOT_1
0
GOT_1
0
GOT_10
0
GOT_10
1
FOUND
0
GOT_10
0
IDLE
0
FOUND
x
IDLE
1
Deux process séparent le registre d'état et la logique de transition. Une affectation concurrente décode la sortie Moore :
library IEEE;use IEEE.STD_LOGIC_1164.ALL;entity fsm_detector is port ( i_clk : in std_logic; i_rst : in std_logic; i_data : in std_logic; o_found : out std_logic );end entity fsm_detector;architecture rtl of fsm_detector is -- Déclaration du type état type t_state is (IDLE, GOT_1, GOT_10, FOUND); signal r_state : t_state; signal w_next : t_state;begin -- Process 1 : registre d'état (séquentiel) p_state_reg : process(i_clk) begin if rising_edge(i_clk) then if i_rst = '1' then r_state <= IDLE; else r_state <= w_next; end if; end if; end process p_state_reg; -- Process 2 : logique de transition (combinatoire) p_next_state : process(r_state, i_data) begin w_next <= r_state; -- par défaut : rester dans l'état case r_state is when IDLE => if i_data = '1' then w_next <= GOT_1; end if; when GOT_1 => if i_data = '0' then w_next <= GOT_10; else w_next <= GOT_1; end if; when GOT_10 => if i_data = '1' then w_next <= FOUND; else w_next <= IDLE; end if; when FOUND => w_next <= IDLE; when others => w_next <= IDLE; end case; end process p_next_state; -- Sorties Moore : dépendent uniquement de r_state o_found <= '1' when r_state = FOUND else '0';end architecture rtl;
On peut déplacer le décodage dans un troisième process lorsque les sorties deviennent plus complexes. Il remplace alors l'affectation correspondante ; adapte les ports si tu ajoutes o_active :
-- Process 3 : logique de sortie (combinatoire - Moore)p_outputs : process(r_state)begin -- Valeurs par défaut (évite les latches) o_found <= '0'; o_active <= '0'; case r_state is when FOUND => o_found <= '1'; when GOT_1 | GOT_10 => o_active <= '1'; when others => null; end case;end process p_outputs;
Ajouter le temps et le comptage
Cette FSM de feu tricolore associe un compteur à chaque durée :
library IEEE;use IEEE.STD_LOGIC_1164.ALL;use IEEE.NUMERIC_STD.ALL;entity traffic_light is generic ( g_CLK_FREQ : positive := 100_000_000 -- 100 MHz ); port ( i_clk : in std_logic; i_rst : in std_logic; o_rouge : out std_logic; o_orange: out std_logic; o_vert : out std_logic );end entity traffic_light;architecture rtl of traffic_light is type t_light is (ROUGE, ORANGE, VERT); constant c_ROUGE_DUR : unsigned(63 downto 0) := to_unsigned(30, 32) * to_unsigned(g_CLK_FREQ, 32); -- 30s constant c_ORANGE_DUR : unsigned(63 downto 0) := to_unsigned(3, 32) * to_unsigned(g_CLK_FREQ, 32); -- 3s constant c_VERT_DUR : unsigned(63 downto 0) := to_unsigned(25, 32) * to_unsigned(g_CLK_FREQ, 32); -- 25s signal r_state : t_light; signal r_counter : unsigned(63 downto 0);begin p_fsm : process(i_clk) begin if rising_edge(i_clk) then if i_rst = '1' then r_state <= ROUGE; r_counter <= (others => '0'); else r_counter <= r_counter + 1; case r_state is when ROUGE => if r_counter = c_ROUGE_DUR - 1 then r_state <= VERT; r_counter <= (others => '0'); end if; when VERT => if r_counter = c_VERT_DUR - 1 then r_state <= ORANGE; r_counter <= (others => '0'); end if; when ORANGE => if r_counter = c_ORANGE_DUR - 1 then r_state <= ROUGE; r_counter <= (others => '0'); end if; end case; end if; end if; end process p_fsm; -- Sorties Moore o_rouge <= '1' when r_state = ROUGE else '0'; o_orange <= '1' when r_state = ORANGE else '0'; o_vert <= '1' when r_state = VERT else '0';end architecture rtl;
État
Durée
État suivant
ROUGE
30 s
VERT
VERT
25 s
ORANGE
ORANGE
3 s
ROUGE
Le compteur de 64 bits évite le dépassement de la plage d'un entier usuel pour 30 secondes à 100 MHz. g_CLK_FREQ doit correspondre à la fréquence réelle et être strictement positif.
Pour un sérialiseur, un contrôleur SPI/UART ou un traitement de plusieurs octets, un compteur suit le nombre d'éléments traités. Cet extrait envoie huit bits, MSB d'abord, puis active o_done :
-- Sérialiseur 8 bits : envoie 8 bits un par untype t_ser is (IDLE, SHIFT);signal r_state : t_ser;signal r_shreg : std_logic_vector(7 downto 0);signal r_count : unsigned(2 downto 0);process(i_clk)begin if rising_edge(i_clk) then if i_rst = '1' then r_state <= IDLE; r_count <= (others => '0'); o_bit <= '0'; o_done <= '0'; else o_done <= '0'; case r_state is when IDLE => if i_valid = '1' then r_shreg <= i_data; r_count <= (others => '0'); r_state <= SHIFT; end if; when SHIFT => o_bit <= r_shreg(7); r_shreg <= r_shreg(6 downto 0) & '0'; -- décalage gauche r_count <= r_count + 1; if r_count = 7 then o_done <= '1'; r_state <= IDLE; end if; when others => r_state <= IDLE; end case; end if; end if;end process;
Définir les valeurs de départ
Le reset doit établir l'état, les compteurs et les sorties nécessaires au redémarrage :
if i_rst = '1' then r_state <= IDLE; -- état de départ définiend if;
En combinatoire, une valeur par défaut évite une mémorisation involontaire :
-- En début de process de sortieo_valid <= '0';o_data <= (others => '0');-- Puis surcharger dans chaque case
Un type énuméré par FSM rend ses états lisibles :
type t_uart_state is (IDLE, START, DATA, PARITY, STOP);-- Chaque FSM a son propre type → nommage clair
Tous les choix VHDL doivent être couverts, éventuellement avec cette branche de repli :
when others => r_state <= IDLE; -- état de repli du modèle VHDL
Elle ne garantit pas la récupération matérielle après corruption de l'encodage. Pour cette exigence, utilise les options de FSM sûre, comme FSM_SAFE_STATE dans Vivado, et examine la netlist.
Choisir et vérifier l'encodage
Encodage
Usage
Ressources
Binaire
Peu d'états
Minimum de bascules
One-hot
Beaucoup d'états
Une bascule par état ; timing à vérifier
Gray
Compteurs séquentiels
Un bit change entre codes consécutifs de la séquence Gray
Laisse d'abord le synthétiseur choisir, puis vérifie les ressources et le timing. One-hot utilise davantage de bascules et possède toujours des combinaisons illégales ; il ne remplace pas une stratégie de récupération. Distingue aussi l'initialisation à la configuration, dépendante du FPGA et des outils, du reset pendant le fonctionnement.