Sequence Detector Verilog Code: 1011 Mealy & Moore FSM
A sequence detector is a finite state machine (FSM) that scans a serial input one bit per clock and raises a flag the instant a target pattern appears. This tutorial gives you complete, runnable sequence detector Verilog code for the pattern 1011, written four ways that exams and interviews love to compare: Moore and Mealy style, each in overlapping and non-overlapping modes. Every listing below is self-contained Verilog-2005 with its own testbench that streams the bits 1011011 into the design, so you can compile it and watch the detections for yourself.
Two decisions shape the design. Overlap means the end of one match may begin the next: in the stream 1011011 the final 1 of the first 1011 is reused as the first 1 of a second match, so an overlapping detector reports two hits. A non-overlapping detector discards that bit and starts over, reporting one. Moore machines tie the output to the current state, so the flag appears one clock after the last bit arrives; Mealy machines tie the output to the state and the current input, so the flag appears during the last bit. Same pattern, different timing and different gate count.
Modelling 1011 as states
The cleanest way to think about any single-pattern detector is: how much of the target have I matched so far? For 1011 that gives five prefixes — the empty string, 1, 10, 101, and the full 1011. Each becomes a state. On every clock the FSM reads din and moves to the state for the longest prefix of 1011 that is now a suffix of everything seen. That rule is what makes a 0 after 101 fall back to 10 (because the recent bits still end in 10) instead of all the way to the start.
| State | Matched prefix | din = 0 | din = 1 |
|---|---|---|---|
| S0 | empty | S0 | S1 |
| S1 | 1 | S2 | S1 |
| S2 | 10 | S0 | S3 |
| S3 | 101 | S2 | S4 (detect) |
| S4 | 1011 | S2 | S1 |
The last row is where overlap lives: after a full 1011 a trailing 1 jumps to S1 and a 0 to S2, reusing as much of the just-seen bits as possible.
Moore FSM: overlapping 1011 detector
The Moore version uses all five states and makes detected purely a function of the state: detected = (state == S4). Because S4 is only entered on the clock edge that consumes the final 1, the flag is high during the cycle after that bit. The design splits cleanly into three blocks — a combinational next-state block, a clocked state register, and the output assignment — which is the pattern synthesis tools handle best.
// seq_moore_1011.v -- Moore FSM, detects "1011" (overlapping)
module seq_moore_1011 (
input wire clk,
input wire rst, // synchronous, active-high
input wire din, // serial input, one bit per clock
output wire detected // pulses high while FSM sits in ACCEPT
);
localparam [2:0] S0 = 3'd0, // matched ""
S1 = 3'd1, // matched "1"
S2 = 3'd2, // matched "10"
S3 = 3'd3, // matched "101"
S4 = 3'd4; // matched "1011" (accept)
reg [2:0] state, nxt;
// Next-state logic (combinational)
always @(*) begin
case (state)
S0: nxt = din ? S1 : S0;
S1: nxt = din ? S1 : S2;
S2: nxt = din ? S3 : S0;
S3: nxt = din ? S4 : S2;
S4: nxt = din ? S1 : S2; // overlap: reuse trailing '1'
default: nxt = S0;
endcase
end
// State register (sequential)
always @(posedge clk) begin
if (rst) state <= S0;
else state <= nxt;
end
// Moore output depends on state only
assign detected = (state == S4);
endmodule
// -------- testbench (feeds a serial bit stream) --------
module tb_moore;
reg clk, rst, din;
wire detected;
integer i, hits;
// Stream sent MSB-first: 1 0 1 1 0 1 1 (plus flush zeros)
// Overlapping 1011 appears at bit 4 and again at bit 7.
localparam STREAM_LEN = 10;
reg [0:STREAM_LEN-1] stream = 10'b1011011000;
seq_moore_1011 dut (.clk(clk), .rst(rst), .din(din), .detected(detected));
initial clk = 1'b0;
always #5 clk = ~clk;
initial begin
rst = 1'b1; din = 1'b0; hits = 0;
@(negedge clk); @(negedge clk);
rst = 1'b0;
$display("time | bit | state | detected");
for (i = 0; i < STREAM_LEN; i = i + 1) begin
din = stream[i];
@(negedge clk); // state has settled after the posedge
$display("%4t | %b | %0d | %b", $time, din, dut.state, detected);
if (detected) begin
hits = hits + 1;
$display(" --> 1011 DETECTED (Moore, overlapping)");
end
end
$display("Total detections = %0d (expected 2)", hits);
$finish;
end
endmoduletime | bit | state | detected
30 | 1 | 1 | 0
40 | 0 | 2 | 0
50 | 1 | 3 | 0
60 | 1 | 4 | 1
--> 1011 DETECTED (Moore, overlapping)
70 | 0 | 2 | 0
80 | 1 | 3 | 0
90 | 1 | 4 | 1
--> 1011 DETECTED (Moore, overlapping)
100 | 0 | 2 | 0
110 | 0 | 0 | 0
120 | 0 | 0 | 0
Total detections = 2 (expected 2)
/var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmpgmkxxux0/seq_moore_1011.v:69: $finish called at 120 (1s)Compile and run it with iverilog -g2005 -o sim seq_moore_1011.v && vvp sim. The log prints the state after each bit. You will see detected go high twice, once after the fourth bit and again after the seventh, confirming the overlapping behaviour on 1011011.
Mealy FSM: overlapping 1011 detector
The Mealy version needs only four states (S0–S3) because detection happens on a transition rather than in a dedicated accept state. While the machine sits in S3 (meaning 101 has been matched) and din is 1, detected is asserted combinationally in that same cycle, and the next state becomes S1 to reuse the trailing 1. Fewer states usually means less logic, and the result arrives one clock earlier than Moore — useful when latency matters.
// seq_mealy_1011.v -- Mealy FSM, detects "1011" (overlapping)
module seq_mealy_1011 (
input wire clk,
input wire rst, // synchronous, active-high
input wire din, // serial input, one bit per clock
output reg detected // asserted on the detecting transition
);
localparam [1:0] S0 = 2'd0, // matched ""
S1 = 2'd1, // matched "1"
S2 = 2'd2, // matched "10"
S3 = 2'd3; // matched "101"
reg [1:0] state, nxt;
// Next-state + Mealy output (combinational)
always @(*) begin
nxt = state;
detected = 1'b0;
case (state)
S0: nxt = din ? S1 : S0;
S1: nxt = din ? S1 : S2;
S2: nxt = din ? S3 : S0;
S3: begin
if (din) begin
detected = 1'b1; // 101 + 1 => 1011 seen
nxt = S1; // overlap: trailing '1' starts next
end else begin
nxt = S2; // 101 + 0 => suffix "10"
end
end
default: nxt = S0;
endcase
end
// State register (sequential)
always @(posedge clk) begin
if (rst) state <= S0;
else state <= nxt;
end
endmodule
// -------- testbench (feeds a serial bit stream) --------
module tb_mealy;
reg clk, rst, din;
wire detected;
integer i, hits;
// Same stream as the Moore demo: 1 0 1 1 0 1 1 (plus flush zeros)
localparam STREAM_LEN = 10;
reg [0:STREAM_LEN-1] stream = 10'b1011011000;
seq_mealy_1011 dut (.clk(clk), .rst(rst), .din(din), .detected(detected));
initial clk = 1'b0;
always #5 clk = ~clk;
initial begin
rst = 1'b1; din = 1'b0; hits = 0;
@(negedge clk); @(negedge clk);
rst = 1'b0;
$display("time | bit | state | detected");
for (i = 0; i < STREAM_LEN; i = i + 1) begin
din = stream[i];
#1; // let Mealy output settle on the current bit
$display("%4t | %b | %0d | %b", $time, din, dut.state, detected);
if (detected) begin
hits = hits + 1;
$display(" --> 1011 DETECTED (Mealy, overlapping)");
end
@(negedge clk);
end
$display("Total detections = %0d (expected 2)", hits);
$finish;
end
endmoduletime | bit | state | detected
21 | 1 | 0 | 0
31 | 0 | 1 | 0
41 | 1 | 2 | 0
51 | 1 | 3 | 1
--> 1011 DETECTED (Mealy, overlapping)
61 | 0 | 1 | 0
71 | 1 | 2 | 0
81 | 1 | 3 | 1
--> 1011 DETECTED (Mealy, overlapping)
91 | 0 | 1 | 0
101 | 0 | 2 | 0
111 | 0 | 0 | 0
Total detections = 2 (expected 2)
/var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmpxcd1v_2a/seq_mealy_1011.v:73: $finish called at 120 (1s)Notice in the log that detected pulses while the final 1 is still being presented (state shows 3 at that instant), a full cycle ahead of the Moore design. The trade-off: a Mealy output can glitch if din is noisy, because it follows the input directly within the cycle.
Non-overlapping 1011 detector
To turn off overlap, change exactly one transition. In the accept state S4, instead of reusing the trailing 1, restart the search as if from the beginning. Everything else is identical. This version is a Moore machine so you can compare it directly against the first listing on the same input.
// seq_moore_1011_novlp.v -- Moore FSM, detects "1011" (NON-overlapping)
// After a hit the machine restarts the search from scratch (no reuse of '1').
module seq_moore_1011_novlp (
input wire clk,
input wire rst,
input wire din,
output wire detected
);
localparam [2:0] S0 = 3'd0, // matched ""
S1 = 3'd1, // matched "1"
S2 = 3'd2, // matched "10"
S3 = 3'd3, // matched "101"
S4 = 3'd4; // matched "1011" (accept, then restart)
reg [2:0] state, nxt;
always @(*) begin
case (state)
S0: nxt = din ? S1 : S0;
S1: nxt = din ? S1 : S2;
S2: nxt = din ? S3 : S0;
S3: nxt = din ? S4 : S2;
S4: nxt = din ? S1 : S0; // NO overlap: behave like a fresh S0
default: nxt = S0;
endcase
end
always @(posedge clk) begin
if (rst) state <= S0;
else state <= nxt;
end
assign detected = (state == S4);
endmodule
// -------- testbench (feeds a serial bit stream) --------
module tb_novlp;
reg clk, rst, din;
wire detected;
integer i, hits;
// Same stream 1 0 1 1 0 1 1 : with overlap you get 2 hits,
// without overlap only the first 1011 (bit 4) counts.
localparam STREAM_LEN = 10;
reg [0:STREAM_LEN-1] stream = 10'b1011011000;
seq_moore_1011_novlp dut (.clk(clk), .rst(rst), .din(din), .detected(detected));
initial clk = 1'b0;
always #5 clk = ~clk;
initial begin
rst = 1'b1; din = 1'b0; hits = 0;
@(negedge clk); @(negedge clk);
rst = 1'b0;
$display("time | bit | state | detected");
for (i = 0; i < STREAM_LEN; i = i + 1) begin
din = stream[i];
@(negedge clk);
$display("%4t | %b | %0d | %b", $time, din, dut.state, detected);
if (detected) begin
hits = hits + 1;
$display(" --> 1011 DETECTED (non-overlapping)");
end
end
$display("Total detections = %0d (expected 1)", hits);
$finish;
end
endmoduletime | bit | state | detected
30 | 1 | 1 | 0
40 | 0 | 2 | 0
50 | 1 | 3 | 0
60 | 1 | 4 | 1
--> 1011 DETECTED (non-overlapping)
70 | 0 | 0 | 0
80 | 1 | 1 | 0
90 | 1 | 1 | 0
100 | 0 | 2 | 0
110 | 0 | 0 | 0
120 | 0 | 0 | 0
Total detections = 1 (expected 1)
/var/folders/l0/gs5hnkm56g54bmxg32r6nnwr0000gn/T/tmp37_qu6fb/seq_moore_1011_novlp.v:67: $finish called at 120 (1s)Feeding the same 1011011, the overlapping Moore detector found two matches but this one finds only a single match at bit 4, because the 1 that would have seeded the second match is thrown away. The table sums up the contrast:
| Behaviour on stream 1011011 | Overlapping | Non-overlapping |
|---|---|---|
| Matches reported | 2 | 1 |
| Accept state (S4) exit on din = 1 | S1 (reuse trailing 1) | S1 (fresh search) |
| Accept state (S4) exit on din = 0 | S2 (keep “10”) | S0 (discard) |
Common mistakes
- Blocking assignment in the state register. The state flip-flop must use non-blocking (
<=) inside the clocked block. Mixing blocking and non-blocking there causes simulation races and sim-versus-synthesis mismatches. - Wrong fallback transition. After
101a0should return to S2, because the recent bits still end in10. Dropping to S0 here silently misses any match that could reuse that10. - Thinking overlap changes the whole machine. Overlap is decided entirely by where the accept state goes next; the first four transitions are identical in both modes.
- Comparing Mealy and Moore at the same instant. They are meant to differ by one clock — that is the definition, not a bug.
- Forgetting reset. Without a reset (or an initial value) the state starts as X in simulation and the FSM never leaves the unknown region.
- Accidental latches. Always give the combinational next-state block a default assignment or a
default:case arm so every branch assignsnxt.
Quick check
Why does an overlapping detector report two matches in 1011011 but a non-overlapping one reports only one?
The trailing 1 of the first 1011 is reused as the leading 1 of the next pattern. Overlapping mode keeps that context (the accept state falls back to S2 on a 0), so the second 1011 completes. Non-overlapping mode clears the context and restarts from S0, so the second match never forms.
How many states does the Moore 1011 detector need, and how many does the Mealy version need?
Moore needs five (S0–S4, including a dedicated accept state) because its output depends only on the state. Mealy needs four (S0–S3) because detection is signalled on the transition out of S3 rather than by entering a separate state.
Why does the Mealy output appear one clock earlier than the Moore output?
Moore’s detected is a function of the registered state, so it is valid the cycle after the final bit is clocked in. Mealy’s detected is combinational on the current state and current din, so it is valid during the cycle the final bit is presented.
In the next-state logic, why must a 0 received in state S3 (after 101) go to S2 rather than S0?
After 101 a 0 makes the recent history end in 1010, whose longest suffix that is also a prefix of 1011 is 10. That corresponds to S2, so jumping to S0 would throw away a valid partial match.
Share your question in comments or talk to our mentor team for batch guidance.
Open this design in the free in-browser simulator — edit, compile and see the waveform/log instantly.
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