Control vs datapath
Open up almost any digital block and you'll find two kinds of logic living side by side. The datapath is where the numbers actually flow — registers, muxes, adders, the combinational machinery that transforms data. The control is the small unit standing over it, pulling levers: *load this register now, select that mux input, start the multiply this cycle.* The datapath is the kitchen; control is the chef calling out the order of operations.
Why split them in your head? Because they fail differently and you design them differently. Datapath bugs look like wrong numbers; control bugs look like the right numbers at the wrong time — or a machine that hangs forever waiting for a step that never fires. When a behavior is mostly *'do these things in this sequence, depending on what happens,'* that sequencing is control, and control is what an FSM is for.
What a state machine is
A finite state machine is just this: a small set of named states, exactly one of which is 'current' at any moment, plus transition rules that say which state comes next based on the inputs. Think of a traffic light. It has three states — GREEN, YELLOW, RED — it's only ever in one of them, and a tick of the clock (or a timer) moves it to the next. It can never be 'a little bit green.' That *exactly-one-of-N* discipline is the whole point.
Mechanically, an FSM is built from two pieces of hardware you already know. A state register — a bank of flip-flops — holds the current state and only changes on the clock edge; that's the sequential part, the memory. Around it sits next-state logic — pure combinational gates that look at the current state plus the inputs and compute *where to go next.* Every clock tick, the register latches that next state, and the cycle repeats.
Moore vs Mealy
There are two flavors of FSM, and the only difference is where the outputs come from. In a Moore machine, outputs depend on the current state alone — the green light is on *because* you're in the GREEN state, full stop. In a Mealy machine, outputs depend on the state and the current inputs together, so an input can change the output *in the same cycle*, before the state even moves.
The trade is real. Moore outputs are glitch-free and registered-clean — they change only just after a clock edge — but a Mealy machine often needs fewer states and can react one cycle sooner, because it doesn't have to wait to move into a dedicated output state. The cost: Mealy outputs are combinational functions of the inputs, so they can glitch and they tie your timing to whoever drives those inputs.
Drawing the state diagram
Before you write a line of Verilog, draw the machine. The notation is small: each state is a bubble, each transition is an arrow labeled with the input condition that triggers it, and one arrow comes in from nowhere to mark the reset state. For a Moore machine, write each output *inside* the bubble; for Mealy, write it *on the arrow.* The diagram is the spec — get it right on paper and the code nearly writes itself.
Let's make it concrete with a vending-machine controller that dispenses at 15 cents and only takes nickels and dimes. The states are how much money it has seen: S0 (0c), S5 (5c), S10 (10c), and S15 (dispense, then return to S0). From S0, a nickel goes to S5 and a dime to S10; from S5, a nickel goes to S10 and a dime reaches 15; from S10, either coin pushes it to 15 or more and fires the dispense output. Four bubbles, a handful of arrows — that is the entire brain.
- List the states by writing down every distinct situation the block can be in (here: how much money has been inserted). Give each a clear name.
- Pick the reset state — the one the machine powers up into. Draw the lone incoming arrow to it (here: S0, no money).
- For each state, ask 'for every possible input, where do I go?' and draw one labeled arrow per case. Leaving a case out is a silent bug.
- Place the outputs: inside the bubbles for Moore (dispense lives in S15), or on the arrows for Mealy. Now the diagram is a complete spec you can code from.
Coding an FSM in Verilog
The house style is the two-block FSM, and it maps one-to-one onto the hardware from Section 2. One clocked block is the state register — it does nothing but copy *next_state* into *state* on each clock edge (and snap to reset). One combinational block is the next-state logic — a clean case statement that, for the current state, decides where to go. Keeping these separate is the single best habit for readable, synthesizable FSMs.
// Block 1: the state register (sequential) always @(posedge clk or posedge rst) if (rst) state <= S0; // reset to the start state else state <= next_state; // latch next state each clock edge
// Block 2: next-state logic (combinational)
always @(*) begin
next_state = state; // DEFAULT: stay put — no latches
case (state)
S0: if (nickel) next_state = S5;
else if (dime) next_state = S10;
S5: if (nickel) next_state = S10;
else if (dime) next_state = S15;
S10: if (nickel || dime) next_state = S15;
S15: next_state = S0; // dispensed; back to start
default: next_state = S0; // covers unused encodings
endcase
endOutputs hang off this same skeleton. For a Moore machine, drive them from *state* alone (assign dispense = (state == S15);). For Mealy, fold the inputs in too. Some teams add a third block just for outputs — fine, as long as state register, next-state, and output logic stay visibly separate.
State encoding (binary vs one-hot)
Your states have names like S0 and S10, but the flip-flops only know bits — so each state needs a binary pattern, and how you assign those patterns is the *encoding.* The two classic choices are binary and one-hot, and the difference is a textbook flip-flops-versus-logic trade.
Binary encoding packs N states into about ceil(log2(N)) flip-flops — 4 states fit in 2 bits (00, 01, 10, 11). Few registers, but the next-state logic must *decode* those bits, so you pay in combinational gates. One-hot gives each state its own flip-flop — exactly one bit is hot at a time (0001, 0010, 0100, 1000). That burns more flip-flops, but each transition test becomes a single-bit check, so the logic is shallow and fast.