-------------------------------------------------------------
--	Filename:  AUX_DACS_ADC.VHD
-- Author: 
--  	JW / WHOI
--		Alain Zarembowitch / MSS, 
--	Version: 0
--	Date last modified: 11/22/11
-- Inheritance: 	com3504test.vhd  5/29/11
--
-- description:  The COM-3504 module comprises two auxiliary 12-bit DACs and 
-- one auxiliary 12-bit ADC in addition to the main high-speed ADCs and DACs.
-- Since these three auxiliary devices share a common SPI bus, access must be regulated.
-- This is the purpose of this component.
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
library UNISIM;
use UNISIM.VComponents.all;

entity AUX_DACS_ADC is
	generic (
		CLK_FREQUENCY: integer := 120	 -- reference clock frequency in MHz
	);
    port ( 
			--// Clocks Resets
			CLK: in std_logic;
				-- reference clock 
				-- Adjust dividers with the DAC_AD5621 and AD7276_ADC_DRIVER components to lower speed to specs.
			ASYNC_RESET: in std_logic;

			--// User interface
			AUXDAC1_DIN: in std_logic_vector(11 downto 0);
			AUXDAC2_DIN: in std_logic_vector(11 downto 0);
			AUXADC1_DOUT: out std_logic_vector(11 downto 0);
			
			-- the scheduler within is based on a 16 timeslot period. 
			-- one transaction (AUXDAC1, AUXDAC2 or AUXADC1) can be performed for each timeslot
			-- (mutually exclusive) as controlled below. Set '1' to perform a transaction.
			-- Example:
			-- TIMESLOTS_AUXDAC1 => x"FEFE",	14 transactions per 16 timeslot period
			-- TIMESLOTS_AUXDAC2 => x"0001", 1 transaction scheduled for timeslot 0
			-- TIMESLOTS_AUXADC1 => x"0100", 1 transaction scheduled for  timeslot 8
			TIMESLOTS_AUXDAC1: in std_logic_vector(15 downto 0);
			TIMESLOTS_AUXDAC2: in std_logic_vector(15 downto 0);
			TIMESLOTS_AUXADC1: in std_logic_vector(15 downto 0);
			
			--// Auxilliary DACs + ADC interface (connect directly to top-level port)
			AUX_SPI1: inout std_logic;	-- SDATA
			AUX_SPI2: out std_logic;	-- SCLK
			AUX_SPI3: out std_logic;	-- AUX DAC1 SYNC#
			AUX_SPI4: out std_logic;	-- AUX DAC2 SYNC#
			AUX_SPI5: out std_logic	-- AUX ADC CS#
				
					
			);
end entity;

architecture Behavioral of AUX_DACS_ADC is
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------

	COMPONENT DAC_AD5621
	generic (
		CLK_FREQUENCY: integer 
	);
	PORT(
		CLK : IN std_logic;
		DATA_IN : IN std_logic_vector(11 downto 0);
		DATA_IN_CLK : IN std_logic;
		OP_MODE : IN std_logic_vector(1 downto 0);          
		DONE : OUT std_logic;
		SYNC_B : OUT std_logic;
		SCLK : OUT std_logic;
		SDIN : OUT std_logic
		);
	END COMPONENT;

	COMPONENT AD7276_ADC_DRIVER
	generic (
		CLK_FREQUENCY: integer 
	);
	PORT(
		CLK : IN std_logic;
		START : IN std_logic;
		SDATA : IN std_logic;          
		DATA_OUT : OUT std_logic_vector(11 downto 0);
		DATA_OUT_CLK : OUT std_logic;
		CS_B : OUT std_logic;
		SCLK : OUT std_logic
		);
	END COMPONENT;


--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------
-- Suffix _D indicates a one clock delay

