State Machine Factoring
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
endCycle-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_rwmust be captured into an internal register only whencmd_validis asserted while the Master FSM is inIDLE.- The Slave FSM and Master FSM must transition simultaneously when handing off execution (i.e., Master enters
WAIT_DPon the exact same clock edge that Slave entersBURST). - All outputs except the state registers,
burst_cnt, and the capturedcmd_rwmust be combinational logic based on the current state.
Topics
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.
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.