Two classic FSM output styles:
| Type | Outputs depend on | Typical timing |
|---|---|---|
| Moore | State only | Change after state updates (registered-friendly) |
| Mealy | State + inputs | Can react same cycle as input (faster, glitchier) |
Moore example sketch
always_comb begin
done = 1'b0;
unique case (state_q)
ST_DONE: done = 1'b1;
default: done = 1'b0;
endcase
end
done is stable for a whole state visit — easy to sample elsewhere.
Mealy example sketch
always_comb begin
grant = 1'b0;
if (state_q == ST_IDLE && req) grant = 1'b1;
end
grant can rise in the same cycle as req, which is useful for combo-ack protocols — but grant may glitch if req glitches.
Registered outputs (practical default)
Many teams implement “Moore-like” control by registering outputs:
always_ff @(posedge clk) begin
if (state_d == ST_DONE) done_q <= 1'b1;
else done_q <= 1'b0;
end
That adds a cycle of latency but cleans timing and CDC-ish interfaces.
Choosing
- Prefer Moore / registered for status flags crossing modules.
- Use Mealy when a same-cycle acknowledge is part of the bus spec — then constrain and review carefully.
- Never feed raw Mealy outputs into async resets or clocks.