Day 77: Clock domain crossing: the metastability problem, restated in RTL
Clock domain crossing, restated in RTL
A clock domain crossing (CDC) is any signal passing between two clocks that aren't related. Sample a signal from clock A with clock B and you risk metastability (Stage 0, Day 28) — and, worse, *silent* corruption that simulation (with its idealized clocks) often won't reveal. CDC is the #1 reason a design that passes simulation fails on real silicon, so it gets rigorous rules.
The dangers are subtle: a single control bit needs a 2-FF synchronizer; but a *multi-bit* bus can't just be synchronized bit-by-bit — different bits may resolve on different cycles, producing a value that never existed. Multi-bit crossings need either gray coding (only one bit changes at a time — used for FIFO pointers, Day 79) or a handshake (hold the data stable, pass a synchronized request/acknowledge).
Why CDC bugs pass simulation
Simulators use perfect, aligned clocks, so setup/hold violations and metastability usually don't manifest — the bug hides until real hardware, where clocks drift. That's why 'why do CDC bugs pass simulation but fail on hardware?' is a named interview checkpoint (and Stage 4 has you deliberately break one on the FPGA). CDC correctness comes from *rules and structure*, not from a passing waveform.
Key terms
- Clock domain crossing
- A signal passing between two unrelated clock domains, risking metastability and data corruption.
- Metastability
- An indeterminate flip-flop state from a setup/hold violation at a crossing (Stage 0).
- Multi-bit crossing hazard
- Bits of a bus resolving on different cycles, yielding a value that never actually existed.
- Gray coding / handshake
- Two safe ways to cross multi-bit data: change one bit at a time, or hold data with a req/ack handshake.
Before moving on, you should be able to
Why can’t you safely cross a multi-bit bus between clock domains by putting a 2-FF synchronizer on each bit?