The short answer: a modern chip has many clocks, and any signal that moves between two unrelated clock domains can go metastable. Safe designs use the right synchroniser for each crossing: a two-flop synchroniser for single-bit levels, pulse or toggle synchronisers for pulses, handshakes for multi-bit control, and asynchronous FIFOs with Gray-coded pointers for data. Resets need care too: assert asynchronously, release synchronously.
Clock domain crossing (CDC) bugs are some of the nastiest bugs in chip design. They often pass simulation, appear only now and then on silicon, and are very hard to reproduce. That is why CDC is one of the most common interview topics. Here is how I would explain the key ideas.
- Why crossing clock domains is risky
- The two-flop synchroniser
- Choosing the right CDC technique
- Clock gating and clock basics
- Resets across clock domains
- How CDC is checked in industry
Table of Contents
Part 1: Why crossing clock domains is risky
A flip-flop needs its input to be stable for a short time around the clock edge (setup and hold). When a signal comes from an unrelated clock, it can change right at that moment. The flop can then go metastable: its output hovers between 0 and 1 for an unpredictable time before settling. If other logic uses that value in the meantime, different parts of the design can see different values, and the chip misbehaves.
Part 2: The two-flop synchroniser

The standard fix for a single-bit signal is two flops in the destination clock domain. The first may go metastable, but it has a whole clock cycle to settle before the second flop samples it, which makes the chance of failure extremely small. Very high-speed designs sometimes use three flops. The synchroniser does not make the value arrive on a particular cycle; it only makes it safe.
// Two-flop synchroniser for a single-bit level signal
module sync_2ff (
input wire clk_b,
input wire rst_b_n,
input wire d_async,
output wire q_sync
);
reg ff1, ff2;
always @(posedge clk_b or negedge rst_b_n) begin
if (!rst_b_n) begin
ff1 <= 1'b0;
ff2 <= 1'b0;
end else begin
ff1 <= d_async;
ff2 <= ff1;
end
end
assign q_sync = ff2;
endmodule
Part 3: Choosing the right CDC technique

- Never synchronise each bit of a multi-bit bus separately: the bits can settle on different cycles and give you a value that never existed.
- A short pulse from a fast clock can be missed completely by a slow clock. Convert it to a toggle, synchronise that, then detect the edge.
- Asynchronous FIFOs use Gray-coded pointers because only one bit changes at a time, so a pointer that is caught mid-change is still a valid value.
Part 4: Clock gating and clock basics
Clock gating saves power by stopping the clock to idle logic. It must use an integrated clock-gating cell (a latch plus an AND gate) rather than a plain AND gate in the clock path, or glitches can create false clock edges. Also be careful with clock muxes, generated clocks and dividers: they all need proper constraints and, where clocks switch, glitch-free switching logic.
Part 5: Resets across clock domains
The common rule is to assert reset asynchronously, so the design resets immediately even without a clock, and to release it synchronously, through a reset synchroniser in each clock domain, so every flop leaves reset on a clean clock edge. Reset domain crossing (RDC) issues are the reset version of CDC bugs, and are checked with dedicated tools.
Part 6: How CDC is checked in industry
Simulation alone cannot catch most CDC bugs, because ordinary RTL simulation does not model metastability. Teams use structural CDC and RDC tools that find every crossing and check that each one has a recognised synchroniser, plus assertions and sometimes formal checks for handshake protocols.
Practise this on VLSI Forge
I built VLSI Forge so you can write RTL in your browser, run it on a real simulator and check every signal in the waveform. Free, nothing to install.
FAQ
What is metastability?
A state where a flip-flop output is neither a clean 0 nor 1 for a while, because its input changed too close to the clock edge. It always resolves eventually, but not in a predictable time.
Why not use one flop as a synchroniser?
One flop gives the metastable value no time to settle before it is used. The second flop provides a full clock cycle for that.
Why Gray code in asynchronous FIFOs?
Only one bit changes between consecutive Gray values, so if a pointer is sampled while changing, you get either the old or the new value, never a wrong one.
Do I need CDC tools if my simulation passes?
Yes. RTL simulation does not model metastability, so CDC bugs usually pass simulation. Structural CDC checks are essential.
