Clocks, Resets & Clock Domain Crossing
When a signal from another clock domain (or an asynchronous input) changes near the sampling edge, a flip-flop can go metastable (an intermediate voltage that resolves unpredictably).
27.1 Metastability
When a signal from another clock domain (or an asynchronous input) changes near the sampling edge, a flip-flop can go metastable (an intermediate voltage that resolves unpredictably). It cannot be eliminated — only made improbable with synchronizers (MTBF analysis).
27.2 Two-flip-flop synchronizer (single bit)
Use 2–3 stages. Only for single-bit, slowly changing signals (levels).
signal sync_ff : std_logic_vector(1 downto 0) := "00";
attribute ASYNC_REG : string;
attribute ASYNC_REG of sync_ff : signal is "TRUE"; -- keep FFs close together (Xilinx)
process (clk_dst)
begin
if rising_edge(clk_dst) then
sync_ff <= sync_ff(0) & async_in;
end if;
end process;
sync_out <= sync_ff(1);27.3 Pulse synchronizer (toggle method)
-- Source domain: convert pulse to toggle
process (clk_src) begin
if rising_edge(clk_src) then
if pulse_src = '1' then toggle <= not toggle; end if;
end if;
end process;
-- Destination: synchronize toggle and detect edges
process (clk_dst) begin
if rising_edge(clk_dst) then
sync <= sync(1 downto 0) & toggle;
end if;
end process;
pulse_dst <= sync(2) xor sync(1);27.4 Multi-bit CDC techniques
Handshake (req/ack with synchronizers) infrequent multi-bit transfers
Asynchronous FIFO (Gray-coded pointers) streaming data between domains Gray code counters counters crossing domains (only one bit changes)
MUX recirculation / enable synchronization data held stable while a synchronized enable crosses Vendor CDC macros
xpm_cdc_single, xpm_cdc_handshake, xpm_cdc_gray, xpm_fifo_async
Never synchronize a multi-bit bus bit-by-bit — bits can arrive in different cycles (data incoherency).
-- Binary ↔ Gray conversion
function bin2gray(b : unsigned) return unsigned is
begin
return b xor shift_right(b, 1);
end function;
function gray2bin(g : unsigned) return unsigned is
variable b : unsigned(g'range);
begin
b(b'high) := g(g'high);
for i in g'high - 1 downto g'low loop
b(i) := b(i + 1) xor g(i);
end loop;
return b;
end function;27.5 Reset strategies
Synchronous reset: simple timing, recommended by Xilinx for most logic.
Asynchronous reset: works without a clock; requires a reset synchronizer (assert async, de-assert sync):
Reset only what needs resetting (control state, valid flags), not data paths — saves routing and enables SRL/BRAM inference.
Hold resets until PLLs lock; sequence resets across domains.
process (clk, arst_n)
begin
if arst_n = '0' then
rst_sr <= (others => '0');
elsif rising_edge(clk) then
rst_sr <= rst_sr(rst_sr'high-1 downto 0) & '1';
end if;
end process;
rst_n_sync <= rst_sr(rst_sr'high);27.6 Clock management
Use PLL/MMCM for frequency synthesis and phase shifting, global buffers for distribution, avoid logic-generated clocks, constrain generated clocks, and analyze CDC with tools (Vivado report_cdc, Questa CDC, SpyGlass).