--******************************************************************************
--* @short   16 bit VME register
--******************************************************************************
--* @author  SAKULIN Hannes  <hsakulin@dsy-srv2.cern.ch>
--* @version $Revision: 1.5 $
--* @date    $Date: 2004/12/17 09:30:38 $
--******************************************************************************
--/
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.Numeric_Std.all;

entity VMEReg is
  generic (
    init_val            : std_logic_vector(15 downto 0);  -- type of LUT
    my_vme_base_address : integer := 0); -- VME address of this instance

  port (
    -- data port
    data  : out std_logic_vector(15 downto 0);


    -- VME port
    vme_addr     : in    std_logic_vector;  -- leave unconstrained 
    vme_data     : in    std_logic_vector;  -- leave unconstrained
    vme_en       : in    std_logic;
    vme_wr       : in    std_logic;
    vme_data_out : out   std_logic_vector;                                    
    vme_en_out   : out   std_logic;        
    vme_clk      : in    std_logic;
    reset        : in    std_logic);
end VMEReg;


-------------------------------------------------------------------------------
-- Implementation
-------------------------------------------------------------------------------

architecture behavioral of VMEReg is

  signal vme_en_i   : std_logic;
  signal Q : std_logic_vector(15 downto 0);
  
begin  -- behavioral
  --------------------------------------------------------------------------------
  -- VME port
  --------------------------------------------------------------------------------
  assert vme_data'high <= 15 report "error: max VME data width is 16 bits" severity error;
  assert vme_addr'high >= 5 report "error: VME addr width has to be greater than 5" severity error;

  -- purpose: decode VME address and generate internal enable signal
  --          ( asynchronous )
  vme_addr_decode : process (vme_addr, vme_en) is
    variable my_addr_vec : std_logic_vector(vme_addr'high downto 0);
    variable selected    : boolean;
  begin  -- process vme_addr_decode
    my_addr_vec := std_logic_vector( TO_UNSIGNED ( my_vme_base_address, vme_addr'high+1 ) );
    selected    := my_addr_vec(vme_addr'high downto 1) = vme_addr(vme_addr'high downto 1);
    vme_en_i <= '0' ;
    if selected then
      vme_en_i <= vme_en;
    end if;
  end process vme_addr_decode;

  -- purpose: register data during write
  --          generate VME enable out when addressed (both read and write)
  reg: process (vme_clk, reset) is
  begin  -- process reg
    if reset = '1' then                 -- asynchronous reset 
        Q <= init_val;
        vme_en_out <= '0';
    elsif vme_clk'event and vme_clk = '1' then  -- rising clock edge
      vme_en_out <= vme_en_i;
      if vme_en_i = '1' and vme_wr = '1' then
        Q <= vme_data;
      end if;
    end if;
  end process reg;
  
  data <= Q;
  vme_data_out <= Q;

end behavioral;