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
  • Timing & Clocking39
  • Reset & CDC34
    • Reset Architecture
    • Metastability and Synchronisation
      • What Metastability Means in Practice
      • The Two-Flop Synchroniser
      • When to Use Three Flops
      • CDC Constraints and Implementation Hygiene
      • Do Not Synchronise Buses Bit by Bit
    • Asynchronous FIFO
    • CDC Protocols
    • Reset Domain Crossing
    • CDC Verification
  • Memory & Buses57
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Metastability and Synchronisation
  1. Topics
  2. RTL Design
  3. Reset & CDC
  4. Metastability and Synchronisation
  5. The Two-Flop Synchroniser

Part 6 · Reset & CDC · Intermediate

The Two-Flop Synchroniser

Two destination-clock flops in series, usage rules, and a 20,000-edge simulation test.

On this page

    Why this matters

    One signal crossing between unrelated clocks can change inside the setup-hold window of the first flop. Two flops in series give that first flop a full period to settle before the rest of the design sees the value.

    After this lesson you can: draw the two-flop synchroniser, state the rules for using it, and explain why a pulse shorter than the destination clock needs a toggle or a handshake.

    The circuit

    Two flip-flops in series, both on the destination clock, with nothing between them. The first flop may become metastable; the second samples one edge later. Usable settling time subtracts clock-to-Q, routing and setup overhead and accounts for clock effects. This lowers failure probability without guaranteeing that every event resolves in time.

    sync2_rtl.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // Synthesizable hardware; rst_dst_n is already release-synchronised to clk_dst.
    module sync2_rtl (
      input logic clk_dst, rst_dst_n, async_level,
      output logic sync_level
    );
      (* ASYNC_REG = "TRUE" *) logic stage1, stage2;
      always_ff @(posedge clk_dst or negedge rst_dst_n)
        if (!rst_dst_n) begin stage1 <= 1'b0; stage2 <= 1'b0; end
        else begin stage1 <= async_level; stage2 <= stage1; end
      assign sync_level = stage2;
    endmodule

    Reset both stages to the same inactive value and suppress consumption until local reset release and pipeline warm-up. ASYNC_REG is flow-specific; adapt it to the target library/tool. An unreset chain is also possible if the protocol masks its unknown startup state. See reset release and implementation hygiene. The delayed meta_ff listing below is simulation-only sampling uncertainty, not this hardware or a physical resolution model.

    Rules for using it

    1. One bit only, or a set of bits that are independent. Several related bits need a different structure.

    2. The source value must stay stable for more than one destination clock period plus setup and hold (the usual engineering rule is at least 1.5 to 2 periods), or the destination may miss it.

    3. No logic between the two flops, and no logic (other than the register) between the source flop and the first synchroniser flop. Logic creates glitches the first flop can catch.

    4. The source should be a register output, not a combinational function of several registers, so it is glitch-free.

    5. Don't branch: use the output of the second flop only. Using the first flop's output (or fanning it out) defeats the settling time.

    In ideal RTL, a stable transition appears just after the second subsequent destination edge: elapsed latency is between roughly one and two periods, plus clock-to-Q. Missing the first capture can add an edge; physical metastability has no deterministic maximum latency. A source that toggles too quickly can lose pulses.

    Fast events need a pulse synchroniser or a handshake (see the CDC handshakes topic).

    Common mistakes

    Common pitfall

    The testbench below (input toggles at least 35 ns apart against a 7 ns clock) never loses an edge because the input is slow compared with the destination clock. A source that toggles twice within one destination period would be undersampled; a synchroniser cannot recover that.

    Interview

    Draw it, name the clock of both flops, say what is not allowed between them, and state the stability rule: the source must hold its value for more than one destination period plus setup and hold, and in practice for at least 1.5 to 2 destination periods.

    Check yourself A signal from a 100 MHz domain crosses to a 20 MHz domain through a 2FF synchroniser. The source pulses high for one 10 ns cycle. Is that safe?

    No: 10 ns is shorter than the 50 ns destination period, so the pulse can fall between two sampling edges and vanish. The source must stretch the pulse, or use a toggle/pulse synchroniser or a handshake.

    Simulation: a lost pulse and the toggle fix

    The waveform below is simulation output for a one-fast-cycle pulse crossing into a slower domain two ways: first a plain two-flop synchroniser, then a toggle scheme as described in the pulse synchroniser lesson. How to read it: one slot is one cycle of clk_f; clk_s shows its own level at each slot.

    • pulse_f is high for a single fast slot (slot 2), between two slow edges, so sync_p stays low in every slot: the plain synchroniser loses the pulse.

    • The same event sent as a toggle holds still: tog_f flips in slot 5 and stays high, giving the slow clock a stable level to sample.

    • sync_t rises in slot 10, two slow edges later, and the edge detector answers with pulse_s high across slots 10 to 12 and low again in slot 13.

    • A level that holds still crosses safely; a pulse shorter than the destination period needs a toggle or a handshake.

    Testbench

    meta_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
    `timescale 1ns/1ps
    
    // Sampling uncertainty only: random digital capture at fixed TCQ after a window hit.
    // No analogue state, late-resolution tail, or downstream disagreement is modelled.
    module meta_ff #(parameter real TCQ = 0.3, TSU = 0.15, THD = 0.1) (
      input  logic clk, d,
      output logic q
    );
      realtime t_d = -100.0, t_clk = -100.0;
      int      meta_events = 0;
      initial q = 1'b0;
    
      always @(d) begin
        t_d = $realtime;
        if ($realtime - t_clk < THD) begin                    // changed just after the edge (hold window)
          meta_events++;  q <= #TCQ $urandom_range(0, 1);
        end
      end
      always @(posedge clk) begin
        t_clk = $realtime;
        if ($realtime - t_d < TSU) begin                      // changed just before the edge (setup window)
          meta_events++;  q <= #TCQ $urandom_range(0, 1);
        end else q <= #TCQ d;
      end
    endmodule
    
    // Simulation-only chain; synthesizable hardware is listed separately above.
    module sync2 (input logic clk, d, output logic q);
      logic q1;
      meta_ff f1 (.clk, .d, .q(q1));       // uncertain capture on model window hits
      meta_ff f2 (.clk, .d(q1), .q(q));    // fixed-delay digital sample one edge later
    endmodule
    

    Finite source-check obligation

    Expected check

    Input toggles at random times (about 35 to 90 ns apart), unrelated to the 7 ns destination clock

    20,000 toggles

    Setup/hold window hits by the first flop (random digital captures)

    At least 100; the recorded run gives 725

    Output edges per input edge

    Exactly 1: no glitch, no lost edge

    Latency

    Ceiling(elapsed time / 7 ns), bins 2 to 3 for this fixed-delay model only

    Final value

    Equals the input

    Remember

    • Cross one bit, or bits that are independent. Put nothing between the two flops.

    • Use only the second flop's output.

    • The source must hold its value for more than one destination period (in practice 1.5 to 2).

    Rule of thumb: a level that holds still crosses safely; a pulse shorter than the destination period does not.

    How this was checked

    Source checker, run with Icarus Verilog 13.0 (2026-10-16): 20,000 input edges give 20,000 output edges, latency bins 2 to 3 and 725 window hits, then PASS. It drives 20,000 slow transitions with random model window hits and a bounded eight-edge final drain. Latency is the ceiling of elapsed input-to-output time divided by 7 ns, including the model's 0.3 ns TCQ; it is a time-bin statistic, not a count of subsequent clock edges. Window hits are exposure coverage, not absorbed physical failures.

    Keep going

    • Practice: Design a CDC synchroniser for a memory-peripheral transfer

    • Practice: A CDC synchroniser glitch caused by clock gating

    • Code lab: Build the 2-flop synchroniser

    • Interview: run a mock interview on this topic

    Related topics

    • When to use 3FF

    Previous

    161 / 350

    Next: When to Use Three Flops

    Up next

    Up nextWhen to Use Three Flops

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • CDC Constraints and Implementation Hygiene
    • Do Not Synchronise Buses Bit by Bit
    clk_fpulse_fsync_pclk_stog_fsync_tpulse_s
    Simulation output: a one-cycle fast pulse lost by a plain two-flop synchroniser (the failing example), then the same event recovered by a toggle scheme (the fix)