State Machines (Mealy/Moore)
Design and implementation of Finite State Machines (FSM) in VHDL: Moore and Mealy.
Finite State Machines (FSM)
An FSM (Finite State Machine) is a sequential circuit that:
- Is in one state at a time
- Transitions between states based on conditions (depend on inputs)
- Produces outputs based on the state (and optionally inputs)
Moore vs Mealy
| Moore | Mealy | |
|---|---|---|
| Outputs depend on | State only | State + Inputs |
| Outputs | More stable | Faster response |
| Latency | 1 extra cycle | Immediate response |
| Recommended for FPGA | Yes (simpler to synthesize) | Possible but watch for glitches |
2-Process Model (Recommended)
Example: 101 sequence detector (Moore).
| Current State | Input i_data | Next State | Output 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 |
The most common style for FPGA: one process for state, one for outputs.
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
-- State type declaration
type t_state is (IDLE, GOT_1, GOT_10, FOUND);
signal r_state : t_state;
signal w_next : t_state;
begin
-- Process 1: state register (sequential)
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: transition logic (combinational)
p_next_state : process(r_state, i_data)
begin
w_next <= r_state; -- default: stay in current state
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;
-- Moore outputs: depend only on r_state
o_found <= '1' when r_state = FOUND else '0';
end architecture rtl;3-Process Model (Variant)
A third process for outputs (useful when outputs are complex).
-- Process 3: output logic (combinational - Moore)
p_outputs : process(r_state)
begin
-- Default values (avoids 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;Complete Example: Traffic Light FSM
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity traffic_light is
generic (
g_CLK_FREQ : integer := 100_000_000 -- 100 MHz
);
port (
i_clk : in std_logic;
i_rst : in std_logic;
o_red : out std_logic;
o_amber : out std_logic;
o_green : out std_logic
);
end entity traffic_light;
architecture rtl of traffic_light is
type t_light is (RED, AMBER, GREEN);
constant c_RED_DUR : integer
| State | Duration | Next State |
|---|---|---|
| RED | 30 s | GREEN |
| GREEN | 25 s | AMBER |
| AMBER | 3 s | RED |
FSM Best Practices
1. Always initialize at reset
if i_rst = '1' then
r_state <= IDLE; -- defined starting state
end if;2. Cover all states with when others
when others =>
r_state <= IDLE; -- safe default state3. Default output values
-- At beginning of output process
o_valid <= '0';
o_data <= (others => '0');
-- Then override in each case4. One enumerated type per FSM
type t_uart_state is (IDLE, START, DATA, PARITY, STOP);
-- Each FSM has its own type → clear namingState Encoding
The synthesizer automatically chooses the encoding. It can be forced:
| Encoding | Usage | Resources |
|---|---|---|
| Binary | Few states | Minimum flip-flops |
| One-hot | Many states | More flip-flops, faster |
| Gray | Sequential counters | Single-bit transitions |
On modern FPGAs, letting the synthesizer decide is generally optimal.
FSM Categories (Pedroni)
It is useful to classify state machines into three categories by complexity:
Category 1 - Regular FSM (simple)
The machine transitions only based on external input signals. No timing, no recursion.
This is the classic FSM: sequence detector, protocol controller, command decoder.
-- Example: rising edge detector
type t_edge is (IDLE, DETECT);
signal r_state : t_edge;
process(i_clk)
begin
if rising_edge(i_clk) then
if i_rst = '1' then
r_state <= IDLE;
else
case r_state is
when IDLE => if i_sig = '1' then r_state <= DETECT; end if;
when DETECT => r_state <= IDLE;
when others => r_state <= IDLE;
end case;
end if;
end if;
end
Category 2 - Timed FSM (with counter)
The machine waits a fixed number of cycles before transitioning. An internal counter measures elapsed time.
Use cases: traffic lights, PWM generators, startup delays.
-- FSM with internal counter
type t_timed is (WAIT_LOW, WAIT_HIGH);
signal r_state : t_timed;
signal r_timer : unsigned(19 downto 0) := (others => '0');
constant c_T_LOW : unsigned(19 downto 0) := to_unsigned(499_999, 20); -- 5 ms @ 100 MHz
constant c_T_HIGH : unsigned(19 downto 0) := to_unsigned(999_999, 20); -- 10 ms @ 100 MHz
process(i_clk)
begin
if rising_edge(i_clk) then
if i_rst = '1' then
r_state
Best practice: reset the counter (
r_timer <= (others => '0')) whenever you change state to guarantee precise timing.
Category 3 - Recursive FSM (variable parameter)
The machine visits states a variable number of times based on an input parameter (N cycles, N bytes, etc.).
Use cases: serializers, SPI/UART controllers, compression engines.
-- 8-bit serializer: sends 8 bits one by one
type 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
Summary Table
| Category | Transition trigger | Examples |
|---|---|---|
| Regular | External inputs | Sequence detector, decoder |
| Timed | Internal counter (fixed N) | Traffic lights, PWM, startup delay |
| Recursive | Internal counter (variable N) | UART TX, SPI, serializer |
Safe State Machines
An FPGA may land in an undefined state at power-up or after a glitch. A safe FSM explicitly handles all unexpected cases.
-- Always include when others
case r_state is
when IDLE => ...
when RUN => ...
when DONE => ...
when others =>
-- Unknown state: return to safe state
r_state <= IDLE;
end case;-- Force one-hot encoding to reduce illegal states (Vivado)
attribute fsm_encoding : string;
attribute fsm_encoding of r_state : signal is "one_hot";On FPGAs, flip-flops do not reset automatically at power-up. Always initialize at reset and always cover
when others.
📝 Test your knowledge - Chapter quiz