Every safe multi-bit crossing follows one idea: arrange that at most one thing can be uncertain at the sampling moment, or hold everything stable until sampling is done. Five patterns cover nearly every design; the table tells you which fits where.
Pattern | Fits | Cost |
|---|---|---|
Gray code plus per-bit synchronisers | Counters and pointers that advance one step at a time. | An encoder, a decoder, and the one-step discipline. |
Handshake (request/acknowledge) | Occasional arbitrary words in either direction. | Round-trip latency on every transfer; control logic both sides. |
Async FIFO | Streams of words with bursty rates. | Memory, pointers, full/empty logic; the heaviest but highest-throughput option. |
Load pulse with held data | Configuration and quasi-static buses written rarely. | Holding logic plus a synchronised pulse; cheap and slow. |
Dual-clock RAM | Shared buffers both sides access. | A macro plus ownership discipline so the two sides never touch the same entry together. |
The detailed protocols live in the handshake, async FIFO, and pulse synchroniser topics of the cdc-protocols part of this course: two-phase and four-phase handshakes, Gray pointer FIFOs with depth sizing, and toggle and stretch pulse schemes. This lesson only maps the choice; those topics teach the circuits.
One changing bit per step points to Gray; anything arbitrary but infrequent points to a handshake; a continuous stream points to a FIFO; rarely written settings point to a load pulse; shared storage points to dual-clock RAM. Independent status flags with no relation to each other are the one case where per-bit synchronisers are genuinely fine.
An async FIFO: it is a continuous stream, and per-sample handshake latency would throttle throughput. A handshake suits occasional words, not streams.
A load pulse with held data in each destination: the value is quasi-static, so holding it stable around a synchronised pulse is correct and far cheaper than FIFOs or handshakes.