Use a synchronizer to convert changes in a signal in one clock domain into changes which are synchronous to another clock domain, while reducing the probability of metastable events propagating.
A synchronizer is a trivial circuit, but it breaks the conventions of synchronous logic while doing its best to contain the consequences. Thus, it is very easy to use a synchronizer incorrectly, leading to worse timing closure at best, or at worst intermittent circuit malfunctions which won't be visible (or even reproducible!) in simulations. We go over the necessary subtleties in the text and code below.
This synchronizer is the fundamental building block of all other CDC circuits, and it must be used under one major constraint to operate properly: Any change on the input signal must hold steady for a minimum of 1.5x longer than the period of the receiving clock to guarantee enough time for three receiving clock edges (posedge/negedge/posedge, or negedge/posedge/negedge) to pass, which guarantees that the input signal will be properly sampled by a posedge.
Any less time, and the input signal could change back before it was sampled by the receiving clock. In other words, assuming single-cycle changes (pulses), the receiving clock domain can have a clock frequency of at most 0.66x that of the sending clock domain. For any higher receiving clock freqency, you must guarantee that the change on the input signal will last enough input clock cycles to be seen by at least three consecutive receiving clock edges.
If you cannot guarantee the duration of a pulse and/or have no knowledge of the relative clock domain frequencies, use a Pulse Synchronizer.
Also, for reasons explained in A Primer on Clock Domain Crossing Theory, the latency of a CDC Synchronizer can vary between 1 and 3 cycles, depending on clock phase and metastability events, and so only one signal may be synchronized at each clock domain crossing. Using multiple CDC Synchronizers in parallel is not deterministic as there is no guarantee they will all have the same latency.
If you need to pass multiple signals (e.g.: a bus), synchronize one signal in each direction as a ready/valid handshake, and capture the other signals (held steady during synchronization) directly in the receiving clock domain once the one signal has synchronized. Remember to constrain and check the delay on the other signals. The CDC Data Synchronizer implements this approach, and the CDC Pulse Synchronizer can also be used to build similar CDC circuits.
You must feed a CDC Synchronizer directly from a register, with no logic between it and the synchronizer. Otherwise, it's possible that multiple logic paths will converge to the synchronizer, and convergent logic can glitch when signals change state (we're not getting into that theory here). Normally, a subsequent register will filter out such glitches since they settle long before the next clock edge. However, a synchronizer's unrelated and asynchronous receiving clock may just happen to sample the input when a glitch occurs, transforming that glitch into a real, and completely wrong, logic pulse in the receiving clock domain! Alternately, a high signal may glitch early to low and be missed by the receiving clock.
On an FPGA, you should not use an I/O register as one of the stages of a synchronizer: they are too far from the main logic fabric, and synchronizer registers must be as close together as possible (see A Primer on Clock Domain Crossing Theory). Thus, your input or output must connect to a dedicated I/O register synchronous to the I/O clock, which in turn connects to a CDC synchronizer driven by the internal clock. This extra I/O register also filters out any input glitches, as outlined above.
`default_nettype none module CDC_Bit_Synchronizer #( parameter EXTRA_DEPTH = 0 // Must be 0 or greater ) ( input wire receiving_clock, input wire bit_in, output reg bit_out );
The minimum valid synchronizer depth is 2. Add more stages if the design requires it. This usually happens near the highest operating frequencies. Consult your device datasheets.
localparam DEPTH = 2 + EXTRA_DEPTH;
For Vivado, we must specify that the synchronizer registers should be placed close together (see: UG912), and to show up as part of MTBF reports.
For Quartus, specify that these register must not be optimized (e.g. moved into the input register of a DSP or BRAM) and to mark them as composing a synchronizer (and so be placed close together).
In both cases, we also specify that the registers must not be placed in I/O register locations.
// Vivado (* IOB = "false" *) (* ASYNC_REG = "TRUE" *) // Quartus (* useioff = 0 *) (* PRESERVE *) (* altera_attribute = "-name SYNCHRONIZER_IDENTIFICATION \"FORCED IF ASYNCHRONOUS\"" *) reg sync_reg [DEPTH-1:0]; integer i; initial begin for(i=0; i < DEPTH; i=i+1) begin sync_reg [i] = 1'b0; end end
Pass the bit through DEPTH registers into the receiving clock domain. Peel out the first iteration to avoid a -1 index.
always @(posedge receiving_clock) begin sync_reg  <= bit_in; for(i = 1; i < DEPTH; i = i+1) begin: cdc_stages sync_reg [i] <= sync_reg [i-1]; end end always @(*) begin bit_out = sync_reg [DEPTH-1]; end endmodule
Back to FPGA Design Elements