Why a single flip-flop isn’t enough
When a flip-flop samples an input that changes at the exact moment of the clock edge (violating setup/hold time), its output can enter a metastable state: neither a clean 0 nor a clean 1, but a voltage level that takes an unpredictable amount of time to resolve to one or the other. If downstream combinational logic reads that flip-flop’s output while it’s still metastable, different gates can interpret the same unsettled voltage differently — one gate sees a 1, another sees a 0 — and the design falls into an inconsistent, unrecoverable state.
This isn’t a corner case you can verify away with more simulation: it’s a physical property of any bistable element sampling an asynchronous input, and it will happen eventually in real silicon.
The fix: give it a whole clock period to settle
The 2-flop synchronizer’s job is not to prevent metastability (that’s not physically possible for a genuinely asynchronous input) — it’s to make the probability of it still being metastable by the time it’s used astronomically small.
- The first flop (
meta) samplesasync_indirectly and may go metastable. - It then has a full clock period to resolve before the second flop (
sync) samples it. syncis what the rest of the destination-domain logic uses — by construction, it only ever sees a clean0or1.
MTBF, conceptually
The mean time between failures of a synchronizer grows exponentially with the amount of settling time you give it:
MTBF ≈ e^(t_settle / τ) / (T0 · f_clk · f_data)
where t_settle is the time available for the metastable flop to resolve (roughly one clock period here), τ is a process-dependent time constant describing how quickly the flip-flop’s bistable element resolves, and T0/f_clk/f_data describe how often a metastability-triggering sample can occur. The key intuition: adding one more clock period of settling time (e.g. going from 2 flops to 3) multiplies MTBF by a large exponential factor, which is why 2 flops is enough for most designs, and very high-frequency or safety-critical designs sometimes add a third stage for extra margin.
Correctness constraints and limits
- This synchronizer is only valid for a single bit that changes slowly relative to
clk(specifically: it must not toggle again before the destination domain has had a chance to sample the current value). It is not safe to use directly on a multi-bit bus — different bits could resolve on different clock edges and be sampled as a nonsense combination. For multi-bit data, use Gray coding (see the Asynchronous FIFO problem) or a full req/ack handshake (see the Handshake Synchronizer problem). - It is also not, by itself, the right tool for capturing a single-cycle pulse — if the source pulse is shorter than one destination clock period, this synchronizer can miss it entirely. See the Pulse Synchronizer problem for that case.
- No simulator can model true analog metastability, so this problem’s testbench (like any digital testbench) can only verify the functional behavior — that the module is genuinely built from two cascaded flops sampling on
clk, with the correct one-cycle-apart timing — not the physical settling behavior that makes it useful in real silicon.