Design and implementation of Finite State Machines (FSM) in VHDL: Moore and Mealy.
A state machine stores the current step of an operation. Transition logic selects the next state from that state and the inputs.
Separate state from outputs
A Moore output depends on state; a Mealy output also depends on inputs:
Moore
Mealy
Outputs depend on
State only
State + Inputs
Outputs
Change with the state
Can change with an input
Latency
Depends on partitioning and registers
Depends on partitioning and registers
Checks
Output decoding and registers
Combinational paths and glitches
The following detector recognizes 101. Its output becomes active in FOUND, then it returns to IDLE. It ignores the input during that return, so it does not handle every overlapping sequence.
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
Two processes separate the state register from transition logic. A concurrent assignment decodes the Moore output:
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;
Move output decoding into a third process when it becomes more complex. This replaces the corresponding assignment; adapt the ports if adding o_active:
-- 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;
Add timing and counting
This traffic-light FSM associates a counter with each duration:
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_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 : unsigned(63 downto 0) := to_unsigned(30, 32) * to_unsigned(g_CLK_FREQ, 32); -- 30s constant c_AMBER_DUR : unsigned(63 downto 0) := to_unsigned(3, 32) * to_unsigned(g_CLK_FREQ, 32); -- 3s constant c_GREEN_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 <= RED; r_counter <= (others => '0'); else r_counter <= r_counter + 1; case r_state is when RED => if r_counter = c_RED_DUR - 1 then r_state <= GREEN; r_counter <= (others => '0'); end if; when GREEN => if r_counter = c_GREEN_DUR - 1 then r_state <= AMBER; r_counter <= (others => '0'); end if; when AMBER => if r_counter = c_AMBER_DUR - 1 then r_state <= RED; r_counter <= (others => '0'); end if; end case; end if; end if; end process p_fsm; -- Moore outputs o_red <= '1' when r_state = RED else '0'; o_amber <= '1' when r_state = AMBER else '0'; o_green <= '1' when r_state = GREEN else '0';end architecture rtl;
State
Duration
Next State
RED
30 s
GREEN
GREEN
25 s
AMBER
AMBER
3 s
RED
A 64-bit counter avoids the usual integer-range overflow for 30 seconds at 100 MHz. g_CLK_FREQ must match the actual clock and be positive.
For a serializer, SPI/UART controller or multi-byte operation, a counter tracks completed items. This fragment sends eight bits MSB first, then asserts o_done:
-- 8-bit serializer: sends 8 bits one by onetype 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'; -- left shift 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;
Define startup values
Reset must establish the state, counters and outputs needed for restart:
if i_rst = '1' then r_state <= IDLE; -- defined starting stateend if;
For combinational logic, default outputs prevent unintended storage:
-- At beginning of output processo_valid <= '0';o_data <= (others => '0');-- Then override in each case
One enumeration per FSM keeps states readable:
type t_uart_state is (IDLE, START, DATA, PARITY, STOP);-- Each FSM has its own type → clear naming
Cover all VHDL choices, using a fallback where needed:
when others => r_state <= IDLE; -- safe default state
This does not guarantee hardware recovery from corrupted encoding. For that requirement, use safe-FSM options such as Vivado's FSM_SAFE_STATE and inspect the netlist.
Choose and check encoding
Encoding
Usage
Resources
Binary
Few states
Minimum flip-flops
One-hot
Many states
One flip-flop per state; check timing
Gray
Sequential counters
One bit changes between consecutive Gray-sequence codes
Start with the synthesizer's choice, then check resources and timing. One-hot uses more flip-flops and still has illegal combinations; it does not replace recovery logic. Also distinguish device- and tool-dependent configuration initialization from reset during operation.