VHDL · Chapter 9.3 · Finite State Machines
State Encoding
An FSM thinks in named states, but the hardware stores bits. State encoding is the mapping between them, and it is a real area, speed, and power decision. Binary encoding packs the states into the fewest flip-flops but needs more next-state logic to decode. One-hot uses one flip-flop per state, with only one bit set at a time, which costs more flip-flops but gives very simple, fast decoding, so FPGAs tend to favour it. Gray encoding changes only one bit per transition, minimising switching for low-power or noise-sensitive designs. The right move in VHDL is to declare states as an enumerated type and let the synthesiser choose or force the encoding, and to never write code that depends on the specific bit pattern. This lesson covers the schemes, their trade-offs, and how to control them safely.
Foundation14 min readVHDLState EncodingOne-hotBinaryGrayFSM
1. Engineering intuition — same states, different bits
The states of an FSM are just labels — IDLE, RUN, DONE — but in silicon each must be a pattern of bits in the state register, and there is more than one sensible way to assign those patterns. Pack them tightly (binary) to use the fewest flip-flops, spread them out (one-hot) to make the decode logic trivial and fast, or order them so each step flips one bit (gray) to minimise switching. None changes what the FSM does — only its size, speed, and power. Because the behaviour is identical, you let the tool pick the encoding to fit your target, and keep your code written in terms of the names, never the bits.
2. Formal explanation — the three common schemes
-- Four states, three encodings:
-- state BINARY ONE-HOT GRAY
-- IDLE 00 0001 00
-- RUN 01 0010 01
-- PAUSE 10 0100 11
-- DONE 11 1000 10
-- BINARY: ~log2(N) flip-flops; compact; more combinational next-state logic.
-- ONE-HOT: N flip-flops; one bit hot; simple/fast decode; many ILLEGAL states (not one-hot).
-- GRAY: ~log2(N) flip-flops; adjacent states differ by ONE bit; least switching.These differ only in the bit patterns assigned to each state. Binary minimises flip-flops; one-hot minimises decode logic (a state test is a single bit) at the cost of N flip-flops and many bit patterns that are not legal states; gray minimises bit-toggles per transition. The number of legal states is the same; the representation is what changes.
3. Production RTL — declare names, let the tool encode
library ieee; use ieee.std_logic_1164.all;
-- Always declare states as an ENUMERATED type — names, not bits.
type state_t is (IDLE, RUN, PAUSE, DONE);
signal state, next_state : state_t;
-- The synthesiser chooses the encoding (often automatically by size/target).
-- To FORCE it, use a synthesis attribute (vendor-specific name shown generically):
attribute fsm_encoding : string;
attribute fsm_encoding of state : signal is "one_hot"; -- or "binary" / "gray" / "auto"
-- Your logic NEVER mentions bit patterns — only the names:
-- case state is when IDLE => ... when RUN => ... end case;What hardware does this become? A state register whose width and bit assignment are set by the chosen
encoding — log2(N) flip-flops for binary/gray, N for one-hot — plus the next-state and output decode the
encoding implies. Because the RTL refers to IDLE/RUN/... by name, changing the encoding (a tool option or
attribute) re-targets the whole FSM without touching a line of logic. That decoupling is the entire point of
using an enum.
4. Hardware interpretation — area vs speed vs power
5. Simulation interpretation — the same machine, different state bits
The same state sequence under binary versus one-hot encoding
8 cycles6. Debugging example — encoding-dependent code (and a one-hot illegal state)
Expected: the FSM works regardless of encoding. Observed: it breaks when the tool changes the encoding,
or a glitch/upset leaves a one-hot register in an illegal (multi-hot or zero-hot) pattern from which it never
recovers. Root cause: for the first, the code compared the state to a bit pattern (e.g. state = "01") instead of a name, so it depended on the encoding; for the second, a one-hot FSM has many illegal
patterns and no defined recovery. Fix: always compare against the enum names, never bit patterns; and
add safe-state recovery (a when others => next_state <= IDLE;) so any illegal state returns to a known one
(lesson 9.8). Engineering takeaway: write FSM logic in terms of state names so encoding is the tool's
choice, and handle illegal states explicitly — especially with one-hot, which has many of them.
-- BUG: depends on the encoding.
-- if state = "01" then ... -- breaks if the tool re-encodes
-- FIX: compare names; let the tool encode.
case state is
when RUN => ...
when others => next_state <= IDLE; -- safe recovery from any illegal/unexpected state
end case;7. Common mistakes & what to watch for
- Comparing the state to bit patterns. Use enum names; never hard-code
"01"-style patterns. - Ignoring illegal states (especially one-hot). Add a
when otherssafe recovery (lesson 9.8); one-hot has many illegal patterns. - Forcing an encoding without reason. Let the tool pick by default; force only for a measured area/speed/ power or robustness goal.
- Assuming one-hot is always best (or always worst). It suits FPGAs and timing-critical decode; binary/gray suit flip-flop-limited or low-power designs.
- Forgetting gray's adjacency requirement. Gray's benefit only holds if transitions are between adjacent codes; arbitrary FSM transitions may not be gray-adjacent.
8. Engineering insight & continuity
State encoding is a representation choice that trades area, speed, and power without changing behaviour — which is exactly why you declare states as an enumerated type and code in names, leaving the encoding to a tool option or attribute. One-hot for fast, simple decode on flip-flop-rich FPGAs; binary or gray when flip-flops or power are constrained. The one discipline that crosses all encodings is to keep logic name-based and to handle illegal states. With outputs (Moore/Mealy) and encoding settled, the module turns to organising the three FSM blocks into clean code: the next lesson, The Two-Process FSM, presents the recommended style — one clocked process for the state register and one combinational process for next-state and outputs.