VHDL · Chapter 9.8 · Finite State Machines
Safe FSMs and Illegal-State Recovery
An FSM has a finite set of legal states, but its state register can hold more bit patterns than that, the illegal states such as unused binary codes or any non-one-hot pattern in a one-hot machine. In normal operation the FSM never enters them, yet a single-event upset, a glitch, a metastable capture, or a reset problem can drive it into one, and a naive machine may then sit there forever. A safe FSM guarantees recovery, so from any state, including illegal ones, it returns to a known legal state. This lesson shows how to add that recovery for every unlisted state, why one-hot encodings have especially many illegal patterns, what the safe-FSM synthesis attribute does, and how to keep the synthesiser from optimising the recovery logic away as unreachable.
Foundation14 min readVHDLFSMSafe StateIllegal StateRecoveryReliability
1. Engineering intuition — plan for the state you should never be in
You design an FSM to move among its legal states, but the hardware can end up elsewhere: a cosmic-ray upset flips a state bit, a glitch or metastable capture lands the register on an unused code, or a reset issue leaves it undefined. If your transition logic only describes the legal states, the machine has no defined move from an illegal one — so it can freeze. A safe FSM anticipates this: it makes every possible state, legal or not, lead back to a known state (usually idle/reset). It is cheap insurance, and for anything that must not hang — safety, long-running, or radiation-exposed systems — it is mandatory.
2. Formal explanation — recovery for every state
library ieee; use ieee.std_logic_1164.all;
type state_t is (IDLE, RUN, PAUSE, DONE); -- 4 legal states
signal state, next_state : state_t;
nlogic : process (all)
begin
next_state <= state; -- default: stay
case state is
when IDLE => if go = '1' then next_state <= RUN; end if;
when RUN => if fin = '1' then next_state <= DONE; end if;
when PAUSE => next_state <= RUN;
when DONE => next_state <= IDLE;
when others => next_state <= IDLE; -- SAFE RECOVERY: any illegal state → IDLE
end case;
end process;The when others => next_state <= IDLE; is the recovery: it defines a transition from any state the case did
not explicitly list — which, for an enum that the tool may encode with spare codes, includes the illegal
patterns. From any illegal state the machine returns to IDLE within a clock. Without it, an illegal state has no
defined exit and the FSM can hang.
3. Production RTL — safe one-hot and the synthesis attribute
library ieee; use ieee.std_logic_1164.all;
-- (A) Tell the tool to build a SAFE FSM (recover from illegal states) via an attribute.
attribute fsm_safe_state : string;
attribute fsm_safe_state of state : signal is "reset_state"; -- recover illegal → reset state
-- (vendor attribute names vary; "safe_fsm"/"fsm_safe_state" select a safe implementation)
-- (B) For one-hot, an explicit check: a legal one-hot has exactly one bit set.
-- If 'state_oh' is ever NOT one-hot (zero or multiple bits), force recovery.
-- if (number of set bits in state_oh) /= 1 then next_state <= IDLE; end if;What hardware does this become? With the safe-FSM attribute (or explicit when others), the synthesiser
adds logic so any out-of-range or non-one-hot pattern transitions to the reset/idle state. For one-hot machines
this matters most — a one-hot register has 2^N patterns but only N legal ones, so almost every pattern is
illegal, and an upset is likely to produce an illegal (multi-hot or zero-hot) pattern that needs recovery.
4. Hardware interpretation — every state leads home
5. Simulation interpretation — upset, then recover
An upset drives the FSM to an illegal state; safe recovery returns it to IDLE
8 cycles6. Debugging example — the recovery the tool deleted
Expected: the FSM recovers from illegal states. Observed: in the gate-level netlist the recovery is
gone — the when others branch was optimised away — so an injected upset hangs the FSM. Root cause: the
synthesiser proved the illegal states are unreachable in normal operation and removed the recovery logic as
dead code; it does not know you want it for upset tolerance. Fix: use the vendor safe-FSM attribute
(which tells the tool to keep/insert recovery) rather than relying on a when others it may delete; for
critical FSMs, verify the recovery survives to the netlist (and consider explicit one-hot checks). Engineering
takeaway: a when others recovery can be optimised away because it looks unreachable — enable the safe-FSM
attribute to make the tool preserve illegal-state recovery, and confirm it in the netlist.
-- The 'when others' may be removed as unreachable; the safe-FSM attribute tells the tool to keep recovery.
attribute fsm_safe_state of state : signal is "reset_state";
-- ... and still write the explicit recovery for simulation/intent:
when others => next_state <= IDLE;7. Common mistakes & what to watch for
- No illegal-state recovery. An upset can hang the FSM; add
when others => <known state>(and the safe-FSM attribute). - Relying only on
when others. The tool may delete it as unreachable; use the safe-FSM attribute to preserve recovery, and verify in the netlist. - Ignoring one-hot's many illegal states. One-hot registers have far more illegal than legal patterns; recovery (or a one-hot check) is especially important.
- Recovering to a busy/unsafe state. Recover to idle/reset (a benign known state), not into the middle of an operation.
- Assuming reset alone is enough. Reset fixes power-up, not a mid-operation upset; recovery handles illegal states that arise during running.
8. Engineering insight & continuity
A safe FSM treats illegal states as inevitable, not impossible: from any state, legal or not, it returns to a
known one, guaranteeing the machine can never hang. The mechanism is a when others recovery plus the safe-FSM
synthesis attribute that keeps the tool from optimising it away — essential for one-hot encodings and for any
system that must not freeze. This is the reliability capstone of FSM design. The module's final lesson pulls
together everything that can go wrong — the Common FSM Bugs — into a single catalog with fixes, before the
curriculum moves to Packages and Reuse.
Standards & specifications
- Governing standard
- IEEE Std 1076 (VHDL)(opens IEEE in a new tab)
Defines the VHDL language — types, the simulation cycle, and the semantics a conforming analyser and simulator must implement. Synthesis restrictions and vendor coding rules are tool behaviour, not language rules.
This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.
Where this fits
Part of the VHDL curriculum.
