Clock-Domain Crossing
A clock-domain crossing, or CDC, happens when a signal generated by one clock is used by logic running on another unrelated clock. CDC mistakes can pass simulation and fail randomly in hardware.
Learning Objectives
You will learn to:
- explain metastability at a practical level;
- use a two-flop synchronizer for single-bit level signals;
- avoid unsafe multi-bit crossings;
- choose between pulse synchronizers, handshakes, and asynchronous FIFOs.
Why CDC Is Dangerous
If an input changes too close to a receiving clock edge, a flip-flop may become metastable for a short time. It eventually resolves to 0 or 1, but not necessarily soon enough for downstream logic.
title "Illustrative CDC hazard"
time start=0 end=10 unit=ns divisions=10
CLK_A: square label="source clock" low=0 high=1 duty=50 cycles=2 unit=logic color=#2563eb
CLK_B: square label="destination clock" low=0 high=1 duty=50 cycles=3 phase=20 unit=logic color=#7c3aed
SIG_A: step label="signal from clk A" low=0 high=1 at=4.7 unit=logic color=#dc2626
SYNCED: step label="safe after synchronizer latency" low=0 high=1 at=7 unit=logic color=#16a34a
marker RISK at=5 label="near edge"
This is explanatory. Metastability is analog behavior inside a digital flip-flop.
Two-Flop Synchronizer
For a single-bit level signal:
reg sync1;
reg sync2;
always @(posedge dst_clk) begin
sync1 <= async_signal;
sync2 <= sync1;
end
assign safe_signal = sync2;
The first flop may become metastable. The second flop gives it time to resolve before the signal fans out.
Do Not Synchronize Multi-Bit Buses Bit-by-Bit
If you synchronize each bit of a multi-bit counter separately, the destination may see a mixture of old and new bits. Use:
- a handshake protocol;
- a gray-coded pointer for FIFO control;
- an asynchronous FIFO;
- a source-domain register plus valid/ack scheme.
Pulse Crossing
A one-cycle pulse in the source clock domain may be too narrow to be sampled by the destination clock. Convert pulses to toggles or use a handshake.
Worked Example: Button Input
A mechanical button is not synchronous to your FPGA clock. Treat it as asynchronous:
- synchronize the raw input;
- debounce it;
- edge-detect the debounced signal inside the clock domain.
Do not feed a raw button into a state machine.
Common Mistakes
- Assuming simulation models metastability.
- Synchronizing a multi-bit bus one bit at a time.
- Crossing a one-cycle pulse directly.
- Using an async reset release as though it were safe CDC.
- Forgetting that every clock domain needs its own CDC review.
Summary
CDC bugs are intermittent because they depend on timing relationships. Use two-flop synchronizers for single-bit level signals, handshakes or FIFOs for data, and explicit review for every signal crossing clock domains.
Next: Block RAM, ROM, and FIFOs.
Further Reading
- Vendor CDC design guides
- Clifford Cummings papers on asynchronous FIFO design
- FPGA methodology documents on metastability and synchronizers