--******************************************************************************
--* @short   Error Monitor for 4 x 4 bits. 
--*
--*          The error monitor monitors up to four bits for four muons.
--*          An error status register indicates whether any of the bits were
--*          set since  the status register was last read. Reading the status
--*          register clears the error bits.
--*          The status register contains in its lowest four bits the error
--*          flags of of muon 0, in the next four bits the error flags of muon
--*          1 and so forth.
--*
--*          The number of events with an error bit set is separately counted
--*          for each bit over the period of an orbit. The counters are
--*          automatically cleared at each bc_reset. This means that the value
--*          read corresponds to the orbit just before the VME read.
--*
--******************************************************************************
--* @author  SAKULIN Hannes  <hsakulin@dsy-srv2.cern.ch>
--* @version $Revision: 1.1 $
--* @date    $Date: 2005/01/10 16:30:16 $x
--******************************************************************************
--/
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.Numeric_Std.all;
use work.VMEMux.all;
use work.IFVMEAddrMap.all;

entity ErrorMonitor4x4bit is
  generic (
    status_register_address : integer := 0;
    counter_register_addresses : TBaseArray(0 to 3)); 

  port (
    -- data port
    bit0 : in std_logic_vector(0 to 3);
    bit1 : in std_logic_vector(0 to 3);
    bit2 : in std_logic_vector(0 to 3);
    bit3 : in std_logic_vector(0 to 3);
    
    bc_reset     : in    std_logic;

    -- 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;

    
    clk          : in    std_logic;
    reset        : in    std_logic);

end ErrorMonitor4x4bit;


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

architecture behavioral of ErrorMonitor4x4bit is

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

  signal vme_en_out_d : std_logic;
  signal vme_en_out_status_pulse : std_logic;
  
  signal error_flags : std_logic_vector(15 downto 0);
  
begin  -- behavioral

  -----------------------------------------------------------------------------
  --* generate error flags
  -----------------------------------------------------------------------------
  gen_error_flags: process (clk, reset) is
  begin  -- process gen_error_flags
    if reset = '1' then
      error_flags <= ( others => '0');
    elsif clk'event and clk = '1' then

      if vme_en_out_status_pulse = '1' then
        error_flags <= ( others => '0');
      else  
        for imu in 0 to 3 loop
     
          if bit0(imu) = '1' then
            error_flags(4*imu) <= '1';
          end if;
     
          if bit1(imu) = '1' then
            error_flags(4*imu+1) <= '1';
          end if;
     
          if bit2(imu) = '1' then
            error_flags(4*imu+2) <= '1';
          end if;
     
          if bit3(imu) = '1' then
            error_flags(4*imu+3) <= '1';
          end if;
          
        end loop;  -- imu
      end if;

    end if;
  end process gen_error_flags;

  -----------------------------------------------------------------------------
  --* error flag register
  -----------------------------------------------------------------------------
  error_flag_reg: entity work.VMEStatusReg
    generic map (
      my_vme_base_address => status_register_address)
    port map (
      data         => error_flags,
      vme_addr     => vme_addr,
      vme_en       => vme_en,
      vme_wr       => vme_wr,
      vme_data_out => vme_data_out_i(16),
      vme_en_out   => vme_en_out_i(16),
      vme_clk      => clk,
      reset        => reset);


  -----------------------------------------------------------------------------
  --* generate pulse when enable for status register read is cleared
  -----------------------------------------------------------------------------
  gen_enable_out_pulse: process (clk, reset) is
  begin  -- process gen_enable_out_pulse
    if reset = '1' then
      vme_en_out_d <= '0';
      vme_en_out_status_pulse <= '0';
    elsif clk'event and clk = '1' then  -- rising clock edge
      vme_en_out_d <= vme_en_out_i(16);
      vme_en_out_status_pulse <= vme_en_out_d and not vme_en_out_i(16);
    end if;
  end process gen_enable_out_pulse;
  

  -----------------------------------------------------------------------------
  -- generate error counters
  -----------------------------------------------------------------------------


  gen_counters: for imu in 0 to 3 generate
  begin  -- generate gen_counters
    
    error_counter0: entity work.ErrorCounter
      generic map (
        my_vme_base_address => counter_register_addresses(imu))
      port map (
        count_enable => bit0(imu),
        bc_reset   => bc_reset,
        vme_addr     => vme_addr,  vme_en => vme_en, vme_wr => vme_wr,
        vme_data_out => vme_data_out_i(0+4*imu),
        vme_en_out   => vme_en_out_i(0+4*imu),
        clk          => clk, reset => reset);
    
    error_counter1: entity work.ErrorCounter
      generic map (
        my_vme_base_address => counter_register_addresses(imu)+2)
      port map (
        count_enable => bit1(imu),
        bc_reset   => bc_reset,
        vme_addr     => vme_addr,  vme_en => vme_en, vme_wr => vme_wr,
        vme_data_out => vme_data_out_i(1+4*imu),
        vme_en_out   => vme_en_out_i(1+4*imu),
        clk          => clk, reset => reset);
    
    error_counter2: entity work.ErrorCounter
      generic map (
        my_vme_base_address => counter_register_addresses(imu)+4)
      port map (
        count_enable => bit2(imu),
        bc_reset   => bc_reset,
        vme_addr     => vme_addr,  vme_en => vme_en, vme_wr => vme_wr,
        vme_data_out => vme_data_out_i(2+4*imu),
        vme_en_out   => vme_en_out_i(2+4*imu),
        clk          => clk, reset => reset);
    
    error_counter3: entity work.ErrorCounter
      generic map (
        my_vme_base_address => counter_register_addresses(imu)+6)
      port map (
        count_enable => bit3(imu),
        bc_reset   => bc_reset,
        vme_addr     => vme_addr,  vme_en => vme_en, vme_wr => vme_wr,
        vme_data_out => vme_data_out_i(3+4*imu),
        vme_en_out   => vme_en_out_i(3+4*imu),
        clk          => clk, reset => reset);
    
    
  end generate gen_counters;

  -----------------------------------------------------------------------------
  -- multiplex VME outputs
  -----------------------------------------------------------------------------
  mux_vme(vme_data_out_i, vme_en_out_i, vme_data_out, vme_en_out);
  
end behavioral;