----------------------------------------------
-- MSS copyright 2011-2012
-- Filename: CROSS_CLK_DOMAINS.VHD
-- Authors: 	Alain Zarembowitch / MSS
-- Edit date: 7/11/11
-- Revision: 5
-- Inheritance: n/a
--
-- Description: send sampled-waveform samples glitch-free across two clock domains.
-- During the resampling, some samples will be lost. Therefore, only use this component
-- for waveform resampling whereby loss of data is acceptable.
--
-- Rev 5 3/12/12 AZ
-- Added another pipeline for glitch prevention 
----------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity CROSS_CLK_DOMAINS is
	generic (
		NBITS: in integer := 14
	);
    port ( 

	--// GLOBAL CLOCKS
   CLK_A : in std_logic;				-- 'from' clock domain
   CLK_B : in std_logic;				-- 'to' clock domain
	ASYNC_RESET: in std_logic;

	DATA_IN: in std_logic_vector((NBITS-1) downto 0);
	DATA_OUT: out std_logic_vector((NBITS-1) downto 0)

	);
end entity;

architecture behavioral of CROSS_CLK_DOMAINS is
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------
--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------
-- Suffix _D indicates a one CLK delayed version of the net with the same name
-- Suffix _E indicates an extended precision version of the net with the same name
-- Suffix _N indicates an inverted version of the net with the same nameend Behavioral;
signal FLAG_A_BN: std_logic := '0';
signal FLAG_A_BN_DF: std_logic := '0';
signal FLAG_A_BN_D: std_logic := '0';
signal DATA_IN_A: std_logic_vector((NBITS-1) downto 0) := (others => '0');
signal DATA_IN_B: std_logic_vector((NBITS-1) downto 0) := (others => '0');
signal DATA_IN_A_D: std_logic_vector((NBITS-1) downto 0) := (others => '0');
signal DATA_IN_B_D: std_logic_vector((NBITS-1) downto 0) := (others => '0');


--------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
begin

--// CLK_A DOMAIN ---------------------------------------------
-- write to A side or B side
RECLOCK_001: process(ASYNC_RESET, CLK_A)
begin
	if(ASYNC_RESET = '1') then
		DATA_IN_A <= (others => '0');
		DATA_IN_B <= (others => '0');
	elsif rising_edge(CLK_A) then
		FLAG_A_BN <= not FLAG_A_BN;
		if(FLAG_A_BN = '0') then
			-- direct to A side
			DATA_IN_A <= DATA_IN;
		else
			-- direct to B side
			DATA_IN_B <= DATA_IN;
		end if;
	end if;
end process;

-- reclock A_BN flag at the falling edge of CLK_A
RECLOCK_002: process(ASYNC_RESET, CLK_A)
begin
	if(ASYNC_RESET = '1') then
		FLAG_A_BN_DF <= '0';
	elsif falling_edge(CLK_A) then
		FLAG_A_BN_DF <= FLAG_A_BN;
	end if;
end process;

--// CLK_B DOMAIN ---------------------------------------------
-- reclock with CLK_B
RECLOCK_003: process(ASYNC_RESET, CLK_B, FLAG_A_BN_DF, DATA_IN_A, DATA_IN_B)
begin
	if(ASYNC_RESET = '1') then
		FLAG_A_BN_D <= '0';
		DATA_IN_A_D <= (others => '0');
		DATA_IN_B_D <= (others => '0');
	elsif rising_edge(CLK_B) then
		FLAG_A_BN_D <= FLAG_A_BN_DF;
		DATA_IN_A_D <= DATA_IN_A;
		DATA_IN_B_D <= DATA_IN_B;
	end if;
end process;

-- reclock input samples with processing clock when input samples are 
-- stable in the A or B buffer.
RECLOCK_MOD_OUTPUT_003: process(ASYNC_RESET, CLK_B)
begin
	if(ASYNC_RESET = '1') then
		DATA_OUT <= (others => '0');
	elsif rising_edge(CLK_B) then
		if(FLAG_A_BN_D = '1') then
			-- read from stable A side
			DATA_OUT <= DATA_IN_A_D;
		else
			-- read from stable B side
			DATA_OUT <= DATA_IN_B_D;
		end if;
	end if;
end process;

end behavioral;