--// AUXILIARY DACs + ADC
signal AUXDAC1_SCLK: std_logic;
signal AUXDAC1_SDIN: std_logic;
signal AUXDAC2_SCLK: std_logic;
signal AUXDAC2_SDIN: std_logic;
signal AUXADC1_SCLK: std_logic := '0';
signal SCHEDULER_STATE: integer range 0 to 9 := 0;
signal AUX_SPI3_local: std_logic := '1';
signal AUX_SPI4_local: std_logic := '1';
signal AUX_SPI5_local: std_logic := '1';
signal AUX_DAC1_ENABLE: std_logic := '0';
signal AUX_DAC2_ENABLE: std_logic := '0';
signal AUX_ADC1_ENABLE: std_logic := '0';
signal AUX_DAC1_DONE: std_logic := '0';
signal AUX_DAC2_DONE: std_logic := '0';
signal AUX_ADC1_DONE: std_logic := '0';
--// SCHEDULER
signal TS_COUNTER: std_logic_vector(15 downto 0) := x"0000";	-- periodic timeslot counter.
--------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
begin


--// AUXILIARY DACs (AD5621) -----------------------------------------------------
-- Two auxiliary DACs
AUX_DAC1: DAC_AD5621 
	GENERIC MAP(
		CLK_FREQUENCY => CLK_FREQUENCY
	)
	PORT MAP(
	CLK => CLK,							-- synchronous clock
	DATA_IN => AUXDAC1_DIN,		-- user 12-bit input data
	DATA_IN_CLK => AUX_DAC1_ENABLE,		-- user enable
	OP_MODE(0) => '0',			-- "00" for normal DAC operation, "11" for high impedance output
	OP_MODE(1) => '0',
	DONE => AUX_DAC1_DONE,				-- tell user when the DAC is ready for the next input sample
  	--// DAC interface
  	SYNC_B => AUX_SPI3_local,					-- DAC serial connections. Do not modify.
  	SCLK => AUXDAC1_SCLK,						-- DAC serial connections. Do not modify.
  	SDIN => AUXDAC1_SDIN						-- DAC serial connections. Do not modify.
	);

AUX_DAC2: DAC_AD5621 
	GENERIC MAP(
		CLK_FREQUENCY => CLK_FREQUENCY
	)
	PORT MAP(
	CLK => CLK,							-- synchronous clock
	DATA_IN => AUXDAC2_DIN,		-- user 12-bit input data
	DATA_IN_CLK => AUX_DAC2_ENABLE,		-- user enable
	OP_MODE(0) => '0',			-- "00" for normal DAC operation, "11" for high impedance output
	OP_MODE(1) => '0',
	DONE => AUX_DAC2_DONE,				-- tell user when the DAC is ready for the next input sample
  	--// DAC interface
  	SYNC_B => AUX_SPI4_local,					-- DAC serial connections. Do not modify.
  	SCLK => AUXDAC2_SCLK,						-- DAC serial connections. Do not modify.
  	SDIN => AUXDAC2_SDIN						-- DAC serial connections. Do not modify.
	);



--// AUXILIARY ADC (AD7276) -----------------------------------------------------
AD7276_ADC_DRIVER_001: AD7276_ADC_DRIVER 
	GENERIC MAP(
		CLK_FREQUENCY => CLK_FREQUENCY
	)
	PORT MAP(
	CLK => CLK,
	START => AUX_ADC1_ENABLE,
	DATA_OUT => AUXADC1_DOUT,
	DATA_OUT_CLK => AUX_ADC1_DONE,
	CS_B => AUX_SPI5_local,
	SCLK => AUXADC1_SCLK,
	SDATA => AUX_SPI1
);

