Two-Flop Synchronizer

Easy · Clock Domain Crossing · Sequential Logic

Implement the most important circuit in clock-domain crossing: a multi-flop synchronizer that brings a single-bit level signal from another clock domain into the clk domain.

Background: why two flops?

A flip-flop only produces a clean 0 or 1 if its input is stable for a short window around the clock edge (setup and hold time). A signal coming from another clock domain (or from a button, or an asynchronous chip) can change at any moment, including inside that window. When that happens the flop can become metastable: its output hovers between 0 and 1 for an unpredictable time before settling to one of them. If downstream logic reads that half-way value, different gates may see different values and the design can fail in strange ways.

The probability that a metastable flop is still unresolved after a time t decays exponentially, roughly exp(-t / tau). A synchronizer therefore samples the signal with one flop and gives it a whole clock period to settle before a second flop samples it again. Only the last flop's output is used by the rest of the design. The reliability is measured as MTBF (mean time between failures):

MTBF = exp(t_resolve / tau) / (T0 * f_clk * f_data)

Every extra stage adds one clock period to t_resolve, which multiplies the MTBF by a huge factor. Two stages are the usual choice; very fast clocks or safety-critical designs use three.

Rules that come with it:

can arrive with some bits from the old value and some from the new one. (Later problems cover pulse synchronizers and Gray-code FIFOs for those cases.)

Simulation cannot show metastability. Simulators model a flip-flop as an ideal device, so in this problem (and in the hidden tests) the input d is driven synchronously to clk and the only observable behavior is the latency of the chain. That is exactly what is graded.

Specification

module two_flop_sync #(
    parameter int STAGES = 2   // number of flip-flops in the chain, STAGES >= 2
) (
    input  logic clk,
    input  logic rst,   // synchronous, active-high
    input  logic d,     // asynchronous single-bit level input
    output logic q      // d, synchronized into the clk domain
);

flop samples d; each next flop samples the previous one; q is the output of the last flop (no logic between the last flop and q).

edge n + STAGES − 1. Put differently: a value driven on d during cycle k is visible on q during cycle k + STAGES. With STAGES = 2, q is d delayed by exactly 2 cycles.

1, every flop in the chain becomes 0 (so q is 0 in the cycle after that edge, and no value of d seen during reset ever reaches q). rst must have no effect between clock edges.

travelled through the whole chain (latency rule above).

Write your module so that it works for any STAGES >= 2. The hidden tests build it with the default STAGES = 2 and also with other values of STAGES.

Example

d rises in cycle 2 and falls in cycle 6; q follows exactly two cycles later.

cycle0123456789
rst1000000000
d0011110000
qx000111100

Sign up free to solve Two-Flop Synchronizer in your browser.

More Clock Domain Crossing problems