Clock Domain Crossing (CDC)

The art of safely transferring data between asynchronous clock domains. Essential for multi-clock SoC designs.

1. What is CDC & Why Do We Need It?

What is CDC?

Clock Domain Crossing (CDC) occurs whenever a signal is launched by a Flip-Flop in one clock domain (Source) and sampled by a Flip-Flop in a different clock domain (Destination). If the clocks are asynchronous (no fixed phase relationship), the setup and hold times relative to the destination clock generally cannot be guaranteed.

Why is it Critical?

Modern SoCs have dozens of clocks (CPU at 3GHz, DDR at 1.6GHz, USB at 480MHz, UART at 1MHz). Different modules MUST communicate. Without proper synchronization, you risk:

  • Metastability: The destination flop output settles at an unknown voltage (neither 0 nor 1), potentially propagating errors.
  • Data Incoherence: Sampling multi-bit buses at different times (Skew), receiving invalid values.
  • Data Loss: Fast pulses missed by slow clocks.

2. Metastability & The 2-FF Synchronizer

Metastability happens when data changes inside the setup/hold window of a Flip-Flop. The output may oscillate or hover at VDD/2 for an indefinite time.

Implementation: 2-FF Synchronizer (For Single Bits)
module synchronizer_2ff (
    input  wire clk_dest,  // Destination Clock
    input  wire rst_n,
    input  wire d_async,   // Asynchronous Input
    output reg  d_sync     // Synchronized Output
);
    reg q1;
    // Standard 2-stage shift register
    // Place these FFs close together during P&R (set_false_path)
    always @(posedge clk_dest or negedge rst_n) begin
        if (!rst_n) begin
            q1     <= 1'b0;
            d_sync <= 1'b0;
        end else begin
            q1     <= d_async; // Stage 1: May become Metastable
            d_sync <= q1;      // Stage 2: Likely Stable (filtered)
        end
    end
endmodule

Why 2 Flip-Flops? The first flop (q1) allows the metastability to resolve. By the time the second flop samples (one clock cycle later), the probability of q1 still being metastable is near zero (measured by MTBF - Mean Time Between Failures). For very high speeds, 3-FF synchronizers are used.

3. Pulse Stretchers (Fast-to-Slow)

If a pulse in the Fast Domain is narrower than the period of the Slow Domain, the slow clock might miss it entirely (sampling between pulses).

Rule of Thumb: The source pulse must be at least 1.5x wider than the destination clock period to be safely sampled by a 2-FF synchronizer.

How to Implement:

Use a "Toggle" mechanism. Toggle a signal on every pulse in the source. Synchronize the toggle to the destination. Perform an XOR with the previous value (edge detection) to recreate the pulse.

4. Multi-Bit Synchronization (The Danger Zone)

FATAL ERROR: Never use 2-FF synchronizers on individual bits of a Data Bus or Counter.

Why? Clock Skew. If bits D[0] and D[1] transition from `00` to `11` simultaneously, delay variations might cause D[0] to arrive in cycle N and D[1] in cycle N+1. The destination would see `01` or `10` momentarily. This is catastrophic for pointers.

Solution A: Mux-Recirculation (Handshake)

Keep the Data Bus stable. Send a `Valid` signal. Synchronize only the `Valid` signal (using 2-FF). Once the destination sees `synchronized_valid`, it is safe to sample the Data Bus.

Solution B: Gray Codes (For Counters/Pointers)

Gray codes ensure that only **one bit changes** at a time when incrementing (e.g., `00` -> `01` -> `11` -> `10`). Even if skew exists, the sampled value will either be the *Old Count* or the *New Count*. Both are valid states. This is the heart of Async FIFO design.