Skip to content

VHDL · Chapter 9.6 · Finite State Machines

The Three-Process FSM

The three-process style takes the two-process split one step further and gives the output logic its own process, separate from next-state. The machine becomes three clearly labelled blocks: a clocked state register, a combinational next-state process, and a dedicated output process that can be combinational or registered. The payoff is clarity and flexibility, because each process does exactly one job, and you can change the output discipline, whether Moore, Mealy, or registered, by editing only the output process without touching the transition logic. For large or output-heavy FSMs this separation pays for its extra verbosity, while for tiny machines the two-process style is usually enough. This lesson presents the three-process template and explains when its clarity is worth it.

Foundation13 min readVHDLFSMThree-ProcessOutput LogicCoding StyleRTL

1. Engineering intuition — one job per process

An FSM really has three distinct jobs: hold the state (sequential), decide the next state (combinational), and drive the outputs (combinational or registered). The three-process style gives each its own process, so the code reads like the textbook block diagram. The big practical benefit is isolation of the output logic: when outputs are complex, or when you want to switch an output from combinational (Mealy) to registered for timing, you edit only the output process and leave the transition logic untouched. The cost is more text — three processes for what a smaller machine could say in two — so it shines on larger, output-rich controllers.

2. Formal explanation — the three-process template

three_process_fsm.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
library ieee; use ieee.std_logic_1164.all;
type state_t is (IDLE, RUN, DONE);
signal state, next_state : state_t;
 
-- (1) STATE REGISTER (clocked).
sreg : process (clk, rst_n)
begin
  if rst_n = '0' then        state <= IDLE;
  elsif rising_edge(clk) then state <= next_state;
  end if;
end process;
 
-- (2) NEXT-STATE logic (combinational) — ONLY transitions, no outputs.
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 DONE =>                    next_state <= IDLE;
  end case;
end process;
 
-- (3) OUTPUT logic (combinational here) — ONLY outputs, isolated and easy to restyle.
ologic : process (all)
begin
  busy <= '0'; done <= '0';                      -- default every output (latch-free)
  case state is
    when RUN  => busy <= '1';                    -- Moore outputs from state
    when DONE => done <= '1';
    when others => null;
  end case;
end process;

Three single-purpose processes: the clocked sreg holds the state; the combinational nlogic computes only next_state (defaulted to stay); the combinational ologic computes only the outputs (every output defaulted to avoid latches). The output process is self-contained — to make busy registered, or Mealy, you change only ologic.

3. Production RTL — swapping the output style in isolation

restyle_outputs.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
library ieee; use ieee.std_logic_1164.all;
-- Same sreg and nlogic as above; only the OUTPUT process changes to register the outputs:
oreg : process (clk, rst_n)
begin
  if rst_n = '0' then busy <= '0'; done <= '0';
  elsif rising_edge(clk) then
    busy <= '0'; done <= '0';                    -- registered outputs (glitch-free, +1 cycle)
    case next_state is                           -- decode the state being ENTERED → output aligns
      when RUN  => busy <= '1';
      when DONE => done <= '1';
      when others => null;
    end case;
  end if;
end process;

What hardware does this become? The same state register and next-state logic, but now the outputs come from flip-flops decoded from next_state (so a registered output aligns with the state it represents). The point is that this change touched only the output process — the transition logic is untouched. That isolation is the three-process style's signature advantage.

4. Hardware interpretation — three blocks, three processes

three-process FSM: state register, next-state process, output processnext_statestatestatenext-state processcombinational transitionsstate registerprocessclocked + resetoutput processMoore / Mealy / registered(isolated)inputsgo, fin, ...outputsbusy, done12
The three-process FSM maps each process to one hardware block: the clocked state register, the combinational next-state logic, and the (combinational or registered) output logic. The state register feeds both the next-state logic (current state for transitions) and the output logic (state for outputs). Isolating the output logic in its own process means its style — Moore, Mealy, or registered — can be chosen independently of the transition logic, which is why this style scales to large, output-heavy controllers.

5. Simulation interpretation — same behaviour, clearer code

Three-process FSM: state register, next-state, and outputs each from their own process

8 cycles
Three-process FSM: state register, next-state, and outputs each from their own processnext-state process: go → next_state=RUNnext-state process: go…state register captures RUN; output process drives busy from the statestate register capture…clkgo01000000stateIDLEIDLERUNRUNDONEIDLEIDLEIDLEnext_stateIDLERUNRUNDONEIDLEIDLEIDLEIDLEbusy00110000t0t1t2t3t4t5t6t7
The three processes cooperate exactly like the two-process FSM — next-state logic computes next_state, the register captures it, the output process decodes busy from the state — but each job is in its own clearly-labelled process. The behaviour is identical to the two-process version; the difference is code organisation and the ease of restyling outputs.

6. Debugging example — the duplicated default, or output/next-state confusion

Expected: clean, independent processes. Observed: a latch on an output or next_state, or outputs that do not match the state. Root cause: one of the combinational processes (next-state or output) missed its defaultsnext_state <= state in nlogic, or every output in ologic — inferring a latch; or the output process decoded the wrong state signal (current vs next). Fix: default next_state in the next-state process and every output in the output process; decide deliberately whether outputs decode the current state (aligned with combinational) or the next state (for registered alignment). Engineering takeaway: each combinational FSM process needs its own complete defaults, and the output process must decode the intended state signal — the separation that gives clarity also means each process must independently be latch-free.

defaults_per_process.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- next-state process: default next_state.   output process: default every output.
nlogic : process(all) begin next_state <= state; case state is ... end case; end process;
ologic : process(all) begin busy <= '0'; done <= '0'; case state is ... end case; end process;

7. Common mistakes & what to watch for

  • Missing defaults in either combinational process. Default next_state and every output; each process must be independently latch-free.
  • Decoding the wrong state in the output process. Current state for combinational outputs; next state for registered outputs that should align with the entered state.
  • Using three processes for a trivial FSM. Overkill; the two-process style is usually enough for small machines.
  • Mixing next-state and output logic across the processes. Keep transitions in the next-state process and outputs in the output process — that separation is the whole point.
  • Inconsistent style across FSMs in a project. Pick a default style and apply it consistently; reserve three-process for the output-heavy cases.

8. Engineering insight & continuity

The three-process FSM is the maximum-clarity style: one process each for holding state, deciding transitions, and driving outputs, so the code mirrors the textbook diagram and the output logic can be restyled in isolation. It pays for its verbosity on large, output-rich controllers; for small machines the two-process style is leaner. Across all three styles (one-, two-, three-process), the choice is really about where the outputs live and how much separation you want — which makes output logic a first-class design decision. The next lesson, FSM Output Logic and Registered Outputs, treats exactly that: how to design Moore, Mealy, and registered outputs cleanly, whichever coding style you use.