--=============================================================================
--! @file DUTInterfaces_rtl.vhd
--=============================================================================
--
-------------------------------------------------------------------------------
-- --
-- University of Bristol, High Energy Physics Group.
-- --
------------------------------------------------------------------------------- --
-- VHDL Architecture fmc_mTLU_lib.DUTInterfaces.rtl
--
--! @brief \n
--! \n
--
--! @author David Cussans , David.Cussans@bristol.ac.uk
--
--! @date 15:09:50 11/09/12
--
--! @version v0.1
--
--! @details
--! Address map:\n
--! 5-bit decoded
--! 0x00000000 - DUT interface mode, two bits per DUT. Up to 12 inputs XXXXXXXXBBAA99887766554433221100\n
--!            - mode: 0 = EUDET mode , 1 = synchronous ( LHC / Timepix ) , 2,3=reserved
--! 
--
--!
--! <b>Dependencies:</b>\n
--!
--! <b>References:</b>\n
--!
--! <b>Modified by:</b>\n
--! Author: 
-------------------------------------------------------------------------------
--! \n\n<b>Last changes:</b>\n
-------------------------------------------------------------------------------
--! @todo <next thing to do> Indicate if the DUT works under AIDA/EUDET style\n
--! <another thing to do> \n
--
--------------------------------------------------------------------------------
-- 
-- Created using using Mentor Graphics HDL Designer(TM) 2010.3 (Build 21)
--
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;

USE work.ipbus.all;
use work.ipbus_reg_types.all;

library unisim;
use unisim.VComponents.all;


ENTITY DUTInterfaces IS
   GENERIC( 
      g_NUM_DUTS    : positive := 3;
      g_IPBUS_WIDTH : positive := 32
   );
   PORT( 
      --busy_from_dut_n_i       : IN     std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);     -- BUSY input from DUTs
      --busy_from_dut_p_i       : IN     std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);     -- BUSY input from DUTs
      clk_4x_logic_i          : IN     std_logic;
      clk_from_dut_n_i        : IN     std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);     -- clocks trigger data when in EUDET mode
      clk_from_dut_p_i        : IN     std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);     -- clocks trigger data when in EUDET mode
      ipbus_clk_i             : IN     std_logic;
      ipbus_i                 : IN     ipb_wbus;                                     -- Signals from IPBus core to slave
      ipbus_reset_i           : IN     std_logic;
      strobe_4x_logic_i       : IN     std_logic;                                    -- ! goes high every 4th clock cycle
      trigger_counter_i       : IN     std_logic_vector (g_IPBUS_WIDTH-1 DOWNTO 0);
      trigger_i               : IN     std_logic;                                    -- goes high when trigger logic issues a trigger
	 --shutter_i               : IN     std_logic;                                    -- goes high when trigger logic issues a shutter
      ipbus_o                 : OUT    ipb_rbus;                                     -- signals from slave to IPBus core
      --reset_or_clk_to_dut_n_o : OUT    std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);     -- ! Either reset line or trigger
      --reset_or_clk_to_dut_p_o : OUT    std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);     -- ! Either reset line or trigger
      --trigger_to_dut_n_o      : OUT    std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);     -- ! Trigger output
      --trigger_to_dut_p_o      : OUT    std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);     -- ! Trigger output
		--shutter_to_dut_n_o    : OUT    std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);     -- ! Shutter output
    --shutter_to_dut_p_o      : OUT    std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);     -- ! Shutter output
		output_0_p					: OUT 	std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);
		output_0_n					: OUT 	std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);
		output_1_p					: OUT 	std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);
		output_1_n					: OUT 	std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);
		output_2_p					: OUT 	std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);
		output_2_n					: OUT 	std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);
		output_3_p					: OUT 	std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);
		output_3_n					: OUT 	std_logic_vector (g_NUM_DUTS-1 DOWNTO 0);
      veto_o                  : OUT    std_logic                                     -- goes high when one or more DUT are busy
   );

-- Declarations

END ENTITY DUTInterfaces ;

--
ARCHITECTURE rtl OF DUTInterfaces IS

  signal s_intermediate_busy_or : std_logic_vector(g_NUM_DUTS downto 0);  -- OR tree
  signal s_veto : std_logic;
  signal s_strobe_4x_logic_d1, clk_2x_logic : std_logic;
  signal s_busy_from_dut , s_clk_from_dut , s_reset_or_clk_to_dut , s_trigger_to_dut , s_shutter_to_dut: std_logic_vector(g_NUM_DUTS-1 downto 0);
  signal s_DUT_mask : std_logic_vector(g_NUM_DUTS-1 downto 0) := (others => '0');   	--! Mask for the DUTs not used
  signal s_EnableOutput : std_logic_vector(g_IPBUS_WIDTH-1 downto 0) := (others => '0');
  
  constant c_N_CTRL : positive := 2;
  constant c_N_STAT : positive := 2;
  signal s_status_to_ipbus, s_sync_status_to_ipbus : ipb_reg_v(c_N_STAT-1 downto 0);
  signal s_control_from_ipbus,s_sync_control_from_ipbus  : ipb_reg_v(c_N_CTRL-1 downto 0);
