2026-07-10
You know how to synchronize a single-bit control signal with a two-flop synchronizer, and you know how to pass wide data through an async FIFO. But there's a middle ground you'll hit constantly in real designs: you have a wide bus that changes slowly, and building a FIFO is overkill. The answer is an enable-based multi-bit synchronizer, also called an MCP (multi-cycle path) handshake.
The trap: if you just drop each bit of an 8-bit bus through its own two-flop synchronizer, the bits will arrive at the destination on different clock edges. When the source bus changes from 0x0F to 0x10, five bits are flipping. Some cross first, some cross second. The destination sees garbage transients like 0x1F, 0x00, or 0x1E for a cycle before settling. If the destination is a comparator or a state machine input, that transient causes a real, observable bug.
The fix is decoupling the data from the synchronization:
The critical constraint: the source must hold the data stable for at least the enable's round-trip synchronization time before changing it again. That's typically 3–4 destination clocks (2 flops of sync + 1 for edge detect + margin). Static timing analysis is told to ignore the data-bus path via a set_false_path or set_max_delay constraint — hence "MCP handshake."
Real example: A CPU writes a configuration register (16-bit divisor) into a UART running on a separate 48 MHz clock while the CPU runs at 400 MHz. The CPU writes the value, then pulses a "config_valid" bit. The 16 data bits fly across combinationally. The valid pulse crosses through a two-flop sync. The UART side sees the synchronized edge and latches the divisor. No FIFO needed for something that changes once every million cycles.
Rule of thumb: If the source updates the bus faster than 4 × destination clock period, use a FIFO. Slower than that? Enable-synchronize it. For a 100 MHz destination, that's the crossover at ~25 MHz update rate — anything slower gets the cheap handshake.
The savings are real: an 8-bit MCP handshake costs ~10 flops. An 8-bit async FIFO with even 4 entries costs ~80 flops plus Gray-coded pointer logic.
