CodiodeCodiode
Home
Problem Solving
Skill Tracks
My Assignments
Contests
Leaderboard
Community
Settings
Codiode/Problems/FSM Design

State Machine Factoring

HardVerilog / SystemVerilogBuild

High-performance memory controllers often manage complex protocols with dozens of states. Implementing a single unified Finite State Machine (FSM) for both command issuing and data bursting creates massive combinational logic cones and routing congestion. Factoring the design into a Master FSM for command handshaking and a Slave FSM for datapath bursting significantly reduces total area and improves timing closure.

The module solution coordinates read and write commands with a memory interface. The Master FSM waits for a valid command, captures the read or write type, issues a request to memory, and waits for an acknowledgment. Once acknowledged, the Master FSM delegates the data transfer to the Slave FSM and waits for it to complete. The Slave FSM manages a 4-beat data burst, driving an active flag and a 2-bit counter. By exposing the state registers of both FSMs as outputs, the factored architecture is strictly enforced.

Timing and Reset Rules: • Clock edge: posedge clk • Reset: rst_n is an asynchronous, active-low reset. • Reset values: master_state goes to 0 (IDLE), slave_state goes to 0 (IDLE), burst_cnt goes to 0, and the internal captured cmd_rw register goes to 0. All combinational outputs evaluate accordingly. • Master FSM Transitions: - 2'b00 (IDLE): If cmd_valid is 1, captures cmd_rw internally and transitions to WAIT_ACK. - 2'b01 (WAIT_ACK): If mem_ack is 1, transitions to WAIT_DP. - 2'b10 (WAIT_DP): Waits for the Slave FSM to complete. When burst_cnt reaches 3, transitions to IDLE. • Slave FSM Transitions: - 1'b0 (IDLE): When the Master FSM transitions from WAIT_ACK to WAIT_DP (i.e., Master is in WAIT_ACK and mem_ack is 1), the Slave FSM simultaneously transitions to BURST. - 1'b1 (BURST): burst_cnt increments by 1 each clock cycle. When burst_cnt is 3, transitions to IDLE.

Worked Trace (Single Read Command): • Cycle 1: rst_n=0 → master_state=0, slave_state=0, cmd_ready=1. • Cycle 2: rst_n=1, cmd_valid=1, cmd_rw=0 → Master captures cmd_rw. • Cycle 3: cmd_valid=0, mem_ack=1 → master_state=1 (WAIT_ACK), mem_req=1, mem_rw=0. • Cycle 4: mem_ack=0 → master_state=2 (WAIT_DP), slave_state=1 (BURST), burst_cnt=0, dp_active=1. • Cycle 5: Inputs held → master_state=2, slave_state=1, burst_cnt=1, dp_active=1. • Cycle 6: Inputs held → master_state=2, slave_state=1, burst_cnt=2, dp_active=1. • Cycle 7: Inputs held → master_state=2, slave_state=1, burst_cnt=3, dp_active=1. • Cycle 8: Inputs held → master_state=0 (IDLE), slave_state=0 (IDLE), cmd_ready=1, dp_active=0.

FSM Architecture:

flowchart LR
    subgraph Master FSM
    M_IDLE((00: IDLE)) -->|cmd_valid=1| M_WAIT_ACK((01: WAIT_ACK))
    M_IDLE -->|cmd_valid=0| M_IDLE
    M_WAIT_ACK -->|mem_ack=1| M_WAIT_DP((10: WAIT_DP))
    M_WAIT_ACK -->|mem_ack=0| M_WAIT_ACK
    M_WAIT_DP -->|burst_cnt=3| M_IDLE
    M_WAIT_DP -->|burst_cnt!=3| M_WAIT_DP
    end
    subgraph Slave FSM
    S_IDLE((0: IDLE)) -->|Master enters WAIT_DP| S_BURST((1: BURST))
    S_IDLE -->|Otherwise| S_IDLE
    S_BURST -->|burst_cnt=3| S_IDLE
    S_BURST -->|burst_cnt!=3| S_BURST
    end

Cycle-by-cycle Waveform:

{ "signal": [
  { "name": "clk", "wave": "p......." },
  { "name": "rst_n", "wave": "01......" },
  { "name": "cmd_valid", "wave": "010....." },
  { "name": "mem_ack", "wave": "0.10...." },
  { "name": "master_state", "wave": "22222222", "data": ["0", "0", "1", "2", "2", "2", "2", "0"] },
  { "name": "slave_state", "wave": "22222222", "data": ["0", "0", "0", "1", "1", "1", "1", "0"] },
  { "name": "burst_cnt", "wave": "22222222", "data": ["0", "0", "0", "0", "1", "2", "3", "0"] }
], "head": { "text": "Cycle-by-cycle trace of a complete command and 4-beat burst." } }

| Signal | Direction | Width | Description | |---|---|---|---| | clk | input | 1 | Positive-edge triggered clock | | rst_n | input | 1 | Asynchronous active-low reset; all registers go to 0 | | cmd_valid | input | 1 | Indicates a new command is available | | cmd_rw | input | 1 | Command type: 0 for Read, 1 for Write | | mem_ack | input | 1 | Memory acknowledges the request | | cmd_ready | output | 1 | High when Master FSM is in IDLE (0) | | mem_req | output | 1 | High when Master FSM is in WAIT_ACK (1) | | mem_rw | output | 1 | Captured cmd_rw value; 0 when Master is in IDLE | | dp_active | output | 1 | High when Slave FSM is in BURST (1) | | burst_cnt | output | 2 | 0 to 3 counter active during BURST | | master_state | output | 2 | Master FSM state: 0=IDLE, 1=WAIT_ACK, 2=WAIT_DP | | slave_state | output | 1 | Slave FSM state: 0=IDLE, 1=BURST |

Constraints

  • The design must strictly implement the two separate FSM state variables as defined in the port list.
  • cmd_rw must be captured into an internal register only when cmd_valid is asserted while the Master FSM is in IDLE.
  • The Slave FSM and Master FSM must transition simultaneously when handing off execution (i.e., Master enters WAIT_DP on the exact same clock edge that Slave enters BURST).
  • All outputs except the state registers, burst_cnt, and the captured cmd_rw must be combinational logic based on the current state.

Topics

FSMMaster-SlaveControl LogicSynthesis Intuition

Solve this problem

Write the module in Verilog, SystemVerilog or VHDL. Your submission is compiled and simulated against a real testbench — you get the waveform back, not a stored answer.

This problem is part of Codiode Pro. The statement above is free to read.

Sign in to solveSee what Pro unlocks

The circuit builder and code editor need a desktop screen. On a phone, read the problem here and open it on a laptop to solve.

Related problems

  • Glitch Free Gray Code FSMHard
  • Serial Adder Mealy MachineMedium
  • Three Process Moore FSM TemplateEasy
  • Lookahead FSM Sequence DetectorHard
  • Traffic Light Controller with TimerMedium
  • Arbiter FSM with Fixed PriorityHard
  • One Hot Encoding Flip Flop CountMedium
  • Typedef Enum State MachineEasy

Browse all problems · Learning tracks