FSM Verilog Code: Mealy vs Moore (1011 Detector)
A finite state machine (FSM) is the backbone of almost every control path in digital design, and writing clean, synthesizable FSM Verilog code is a skill interviewers test constantly. This tutorial gives you two complete, runnable sequence detectors for the pattern 1011 — one Moore, one Mealy — written in the industry-standard three-always-block style. Copy the code, run it in Icarus Verilog, and read the walkthrough to understand exactly why each block exists.
📘 New to the concept? Read the theory first: Finite State Machines: Mealy vs Moore.
Mealy vs Moore in one paragraph
Both are FSMs; the difference is where the output comes from. A Moore machine’s output depends only on the current state, so it stays glitch-free and changes synchronously one cycle after the triggering input. A Mealy machine’s output depends on the current state and the current input, so it reacts one cycle earlier and usually needs fewer states — at the cost of combinational paths that can glitch if you feed them straight to another block. For a sequence detector, the Mealy version detects 1011 as the last bit arrives, while the Moore version flags it on the next clock edge.
The 3-always-block coding style
Professional RTL splits an FSM into three separate blocks. This is the pattern tools expect and reviewers look for:
- Block 1 — state register: the only sequential (
posedge clk) block. It does nothing but copynext_stateintostate, with a reset. - Block 2 — next-state logic: pure combinational (
always @(*)). Acaseonstatecomputesnext_statefrom the inputs. - Block 3 — output logic: combinational. For Moore it reads only
state; for Mealy it readsstateand the inputs.
Keeping the register separate from the logic makes the design easy to read, prevents accidental latches, and gives synthesis a predictable structure.
Moore 1011 sequence detector (Verilog + testbench)
This is an overlapping detector: after a match, the trailing 1 can start the next pattern. States track how much of 1011 we have seen so far. Run it with iverilog -g2005 -o sim seq_detector_moore.v && vvp sim.
// Moore FSM: overlapping sequence detector for "1011"
// 3-always-block coding style: state register, next-state logic, output logic
module seq_detector_moore (
input wire clk,
input wire rst_n, // active-low synchronous reset
input wire din, // serial data input, MSB-first
output reg dout // pulses high the cycle AFTER the 4th matching bit
);
// State encoding (localparam keeps it readable and synthesizable)
localparam [2:0] S_IDLE = 3'd0, // no useful bits yet
S_1 = 3'd1, // seen "1"
S_10 = 3'd2, // seen "10"
S_101 = 3'd3, // seen "101"
S_1011 = 3'd4; // seen "1011" -> match
reg [2:0] state, next_state;
// 1) State register: the ONLY sequential block
always @(posedge clk) begin
if (!rst_n)
state <= S_IDLE;
else
state <= next_state;
end
// 2) Next-state logic: pure combinational, no memory
always @(*) begin
next_state = state; // safe default avoids latches
case (state)
S_IDLE : next_state = din ? S_1 : S_IDLE;
S_1 : next_state = din ? S_1 : S_10;
S_10 : next_state = din ? S_101 : S_IDLE;
S_101 : next_state = din ? S_1011: S_10;
S_1011 : next_state = din ? S_1 : S_10; // overlap-aware
default: next_state = S_IDLE;
endcase
end
// 3) Output logic: Moore output depends ONLY on the current state
always @(*) begin
dout = (state == S_1011);
end
endmodule
module tb_seq_detector_moore;
reg clk, rst_n, din;
wire dout;
integer i;
// stimulus: 1 0 1 1 0 1 1 -> contains overlapping "1011" twice
reg [0:6] stream = 7'b1011011;
seq_detector_moore dut (.clk(clk), .rst_n(rst_n), .din(din), .dout(dout));
initial clk = 1'b0;
always #5 clk = ~clk; // 100 MHz
initial begin
$display("time rst din state_out match");
rst_n = 1'b0; din = 1'b0;
@(negedge clk); rst_n = 1'b1; // release reset
for (i = 0; i < 7; i = i + 1) begin
din = stream[i];
@(posedge clk); // din sampled here
#1; // let combinational dout settle
$display("%4t %b %b -> %b", $time, rst_n, din, dout);
if (dout) $display(" >> MATCH: 1011 detected ending at bit index %0d", i);
end
din = 1'b0;
@(posedge clk); #1;
$display("%4t %b %b -> %b", $time, rst_n, din, dout);
if (dout) $display(" >> MATCH: 1011 detected (trailing)");
$display("Simulation finished.");
$finish;
end
endmodule
time rst din state_out match
16 1 1 -> 0
26 1 0 -> 0
36 1 1 -> 0
46 1 1 -> 1
>> MATCH: 1011 detected ending at bit index 3
56 1 0 -> 0
66 1 1 -> 0
76 1 1 -> 1
>> MATCH: 1011 detected ending at bit index 6
86 1 0 -> 0
Simulation finished.
/var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmpqsn2qos2/seq_detector_moore.v:79: $finish called at 86 (1s)How the Moore machine works, block by block
- Encoding: five states hold how much of the pattern matched so far.
S_1means the last bit seen was1;S_101means the last three bits were101;S_1011is the hit. - Register block: on every rising clock edge it loads
next_state, or resets toS_IDLEwhenrst_nis low. No logic lives here — that is the whole point. - Next-state block: the first line,
next_state = state;, is a default that guarantees every branch assigns a value, so synthesis never infers a latch. Eachcasearm answers one question: “given what I’ve matched and the new bit, how much do I now match?” The interesting arm isS_101: a1completes1011(go toS_1011), but a0drops us back toS_10because the tail...10is still a partial match. - Overlap handling: from
S_1011, a new1jumps toS_1(the trailing1seeds the next pattern) and a0goes toS_10. That is what makes this an overlapping detector. - Output block:
doutis simplystate == S_1011. Because it reads only the state, the pulse is one clean cycle wide and aligned to the clock.
In the log you can see 1011011 trigger two overlapping matches — at bit index 3 and again at bit index 6.
Mealy 1011 sequence detector
The Mealy version needs only four states because the final match is signalled on the transition rather than in a dedicated state. Watch the timing difference in the log.
// Mealy FSM: overlapping sequence detector for "1011"
// 3-always-block style. Mealy output depends on state AND current input,
// so the detect pulse appears one cycle earlier than the Moore version.
module seq_detector_mealy (
input wire clk,
input wire rst_n, // active-low synchronous reset
input wire din, // serial data input, MSB-first
output reg dout // high during the cycle the 4th bit arrives
);
localparam [1:0] S_IDLE = 2'd0, // no useful bits
S_1 = 2'd1, // seen "1"
S_10 = 2'd2, // seen "10"
S_101 = 2'd3; // seen "101"
reg [1:0] state, next_state;
// 1) State register
always @(posedge clk) begin
if (!rst_n)
state <= S_IDLE;
else
state <= next_state;
end
// 2) Next-state logic
always @(*) begin
next_state = state;
case (state)
S_IDLE : next_state = din ? S_1 : S_IDLE;
S_1 : next_state = din ? S_1 : S_10;
S_10 : next_state = din ? S_101 : S_IDLE;
S_101 : next_state = din ? S_1 : S_10; // on the matching 1, overlap back to S_1
default: next_state = S_IDLE;
endcase
end
// 3) Output logic: Mealy output = f(state, input)
always @(*) begin
dout = (state == S_101) && (din == 1'b1); // last bit of 1011 seen
end
endmodule
module tb_seq_detector_mealy;
reg clk, rst_n, din;
wire dout;
integer i;
reg [0:6] stream = 7'b1011011; // two overlapping "1011" matches
seq_detector_mealy dut (.clk(clk), .rst_n(rst_n), .din(din), .dout(dout));
initial clk = 1'b0;
always #5 clk = ~clk;
initial begin
$display("time rst din match");
rst_n = 1'b0; din = 1'b0;
@(negedge clk); rst_n = 1'b1;
for (i = 0; i < 7; i = i + 1) begin
din = stream[i];
#1; // Mealy output reacts to din within the cycle
$display("%4t %b %b %b", $time, rst_n, din, dout);
if (dout) $display(" >> MATCH: 1011 detected as bit index %0d arrives", i);
@(posedge clk);
end
$display("Simulation finished.");
$finish;
end
endmodule
time rst din match
11 1 1 0
16 1 0 0
26 1 1 0
36 1 1 1
>> MATCH: 1011 detected as bit index 3 arrives
46 1 0 0
56 1 1 0
66 1 1 1
>> MATCH: 1011 detected as bit index 6 arrives
Simulation finished.
/var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmp5zrpwqbx/seq_detector_mealy.v:71: $finish called at 75 (1s)What changed versus the Moore version
- One fewer state: there is no
S_1011. When we are inS_101and a1arrives, that is the match, so we assert the output and move straight toS_1for overlap. - The output line is the key:
dout = (state == S_101) && (din == 1'b1);. Becausedinis in the expression,doutis a Mealy output — it goes high the instant the fourth bit is present, before the next clock edge. - Same three-block skeleton: register, next-state, output. Only the output block’s sensitivity to
dindistinguishes Mealy from Moore.
Mealy vs Moore: which should you use?
| Property | Moore | Mealy |
|---|---|---|
| Output depends on | State only | State and input |
| States for 1011 detector | 5 | 4 |
| Detection timing | One cycle later | Same cycle as last bit |
| Output glitches | None (registered by state) | Possible on input changes |
| Best when | You need safe, synchronous outputs | You need lower latency or fewer states |
A common safe compromise is to build a Mealy next-state machine but register the output, giving you a Moore-like clean pulse one cycle later.
Common mistakes to avoid
- Mixing blocking and non-blocking. Use non-blocking (
<=) in the sequential block and blocking (=) in combinational blocks. Mixing them causes simulation-vs-synthesis mismatches. - Forgetting the default assignment. Without
next_state = state;(or a fulldefaultarm), an incompletely specifiedcaseinfers an unwanted latch. - Putting logic in the clocked block. Computing outputs or next state inside
always @(posedge clk)defeats the readability of the three-block style and hides timing. - Ignoring overlap. Decide up front whether matches can overlap. A non-overlapping detector would return to
S_IDLEafter a hit instead of reusing the trailing1. - Not resetting the state register. An FSM that powers up in an unknown state can lock up; always reset to a known state.
- Using
always @(posedge clk or negedge rst_n)when you meant synchronous reset. The sensitivity list decides async vs sync reset — match it to your design intent.
Quick check
Why does the Moore detector need five states but the Mealy only four?
Moore needs a dedicated “match” state (S_1011) because its output reads only the state. Mealy signals the match on the transition out of S_101 using the input, so no extra state is required.
What does the line next_state = state; at the top of the combinational block prevent?
It provides a default so every path assigns next_state. Without it, an unassigned branch would make synthesis infer a latch, creating a subtle hardware bug.
In the overlapping detector, where does the FSM go after a successful 1011 match on a following 1?
To S_1. The trailing 1 of 1011 becomes the first bit of a potential new match, which is exactly what “overlapping” means.
Why can a Mealy output glitch while a Moore output cannot?
The Mealy output is combinational on the input, so any mid-cycle change on din can momentarily change dout. The Moore output is a function of the registered state only, so it is stable for the whole cycle.
Share your question in comments or talk to our mentor team for batch guidance.
Learn Verilog with mentors, labs and placement support
This free series is maintained by the ChipXpert training team in Hyderabad & Bengaluru. Go deeper with instructor-led courses on real EDA tools.
Explore VLSI Courses