--******************************************************************************
--* @short   Simulation and Spy Logic that goes into the Input or Sort FPGA
--*             
--******************************************************************************
--* @author  SAKULIN Hannes  <hsakulin@dsy-srv5.cern.ch>
--* @date    $Date: 2005/01/13 08:35:55 $
--* @version $Revision: 1.9 $
--******************************************************************************
--/
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.Numeric_std.all;
use work.ReadOutBufTypes.all;
use work.VMEMux.all;
-- pragma translate_off
library UNISIM;
use UNISIM.VCOMPONENTS.all;
-- pragma translate_on

entity SimuSpyLogic is
  
  generic (
    depth1k                     : integer := 0;  -- 0 for 4k, 1 for 1k
    nwords                      : integer := 4;   -- width of readout logic in 32bit words
    simuspyconfig_reg_addr      : integer;
    spydepth_reg_addr           : integer;
    spyarmpulse_reg_addr        : integer;
    spydone_reg_addr            : integer;
    simuspyram_vme_base_address : integer := 16#10000#);

  port (
    iData          : in TReadoutData_vec(0 to nwords-1);
    
    iPreBCRes      : in std_logic;
    iBCRes         : in std_logic;

    oData          : out TReadoutData_vec(0 to nwords-1);
    oSimuMode      : out std_logic;
    oDummyIsBCReset: out std_logic;
    
    -- VME port 
    vme_addr       : in    std_logic_vector;
    vme_data       : in    std_logic_vector;
    vme_en         : in    std_logic;
    vme_wr         : in    std_logic;

    vme_data_out   : out   std_logic_vector(15 downto 0);
    vme_en_out     : out   std_logic;

    -- Clock, control
    clk            : in    std_logic;
    reset          : in    std_logic
    );  

end entity SimuSpyLogic;


architecture behavioral of SimuSpyLogic is

  component simuspy4k
	port (
	addra: IN std_logic_VECTOR(12 downto 0);
	addrb: IN std_logic_VECTOR(11 downto 0);
	clka: IN std_logic;
	clkb: IN std_logic;
	dina: IN std_logic_VECTOR(15 downto 0);
	dinb: IN std_logic_VECTOR(31 downto 0);
	douta: OUT std_logic_VECTOR(15 downto 0);
	doutb: OUT std_logic_VECTOR(31 downto 0);
	ena: IN std_logic;
	enb: IN std_logic;
	wea: IN std_logic;
	web: IN std_logic);
  end component;

  component simuspy1k
	port (
	addra: IN std_logic_VECTOR(10 downto 0);
	addrb: IN std_logic_VECTOR(9 downto 0);
	clka: IN std_logic;
	clkb: IN std_logic;
	dina: IN std_logic_VECTOR(15 downto 0);
	dinb: IN std_logic_VECTOR(31 downto 0);
	douta: OUT std_logic_VECTOR(15 downto 0);
	doutb: OUT std_logic_VECTOR(31 downto 0);
	ena: IN std_logic;
	enb: IN std_logic;
	wea: IN std_logic;
	web: IN std_logic);
  end component;

-- Synplicity black box declaration
  attribute syn_black_box : boolean;
  attribute syn_black_box of simuspy4k: component is true;
  attribute syn_black_box of simuspy1k: component is true;

  signal rw_addr : std_logic_vector(11 downto 0);  -- 4k
  signal we_simuspy : std_logic;

  signal en_simuspy : std_logic;
  
  signal vme_data_out_i   : TVMEData_vec (0 to nwords);
  signal vme_en_out_i     : TVMEEnable_vec (0 to nwords);

  signal vme_en_i         : TVMEEnable_vec (0 to nwords-1);

begin  -- architecture behavioral

  -----------------------------------------------------------------------------
  --* SimuSpyControlLogic
  -----------------------------------------------------------------------------

  ctrl: entity work.SimuSpyControlLogic
    generic map (
      simuspyconfig_reg_addr => simuspyconfig_reg_addr,
      spydepth_reg_addr      => spydepth_reg_addr,
      spyarmpulse_reg_addr   => spyarmpulse_reg_addr,
      spydone_reg_addr       => spydone_reg_addr)
    port map (
      iPreBCRes       => iPreBCRes,
      iBCRes          => iBCRes,
      
      oSimuMode       => oSimuMode,
      oDummyIsBCReset => oDummyIsBCReset,
      
      oWE_simuspy     => we_simuspy,
      oRW_addr        => rw_addr,
      
      vme_addr        => vme_addr,
      vme_data        => vme_data,
      vme_en          => vme_en,
      vme_wr          => vme_wr,
      
      vme_data_out    => vme_data_out_i(nwords),
      vme_en_out      => vme_en_out_i(nwords),
      
      clk             => clk,
      reset           => reset);
  

  en_simuspy <= '1';
  

  -----------------------------------------------------------------------------
  -- instantiate the Simu/Spy Memory
  -----------------------------------------------------------------------------
  per_dataword: for i in 0 to (nwords -1) generate
  begin  -- generate per_dataword

    -----------------------
    -- vme control logic
    -----------------------
    vme_addr_decode : process (vme_addr, vme_en) is
      variable my_addr_vec  : std_logic_vector(vme_addr'high downto 0);
      variable selected     : boolean;
      variable my_base_addr : integer;                                                 
    begin  -- process vme_addr_decode
      my_base_addr := simuspyram_vme_base_address + i*16384;
      my_addr_vec := std_logic_vector( TO_UNSIGNED (my_base_addr, vme_addr'high+1 ) );
      selected    := my_addr_vec(vme_addr'high downto 14) = vme_addr(vme_addr'high downto 14);
      vme_en_i(i) <= '0' ;
      if selected then
        vme_en_i(i) <= vme_en;
      end if;
    end process vme_addr_decode;

    -- register output enable
    reg_enout: process (clk) is
    begin  
      if clk'event and clk = '1' then
        vme_en_out_i(i) <= vme_en_i(i) ; --and ( not vme_wr );    
      end if;
    end process reg_enout;

    gen_4k: if (depth1k = 0) generate
    begin  -- generate gen_4k
    simuspy_block: simuspy4k
      port map (
        -- VME Port
        addra => vme_addr(13 downto 1),
        dina  => vme_data,
        douta => vme_data_out_i(i),
        clka  => clk,
        wea   => vme_wr,
	ena   => vme_en_i(i),

        -- GMT Port
        addrb => rw_addr,
        dinb  => iData(i),
        doutb => oData(i), 
        clkb  => clk,
        web   => we_simuspy,
        enb   => en_simuspy);      
    end generate gen_4k;

    gen_1k: if (depth1k = 1) generate
    begin  -- generate gen_4k
    simuspy_block: simuspy1k
      port map (
        -- VME Port
        addra => vme_addr(11 downto 1),
        dina  => vme_data,
        douta => vme_data_out_i(i),
        clka  => clk,
        wea   => vme_wr,
	ena   => vme_en_i(i),

        -- GMT Port
        addrb => rw_addr(9 downto 0),
        dinb  => iData(i),
        doutb => oData(i), 
        clkb  => clk,
        web   => we_simuspy,
        enb   => en_simuspy);      
    end generate gen_1k;
    
  end generate per_dataword;

  
  -- multiplex vme_data_output
  mux_vme(vme_data_out_i, vme_en_out_i, vme_data_out, vme_en_out);

end architecture behavioral;