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
    • Pulse Synchronizers
    • Handshake Protocols Across Domains
    • Async FIFO CDC
    • CDC Protocol Verification
      • Assertions for Protocols
      • Formal Protocol Checks
      • Coverage and Stress
      • Metastability-Aware Simulation
  • Reconvergence and Gray Coding16
  • 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

‹CDC Protocol Verification
  1. Topics
  2. CDC & RDC
  3. CDC Protocols and Handshakes
  4. CDC Protocol Verification
  5. Metastability-Aware Simulation

Part 3 · CDC Protocols and Handshakes · All levels

Metastability-Aware Simulation

Injecting random old/new resolutions in the capture window, and what the result does and does not prove.

On this page

    Why it matters

    Ordinary simulation resolves every setup-hold race deterministically: the flop takes the old or the new value according to simulator event order, always the same way for the same stimulus. Real silicon resolves late and unpredictably. A metastability-aware model replaces the deterministic outcome with a random old-or-new choice whenever data changes inside a window around the clock edge, so the testbench exercises both resolutions across many runs.

    The injection technique

    The model keeps a copy of data delayed by the modelled setup window (1 ns). If the live data differs from that copy at the clock edge, the change fell inside the window and the output resolves pseudo-randomly to the old or the new value; otherwise it captures exactly. The randomness comes from a fixed-seed LFSR that advances only on window hits, so the run is fully reproducible. The listing below is a compact runnable demonstration: exact capture outside the window, and a reproducible mix of old and new resolutions inside it:

    inject_ff.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    `timescale 1ns/1ps
    
    // Compact metastability-injection flop: window hits resolve to old or new
    // from a fixed-seed LFSR, clean captures stay exact. The window is detected
    // with a delayed copy of d (no $realtime bookkeeping), and the seed makes
    // the run bit-identical on every supported engine. The full design-side
    // model with hold-window handling is built in the RTL synchroniser lessons.
    module inject_ff (
      input logic clk, d, output logic q
    );
      wire d_old;                       // d as it was 1 ns ago (the setup window)
      assign #1.0 d_old = d;
      logic [15:0] lfsr = 16'hACE1;     // fixed seed: reproducible resolutions
      initial q = 1'b0;
      always @(posedge clk) begin
        if (d_old !== d) begin           // changed inside the window: inject
          lfsr <= {lfsr[14:0], lfsr[15] ^ lfsr[13] ^ lfsr[12] ^ lfsr[10]};
          q <= lfsr[0] ? d : q;         // take the new value or keep the old one
        end
        else q <= d;                    // clean capture: exact
      end
    endmodule
    
    module tb_inject;
      logic clk = 0, d = 0, q;
      inject_ff dut (.clk, .d, .q);
      always #5 clk = ~clk;                            // edges at 5, 15, 25, ...
      int ones = 0, zeros = 0, safe_errors = 0;
      initial begin
        repeat (100) begin                             // clean changes: exact
          @(negedge clk); d = ~d;
          @(posedge clk); #1;
          if (q !== d) safe_errors++;
        end
        repeat (400) begin                             // window hits: mixed
          @(negedge clk); #4.5 d = ~d;                 // 0.5 ns before the edge
          @(posedge clk); #1;
          if (q === d) ones++; else zeros++;
        end
        $display("safe errors %0d, window: new %0d old %0d", safe_errors, ones, zeros);
        if (safe_errors == 0 && ones > 50 && zeros > 50)
          $display("PASS: exact outside the window, mixed old/new inside it");
        else $display("FAIL");
        $finish;
      end
    endmodule

    The run prints safe errors 0, window: new 267 old 133 on both supported engines: zero wrong values outside the window, and a genuine mix of 267 new-value and 133 old-value resolutions across the 400 window hits.

    What the result proves, and what it does not

    The run shows

    It proves

    It does not prove

    Correct behaviour across many random resolutions

    The protocol tolerates either resolution of any single crossing

    Anything about resolution time or failure rates

    A mutation (e.g. binary pointers) failing

    The testbench is sensitive to the CDC structure

    That all structures present are correct

    Clean behaviour with the injection disabled

    Functional correctness of the logic

    CDC safety at all

    Injection is a complement to structural checks and formal proof, not a substitute: it exercises resolutions, not timing, and it says nothing about mean time between failures. Use it to shake out protocol bugs that only appear under one resolution, and cite the structural classification for the metastability argument itself.

    Common mistakes

    Common pitfall

    Claiming a simulator reproduces real metastability. It does not: the model resolves within the cycle to a clean value, while real metastability resolves late. The model tests protocol tolerance to either outcome, which is valuable but different.

    Check yourself An injection run passes 10,000 randomised crossings with zero errors. Can the design still fail in silicon?

    Yes, if the structure is wrong in a way random resolutions do not expose (for example a torn bus that usually resolves consistently), or if the real failure rate exceeds the budget. Injection complements structural signoff; it never replaces it.

    Related topics

    • Coverage and stress

    • RTL: Metastability and Synchronisation

    • RTL: CDC verification

    Previous

    46 / 179

    Next: Reconvergence and Gray Coding

    Up next

    Up nextReconvergence and Gray Coding

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Assertions for Protocols
    • Formal Protocol Checks