EN
← Back to Skills
IntermediateRTL Design

FSM Generator

Generate finite state machines in 1/2/3-block architectures, Moore or Mealy. Includes state encoding strategy (binary/Gray/one-hot), unreachable state recovery, and glitch-free output generation.

💡 Copy this Skill description into your AI Agent's system prompt (Cursor, Claude Code, Copilot), then describe your design needs. The Agent will generate code following the rules defined in this Skill. Download the .md file at the bottom of this page.


name: fsm-generator description: > Generate a complete, synthesizable Finite State Machine (FSM) in Verilog/SystemVerilog from a state transition diagram description. Supports Moore, Mealy, 1-block, 2-block, and 3-block architectures. Generates production-quality code with proper state encoding, unreachable state handling, and glitch-free outputs. Encodes rules for choosing between binary, Gray, and one-hot encoding based on target technology and state count. category: rtl-design level: intermediate

Purpose

Generate a complete FSM implementation from a natural language or tabular description of states, transitions, and outputs. The generated FSM must be functionally correct, synthesizable, glitch-free, and follow the chosen architectural pattern consistently.

Input Specification

The user provides:

Required Information

  • States: List of named states with descriptions
  • Transitions: For each state, what inputs cause transitions to which next state
  • Outputs: What outputs are asserted in each state (Moore) or per transition (Mealy)

Optional Information (sensible defaults applied)

  • FSM type: Moore (default) or Mealy
  • Architecture: 1-block, 2-block, or 3-block (default: 3-block)
  • State encoding: binary, Gray, one-hot (default: binary for ASIC, one-hot for FPGA)
  • Reset state: which state to enter on reset (default: first state listed)
  • Safe FSM: whether to add recovery from unreachable states (default: yes)

Output Specification

Generate a complete module containing:

  1. State encoding declaration (localparam for each state with explicit values)
  2. State register (sequential always_ff block with proper reset)
  3. Next-state logic (combinational always_comb block, latch-free)
  4. Output logic (combinational or registered, depending on Moore vs Mealy)
  5. Safety logic if enabled (unreachable state recovery, timeout counter)

Core Design Rules

Rule 1: Architecture Selection

| Architecture | When to Use | Pros | Cons | |-------------|-------------|------|------| | 3-block | Default for all FSMs | Best readability, clean separation, easiest to modify | Slightly more lines of code | | 2-block | Simple FSMs (< 5 states) | Reasonable readability | Output logic mixed with next-state | | 1-block | Never recommend | — | Unreadable, error-prone, hard to modify |

Always default to 3-block. The additional few lines of code are worth the clarity.

Rule 2: State Encoding Strategy

One-hot (FPGA):

systemverilog
localparam IDLE   = 4'b0001;
localparam RUN    = 4'b0010;
localparam DONE   = 4'b0100;
localparam ERROR  = 4'b1000;
  • Pro: Single-bit state check = fast, small combinational logic
  • Con: N states need N flip-flops
  • Use when: FPGA target, or state count ≤ 16 in ASIC

Binary (ASIC, many states):

systemverilog
localparam IDLE   = 2'b00;
localparam RUN    = 2'b01;
localparam DONE   = 2'b10;
localparam ERROR  = 2'b11;
  • Pro: log2(N) flip-flops, area-efficient
  • Con: Wider combinational logic for state decoding
  • Use when: ASIC target, or state count > 16

Gray (low-power, specific transitions):

systemverilog
localparam IDLE   = 2'b00;
localparam RUN    = 2'b01;
localparam DONE   = 2'b11;
localparam ERROR  = 2'b10;
  • Pro: Only 1 bit changes between adjacent states, lower dynamic power
  • Con: Encoding constraints on state ordering
  • Use when: sequential state progression (pipeline stages, counters), power-critical designs

Rule 3: Moore vs Mealy Selection

Moore (default):

  • Output depends ONLY on current state
  • Outputs change one cycle AFTER state change — registered, glitch-free
  • More states may be needed
  • Use for: control signals, status flags, any output going to another synchronous block

Mealy:

  • Output depends on state AND inputs
  • Outputs change IMMEDIATELY with input change — can be glitchy if inputs are not clean
  • Fewer states may be needed
  • Use for: combinational handshake signals (ready, ack), sequence detectors

