How to Handle Multiple Clock Domains in VHDL: Best Practices
clock domain crossing (CDC) techniques like synchronizer flip-flops or FIFOs to safely transfer signals between domains. Directly connecting signals across different clocks causes metastability and unreliable behavior, so proper synchronization circuits must be implemented.Why This Happens
When signals move between different clock domains without proper synchronization, the receiving domain may sample signals at unstable times. This causes metastability, where flip-flops enter an undefined state, leading to unpredictable outputs and system failures.
Here is an example of broken VHDL code that directly connects signals from one clock domain to another without synchronization:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity broken_cdc is
Port (
clk_a : in std_logic;
clk_b : in std_logic;
signal_a : in std_logic;
signal_b : out std_logic
);
end broken_cdc;
architecture Behavioral of broken_cdc is
begin
-- Direct assignment across clock domains (WRONG)
process(clk_b)
begin
if rising_edge(clk_b) then
signal_b <= signal_a; -- signal_a is from clk_a domain
end if;
end process;
end Behavioral;The Fix
To fix this, use a two-stage synchronizer for single-bit signals crossing clock domains. This reduces metastability risk by giving the signal time to settle before use.
For multi-bit data, use asynchronous FIFOs or handshake protocols to safely transfer data.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity fixed_cdc is
Port (
clk_a : in std_logic;
clk_b : in std_logic;
signal_a : in std_logic;
signal_b : out std_logic
);
end fixed_cdc;
architecture Behavioral of fixed_cdc is
signal sync_stage1, sync_stage2 : std_logic := '0';
begin
-- Two-stage synchronizer for crossing clk_a to clk_b domain
process(clk_b)
begin
if rising_edge(clk_b) then
sync_stage1 <= signal_a;
sync_stage2 <= sync_stage1;
end if;
end process;
signal_b <= sync_stage2;
end Behavioral;Prevention
To avoid clock domain crossing issues in the future:
- Always identify signals crossing clock domains early in design.
- Use two-stage synchronizers for single-bit signals.
- Use asynchronous FIFOs or handshake protocols for multi-bit data.
- Simulate CDC behavior with specialized tools or assertions.
- Follow coding guidelines and use lint tools that detect unsafe CDC.
Related Errors
Common related errors include:
- Metastability: Flip-flops fail to settle, causing random outputs.
- Data corruption: Multi-bit signals sampled partially, causing invalid data.
- Timing violations: Setup and hold times not met across domains.
Quick fixes involve adding synchronizers, FIFOs, or redesigning clock domain boundaries.