--******************************************************************************
--* @short      Muon Merger. Merges the RPC and DT/CSC muons.
--*
--******************************************************************************
--* @author  SAKULIN Hannes  <hsakulin@dsy-srv3.cern.ch>
--* @date    $Date: 2005/01/31 15:17:29 $
--* @version $Revision: 1.3 $
--******************************************************************************
--/
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.Numeric_Std.all;
use WORK.GMTTypes.all;
use WORK.LFTypes.all;
use work.LFVMEAddrMap.all;
use work.LFTiming.all;
use work.VMEMux.all;

entity LFMuonMerger is
  
  generic (
    idx_merger            : integer;    -- 0: brl, 1: fwd
    muon_merger_lat_start : integer := 4);  -- start latency

  port (
    -- INPUTS
    iRPCGMTMuons          : in TGMTMu_vector(0 to 3);
    iDTCSCGMTMuons        : in TGMTMu_vector(0 to 3);
    iFineHaloDTCSC        : in std_logic_vector(0 to 3);
    iRPCisMIP,
    iDTCSCisMIP,
    iRPCisISO,
    iDTCSCisISO           : in std_logic_vector (0 to 3); -- 1/2 bx later
    
    iPairMatrix           : in TPairMatrix;
    

    iSelectMatrix_phi     : in TPairMatrix;  -- 1 for DT/CSC
    iSelectMatrix_eta     : in TPairMatrix;
    iSelectMatrix_pt      : in TPairMatrix;
    iSelectMatrix_charge  : in TPairMatrix;
    iSelectMatrix_MIP     : in TPairMatrix;
    iSelectMatrix_ISO     : in TPairMatrix;
  
    iSpecialBit_eta       : in std_logic;
    iSpecialBit_pt        : in std_logic;
    iSpecialBit_charge    : in std_logic;
    iSpecialBit_MIP       : in std_logic;
    iSpecialBit_ISO       : in std_logic;

    iSpecialMIPMergeUseAND : in std_logic;
    iSpecialISOMergeUseAND : in std_logic;
    iHaloOverwritesMatched : in std_logic;

  -- OUTPUTS
    oMergedGMTMuons       : out TGMTMu_vector(0 to 3);
    oIdxBits              : out TIndexBits_vector(0 to 3);

    -- 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 and control
    clk            : in    std_logic;
    sinit          : in    std_logic
  );  
  
end entity LFMuonMerger;

architecture behavioral of LFMuonMerger is

  procedure mux_matrix (
    constant Matrix    : in  TPairMatrix;
    constant idx_dt    : in  integer;
    constant which_rpc : in  std_logic_vector(0 to 3);
    signal   muxedbit  : out std_logic) is
  begin
    muxedbit <= (Matrix(idx_dt,0) and which_rpc(0)) or
                (Matrix(idx_dt,1) and which_rpc(1)) or
                (Matrix(idx_dt,2) and which_rpc(2)) or
                (Matrix(idx_dt,3) and which_rpc(3));
  end;
          
  signal sMergedGMTMuons  : TGMTMu_vector(0 to 3);
  signal sIdxBits         : TIndexBits_vector(0 to 3);

  signal vme_data_out_i   : TVMEData_vec (0 to 3);
  signal vme_en_out_i     : TVMEEnable_vec (0 to 3);
  
