Skip to content

Instantly share code, notes, and snippets.

@raczben
Created June 18, 2020 07:36
Show Gist options
  • Save raczben/8eccd02dc69e339cc70dee075137819f to your computer and use it in GitHub Desktop.
Save raczben/8eccd02dc69e339cc70dee075137819f to your computer and use it in GitHub Desktop.
Coherent CDC -- transfer signals between two clock domains.
----------------------------------------------------------------------------------------------------
--
-- Coherent CDC
--
-- This module transfer signals between two clock domains.
--
-- Use this module to transfer slow signal groups, where
-- - the latency is not critical, but
-- - the coherency is mandatory.
--
-- Tipical use case: You want to know (print out, log, etc) the amount of the received bytes on an
-- interface, which has its own clock. The interface has a counter (runs on its clock), and the
-- logger (a processor) runs on different clock. In this case the latency of the counter's read
-- (the time when we get the counter's value) doesn't care. BUT we want to get a valid (ie coherent)
-- counter value.
--
-- This is not for data-streams, ie this is not a FIFO.
--
-- Behavior:
-- The module generates a square wave in the source clock domain. The rising edge of this square
-- wave is the event for sample the data (on both side), but the target side inserts delay, to
-- sample stable data.
----------------------------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity coherent_cdc is
generic (
-- The width of the data to be transfer
g_data_width : integer := 32;
-- This generic determines the latency.
-- If the target clock is faster, set g_clock_ratio greater or equal to 2
-- If the target clock is slower, set g_clock_ratio at least the the ratio of the two clock's
-- period time (T_trg/T_src).
g_clock_ratio : integer := 10
);
port (
-- Source clock the clock signal of the source domain
i_src_clk : in std_logic;
-- Target clock the clock signal of the target domain
i_trg_clk : in std_logic;
i_rst_src : in std_logic := '0';
-- Group of data to be transfer to another domain.
i_data : in std_logic_vector(g_data_width-1 downto 0) := (others => '0');
-- Group of data to be transfer to another domain.
o_data : out std_logic_vector(g_data_width-1 downto 0)
);
end coherent_cdc;
architecture behavioral of coherent_cdc is
-- Sample counter, aka. square wave counter.
signal q_sample_cntr : unsigned(7 downto 0) := (others => '0');
-- The square wave: the rising edge is the sampling event
signal q_sample_wave_src : std_logic;
signal q_sample_wave_src_d1 : std_logic; -- delayed
-- The square wave in the target domain.
signal q_sample_wave_trg_d1 : std_logic; -- aka. meta_0
signal q_sample_wave_trg_d2 : std_logic;
signal q_sample_wave_trg_d3 : std_logic;
-- The sample events
signal c_sample_src : std_logic;
signal c_sample_trg : std_logic;
-- Group of data to be transfer, in source and target domains.
signal q_data_src : std_logic_vector(g_data_width-1 downto 0) := (others => '0');
signal q_data_trg : std_logic_vector(g_data_width-1 downto 0);
constant const_sample_cntr_max_val :integer := g_clock_ratio - 1;
begin
-- The counter to generate the square wave
proc_sample_cntr: process( i_src_clk ) is
begin
if rising_edge (i_src_clk) then
if i_rst_src = '1' then
q_sample_cntr <= (others => '0');
elsif q_sample_cntr = const_sample_cntr_max_val then
q_sample_cntr <= (others => '0');
else
q_sample_cntr <= q_sample_cntr + 1;
end if;
end if; -- rising_edge (i_src_clk)
end process;
-- Generate the square wave
proc_sample_wave_src: process( i_src_clk ) is
begin
if rising_edge (i_src_clk) then
if i_rst_src = '1' then
q_sample_wave_src <= '0';
elsif q_sample_cntr = const_sample_cntr_max_val then
q_sample_wave_src <= not q_sample_wave_src;
end if;
end if; -- rising_edge (i_src_clk)
end process;
-- Delay the square wave, for edge detector
proc_sample_wave_src_delay: process( i_src_clk ) is
begin
if rising_edge (i_src_clk) then
q_sample_wave_src_d1 <= q_sample_wave_src;
end if; -- rising_edge (i_src_clk)
end process;
-- CDC of the square wave
proc_sample_wave_trg_delay: process( i_trg_clk ) is
begin
if rising_edge (i_trg_clk) then
q_sample_wave_trg_d1 <= q_sample_wave_src_d1;
q_sample_wave_trg_d2 <= q_sample_wave_trg_d1;
q_sample_wave_trg_d3 <= q_sample_wave_trg_d2;
end if; -- rising_edge (i_trg_clk)
end process;
-- The edge detectors, aka. the sample enable signals
c_sample_src <= '1' when q_sample_wave_src = '1' and q_sample_wave_src_d1 = '0'
else '0';
c_sample_trg <= '1' when q_sample_wave_trg_d2 = '1' and q_sample_wave_trg_d3 = '0'
else '0';
-- Sample input data in the source domain
proc_data_src: process( i_src_clk ) is
begin
if rising_edge (i_src_clk) then
if c_sample_src = '1' then
q_data_src <= i_data;
end if;
end if; -- rising_edge (i_src_clk)
end process;
-- Sample data in the target domain
proc_data_trg: process( i_trg_clk ) is
begin
if rising_edge (i_trg_clk) then
if c_sample_trg = '1' then
q_data_trg <= q_data_src;
end if;
end if; -- rising_edge (i_trg_clk)
end process;
o_data <= q_data_trg;
end behavioral;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment