2-Flop Synchronizer vs Toggle vs Handshake vs Async FIFO: CDC
Between asynchronous clock domains there will always be moments when the receiving flip-flop cannot meet its setup or hold time, so signals are passed through circuits designed on the assumption that metastability will occur. The basic one is the synchronizer, which receives a 1-bit level signal through two flip-flops. A toggle synchronizer carries short pulses, a handshake carries occasional multi-bit data, and an asynchronous FIFO carries continuous, high-volume data. All of them share one idea: only a 1-bit signal, or a Gray code that changes by only one bit per step, is ever synchronized.
| Aspect | 2-flop synchronizer | Toggle synchronizer | Handshake | Asynchronous FIFO |
|---|---|---|---|---|
| What it can carry | A 1-bit level signal (a slowly changing control signal) | A 1-bit pulse (an event) | Multi-bit data, one word at a time, occasionally | A stream of multi-bit data (continuous, high volume) |
| How it works | Passes the signal through two flip-flops on the receiving clock, giving any metastability in the first stage time to resolve before the second stage captures it | Turns each pulse into a level that flips on the sending side, synchronizes it, and recovers the pulse on the receiving side by XORing it with a one-stage-delayed copy | Holds the data, passes req through a synchronizer, and once the receiver has captured the data, returns ack through a synchronizer | Writes into a dual-port memory and synchronizes Gray-coded pointers into the other domain to decide full and empty |
| Signals that are synchronized | The signal itself | The toggle signal (1 bit) | req and ack (1 bit each); the data is not synchronized | Gray-coded pointers (only 1 bit changes per step) |
| Throughput | The signal must change much more slowly than the receiving clock period | Pulses must be spaced by more than the few receiving cycles needed to detect each change | Slow: one 4-phase transfer takes 8 or more cycles across both domains | Fast: one word can be written and read every cycle |
| Typical latency to the receiver | About 2 receiving-clock cycles | About 2 to 3 receiving-clock cycles | About 2 cycles for req to arrive; sending the next word must also wait for ack to come back | About 2 to 3 cycles until a written word is visible on the read side |
| Main pitfalls | Used on multi-bit data, bits can be captured in different cycles and an intermediate value appears; short pulses from a faster domain can be lost | If pulses come too close together, the toggle signal returns to its old value and two events are missed | The data must not change until ack returns | The depth is set from the burst length and the read/write rate difference, plus margin for the synchronization delay |
| Circuit size | 2 flip-flops (sometimes 3 stages for fast clocks) | A few flip-flops and an XOR | req/ack synchronizers and state machines on both sides | Memory, pointers with Gray-code conversion, synchronizers and full/empty logic |
| Typical uses | Control signals such as enables, asynchronous external inputs | Done or interrupt notifications that last only one cycle in a fast domain | Passing configuration register values | Data transfer between buses or interfaces running on different clocks |
Figures are typical orders of magnitude and vary by process generation and product.