--------------------------------------------------------------------------
-- MSS copyright 2014
-- Filename: MUXED_OUTPUT_2DDS.VHD 
-- Last modified: 3/31/12
-- Inheritance: MUXED_OUTPUT.VHD 2-1-03, COM4004_MUXED_OUTPUT.VHD 3/31/12
-- Authors: 
--		Alain Zarembowitch / MSS
--		Bengt Bengtsson / MSS
-- Description:
--		Take a complex data stream and generate a multiplexed I/Q output to the dual DAC or DDS. 
--    The DDS provides the mux clock DDS_CLK_IN
-- 	Equivalent to resampling. Performs signed to unsigned conversion.
--    Compatible with AD9785 DDS
---------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;  
use IEEE.numeric_std.ALL;
Library UNISIM;
use UNISIM.vcomponents.all;

entity MUXED_OUTPUT_2DDS is port ( 
	CLK: in std_logic;
		-- Reference clock for input samples
	SYNC_RESET: in std_logic;
	-- clk-synchronous reset, active high

	--// INPUTS
	DATA_I_IN: in std_logic_vector(15 downto 0);
	DATA_Q_IN: in std_logic_vector(15 downto 0);
		-- format 2's complement
	TX_ENABLE_IN: in std_logic;

	DDS_CLK_IN: in std_logic;
		-- DDS-supplied mux clock (2x sampling rate)

	--// OUTPUTS (synchronous with DDS_CLK_IN)
	DATA_OUT: out std_logic_vector(15 downto 0);
		-- muxed output to the DDS. Format: unsigned (offset-binary) 
	TX_ENABLE_OUT: out std_logic
		-- 


	);
end entity;


architecture BEHAVIOR of MUXED_OUTPUT_2DDS is
--------------------------------------------------------------------------
-- COMPONENTS
--------------------------------------------------------------------------
	COMPONENT CROSS_CLK_DOMAINS
	generic (
		NBITS: in integer
	);
	PORT(
		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 COMPONENT;

--------------------------------------------------------------------------
-- SIGNALS
--------------------------------------------------------------------------
-- Clocks
signal DDS_CLK_INg: std_logic := '0';

-- Reclocked inputs
signal DATA_IN: std_logic_vector(32 downto 0) := (others => '0');
signal DATA2: std_logic_vector(32 downto 0) := (others => '0');
signal DATA2_I: std_logic_vector(15 downto 0) := (others => '0');
signal DATA2_Q: std_logic_vector(15 downto 0) := (others => '0');
signal DATA2_Q_D: std_logic_vector(15 downto 0) := (others => '0');
signal TX_ENABLE2: std_logic := '0';
signal I_QN: std_logic := '0';
signal DATA3: std_logic_vector(15 downto 0) := (others => '0');
signal TX_ENABLE3: std_logic := '0';
--------------------------------------------------------------------------
-- IMPLEMENTATION
--------------------------------------------------------------------------
begin

--// CLOCKS
-- Turn external sampling clock into a global buffer for controlled timing.
BUFG_001: BUFG port map(I => DDS_CLK_IN, O => DDS_CLK_INg);  

DATA_IN <= TX_ENABLE_IN & DATA_Q_IN & DATA_I_IN;

CROSS_CLK_DOMAINS_001: CROSS_CLK_DOMAINS 
generic map(
	NBITS => 33
)
PORT MAP(
	ASYNC_RESET => SYNC_RESET,
	CLK_A => CLK,  -- processing clock at the top level 
	CLK_B => DDS_CLK_INg,
	DATA_IN => DATA_IN,  
	DATA_OUT => DATA2
);

DATA2_I <= DATA2(15 downto 0);
DATA2_Q <= DATA2(31 downto 16);
TX_ENABLE2 <= DATA2(32);

-- Alternate between I and Q samples 
I_QN_GEN: process(DDS_CLK_INg)
begin
	if rising_edge(DDS_CLK_INg) then
		if(TX_ENABLE2 = '1') then
			I_QN <= not I_QN;
	  	else
			I_QN <= '1';
		end if;
	end if;
end process; 


-- Keep I & Q samples together during mux
KEEP_I_Q_TOGETHER: process(DDS_CLK_INg)
begin
	if rising_edge(DDS_CLK_INg) then
		if(I_QN = '1') and (TX_ENABLE2 = '1') then
			DATA3(14 downto 0) <= DATA2_I(14 downto 0);
			DATA3(15) <= not DATA2_I(15);
			DATA2_Q_D(14 downto 0) <= DATA2_Q(14 downto 0);
			DATA2_Q_D(15) <= not DATA2_Q(15);
			TX_ENABLE3 <= '1';
		elsif(I_QN = '0') then
			DATA3 <= DATA2_Q_D;
			TX_ENABLE3 <= '0';
		else
			TX_ENABLE3 <= '0';
		end if;
	end if;
end process; 

	
-- Final reclocking for best timing performance
RECLOCK_003: process(DDS_CLK_INg)
begin
	if rising_edge(DDS_CLK_INg) then
		TX_ENABLE_OUT <= TX_ENABLE3;
		DATA_OUT <= DATA3;
  	end if;
end process;


end behavior;
