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

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
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. Coding Rules That Prevent Latent Bugs
On this page

    Part 4 of 9, lesson 4 of 27Part 4 of 9/FSM & Control/Lesson 4 of 27Intermediate

    Coding Rules That Prevent Latent Bugs

    Five FSM coding rules that prevent latches and hidden state.

    A path that leaves next or an output unassigned infers a latch, and an unused state encoding can trap the machine after a bit flip. Five coding rules close both gaps.

    After this lesson you can: apply the five FSM coding rules, find the unassigned paths that infer a latch, and write a recovery default.

    Five rules

    1. Default every output and `next` at the top of the combinational block.

    2. Give the `case` an explicit recovery default for its RTL illegal-state behavior; verify mapped recovery separately when required.

    3. Reset the state register to a known, legal state; reset anything the outputs depend on.

    4. One driver per signal. Never assign the same variable from two processes.

    5. Partition by responsibility. Controller bookkeeping may include counters; GCD operand arithmetic belongs to its datapath.

    Missing defaults infer latches

    Without defaults, some paths leave outputs unassigned. Synthesis then infers a latch, as the faulty module below shows.

    fsm_bad.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // yosys: latch
    module fsm_bad (
      input  logic [1:0] state,
      input  logic       go,
      output logic [1:0] next,
      output logic       busy
    );
      always_comb begin
        case (state)
          2'd0: begin busy = 1'b0; if (go) next = 2'd1; end   // next not assigned when go == 0
          2'd1: begin busy = 1'b1; next = 2'd2; end
          2'd2: begin busy = 1'b1; next = 2'd0; end
        endcase                                                // state 3, and busy/next unassigned there
      end
    endmodule
    Diagram
    ERROR: Latch inferred for signal `\fsm_bad.\next' from always_comb process

    Yosys stops at the first error, so only next is reported; busy has the same problem in state 3.

    fsm_good.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // yosys: ok
    module fsm_good (
      input  logic [1:0] state,
      input  logic       go,
      output logic [1:0] next,
      output logic       busy
    );
      always_comb begin
        next = state;  busy = 1'b0;                            // defaults: every path now assigns both
        case (state)
          2'd0: if (go) next = 2'd1;
          2'd1: begin busy = 1'b1; next = 2'd2; end
          2'd2: begin busy = 1'b1; next = 2'd0; end
          default: next = 2'd0;                                // illegal state: recover
        endcase
      end
    endmodule

    An unintended latch adds hidden storage outside the state register and can violate the intended reset and timing contract. Simulation may correctly model that storage; the problem is the mismatch with combinational design intent, not an inevitable simulation/silicon disagreement. Read lint and synthesis diagnostics.

    Illegal states need a default

    With a 2-bit state and 3 legal values, one encoding is unused. A bit flip or a bad reset can land there.

    The assigned default defines RTL next-state recovery to IDLE. FSM extraction, recoding and unreachable-state optimization can change behavior outside reset-reachable operation; it is not physical fault recovery. See illegal states and recovery for fault models, containment and mapped-state checks.

    Case form

    No explicit item matches

    Overlapping explicit items

    unique case with assigned default

    Executes default; no no-match violation

    Still violates uniqueness

    unique case without default

    No-match violation; synthesis may assume coverage

    Violates uniqueness

    Pre-case assignment, unique case without default

    Assignment defines RTL value but does not suppress no-match violation

    Violates uniqueness

    Adding unique does not turn an explicitly assigned case-default into a don't-care. Omitting the case-default makes a coverage promise to synthesis even if a pre-case assignment keeps simulation deterministic. Diagnose illegal states explicitly when a default is present; do not depend on a no-match warning. See the language foundations and the DVCon paper on SystemVerilog-2009 priority, unique and unique0.

    Common mistakes

    “What causes a latch in an FSM and how do you prevent it?” Unassigned outputs on some path of a combinational block. Give defaults at the top, cover all states, and run lint or synthesis to confirm.

    Check yourself In fsm_bad, name two different paths on which a signal is left unassigned.

    (1) State 0 with go == 0: next is not assigned. (2) State 3 (not covered by the case): both next and busy are not assigned. In state 0, busy is always assigned; only next depends on go.

    • Default every output and next at the top of the combinational block.

    • Give the case a recovery default, and reset the state register to a legal state.

    • One driver per signal; the unique keyword does not make a default a don't-care.

    • Practice: Safe state machine with illegal-state recovery

    • Practice: Incomplete case and unique0: simulation vs synthesis

    • Interview: run a mock interview on this topic

    Related topics

    • Latch inference

    • FSM bug stories

    Previous

    92 / 350

    Next: Worked Example: GCD

    Up next

    Up nextWorked Example: GCD

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Split Design: Intent First
    • Signal Contract Between FSM and Datapath
    • FSM Bug Stories