Slack Latches and Mesochronous Interfaces: How Hardware Bridges Two Clocks That Agree on Frequency but Not Phase

2026-08-16

Two clocks are mesochronous when they run at exactly the same frequency but with an unknown, possibly drifting phase relationship. This happens all the time: a SerDes recovers a clock from an incoming data stream, and that recovered clock has the same frequency as the local reference (both came from the same crystal upstream) but arrives with arbitrary phase offset due to cable delay, PCB traces, and temperature.

You can't treat it as a pure synchronous handoff — the phase offset can violate setup/hold at the receiving flop. But you also don't need a full asynchronous FIFO with gray-coded pointers, because you know the pointers can never actually drift apart. That's overkill and wastes latency.

The clean answer is a slack latch (also called a phase-compensating FIFO or "bubble" FIFO). It's a tiny 2-to-4 entry buffer where the write pointer runs on the transmit clock and the read pointer runs on the receive clock, but both pointers increment every cycle. The buffer's only job is to absorb the fixed phase offset plus a little bit of jitter. Because both sides consume and produce one word per cycle, the pointers never drift — they just sit at a constant offset determined by the phase relationship at startup.

Real example: PCIe Gen3+ uses this pattern between the recovered RX clock and the core clock. Both are 250 MHz (or whatever the link rate divided down gives you), both derived ultimately from the same reference, but the recovered clock has cable-delay-dependent phase. A 4-entry slack FIFO sits between them, initialized so the read pointer trails the write pointer by ~2 entries. That gives ±1 entry of margin for jitter and slow phase wander from temperature.

Rule of thumb for sizing: depth = ceil(2 × max_phase_drift / clock_period) + 2 margin entries. If your two clocks can drift up to ±0.5 UI (unit intervals) of phase relative to each other over the operating window, you need at least 4 entries. Anything less and you'll either underflow (read pointer catches write pointer) or overflow.

The magic trick is that latency through a slack latch is deterministic — always exactly the initial pointer offset in cycles. Contrast with a true async FIFO, where latency depends on fill level and gray-code synchronizer stages, usually 3-4 cycles of uncertainty. For latency-sensitive protocols like coherent interconnects, mesochronous slack latches save real nanoseconds.

The failure mode is subtle: if you get the initial pointer offset wrong at reset (say, phase happens to be near a metastability window), the first few words can be garbage. Good designs re-align pointers during link training before user traffic starts.

Key Takeaway: When two clocks share a frequency but not a phase, a small slack latch with fixed pointer offset gives you deterministic-latency bridging without the overhead of a full asynchronous FIFO.

All newsletters