--******************************************************************************
--* @short   Control Logic for Simulation And Spy Logic
--*
--*          This control logic is used in the SimuSpyLogic and in the
--*          MIAUSimuLogic.
--*
--*          Via VME Command and Status registers it generated control signals
--*          for the simulation and spy logic.
--*
--*    @port iPreBCRes is a BC-reset pulse used when simulationg data
--*    @port iBCRes is the BC-reset pulse used in spy-mode
--*
--*    @port oSimuMode is 1 in simulation mode, 0 in spy mode
--*    @port oDummyIsBCReset is 1 if the dummy input should be used as a
--*          bcreset at chip level (for asynchronous tests)
--*
--*    @port oWE_simuspy is the WE signal for the Simu/Spy memory in spy-mode
--*    @port oRW_addr is the r/w address for the Simu/Spy memory      
--*
--******************************************************************************
--* @author  SAKULIN Hannes  <hsakulin@dsy-srv5.cern.ch>
--* @date    $Date: 2005/01/19 15:35:30 $
--* @version $Revision: 1.1 $
--******************************************************************************
--/
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.Numeric_std.all;
use work.VMEMux.all;
-- pragma translate_off
library UNISIM;
use UNISIM.VCOMPONENTS.all;
-- pragma translate_on

entity SimuSpyControlLogic is
  
  generic (
    simuspyconfig_reg_addr      : integer;
    spydepth_reg_addr           : integer;
    spyarmpulse_reg_addr        : integer;
    spydone_reg_addr            : integer);

  port (
    
    iPreBCRes      : in std_logic;
    iBCRes         : in std_logic;

    oSimuMode      : out std_logic;
    oDummyIsBCReset: out std_logic;

    oWE_simuspy    : out std_logic;
    oRW_addr       : out std_logic_vector(11 downto 0);  -- 4k
    
    -- 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 SimuSpyControlLogic;


architecture behavioral of SimuSpyControlLogic is

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

  signal spy_armed  : std_logic;

  signal full_pulse    : std_logic := '0';

  signal sBCRes : std_logic;
  signal sSimuSpyConfig_Reg : std_logic_vector(15 downto 0);
  signal sSpyDepth          : std_logic_vector(15 downto 0);
  signal sSpyArmPulse       : std_logic_vector(15 downto 0);
  signal sSpyDone           : std_logic_vector(15 downto 0);
  
  signal vme_data_out_i   : TVMEData_vec (0 to 3);
  signal vme_en_out_i     : TVMEEnable_vec (0 to 3);

begin  -- architecture behavioral

  -----------------------------------------------------------------------------
  --* SIMU/SPY Config Register
  -----------------------------------------------------------------------------
  -- 
  -- 0   0   0   0  |  0   0   0   0   |  0   0   0   0   |  0   0   0   0
  --
  --                                                                     mode 0:spy
  --                                                                     1: simulate
  --
  --                                                                  use dummy
  --                                                                  as bcreset
  --
  
  simuspy_config_reg: entity work.VMEReg
    generic map (
      init_val            => "0000000000000000",
      my_vme_base_address => simuspyconfig_reg_addr )
    port map (
      data         => sSimuSpyConfig_Reg,        
      reset        => reset,
      
      vme_addr => vme_addr, vme_data => vme_data, vme_en => vme_en, vme_wr => vme_wr,
      vme_data_out => vme_data_out_i(0),
      vme_en_out   => vme_en_out_i(0),
      vme_clk      => clk);

  oSimuMode       <= sSimuSpyConfig_Reg(0);
  oDummyIsBCReset <= sSimuSpyConfig_Reg(1);

  -----------------------------------------------------------------------------
  --* Spy Depth register (last address of spy in 32-bit words)
  -----------------------------------------------------------------------------  
  spy_depth_reg: entity work.VMEReg
    generic map (
      init_val            => "0000001111111111",
      my_vme_base_address => spydepth_reg_addr )
    port map (
      data         => sSpyDepth,        
      reset        => reset,
      
      vme_addr => vme_addr, vme_data => vme_data, vme_en => vme_en, vme_wr => vme_wr,
      vme_data_out => vme_data_out_i(1),
      vme_en_out   => vme_en_out_i(1),
      vme_clk      => clk);

  -----------------------------------------------------------------------------
  --* Spy ARM register. Write to it to arm the spy.
  -----------------------------------------------------------------------------
    simu_arm_pulse_reg: entity work.VMEWritePulseReg
    generic map (
      my_vme_base_address => spyarmpulse_reg_addr )
    port map (
      data_pulse   => sSpyArmPulse,        
      reset        => reset,
      
      vme_addr => vme_addr, vme_data => vme_data, vme_en => vme_en, vme_wr => vme_wr,
      vme_data_out => vme_data_out_i(2),
      vme_en_out   => vme_en_out_i(2),
      vme_clk      => clk);

  -----------------------------------------------------------------------------
  --* Spy Arm logic
  --*
  --* Spy is armed with a pulse
  --* write_enable is set at next bcreset
  --* write enable is cleared at 2nd bcreset or counter full
  -----------------------------------------------------------------------------

  spy_arm_logic: process (clk, reset) is
  begin  -- process spy_arm_logic
    if reset = '1' then
      spy_armed <= '0';
      we_simuspy <= '0';
      sSpyDone <= "0000000000000000";
    elsif clk'event and clk = '1' then
      if sSimuSpyConfig_Reg(0) = '0' then -- only in spy mode

        -- arm the spy with a VME write
        if sSpyArmPulse(0) = '1' then
          spy_armed <= '1';          
          sSpyDone <= "0000000000000000";
        end if;

        -- enable wites at the next BCreset
        if spy_armed = '1' and sBCRes = '1' then
          we_simuspy <= '1';
          spy_armed <= '0';
        end if;

        -- disable writes at the following BCreset or full pulse
        if we_simuspy = '1' and (sBCRes = '1' or full_pulse = '1') then
          we_simuspy <= '0';
          sSpyDone <= "0000000000000001";
        end if;
        
      end if;      
    end if;
  end process spy_arm_logic;
  
  -----------------------------------------------------------------------------
  --* Spy Done Register
  -----------------------------------------------------------------------------
  spy_done_reg: entity work.VMEStatusReg
    generic map (
      my_vme_base_address => spydone_reg_addr)
    port map (
      data         => sSpyDone,

      vme_addr => vme_addr, vme_en => vme_en, vme_wr => vme_wr,
      vme_data_out => vme_data_out_i(3),
      vme_en_out   => vme_en_out_i(3),
      vme_clk      => clk,
      reset        => reset);
  
  -----------------------------------------------------------------------------
  -- read/write counter
  -----------------------------------------------------------------------------
  -- in simulation mode, need to reset the counter earlier
  sBCRes <= iPreBCRes when sSimuSpyConfig_Reg(0) = '1' else iBCRes;  
  
  rw_counter: process (clk, reset) is
    variable counter : std_logic_vector(11 downto 0) := "000000000000";
  begin  -- process rw_counter (12 bit)
    if reset = '1' then
      counter := "000000000000";
      full_pulse <= '0';      
    elsif clk'event and clk = '1' then
      if sBCRes = '1' then
        counter := "000000000000";
      else
        counter := std_logic_vector(TO_UNSIGNED(TO_INTEGER(UNSIGNED(counter))+1,12));
        if counter = sSpyDepth(11 downto 0) then
          full_pulse <= '1';
        else
          full_pulse <= '0';
        end if;
      end if;
    end if;
    rw_addr <= counter;
  end process rw_counter;


  
  oWE_simuspy <= we_simuspy;
  oRW_addr <= rw_addr;

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