Signoff engineers do not debug "a CDC bug"; they debug one of five concrete failures. Learn to recognise each by its symptom, because the symptom is what the lab or the field report gives you.
1. Metastability escape. An interrupt changes inside the capture flop's setup-hold window; the flop resolves late, and two downstream gates sample different values. The control FSM sees an input that is neither cleanly 0 nor cleanly 1 and jumps to an illegal state. Symptom in the field: a one-in-months lockup that never reproduces on the bench.
2. Lost event. A one-cycle pulse in a fast domain falls entirely between two edges of a slower sampling clock, so the slow domain never sees it. The waveform below shows exactly this: pulse_f rises and falls between two clk_s edges, and the slow capture cap_s stays low throughout. How synchronisers recover the event (toggle and handshake schemes) is design material covered in CDC handshakes.
How to read it: clk_f is the fast clock and clk_s is the slow one. pulse_f rises and falls entirely between two rising edges of clk_s, so cap_s, which samples pulse_f on the slow clock, never sees a high value and stays low in every slot.
3. Duplicated event. A slow-domain write strobe stays high across two edges of a faster clock, and the fast domain treats each high sample as a new write, so one requested write lands twice. The bug is not timing but interpretation: a level was consumed as repeated events.
4. Torn multi-bit bus. A 4-bit binary counter moves from 0111 to 1000 and the destination samples mid-change, catching some new bits and some old ones, for example 1100: a value the counter never held. Each bit had its own synchroniser and each resolved correctly by itself; the combination is the failure. (Bus tearing has its own lesson and waveform elsewhere in this course; here, remember the shape: impossible values on a bus that changes several bits at once.)
5. Stale data. The destination captures a data bus one cycle before the source's new value has propagated, so it processes the previous transfer's data with the current transfer's valid flag. Everything was synchronised and nothing went metastable; the capture was simply ordered too early.
Symptom | Likely cause |
|---|---|
Rare illegal-state lockup, never reproduces | Metastability escape: an unsynchronised input fanning out to several gates |
An event the source sent but the destination never acted on | Lost event: pulse shorter than the destination period, or a gated destination clock |
One request executed twice (double write, double interrupt) | Duplicated event: a level consumed per-cycle as repeated events |
Impossible values on a multi-bit bus | Torn bus: several bits changing at once, synchronised bit by bit |
Right valid flag, previous transfer's data | Stale data: capture ordered before the data settled |
For each crossing, the reviewer asks which of the five modes its scheme prevents and which it invites: is every single-bit input synchronised (mode 1), can a pulse be missed or doubled given the two periods (modes 2 and 3), does any multi-bit value change more than one bit per transfer (mode 4), and is data held stable until the destination has it (mode 5). A scheme that answers all five is ready for waiver-free signoff; anything less needs a written justification.
Nothing about the synchronisers: this is a torn bus. The counter changed several bits at once (7 is 0111, 8 is 1000) and the destination mixed old and new bits. Per-bit synchronisers cannot fix it; the design needs a Gray code, a handshake, or a FIFO.
A duplicated event: the destination counted one level twice. A lost event is the mirror image, a fast pulse the slow domain never saw. Both come from the period mismatch, in opposite directions.