Three-block FSM coding style in Verilog - Time & Space Complexity
We want to understand how the time it takes for a three-block FSM to run changes as the input size grows.
Specifically, we ask: how does the number of steps grow when the FSM processes more inputs?
Analyze the time complexity of the following code snippet.
module fsm_three_block(
input clk, reset, input_signal,
output reg out_signal
);
reg [1:0] state, next_state;
// State register block
always @(posedge clk or posedge reset) begin
if (reset) state <= 2'b00;
else state <= next_state;
end
// Next state logic block
always @(*) begin
case(state)
2'b00: next_state = input_signal ? 2'b01 : 2'b00;
2'b01: next_state = input_signal ? 2'b10 : 2'b00;
2'b10: next_state = 2'b00;
default: next_state = 2'b00;
endcase
end
// Output logic block
always @(*) begin
out_signal = (state == 2'b10);
end
endmodule
This code implements a simple three-block FSM: one block for state updates, one for next state logic, and one for output logic.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The FSM updates its state on every clock cycle.
- How many times: Once per clock cycle, repeating indefinitely as inputs arrive.
The FSM processes one input per clock cycle, updating state and output accordingly.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 state updates and logic evaluations |
| 100 | 100 state updates and logic evaluations |
| 1000 | 1000 state updates and logic evaluations |
Pattern observation: The number of operations grows directly with the number of inputs processed.
Time Complexity: O(n)
This means the time to process inputs grows linearly with the number of inputs.
[X] Wrong: "The FSM runs all states at once, so time grows exponentially with input size."
[OK] Correct: The FSM moves through states one step at a time per clock cycle, so time grows only as inputs increase, not exponentially.
Understanding how FSMs process inputs step-by-step helps you explain timing and performance in hardware design clearly and confidently.
"What if the FSM had nested loops inside the next state logic? How would the time complexity change?"
Practice
Solution
Step 1: Understand the role of each FSM block
The three-block FSM style divides the design into state storage, next state logic, and output logic.Step 2: Identify the block that stores the current state
The state register block usesalways_ffto store the current state in flip-flops.Final Answer:
The state register block using always_ff -> Option CQuick Check:
State storage = always_ff block [OK]
- Confusing next state logic with state storage
- Thinking output logic stores state
- Mixing combinational and sequential blocks
Solution
Step 1: Identify the block type for next state logic
Next state logic is combinational and should usealways_combfor clean synthesis and readability.Step 2: Match the syntax with the correct block
always_comb begin next_state = ... end usesalways_combwith next_state assignment, which is correct for next state logic.Final Answer:
always_comb begin next_state = ... end -> Option AQuick Check:
Next state logic = always_comb block [OK]
- Using always_ff for next state logic
- Mixing sensitivity lists manually
- Assigning state in next state block
state after the rising edge of clk if reset is 0 and current state is 2?typedef enum logic [1:0] {S0=0, S1=1, S2=2} state_t;
state_t state, next_state;
// State register
always_ff @(posedge clk or posedge reset) begin
if (reset) state <= S0;
else state <= next_state;
end
// Next state logic
always_comb begin
case(state)
S0: next_state = S1;
S1: next_state = S2;
S2: next_state = S0;
default: next_state = S0;
endcase
end
// Output logic (not shown)Solution
Step 1: Analyze current state and next state logic
Current state is S2 (2). According to next state logic, from S2 next_state = S0.Step 2: Determine state after clock edge with reset=0
Since reset=0, state updates to next_state, which is S0 (0).Final Answer:
S0 (0) -> Option AQuick Check:
From S2, next_state = S0, so state = S0 after clk [OK]
- Confusing current and next state
- Ignoring reset condition
- Assuming state stays the same
always_ff @(posedge clk or posedge reset) begin
if (reset) state <= S0;
else state = next_state;
end
always_comb begin
case(state)
S0: next_state = S1;
S1: next_state = S0;
default: next_state = S0;
endcase
endSolution
Step 1: Check assignments in always_ff block
In sequential blocks (always_ff), non-blocking assignment (<=) must be used to avoid race conditions.Step 2: Identify the incorrect assignment
The linestate = next_state;uses blocking assignment (=), which is incorrect here.Final Answer:
Using blocking assignment (=) instead of non-blocking (<=) in always_ff block -> Option BQuick Check:
always_ff requires <= for state updates [OK]
- Using = instead of <= in sequential blocks
- Forgetting reset condition
- Incorrect sensitivity list in always_comb
flag which is high only when the FSM is in state S2. Which block should you put the flag assignment in, and what is the correct style?Solution
Step 1: Identify where output signals are assigned in three-block FSM
Output signals based on current state are assigned in the output logic block, which is combinational and usesalways_comb.Step 2: Write the correct assignment for flag
Assignflag = (state == S2);inside the output logic block to reflect current state.Final Answer:
In the output logic block using always_comb, assign flag = (state == S2); -> Option DQuick Check:
Output logic uses always_comb with flag = (state == S2) [OK]
- Assigning outputs in always_ff block
- Using next_state instead of state for outputs
- Ignoring combinational output logic block
Ready to prove it?
Pass the test and this pattern moves unknown
