What you map from the diagram
An FSM diagram always has the same pieces in hardware:
- State register (remembers current state)
- Next-state logic (computes
next_state) - Output logic (computes outputs)
How you place outputs in the diagram decides where they appear in Verilog:
| Model | Output depends on | Where it appears |
|---|---|---|
| Moore | current state only | output logic is a function of state |
| Mealy | state + inputs | output logic is a function of state and inputs |
Rule of thumb when translating a diagram:
- Circle (state) → one
case(state)branch - Arrow (transition) labeled
cond / out→condbecomes theif/elsethat selectsnext_state- for Mealy,
outis assigned inside the same conditional - for Moore,
outusually comes from a dedicated output state
Template: Moore FSM (3 always blocks)
module fsm_moore (
input wire clk,
input wire rst_n,
input wire in,
output reg out
);
// 1) State encoding
localparam S0 = 2'd0,
S1 = 2'd1,
S2 = 2'd2,
S3 = 2'd3;
reg [1:0] state, next_state;
// 2) State register
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
state <= S0;
else
state <= next_state;
end
// 3) Next-state logic (combinational)
always @(*) begin
next_state = state; // default (avoids latches)
case (state)
S0: begin
if (in) next_state = S1;
end
S1: begin
if (in) next_state = S2;
else next_state = S0;
end
S2: begin
if (in) next_state = S2;
else next_state = S3; // output state, for example
end
S3: begin
next_state = S0;
end
default: next_state = S0;
endcase
end
// 4) Output logic (combinational, depends only on state)
always @(*) begin
out = 1'b0; // default
case (state)
S3: out = 1'b1; // Moore output asserted in an output state
default: out = 1'b0;
endcase
end
endmoduleNotes:
- Moore outputs typically change only after a clock edge (because
statechanges on the clock). - If you want a registered output, put
out <= ...in a clockedalways @(posedge clk ...)instead.
Template: Mealy FSM (combined next-state + output)
Mealy outputs are usually computed in the same combinational block as next_state because both depend on (state, inputs).
module fsm_mealy (
input wire clk,
input wire rst_n,
input wire in,
output reg out
);
localparam S0 = 2'd0,
S1 = 2'd1,
S2 = 2'd2;
reg [1:0] state, next_state;
always @(posedge clk or negedge rst_n) begin
if (!rst_n)
state <= S0;
else
state <= next_state;
end
// next_state + out (combinational)
always @(*) begin
next_state = state; // default
out = 1'b0; // default (avoid inferred latches)
case (state)
S0: begin
if (in) next_state = S1;
end
S1: begin
if (in) next_state = S2;
else next_state = S0;
end
S2: begin
if (!in) begin
// Example: transition condition also drives output (Mealy)
out = 1'b1;
next_state = S0;
end
end
default: begin
next_state = S0;
out = 1'b0;
end
endcase
end
endmoduleNotes:
- Mealy outputs can change within the cycle as inputs change (combinationally). That’s correct by definition, but it can create glitches if
inis not synchronized.
Concrete example: Sequence detector “101”
This is a common way to see the Moore/Mealy timing difference:
- Mealy can assert
zin the same cycle the final1arrives. - Moore asserts
zin the next cycle (because it asserts based on the new state).
Moore “101” (pulse one cycle later)
module seq101_moore (
input wire clk,
input wire rst_n,
input wire x,
output reg z
);
localparam IDLE = 2'd0, // nothing
S1 = 2'd1, // saw 1
S10 = 2'd2, // saw 10
S101 = 2'd3; // saw 101 (output state)
reg [1:0] state, next_state;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) state <= IDLE;
else state <= next_state;
end
always @(*) begin
next_state = state;
case (state)
IDLE: if (x) next_state = S1;
S1: if (!x) next_state = S10; else next_state = S1;
S10: if (x) next_state = S101; else next_state = IDLE;
S101: if (x) next_state = S1; else next_state = S10; // allow overlap
default: next_state = IDLE;
endcase
end
always @(*) begin
z = (state == S101);
end
endmoduleMealy “101” (pulse immediately)
module seq101_mealy (
input wire clk,
input wire rst_n,
input wire x,
output reg z
);
localparam IDLE = 2'd0, // nothing
S1 = 2'd1, // saw 1
S10 = 2'd2; // saw 10
reg [1:0] state, next_state;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) state <= IDLE;
else state <= next_state;
end
always @(*) begin
next_state = state;
z = 1'b0;
case (state)
IDLE: begin
if (x) next_state = S1;
end
S1: begin
if (!x) next_state = S10;
else next_state = S1;
end
S10: begin
if (x) begin
z = 1'b1; // Mealy output on transition
next_state = S1; // overlap: last '1' can start a new match
end else begin
next_state = IDLE;
end
end
default: begin
next_state = IDLE;
z = 1'b0;
end
endcase
end
endmodule