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:
- State encoding declaration (localparam for each state with explicit values)
- State register (sequential always_ff block with proper reset)
- Next-state logic (combinational always_comb block, latch-free)
- Output logic (combinational or registered, depending on Moore vs Mealy)
- 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):
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):
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):
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
// =============================================================================
// 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
endRule 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:
defaultbranch in case statement → return to reset state- Optionally: add a timeout counter that resets FSM if stuck in any non-IDLE state
- Optionally: add one-hot encoding validity checker (assert exactly 1 bit set)
// 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
endRule 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:
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)
endRule 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
ifhas anelse(if using if-else instead of case) - [ ] Case statement has
defaultbranch - [ ] 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."
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
endmoduleExample 2: Mealy FSM — AXI Valid/Ready Handshake Controller
Input: "Create a Mealy FSM for AXI-Stream valid/ready handshake control."
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
endmoduleInteraction with Other Skills
verilog-module: Foundation skill — this FSM module follows all its rulesrtl-reviewer: Use after generation to verify FSM correctnesstestbench-simple: Generate a testbench that drives all state transitionsassertion-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.