Rule 4: 3-Block FSM Template

systemverilog
// =============================================================================
// FSM: [name] — [description]
// Type: Moore | Mealy
// Encoding: binary | one-hot | Gray
// Architecture: 3-block
// =============================================================================

// ---- State Encoding ----
localparam [ENCODING] STATE_A = ...;
localparam [ENCODING] STATE_B = ...;
localparam [ENCODING] STATE_C = ...;

logic [ENCODING] state, next_state;

// ---- Block 1: State Register (sequential) ----
always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        state <= STATE_RESET;
    end else begin
        state <= next_state;
    end
end

// ---- Block 2: Next-State Logic (combinational) ----
always_comb begin
    next_state = state;  // DEFAULT: stay in current state
    case (state)
        STATE_A: begin
            if (condition_1)
                next_state = STATE_B;
        end
        STATE_B: begin
            if (condition_2)
                next_state = STATE_C;
            else if (condition_3)
                next_state = STATE_A;
        end
        STATE_C: begin
            // always progresses
            next_state = STATE_A;
        end
        default: begin
            next_state = STATE_RESET;  // recovery from unreachable state
        end
    endcase
end

// ---- Block 3: Output Logic ----
// Moore: combinational or registered, depends only on state
// Mealy: combinational, depends on state + inputs

// For Moore outputs (registered — recommended for glitch-free outputs):
always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        output_signal <= 1'b0;
    end else begin
        output_signal <= 1'b0;  // default
        case (next_state)  // use next_state for one-cycle-earlier assertion
            STATE_C: output_signal <= 1'b1;
            default: ;
        endcase
    end
end

// For Moore outputs (combinational):
always_comb begin
    output_signal = 1'b0;  // default
    case (state)
        STATE_C: output_signal = 1'b1;
        default: ;
    endcase
end

// For Mealy outputs (combinational, state + input):
always_comb begin
    output_signal = 1'b0;  // default
    case (state)
        STATE_B: if (trigger_input) output_signal = 1'b1;
        default: ;
    endcase
end

Rule 5: Unreachable State Handling

Any binary encoding with N flip-flops has 2^N possible states, but only M are defined. The remaining 2^N - M states are unreachable under normal operation but can occur due to SEU (Single Event Upset) or power glitches.

Safe FSM must handle unreachable states:

  1. default branch in case statement → return to reset state
  2. Optionally: add a timeout counter that resets FSM if stuck in any non-IDLE state
  3. Optionally: add one-hot encoding validity checker (assert exactly 1 bit set)
systemverilog
// Timeout-based safety (optional but recommended for safety-critical designs):
logic [TIMEOUT_BITS-1:0] timeout_cnt;

always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        timeout_cnt <= '0;
    end else if (state == IDLE) begin
        timeout_cnt <= '0;
    end else begin
        timeout_cnt <= timeout_cnt + 1'b1;
    end
end

// Force reset if timeout
always_comb begin
    if (timeout_cnt == TIMEOUT_MAX)
        next_state = IDLE;  // override normal next_state logic
end

Rule 6: FSM Output Timing

Understanding when outputs change relative to state changes is critical:

| Output Type | Uses state | Uses next_state | Changes | |------------|-------------|-------------------|---------| | Moore, registered, uses state | Yes | No | 1 cycle AFTER state change | | Moore, registered, uses next_state | No | Yes | SAME cycle as state change | | Moore, combinational, uses state | Yes | No | SAME cycle as state change | | Mealy, combinational | Yes | Yes (inputs too) | IMMEDIATELY with input |

Recommendation: Use Moore + registered outputs with next_state for cleanest timing. This asserts outputs in the same cycle the state transitions, without glitches.

Rule 7: Conditional vs Unconditional Transitions

Always clearly define the priority of transitions from each state:

systemverilog
STATE_A: begin
    // Priority order: top condition checked first
    if (reset_request)           // highest priority
        next_state = IDLE;
    else if (error_detected)
        next_state = ERROR;
    else if (timeout)
        next_state = IDLE;
    else if (start)
        next_state = STATE_B;
    // else: stay in STATE_A (handled by default assignment)
end

