--******************************************************************************
--* @short   Block of CHIP ID and revision / date registers
--*
--*          provides access to a number of consecutive all read-only registers 
--******************************************************************************
--* @author  SAKULIN Hannes  <hsakulin@dsy-srv2.cern.ch>
--* @version $Revision: 1.3 $
--* @date    $Date: 2005/01/13 17:12:23 $
--******************************************************************************
--/
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.Numeric_Std.all;
use work.VMEMux.all;

entity ChipIDRegisters is
  generic (
    idregisters_vme_base_address : integer := 0; -- VME address of this instance
    chipID_h                     : natural := 0;
    chipID_l                     : natural := 0;
    chipRev_h                    : natural := 0;
    chipRev_l                    : natural := 0;
    date_string                  : string  := "$Date: 2005/01/13 17:12:23 $");

  port (
    -- VME port
    vme_addr     : 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 ChipIDRegisters;


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

architecture behavioral of ChipIDRegisters is

  signal vme_data_out_i : TVMEData_vec (0 to 7);
  signal vme_en_out_i   : TVMEEnable_vec (0 to 7);

  function date_from_string (
    constant date_string : string)
    return std_logic_vector is
    variable res  : std_logic_vector(31 downto 0);
  begin  -- function date_from_string
    res := std_logic_vector(TO_UNSIGNED(character'POS(date_string( 8))-character'POS('0'),4)) &
           std_logic_vector(TO_UNSIGNED(character'POS(date_string( 9))-character'POS('0'),4)) &
           std_logic_vector(TO_UNSIGNED(character'POS(date_string(10))-character'POS('0'),4)) &
           std_logic_vector(TO_UNSIGNED(character'POS(date_string(11))-character'POS('0'),4)) &
           std_logic_vector(TO_UNSIGNED(character'POS(date_string(13))-character'POS('0'),4)) &
           std_logic_vector(TO_UNSIGNED(character'POS(date_string(14))-character'POS('0'),4)) &
           std_logic_vector(TO_UNSIGNED(character'POS(date_string(16))-character'POS('0'),4)) &
           std_logic_vector(TO_UNSIGNED(character'POS(date_string(17))-character'POS('0'),4));
    return res;
  end function date_from_string;

  function time_from_string (
    constant date_string : string)
    return std_logic_vector is
    variable res  : std_logic_vector(31 downto 0);
  begin  -- function time_from_string
    res := "11111111" &
           std_logic_vector(TO_UNSIGNED(character'POS(date_string(19))-character'POS('0'),4)) &
           std_logic_vector(TO_UNSIGNED(character'POS(date_string(20))-character'POS('0'),4)) &
           std_logic_vector(TO_UNSIGNED(character'POS(date_string(22))-character'POS('0'),4)) &
           std_logic_vector(TO_UNSIGNED(character'POS(date_string(23))-character'POS('0'),4)) &
           std_logic_vector(TO_UNSIGNED(character'POS(date_string(25))-character'POS('0'),4)) &
           std_logic_vector(TO_UNSIGNED(character'POS(date_string(26))-character'POS('0'),4));
    return res;
  end function time_from_string;

  
begin  -- behavioral

  id0: entity work.VMEReadOnlyReg
    generic map (
      init_val            => (std_logic_vector(TO_UNSIGNED(chipID_l,16))),
      my_vme_base_address => idregisters_vme_base_address)
    port map (
      vme_addr     => vme_addr,
      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      => vme_clk,
      reset        => reset);
  
  id1: entity work.VMEReadOnlyReg
    generic map (
      init_val            => (std_logic_vector(TO_UNSIGNED(chipID_h,16))),
      my_vme_base_address => idregisters_vme_base_address + 2)
    port map (
      vme_addr     => vme_addr,
      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      => vme_clk,
      reset        => reset);
  
  rev0: entity work.VMEReadOnlyReg
    generic map (
      init_val            => (std_logic_vector(TO_UNSIGNED(chipRev_l,16))),
      my_vme_base_address => idregisters_vme_base_address + 4)
    port map (
      vme_addr     => vme_addr,
      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      => vme_clk,
      reset        => reset);
  
  rev1: entity work.VMEReadOnlyReg
    generic map (
      init_val            => (std_logic_vector(TO_UNSIGNED(chipRev_h,16))),
      my_vme_base_address => idregisters_vme_base_address + 6)
    port map (
      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      => vme_clk,
      reset        => reset);
  
  date0: entity work.VMEReadOnlyReg
    generic map (
      init_val            => date_from_string(date_string)(15 downto 0),
      my_vme_base_address => idregisters_vme_base_address + 8)
    port map (
      vme_addr     => vme_addr,
      vme_en       => vme_en,
      vme_wr       => vme_wr,
      vme_data_out => vme_data_out_i(4),
      vme_en_out   => vme_en_out_i(4),
      vme_clk      => vme_clk,
      reset        => reset);
  
  date1: entity work.VMEReadOnlyReg
    generic map (
      init_val            => date_from_string(date_string)(31 downto 16),
      my_vme_base_address => idregisters_vme_base_address + 10)
    port map (
      vme_addr     => vme_addr,
      vme_en       => vme_en,
      vme_wr       => vme_wr,
      vme_data_out => vme_data_out_i(5),
      vme_en_out   => vme_en_out_i(5),
      vme_clk      => vme_clk,
      reset        => reset);

  time0: entity work.VMEReadOnlyReg
    generic map (
      init_val            => time_from_string(date_string)(15 downto 0),
      my_vme_base_address => idregisters_vme_base_address + 12)
    port map (
      vme_addr     => vme_addr,
      vme_en       => vme_en,
      vme_wr       => vme_wr,
      vme_data_out => vme_data_out_i(6),
      vme_en_out   => vme_en_out_i(6),
      vme_clk      => vme_clk,
      reset        => reset);
  
  time1: entity work.VMEReadOnlyReg
    generic map (
      init_val            => time_from_string(date_string)(31 downto 16),
      my_vme_base_address => idregisters_vme_base_address + 14)
    port map (
      vme_addr     => vme_addr,
      vme_en       => vme_en,
      vme_wr       => vme_wr,
      vme_data_out => vme_data_out_i(7),
      vme_en_out   => vme_en_out_i(7),
      vme_clk      => vme_clk,
      reset        => reset);

  mux_vme(vme_data_out_i, vme_en_out_i, vme_data_out, vme_en_out);

end behavioral;