VHDL · Chapter 9.7 · Finite State Machines
FSM Output Logic and Registered Outputs
However you code an FSM, its outputs are a design decision in their own right. Combinational outputs, whether Moore from the state or Mealy from the state and inputs, respond in the same cycle but can carry glitches from the logic that produces them. Registered outputs come straight from a flip-flop, so they are glitch-free with clean edges, at the cost of one cycle of latency. The choice matters. An output that drives another clock domain, sits on a critical path, or must be a clean single-cycle strobe should usually be registered, while an output needed in the same cycle stays combinational. This lesson treats output design as first-class, covering the styles, when to register, how to align a registered output with the state it represents, and keeping it all latch-free.
Foundation14 min readVHDLFSMOutput LogicRegistered OutputsGlitchesTiming
1. Engineering intuition — the output is not an afterthought
It is easy to treat FSM outputs as whatever falls out of the state, but in real designs the quality of an output — its timing and cleanliness — is a deliberate choice. A control signal that enables a write, gates a bus, or crosses to another clock had better be glitch-free and well-timed. So the question for each output is: do I need it this cycle (combinational), or do I want it clean and registered (one cycle later)? Answering that per output — rather than accepting the default — is what separates a robust controller from one that mostly works.
2. Formal explanation — combinational vs registered outputs
library ieee; use ieee.std_logic_1164.all;
-- COMBINATIONAL MOORE: from the state; same cycle, but combinational (can glitch).
busy <= '1' when state = RUN else '0';
-- COMBINATIONAL MEALY: from state + input; immediate response, more glitch-prone.
grant <= '1' when (state = ARB and req = '1') else '0';
-- REGISTERED output: from a flip-flop; glitch-free, ONE cycle later.
-- Decode the NEXT state so the registered output aligns with the state it represents.
process (clk, rst_n) begin
if rst_n = '0' then en_r <= '0';
elsif rising_edge(clk) then
en_r <= '1' when next_state = ACTIVE else '0'; -- registered, aligned to entering ACTIVE
end if;
end process;Combinational outputs (Moore or Mealy) are produced by combinational logic, so they appear in the same cycle but can glitch as that logic settles. Registered outputs are captured in a flip-flop, so they are clean and glitch-free but delayed a cycle. To make a registered output line up with the state it represents, decode the next state (the state being entered) so the flip-flop's output is high during that state, not a cycle after it.
3. Production RTL — registering the outputs that need it
library ieee; use ieee.std_logic_1164.all;
-- Same-cycle status output stays combinational; the bus-enable that must be glitch-free is registered.
busy <= '0' when state = IDLE else '1'; -- combinational Moore status
bus_en_reg : process (clk, rst_n)
begin
if rst_n = '0' then bus_en <= '0';
elsif rising_edge(clk) then
bus_en <= '1' when next_state = DRIVE else '0'; -- registered, glitch-free, aligned to DRIVE
end if;
end process;What hardware does this become? busy is combinational logic off the state register (fine for a status
level). bus_en is its own flip-flop, decoded from next_state so it is asserted exactly during the DRIVE
state, glitch-free — important because it gates a shared bus where a glitch could cause contention. Registering
just the outputs that need it (rather than all of them) gets clean critical signals without adding latency
everywhere.
4. Hardware interpretation — three output options
5. Simulation interpretation — combinational vs registered timing
Combinational output (same cycle) vs registered output (clean, one cycle later)
8 cycles6. Debugging example — the glitch on a critical control output
Expected: a clean control pulse. Observed: a downstream block sees a spurious extra pulse, or a bus shows momentary contention, traced to a glitch on an FSM output. Root cause: the output was a combinational decode of the state (and possibly inputs), so as that logic settled it produced a brief glitch — harmless for a status level but dangerous for an enable, strobe, or cross-domain signal. Fix: register that output (decode the next state so it aligns), giving a glitch-free edge straight from a flip-flop. Engineering takeaway: combinational FSM outputs can glitch; any output that enables, strobes, or crosses domains should be registered — same-cycle status outputs can stay combinational.
-- BUG: combinational strobe can glitch as the decode settles.
-- wr_en <= '1' when state = WRITE else '0';
-- FIX: registered strobe, glitch-free, aligned by decoding next_state.
process (clk) begin
if rising_edge(clk) then wr_en <= '1' when next_state = WRITE else '0'; end if;
end process;7. Common mistakes & what to watch for
- Combinational outputs on critical/cross-domain signals. Register enables, strobes, and CDC outputs; leave same-cycle status combinational.
- Registered output misaligned by a cycle. Decode the next state so the registered output is high during the intended state.
- Latches in the output logic. Default every output (Module 6); applies in any coding style.
- Registering every output reflexively. That adds latency everywhere; register only what needs to be clean.
- Assuming the coding style fixes output quality. Output style (Moore/Mealy/registered) is an independent choice from one/two/three-process.
8. Engineering insight & continuity
FSM output design is a per-output decision about timing and cleanliness: combinational for same-cycle response (Moore stable, Mealy immediate-but-glitchy), registered for glitch-free signals that drive enables, strobes, and other clock domains — aligned by decoding the next state. Treating outputs as first-class, rather than whatever the state decode produces, is what makes a controller robust at its interfaces. With outputs, encoding, and all three coding styles covered, the module turns to robustness against the unexpected: Safe FSMs and Illegal-State Recovery (handling states the machine should never be in), then a consolidated tour of Common FSM Bugs.