0
0
VhdlDebug / FixIntermediate · 4 min read

How to Handle Clock Domain Crossing in VHDL: Fix and Best Practices

To handle clock domain crossing in VHDL, use synchronization techniques like double flip-flop synchronizers for single-bit signals and FIFO buffers for multi-bit data. This prevents metastability and ensures reliable data transfer between different clock domains.
🔍

Why This Happens

When signals move between different clock domains, the receiving flip-flop may sample the signal at an unstable time, causing metastability. This leads to unpredictable outputs and data corruption.

vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity cdc_broken is
    Port ( clk_a : in STD_LOGIC;
           clk_b : in STD_LOGIC;
           signal_a : in STD_LOGIC;
           signal_b : out STD_LOGIC);
end cdc_broken;

architecture Behavioral of cdc_broken is
    signal sync_signal : STD_LOGIC;
begin
    -- Direct assignment crossing clock domains (WRONG)
    process(clk_b)
    begin
        if rising_edge(clk_b) then
            sync_signal <= signal_a; -- signal_a is from clk_a domain
        end if;
    end process;
    signal_b <= sync_signal;
end Behavioral;
Output
Metastability causes unpredictable output on signal_b; simulation may show unstable or oscillating values.
🔧

The Fix

Use a double flip-flop synchronizer to safely transfer single-bit signals across clock domains. This reduces metastability risk by allowing the signal to settle before use.

vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity cdc_fixed is
    Port ( clk_a : in STD_LOGIC;
           clk_b : in STD_LOGIC;
           signal_a : in STD_LOGIC;
           signal_b : out STD_LOGIC);
end cdc_fixed;

architecture Behavioral of cdc_fixed is
    signal sync_ff1, sync_ff2 : STD_LOGIC := '0';
begin
    process(clk_b)
    begin
        if rising_edge(clk_b) then
            sync_ff1 <= signal_a; -- first stage synchronizer
            sync_ff2 <= sync_ff1; -- second stage synchronizer
        end if;
    end process;
    signal_b <= sync_ff2;
end Behavioral;
Output
signal_b reliably follows signal_a with metastability minimized.
🛡️

Prevention

To avoid clock domain crossing issues, always use proper synchronization methods:

  • Use double flip-flop synchronizers for single-bit signals.
  • Use asynchronous FIFOs for multi-bit data transfer.
  • Avoid direct signal assignments across clock domains.
  • Plan clock domains carefully to minimize crossings.
  • Use linting tools and static analysis to detect unsafe crossings.
⚠️

Related Errors

Common related errors include:

  • Metastability: Unstable outputs causing random behavior.
  • Data corruption: Multi-bit signals partially updated causing invalid data.
  • Timing violations: Setup and hold time failures across domains.

Quick fixes involve adding synchronizers, FIFOs, or redesigning clock domains.

Key Takeaways

Always synchronize signals crossing clock domains to prevent metastability.
Use double flip-flop synchronizers for single-bit signals.
Use asynchronous FIFOs for multi-bit data crossing domains.
Avoid direct assignments between different clock domains.
Plan clock domains and crossings carefully to reduce complexity.