In short: A Moore FSM decides outputs from state alone (glitch-free, one cycle later), a Mealy FSM folds inputs into outputs (fewer states, faster response but combinational risk), and on FPGAs one-hot encoding plus an explicit default/reset transition is what keeps a state machine fast, timing-clean, and recoverable from illegal states.
Finite state machines are the control backbone of almost every RTL block you will ever write — a UART, an SPI master, a memory arbiter, a DMA engine, an AXI handshake. Yet FSMs are also where junior designers quietly lose area, timing, and functional safety. This guide walks through the design decisions that matter in silicon, with concrete numbers and the tool behaviour you will actually see in Vivado, Quartus, Synopsys Design Compiler, or Siemens Questa.
Moore vs Mealy: where do the outputs come from?
The only formal difference is the output function. In a Moore machine the output is a function of the current state only: out = f(state). In a Mealy machine the output is a function of state and the current inputs: out = f(state, in). That one change ripples into timing, latency, and testability.
Because a Moore output changes only after a clock edge, it is naturally glitch-free and easy to constrain — the output leaves a flip-flop or a small decode of registered state. A Mealy output can change mid-cycle as soon as an input wiggles, which is why it reacts one cycle earlier but can also create combinational spikes if you feed it to anything asynchronous. For a protocol like SPI, a Mealy machine typically needs 2–3 fewer states to assert cs_n and sclk at exactly the right phase, but you pay for it with a longer input-to-output timing arc that the synthesis tool must close.
Rule of thumb: if a downstream block samples your output on a clock edge, Moore is almost always the safer default. Reserve Mealy for latency-critical handshakes (e.g. an AXI VALID/READY pair) where saving a cycle genuinely matters.
State encoding: binary, gray, and one-hot
How you number the states is not cosmetic — it directly sets the width of the state register and the depth of the next-state logic. Three schemes dominate:
| Encoding | Flip-flops for N states | Next-state logic | Best for |
|---|---|---|---|
| Binary | ceil(log2 N) | Wide, deep decode | ASIC, FF-limited designs |
| Gray | ceil(log2 N) | Medium; 1-bit transitions | Low-power, CDC counters |
| One-hot | N | Shallow, 1 bit per state | FPGA (FF-rich fabric) |
On an FPGA the arithmetic favours one-hot. A Xilinx or Intel fabric is drowning in flip-flops — every LUT already ships with a paired register — so spending N flops instead of log2(N) costs almost nothing, while the next-state logic collapses to a single AND/OR term per state. A 12-state controller in binary needs 4 FFs but a 3–4 LUT-deep decoder; in one-hot it needs 12 FFs but typically a single LUT level, often shaving 1–2 ns off the critical path. That is exactly why Vivado’s FSM_ENCODING attribute and Quartus default to one-hot for FPGA targets, whereas Design Compiler leans toward binary for a cell-area-limited ASIC flow.
Safe state machines: surviving the illegal state
One-hot has a hidden cost: of its 2^N raw encodings, only N are legal. A single-event upset (an alpha particle or a glitchy reset) can flip the register to 0000 or 0110 — a state your case never mentions. If the HDL has no defined recovery, the machine locks up until the next power cycle. In aerospace, automotive (ISO 26262), or any 24/7 datacentre FPGA, that is a field failure.
A safe FSM adds an explicit escape. In SystemVerilog, use a unique case with a default branch that forces the machine back to its reset/idle state, and in Vivado set (* fsm_safe_state = "reset_state" *) so the tool synthesises a hang detector that drives the register to a known-good value. Intel Quartus exposes the same idea through its Safe State Machine setting, and Siemens Questa can formally prove — with an assertion like assert property (@(posedge clk) onehot(state)) — that the live design never leaves the legal set.
Never let the synthesis tool "optimise away" the default branch. If you write case without default, the tool assumes the illegal states are don’t-cares and may build logic that can never recover. Always code the default, and verify it with a fault-injection testbench.
A clean three-process template
The template that survives code review and closes timing cleanly separates concerns into three blocks: a sequential state register, a combinational next-state function, and a combinational (or registered) output function.
- State register — one
always_ffwith synchronous or asynchronous reset toIDLE. Nothing else lives here. - Next-state logic — one
always_combwith aunique case (state)and a mandatorydefault: next = IDLE;. - Output logic — registered for Moore, combinational for Mealy. Keep it a separate block so the intent is unambiguous to both the reader and the tool.
This structure maps one-to-one onto how pipelining in FPGA stages are reasoned about, and it is the same discipline you apply when you push an FSM into a deeper timing-closure flow. For teams who want hands-on labs with Vivado and Questa, our full FPGA and RTL design courses build these templates up from scratch, and for production IP sign-off the engineers at Avecas design services run the same safe-FSM audits on customer silicon.
Putting it together: a worked trade-off
Suppose you are building a memory-controller command sequencer with 9 states. In binary you would use 4 flip-flops and a next-state decoder roughly 3 LUT levels deep — call it 2.1 ns of logic delay at a typical 7 nm speed grade. Re-synthesise as one-hot and you spend 9 flip-flops (still trivial against the tens of thousands on the device) but the decoder drops to a single LUT level, around 0.9 ns, letting you hit a 400 MHz target that the binary version missed. Add Moore outputs so the command bus is glitch-free, and a fsm_safe_state default so a cosmic-ray upset returns you to IDLE within one cycle. That is the whole decision tree in one block.
FAQ
Is Mealy always faster than Moore?
Mealy responds one cycle earlier because the output reacts to inputs within the same cycle, but it adds a combinational input-to-output path that can become your critical timing arc. "Faster to react" is not the same as "easier to close timing."
Why does Vivado default to one-hot for FPGAs?
FPGA fabrics are flip-flop rich, so the extra registers one-hot needs are nearly free, while the shallow next-state logic shortens the critical path. On an ASIC, where every cell costs area, binary is usually preferred instead.
What exactly makes an FSM "safe"?
A safe FSM defines what happens in every illegal or unreachable encoding — typically a default branch plus a tool-generated hang detector — so a bit-flip from an SEU or glitch always recovers to a known reset state rather than locking up.
Do I need a default branch if I cover every legal state?
Yes. With one-hot you only enumerate N of 2^N encodings; without a default, the tool treats the rest as don’t-cares and may synthesise unrecoverable logic. Always code the default and test it with fault injection.
Ready to build glitch-free, timing-clean FSMs in Vivado and Questa with guided labs? Join the CourseTron FPGA & RTL Design track at coursetron.com/courses and ship controllers that survive sign-off. Prefer instructor-led cohorts? See our training partner ChipXpert.
References & Further Reading
- Finite-state machine — Wikipedia
- AMD/Xilinx Vivado Synthesis User Guide (UG901) — FSM encoding & safe state
- Intel Quartus Prime — State Machine HDL Coding Guidelines
- IEEE Std 1364 / SystemVerilog RTL coding — IEEE Xplore
- Cummings, "Coding and Scripting Techniques for FSM Designs" (SNUG) — Sunburst Design papers