begin  -- architecture behavioral
  
  dt: for i in 0 to 3 generate
    signal whichrpc : std_logic_vector(0 to 3);
    signal sMuxedRPCGMTMuon : TGMTMu;

    signal sSelectBit_phi     : std_logic;  -- 1 for DT/CSC
    signal sSelectBit_eta     : std_logic;
    signal sSelectBit_pt      : std_logic;
    signal sSelectBit_charge  : std_logic;
    signal sSelectBit_MIP     : std_logic;
    signal sSelectBit_ISO     : std_logic;
  
    signal sDTCSC_IsMatched : std_logic;

    signal sRPCisMIP   : std_logic;
    signal sRPCisISO   : std_logic;
      
  begin  -- generate merger_unit
    whichrpc <= which_rpc(iPairMatrix, i);

    -- mux the RPC muon
    mux_rpcmu: process (iRPCGMTMuons, whichrpc) is
    begin  -- process mux
      case whichrpc is
        when "1000" => sMuxedRPCGMTMuon <= iRPCGMTMuons(0);
        when "0100" => sMuxedRPCGMTMuon <= iRPCGMTMuons(1);
        when "0010" => sMuxedRPCGMTMuon <= iRPCGMTMuons(2);
        when "0001" => sMuxedRPCGMTMuon <= iRPCGMTMuons(3);
        when others => sMuxedRPCGMTMuon <= ( "00", '0', '0', "000000", "000", "00000", "00000000" );
      end case;
    end process mux_rpcmu;

    -- mux the select matrices
    mux_matrix(iSelectMatrix_phi   , i, whichrpc, sSelectBit_phi   );
    mux_matrix(iSelectMatrix_eta   , i, whichrpc, sSelectBit_eta   );
    mux_matrix(iSelectMatrix_pt    , i, whichrpc, sSelectBit_pt    );
    mux_matrix(iSelectMatrix_charge, i, whichrpc, sSelectBit_charge);
    mux_matrix(iSelectMatrix_MIP   , i, whichrpc, sSelectBit_MIP   );
    mux_matrix(iSelectMatrix_ISO   , i, whichrpc, sSelectBit_ISO   );


    -- mux the Index bits
    mux_idxbits: process (whichrpc) is
    begin  -- process mux
      case whichrpc is
        when "1000" => sIdxBits(i) <= "00" & std_logic_vector(to_unsigned(i,2));
        when "0100" => sIdxBits(i) <= "01" & std_logic_vector(to_unsigned(i,2));
        when "0010" => sIdxBits(i) <= "10" & std_logic_vector(to_unsigned(i,2));
        when "0001" => sIdxBits(i) <= "11" & std_logic_vector(to_unsigned(i,2));
        when others => sIdxBits(i) <= "00" & std_logic_vector(to_unsigned(i,2));
      end case;
    end process mux_idxbits;

    -- mux MIP bits
    sRPCisMIP <= (iRPCisMIP(0) and whichrpc(0)) or
                 (iRPCisMIP(1) and whichrpc(1)) or
                 (iRPCisMIP(2) and whichrpc(2)) or
                 (iRPCisMIP(3) and whichrpc(3));

    -- mux ISO bits
    sRPCisISO <= (iRPCisISO(0) and whichrpc(0)) or
                 (iRPCisISO(1) and whichrpc(1)) or
                 (iRPCisISO(2) and whichrpc(2)) or
                 (iRPCisISO(3) and whichrpc(3));

    -- is the DT/CSC matched ?
    sDTCSC_IsMatched <= whichrpc(0) or whichrpc(1) or whichrpc(2) or whichrpc(3);

    mu: entity work.LFMuonMergerUnit
      generic map (
        idx_merger => idx_merger,
        idx_mu     => i,
        muon_merger_lat_start => muon_merger_lat_start)
      port map (
        iRPCGMTMuon            => sMuxedRPCGMTMuon,
        iDTCSCGMTMuon          => iDTCSCGMTMuons(i),
        
        iFineHaloDTCSC         => iFineHaloDTCSC(i),
        
        iRPCisMIP              => sRPCisMIP,
        iDTCSCisMIP            => iDTCSCisMIP(i),
        iRPCisISO              => sRPCisISO,  
        iDTCSCisISO            => iDTCSCisISO(i),


        iDTCSCisMatched        => sDTCSC_IsMatched,
        
        iSelectBit_phi         => sSelectBit_phi,
        iSelectBit_eta         => sSelectBit_eta,
        iSelectBit_pt          => sSelectBit_pt,
        iSelectBit_charge      => sSelectBit_charge,
        iSelectBit_MIP         => sSelectBit_MIP,
        iSelectBit_ISO         => sSelectBit_ISO,
        
        iSpecialBit_eta        => iSpecialBit_eta,
        iSpecialBit_pt         => iSpecialBit_pt,
        iSpecialBit_charge     => iSpecialBit_charge,
        iSpecialBit_MIP        => iSpecialBit_MIP,
        iSpecialBit_ISO        => iSpecialBit_ISO,
        
        iSpecialMIPMergeUseAND => iSpecialMIPMergeUseAND,
        iSpecialISOMergeUseAND => iSpecialISOMergeUseAND,
        iHaloOverwritesMatched => iHaloOverwritesMatched,
        
        oMergedGMTMuon         => sMergedGMTMuons(i),
        
        vme_addr               => vme_addr,
        vme_data               => vme_data,
        vme_en                 => vme_en,
        vme_wr                 => vme_wr,
        vme_data_out           => vme_data_out_i(i),
        vme_en_out             => vme_en_out_i(i),
        
        clk                    => clk,
        sinit                  => sinit);

   end generate dt;
  

  -- register outputs
  reg_muon: process (clk) is
  begin  
    if clk'event and clk = calc_lf_edge(muon_merger_lat_start + LF_RLAT_MM_DONE) then  
      oMergedGMTMuons <= sMergedGMTMuons;
      oIdxBits <= sIdxBits;
    end if;
  end process reg_muon;

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

end architecture behavioral;