Created
June 18, 2020 07:36
-
-
Save raczben/8eccd02dc69e339cc70dee075137819f to your computer and use it in GitHub Desktop.
Coherent CDC -- transfer signals between two clock domains.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
---------------------------------------------------------------------------------------------------- | |
-- | |
-- 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