Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • RTL Foundations36
  • Combinational Design25
  • Sequential Design27
  • FSM & Control27
    • Controller and Datapath
      • Split Design: Intent First
      • Signal Contract Between FSM and Datapath
      • Two-Process FSM Style
      • Coding Rules That Prevent Latent Bugs
      • Worked Example: GCD
      • FSM Bug Stories
    • Moore vs Mealy
    • State Encoding
    • Multi-Cycle Sequencers
    • UART Transmitter
    • Memory Controller
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Controller and Datapath
  1. Topics
  2. RTL Design
  3. FSM & Control
  4. Controller and Datapath
  5. Two-Process FSM Style

Part 4 · FSM & Control · Intermediate

Two-Process FSM Style

State register in one clocked process, next state and outputs in another.

On this page

    Why this matters

    With one clocked process and one combinational process, defaults at the top mean every path assigns every signal, so no latch appears. Review also shrinks to one table.

    After this lesson you can: write an FSM in the two-process style and compare it with the alternative styles.

    The template

    The structure separates memory from decisions. One process holds the state register, and another decides the next state and outputs.

    Process

    Type

    Job

    State register

    always_ff @(posedge clk or negedge rst_n)

    state <= next and nothing else

    Next-state + outputs

    always_comb

    Decide next and every output from state and inputs

    Flow diagram. Inputs start, a_eq_b and a_gt_b enter the always_comb block. It sends next down to the always_ff state register, which sends state back up to the always_comb block. The always_comb block also drives the outputs load, sub_a, sub_b and done.
    The two processes form one loop: the combinational block turns state and inputs into next and the outputs, and the clocked block turns next into state at each edge

    Follow the loop once per clock: state goes up into the decision block, next comes back down, and the edge copies it into state.

    • The only storage is the state register. Everything the combinational block produces is recomputed from state and the inputs every cycle.

    • Outputs leave from the combinational block, so they change as soon as state changes after an edge.

    • The code below is this picture: the always_ff box is the three-line clocked process, and the always_comb box is the case statement.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // snippet
    typedef enum logic [1:0] {IDLE, RUN, DONE} state_t;
    state_t state, next;
    
    always_ff @(posedge clk or negedge rst_n)
      if (!rst_n) state <= IDLE;
      else        state <= next;
    
    always_comb begin
      // 1. defaults: every output and 'next' gets a value at the top
      next = state;  load = 1'b0;  sub_a = 1'b0;  sub_b = 1'b0;  done = 1'b0;
      // 2. then override per state
      unique case (state)
        IDLE: if (start) begin load = 1'b1; next = RUN; end
        RUN:  if (a_eq_b) next = DONE; else if (a_gt_b) sub_a = 1'b1; else sub_b = 1'b1;
        DONE: begin done = 1'b1; next = IDLE; end
        default: next = IDLE;
      endcase
    end

    Tip

    Name the enum values after what the machine is doing (RUN, WAIT_ACK), not after numbers (S0, S1). The names appear in waveforms and in the synthesis report, so good names save debugging time.

    Why this style

    • No latches: defaults at the top mean every path assigns every signal.

    • Clear reading: the table “in state S, with inputs I, set outputs O and go to N” is the code.

    • Easy to change: adding a state touches the enum and one case branch.

    • Easy to review: the clocked block has only one assignment, so reset and clocking cannot hide a bug.

    Alternatives

    Style

    Verdict

    One process (state and outputs in one always_ff)

    Registers assigned outputs; latency depends on whether expressions describe the current or following transition and when the consumer samples

    Three processes (state, next, outputs separately)

    Separate decode can clarify ownership and review; keep defaults and state/output contracts consistent

    assign with nested ?:

    Unreadable for more than two states

    Common mistakes

    Common pitfall

    Prefer always_comb for explicit combinational intent and its writer/sensitivity rules. Enable and review lint/synthesis assignment checks: neither always_comb nor a clean compile alone proves that every path assigns every output.

    Two processes are this course's preferred template, not a latency rule. A clocked done <= (next == DONE) and a combinational done = (state == DONE) can both assert after the edge entering DONE; clocking done <= (state == DONE) instead delays that indication. Specify the observation edge before comparing styles.

    Check yourself In this template, what belongs inside the clocked state-register process?

    state <= next, plus reset state <= IDLE. Other correct templates may also register outputs or controller bookkeeping; process count alone does not set their latency.

    Remember

    • The clocked process holds state <= next with reset; the combinational process decides next state and outputs.

    • Name states after what the machine does, not S0 and S1.

    • Specify the observation edge before comparing the latency of two styles.

    Keep going

    • Practice: How state transitions are handled in Verilog FSMs

    • Interview: run a mock interview on this topic

    Related topics

    • Coding rules

    Previous

    91 / 350

    Next: Coding Rules That Prevent Latent Bugs

    Up next

    Up nextCoding Rules That Prevent Latent Bugs

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Split Design: Intent First
    • Worked Example: GCD
    • FSM Bug Stories