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

  • How to Use This Course
  • Reading Path
  • CDC/RDC Glossary
  • CDC/RDC Metrics Reference
  • CDC/RDC Interview Prep
  • CDC/RDC Signoff Cheatsheet
  • Clock Domains and Failure Modes8
  • Metastability and Synchronizers16
  • CDC Protocols and Handshakes16
  • Reconvergence and Gray Coding16
    • Gray Code Crossing
      • The One-Bit-Change Rule
      • Gray Counters
      • Where Gray Fails
      • Non-Power-of-Two Depths
    • Reconvergence Analysis
    • Multi-bit Crossing Strategies
    • Reconvergence Debug
  • Reset Domain Crossing16
  • Architecture and Design Rules16
  • CDC Signoff Methodology24
  • RDC Signoff16
  • Debug and Case Studies11
  • CDC and RDC Interview Prep30
  • Capstone: Sign Off a Multi-clock Peripheral4
Loading lesson

‹Gray Code Crossing
  1. Topics
  2. CDC & RDC
  3. Reconvergence and Gray Coding
  4. Gray Code Crossing
  5. Where Gray Fails

Part 4 · Reconvergence and Gray Coding · All levels

Where Gray Fails

Jumps, multi-step increments and post-conversion logic that break the single-bit promise, each with a short example.

On this page

    Gray coding is a contract with three clauses: one step at a time, registered Gray, nothing between the register and the synchroniser. Each clause below shows how the contract breaks and what the destination observes instead of old-or-new.

    Jumps: loads and resets to arbitrary values

    A counter that can be loaded, or reset to a nonzero value, changes several Gray bits in one cycle whenever the jump lands on a distant value. The destination then samples a mixture again, exactly the failure Gray was meant to remove.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    // bad-example: a loadable "Gray" counter. Loading 12 (Gray 1010)
    // while the register holds 3 (Gray 0010) flips two bits at once.
    logic [3:0] bin, gray;
    always_ff @(posedge clk_s or negedge rst_n)
      if (!rst_n) begin bin <= '0; gray <= '0; end
      else if (load) begin bin <= load_val; gray <= (load_val >> 1) ^ load_val; end
      else begin bin <= bin + 4'd1; gray <= ((bin + 4'd1) >> 1) ^ (bin + 4'd1); end

    Fix: if the value can jump, do not Gray-cross it. Use a handshake with held data or a FIFO (see multi-bit strategies).

    Multi-step increments between samples

    If the source advances two or more steps per destination sample, each individual sample is still old-or-new of its step, but values are skipped: the destination never observes the intermediate counts. Logic that must see every value, such as an event counter that subtracts successive samples, silently undercounts.

    design.sv
    1
    2
    3
    4
    // bad-example: differencing Gray samples to count events. With two
    // source steps per destination sample, every second event is never observed.
    always_ff @(posedge clk_d)
      if (gray_d != gray_d_q) events <= events + 1'b1;   // counts samples seen, not steps taken

    Fix: count in the source domain and cross the count, or move the data through a FIFO so nothing is skipped.

    Combinational logic after the Gray conversion

    Decoding, comparing, or re-encoding the Gray value between the register and the synchroniser breaks the argument twice: the logic output can glitch during the step, and in the destination domain separately synchronised Gray bits recombined through logic is reconvergence (see reconvergence analysis). Cross the registered Gray value unchanged; decode after the synchroniser.

    design.sv
    1
    2
    3
    4
    // bad-example: comparing before the crossing. The comparator output
    // glitches while the Gray bits settle, and the glitch crosses as a pulse.
    assign almost_full_s = (gray == 4'b0110);   // do not cross this bit instead of the Gray value
    sync2 u_af (.clk(clk_d), .d(almost_full_s), .q(almost_full_d));   // snippet: synchroniser wrapper

    Common pitfall

    All three failures pass casual simulation. Jumps are rare, skips need a fast source against a slow sampler, and glitches need sub-cycle timing the testbench may never hit. The structural checks (no load on the Gray register, registered source, no logic on the path) exist because simulation alone cannot close these.

    Check yourself A Gray counter has a synchronous load used once at startup to set an initial offset, then counts by one forever. Safe?

    Only if the load is never used while the destination is sampling, which must be proven by the reset and startup sequence, not assumed. The safer review position is that any reachable load disqualifies Gray crossing unless the load value is constrained to a one-bit neighbour of the current value.

    Related topics

    • Gray counters

    • Next: non-power-of-two depths

    Previous

    49 / 179

    Next: Non-Power-of-Two Depths

    Up next

    Up nextNon-Power-of-Two Depths

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • The One-Bit-Change Rule