BEGIN

  
  -- Dummy code.
  s_intermediate_busy_or(0) <= '0';
   --s_busy_from_dut(g_NUM_DUTS-1 downto 0) <= (others=>'0');
  
  -----------------------------------------------------------------------------
  -- IPBus interface 
  -----------------------------------------------------------------------------
  ipbus_registers: entity work.ipbus_ctrlreg_v
    generic map(
      N_CTRL => c_N_CTRL,
      N_STAT => c_N_STAT
      )
    port map(
      clk => ipbus_clk_i,
      reset=> '0',--ipbus_reset_i ,
      ipbus_in=>  ipbus_i,
      ipbus_out=> ipbus_o,
      d=>  s_sync_status_to_ipbus,
      q=>  s_control_from_ipbus,
      stb=>  open
      );

  -- Synchronize registers from logic clock to ipbus.
    sync_status: entity work.synchronizeRegisters
    generic map (
      g_NUM_REGISTERS => c_N_STAT )
    port map (
      clk_input_i => clk_4x_logic_i,
      data_i      =>  s_status_to_ipbus,
      data_o      => s_sync_status_to_ipbus,
      clk_output_i => ipbus_clk_i);

    -- Synchronize registers from logic clock to ipbus.
    sync_ctrl: entity work.synchronizeRegisters
    generic map (
      g_NUM_REGISTERS => c_N_CTRL )
    port map (
      clk_input_i => ipbus_clk_i,
      data_i      =>  s_control_from_ipbus,
      data_o      => s_sync_control_from_ipbus,
      clk_output_i => clk_4x_logic_i);

	-- Map the control registers
	s_DUT_mask <= s_sync_control_from_ipbus(0)(g_NUM_DUTS-1 downto 0);
	s_EnableOutput <= s_sync_control_from_ipbus(1);
	
	-- Map the status registers
	s_status_to_ipbus(0) <= std_logic_vector(to_unsigned(0,g_IPBUS_WIDTH-g_NUM_DUTS)) & s_DUT_mask;
	s_status_to_ipbus(1) <= s_EnableOutput;
  
  
   -- purpose: Writes in the positive pin of the signals an 80MHz clock and the strobe_4x_logic_i in the negative one.
					--The output signals (one signal is an lvds pair) can be enabled independently in the s_EnableOutput via IPBus.
	-- type   : combinational
	-- inputs : clk_2x_logic , strobe_4x_logic_i, s_EnableOutput
	-- outputs: output_0_p, output_0_n, output_1_p, output_1_n, output_2_p, output_2_n, output_3_p, output_3_n
	duts: for dut in 1 to g_NUM_DUTS generate
		
		output_0_p_inst : OBUF
      port map (
        O =>  output_0_p(dut-1),     					
        I =>  s_EnableOutput(0) and clk_2x_logic   -- Buffer input 
      );
		output_0_n_inst : OBUF
      port map (
        O =>  output_0_n(dut-1),     						
        I =>  s_EnableOutput(0) and strobe_4x_logic_i   -- Buffer input 
      );
		
		output_1_p_inst : OBUF
      port map (
        O =>  output_1_p(dut-1),     						
        I =>  s_EnableOutput(1) and clk_2x_logic   -- Buffer input 
      );
		output_1_n_inst : OBUF
      port map (
        O =>  output_1_n(dut-1),     						
        I =>  s_EnableOutput(1) and strobe_4x_logic_i   -- Buffer input 
      );
		
		output_2_p_inst : OBUF
      port map (
        O =>  output_2_p(dut-1),     					
        I =>  s_EnableOutput(2) and clk_2x_logic   -- Buffer input 
      );
		output_2_n_inst : OBUF
      port map (
        O =>  output_2_n(dut-1),     						
        I =>  s_EnableOutput(2) and strobe_4x_logic_i   -- Buffer input 
      );
		output_3_p_inst : OBUF
      port map (
        O =>  output_3_p(dut-1),     						
        I =>  s_EnableOutput(3) and clk_2x_logic   -- Buffer input 
      );
		output_3_n_inst : OBUF
      port map (
        O =>  output_3_n(dut-1),     						
        I =>  s_EnableOutput(3) and strobe_4x_logic_i   -- Buffer input 
      );
		
     
    s_intermediate_busy_or(dut) <= s_intermediate_busy_or(dut-1) or
                                   (s_busy_from_dut(dut-1) and
											  s_DUT_mask(dut-1));
                                     
  end generate duts;

    s_veto <=  s_intermediate_busy_or(g_NUM_DUTS);
	clk_2x_logic <= s_strobe_4x_logic_d1 or strobe_4x_logic_i;  --80 MHz clock
	
  -- purpose: register for internal signals and output signals
  -- type   : combinational
  -- inputs : clk_4x_logic_i , strobe_4x_logic_i , s_veto
  -- outputs: veto_o
  register_signals: process (clk_4x_logic_i)-- , strobe_4x_logic_i , s_veto)
  begin  -- process register_signals
    if rising_edge(clk_4x_logic_i) then
      veto_o <= s_veto;
      s_strobe_4x_logic_d1 <= strobe_4x_logic_i;
      s_reset_or_clk_to_dut <= ( others => (s_strobe_4x_logic_d1 or strobe_4x_logic_i));      
      s_trigger_to_dut <= ( others => trigger_i );
		  --shutter_to_dut <= ( others => shutter_i );
    end if;
  end process register_signals;
  
END ARCHITECTURE rtl;

