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.

StateMatched prefixdin = 0din = 1
S0emptyS0S1
S11S2S1
S210S0S3
S3101S2S4 (detect)
S41011S2S1

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
endmodule
time | 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
endmodule
time | 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
endmodule
time | 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 1011011OverlappingNon-overlapping
Matches reported21
Accept state (S4) exit on din = 1S1 (reuse trailing 1)S1 (fresh search)
Accept state (S4) exit on din = 0S2 (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 101 a 0 should return to S2, because the recent bits still end in 10. Dropping to S0 here silently misses any match that could reuse that 10.
  • 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 assigns nxt.

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.

Have questions about this topic?
Share your question in comments or talk to our mentor team for batch guidance.
▶ Try it in the ChipXpert Lab

Open this design in the free in-browser simulator — edit, compile and see the waveform/log instantly.

Run it in the Lab

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
Next batch starts 18th November 2026
Start your VLSI career with ChipXpert

Live online and classroom batches in Hyderabad & Bengaluru. Fill in your details and a counsellor will call you back.

  • Real EDA tools in your browser: industry-standard EDAReal EDA tools in your browser
  • Recorded sessions on the elearn portalRecorded sessions
  • Placement assistance: resume, mock interviewsPlacement assistance
  • Merit scholarship up to 60% · EMI optionsScholarship up to 60%
Hi! Ask me about courses, fees, batches or discounts. ×
BENGALURU
HYDERABAD