--// SCHEDULER 
-- Time share the SPI bus for the three SPI devices (2 DACs, 1 ADC)
TIMER_GEN: process(CLK)
begin
	if rising_edge(CLK) then
		if(SCHEDULER_STATE = 0) then
			if (TS_COUNTER = 0) then
				TS_COUNTER <= x"0001";	-- 0 is illegal. TS_COUNTER should have one and only one '1'
			elsif((TS_COUNTER and TIMESLOTS_AUXDAC1) /= 0) then
				-- AUX_DAC1 timeslot
				TS_COUNTER <= TS_COUNTER(14 downto 0) & TS_COUNTER(15);	-- shift one notch to the left
				SCHEDULER_STATE <= 1;	
			elsif((TS_COUNTER and TIMESLOTS_AUXDAC2) /= 0) then
				-- AUX_DAC2 timeslot
				TS_COUNTER <= TS_COUNTER(14 downto 0) & TS_COUNTER(15);	-- shift one notch to the left
				SCHEDULER_STATE <= 4;	
			elsif((TS_COUNTER and TIMESLOTS_AUXADC1) /= 0) then
				-- AUX_ADC1 timeslot
				TS_COUNTER <= TS_COUNTER(14 downto 0) & TS_COUNTER(15);	-- shift one notch to the left
				SCHEDULER_STATE <= 7;	
			else
				-- no transaction in this timeslot
				TS_COUNTER <= TS_COUNTER(14 downto 0) & TS_COUNTER(15);	-- shift one notch to the left
			end if;
		end if;
			
		if(SCHEDULER_STATE = 1) then
			-- start AUX_DAC1
			SCHEDULER_STATE <= SCHEDULER_STATE + 1;
		elsif(SCHEDULER_STATE = 2) then
			-- clear DAC1 START
			SCHEDULER_STATE <= SCHEDULER_STATE + 1;
		elsif(SCHEDULER_STATE = 3) and (AUX_DAC1_DONE  = '1') then
			-- AUX_DAC1 last transaction is complete. 
			SCHEDULER_STATE <= 0;
		elsif(SCHEDULER_STATE = 4)  then
			-- start AUX_DAC2
			SCHEDULER_STATE <= SCHEDULER_STATE + 1;
		elsif(SCHEDULER_STATE = 5) then
			-- clear DAC2 START
			SCHEDULER_STATE <= SCHEDULER_STATE + 1;
		elsif(SCHEDULER_STATE = 6) and (AUX_DAC2_DONE  = '1') then
			-- AUX_DAC2 last transaction is complete. 
			SCHEDULER_STATE <= 0;
		elsif(SCHEDULER_STATE = 7) then
			-- start AUX_ADC1
			SCHEDULER_STATE <= SCHEDULER_STATE + 1;
		elsif(SCHEDULER_STATE = 8) then
			-- clear ADC1 START
			SCHEDULER_STATE <= SCHEDULER_STATE + 1;
		elsif(SCHEDULER_STATE = 9) and (AUX_ADC1_DONE = '1') then
			-- AUX_ADC1 last transaction is complete. 
			SCHEDULER_STATE <= 0;
		end if;
			
	end if;
end process;

AUX_DAC1_ENABLE <= '1' when (SCHEDULER_STATE = 1) else '0';
AUX_DAC2_ENABLE <= '1' when (SCHEDULER_STATE = 4) else '0';
AUX_ADC1_ENABLE <= '1' when (SCHEDULER_STATE = 7) else '0';

AUX_SPI1 <= AUXDAC1_SDIN when (SCHEDULER_STATE = 1) or (SCHEDULER_STATE = 2) or (SCHEDULER_STATE = 3) else 
				AUXDAC2_SDIN when (SCHEDULER_STATE = 4) or (SCHEDULER_STATE = 5) or (SCHEDULER_STATE = 6) else 
				'Z';

AUX_SPI2 <= AUXDAC1_SCLK when (SCHEDULER_STATE = 1) or (SCHEDULER_STATE = 2) or (SCHEDULER_STATE = 3) else 
				AUXDAC2_SCLK when	(SCHEDULER_STATE = 4) or (SCHEDULER_STATE = 5) or (SCHEDULER_STATE = 6) else 
				AUXADC1_SCLK when (SCHEDULER_STATE = 7) or (SCHEDULER_STATE = 8) or (SCHEDULER_STATE = 9) else
				'0';

AUX_SPI3 <= AUX_SPI3_local when (SCHEDULER_STATE = 1) or (SCHEDULER_STATE = 2) or (SCHEDULER_STATE = 3) else '1';
AUX_SPI4 <= AUX_SPI4_local when (SCHEDULER_STATE = 4) or (SCHEDULER_STATE = 5) or (SCHEDULER_STATE = 6) else '1';
AUX_SPI5 <= AUX_SPI5_local when (SCHEDULER_STATE = 7) or (SCHEDULER_STATE = 8) or (SCHEDULER_STATE = 9) else '1';

end Behavioral;