Rule 8: FSM Code Generation Checklist

  • [ ] All states have explicit encoding values
  • [ ] Reset state defined (typically IDLE or first state)
  • [ ] Default next_state assignment at top of combinational block (= stay)
  • [ ] Every if has an else (if using if-else instead of case)
  • [ ] Case statement has default branch
  • [ ] All outputs have default values (0 or inactive)
  • [ ] For 3-block: output block is separate from next-state block
  • [ ] For Moore: outputs are registered (recommended) or combinational
  • [ ] For Mealy: outputs are combinational and depend on state + input
  • [ ] No latch inference in any combinational block
  • [ ] Unreachable states handled via default branch
  • [ ] State encoding commented with rationale

Examples

Example 1: 3-Block Moore FSM — Sequence Detector (101)

Input: "Create a Moore FSM that detects the sequence 101 with overlap."

systemverilog
module seq_detector_101 (
    input  logic    clk,
    input  logic    rst_n,
    input  logic    din,
    output logic    detected
);

    // State encoding: binary (4 states)
    localparam IDLE  = 2'b00;  // waiting for first '1'
    localparam S1    = 2'b01;  // got '1'
    localparam S10   = 2'b10;  // got '10'
    localparam S101  = 2'b11;  // got '101' (detected)

    logic [1:0] state, next_state;

    // State register
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) state <= IDLE;
        else        state <= next_state;
    end

    // Next-state logic
    always_comb begin
        next_state = state;
        case (state)
            IDLE:  if (din) next_state = S1;
            S1:    if (din) next_state = S1; else next_state = S10;
            S10:   if (din) next_state = S101; else next_state = IDLE;
            S101:  if (din) next_state = S1; else next_state = S10;
            default: next_state = IDLE;
        endcase
    end

    // Output (registered, uses next_state for same-cycle assertion)
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) detected <= 1'b0;
        else        detected <= (next_state == S101);
    end

endmodule

Example 2: Mealy FSM — AXI Valid/Ready Handshake Controller

Input: "Create a Mealy FSM for AXI-Stream valid/ready handshake control."

systemverilog
module axis_handshake_ctrl (
    input  logic    clk,
    input  logic    rst_n,
    input  logic    s_valid,
    output logic    s_ready,
    input  logic    m_ready,
    output logic    m_valid,
    input  logic    last_beat,
    output logic    transfer_done
);

    localparam IDLE   = 2'b00;
    localparam ACTIVE = 2'b01;
    localparam LAST   = 2'b10;

    logic [1:0] state, next_state;

    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) state <= IDLE;
        else        state <= next_state;
    end

    always_comb begin
        next_state = state;
        case (state)
            IDLE:   if (s_valid && m_ready) begin
                        if (last_beat) next_state = LAST;
                        else           next_state = ACTIVE;
                    end
            ACTIVE: if (s_valid && m_ready) begin
                        if (last_beat) next_state = LAST;
                    end
            LAST:   if (transfer_done) next_state = IDLE;
            default: next_state = IDLE;
        endcase
    end

    // Mealy outputs (combinational)
    always_comb begin
        s_ready       = 1'b1;  // always ready unless in LAST
        m_valid       = 1'b0;
        transfer_done = 1'b0;
        case (state)
            IDLE:   if (s_valid) m_valid = 1'b1;
            ACTIVE: if (s_valid) m_valid = 1'b1;
            LAST: begin
                s_ready       = 1'b0;
                transfer_done = 1'b1;
            end
            default: ;
        endcase
    end

endmodule

Interaction with Other Skills

  • verilog-module: Foundation skill — this FSM module follows all its rules
  • rtl-reviewer: Use after generation to verify FSM correctness
  • testbench-simple: Generate a testbench that drives all state transitions
  • assertion-writer: Generate assertions for FSM properties (state reachability, transition coverage)

Disclaimer

This skill is provided "as is" for reference and educational purposes only. Code generated using this skill should be independently reviewed and verified before use in any production design, tape-out, or safety-critical application. The author(s) and ICHDL assume no liability for any errors, omissions, or damages arising from the use of this skill or any code generated with it.

Usage Rights

You are free to use, modify, and distribute this skill for personal or commercial purposes. Attribution to ICHDL (ichdl.com) is appreciated but not required. Redistribution of this skill in substantially unmodified form must retain this notice.

Download this Skill as .md file

Copy into your AI Agent's system prompt to activate this Skill.