--******************************************************************************
--* @short   Conversion Unit. Converts the DT/CSC and RPC muons into GMT format.
--******************************************************************************
--* @author  SAKULIN Hannes  <hsakulin@dsy-srv3.cern.ch>
--* @date    $Date: 2005/01/31 15:17:29 $
--* @version $Revision: 1.5 $
--******************************************************************************
--/
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 LFConversionUnit is
  
  generic (
    conversion_unit_idx       : integer := 0;   -- 0: brl, 1:fwd
    conversion_unit_lat_start : integer := 0);  -- start latency

  port (
    -- INPUTS
    iDTCSCMuons    : in TSyncedMu_vector4;  -- at 0
    iRPCMuons      : in TSyncedMu_vector4;  -- at 0

    iVLQbitsDTCSC  : in TVLQbits_vector(0 to 3);
    iVLQbitsRPC    : in TVLQbits_vector(0 to 3);
    
    -- OUTPUTS after 1 bx
    oDTCSCGMTMuons : out TGMTMu_vector4;  -- after 1 bx
    oRPCGMTMuons   : out TGMTMu_vector4;  -- after 1 bx
    oFineHaloDTCSC : out std_logic_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 LFConversionUnit;

architecture behavioral of LFConversionUnit is

  signal sDTCSCGMTMuons : TGMTMu_vector4;
  signal sRPCGMTMuons   : TGMTMu_vector4;
  signal sFineHaloDTCSC : std_logic_vector(0 to 3);

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

begin  -- architecture behavioral
  
  conv_DTCSC: for i in 0 to 3 generate
    signal eta_gmt : std_logic_vector(5 downto 0);
  begin  
    sDTCSCGMTMuons(i).pt <= iDTCSCMuons(i).pt;
--    sDTCSCGMTMuons(i).phi <= iDTCSCMuons(i).phi;
    sDTCSCGMTMuons(i).sysign(1) <= not iDTCSCMuons(i).ch_valid;
    sDTCSCGMTMuons(i).sysign(0) <= iDTCSCMuons(i).charge when iDTCSCMuons(i).ch_valid = '1' else '0';        
    sDTCSCGMTMuons(i).mip <= '0';
    sDTCSCGMTMuons(i).isol <= '0';

    -- eta
    etaconv: entity work.lfetaconvlut
      generic map (
        instance_idx        => conversion_unit_idx*2,
        my_vme_base_address => LF_EtaConvLUT_base(0) + i*LF_EtaConvLUT_size
        )
      port map (
        eta_regional => iDTCSCMuons(i).eta,
        eta_gmt      => sDTCSCGMTMuons(i).eta,
        
        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),
        vme_clk      => clk);
    
    -- qual: inputs: q(3) vlq(2) halo(1)
    -- check for halo only in fwd chip
    sDTCSCGMTMuons(i).qual <= std_logic_vector(TO_UNSIGNED(QCODE_HALO,3))
                                when (conversion_unit_idx = 1 and iDTCSCMuons(i).finehalo = '1' ) else
                              std_logic_vector(TO_UNSIGNED(QCODE_DTCSC,3))  when iVLQbitsDTCSC(i) = "00" else
                              std_logic_vector(TO_UNSIGNED(QCODE_VLQ3,3))   when iVLQbitsDTCSC(i) = "11" else
                              std_logic_vector(TO_UNSIGNED(QCODE_VLQ2,3))   when iVLQbitsDTCSC(i) = "10" else
                              std_logic_vector(TO_UNSIGNED(QCODE_VLQ1,3));

    sFineHaloDTCSC(i) <= iDTCSCMuons(i).finehalo;

    -- phi projection
    phipro_dtcsc: entity work.LFPhiProUnit
      generic map (
        phipro_unit_idx       => conversion_unit_idx*2,
        idx_mu                => i,
        phipro_unit_lat_start => conversion_unit_lat_start)
      port map (
        iPhi         => iDTCSCMuons(i).phi,
        iEta         => iDTCSCMuons(i).eta,
        iPt          => iDTCSCMuons(i).pt,
        iCharge      => iDTCSCMuons(i).charge,
        oPhi         => sDTCSCGMTMuons(i).phi,
        
        vme_addr     => vme_addr,
        vme_data     => vme_data,
        vme_en       => vme_en,
        vme_wr       => vme_wr,
        vme_data_out => vme_data_out_i(i+4),
        vme_en_out   => vme_en_out_i(i+4),
        clk          => clk,
        sinit        => sinit);
        
  end generate conv_DTCSC;


  conv_RPC: for i in 0 to 3 generate
    signal eta_gmt : std_logic_vector(5 downto 0);
  begin  
    sRPCGMTMuons(i).pt <= iRPCMuons(i).pt;
--    sRPCGMTMuons(i).phi <= iRPCMuons(i).phi;
    sRPCGMTMuons(i).sysign(1) <= not iRPCMuons(i).ch_valid;
    sRPCGMTMuons(i).sysign(0) <= iRPCMuons(i).charge when iRPCMuons(i).ch_valid = '1' else '0';        
    sRPCGMTMuons(i).mip <= '0';
    sRPCGMTMuons(i).isol <= '0';

    -- eta
    etaconv: entity work.lfetaconvlut
      generic map (
        instance_idx        => conversion_unit_idx*2+1,
        my_vme_base_address => LF_EtaConvLUT_base(1) + i*LF_EtaConvLUT_size
        )
      port map (
        eta_regional => iRPCMuons(i).eta,
        eta_gmt      => sRPCGMTMuons(i).eta,
        
        vme_addr     => vme_addr,
        vme_data     => vme_data,
        vme_en       => vme_en,
        vme_wr       => vme_wr,
        vme_data_out => vme_data_out_i(i+8),
        vme_en_out   => vme_en_out_i(i+8),
        vme_clk      => clk);
    
    -- qual: inputs: q(3) vlq(2) halo(1)
    sRPCGMTMuons(i).qual <= std_logic_vector(TO_UNSIGNED(QCODE_RPC,3))  when iVLQbitsRPC(i) = "00" else
                            std_logic_vector(TO_UNSIGNED(QCODE_VLQ3,3)) when iVLQbitsRPC(i) = "11" else
                            std_logic_vector(TO_UNSIGNED(QCODE_VLQ2,3)) when iVLQbitsRPC(i) = "10" else
                            std_logic_vector(TO_UNSIGNED(QCODE_VLQ1,3));

    -- phi projection
    phipro_rpc: entity work.LFPhiProUnit
      generic map (
        phipro_unit_idx       => conversion_unit_idx*2 + 1,
        idx_mu                => i,
        phipro_unit_lat_start => conversion_unit_lat_start)
      port map (
        iPhi         => iRPCMuons(i).phi,
        iEta         => iRPCMuons(i).eta,
        iPt          => iRPCMuons(i).pt,
        iCharge      => iRPCMuons(i).charge,
        oPhi         => sRPCGMTMuons(i).phi,
        
        vme_addr     => vme_addr,
        vme_data     => vme_data,
        vme_en       => vme_en,
        vme_wr       => vme_wr,
        vme_data_out => vme_data_out_i(i+12),
        vme_en_out   => vme_en_out_i(i+12),
        clk          => clk,
        sinit        => sinit);

  end generate conv_RPC;


  
  reg_outp: process (clk) is
  begin  -- process reg_outp
    if clk'event and clk = calc_lf_edge( conversion_unit_lat_start + LF_RLAT_CONV_DONE) then
      oDTCSCGMTMuons <= sDTCSCGMTMuons;
      oRPCGMTMuons <= sRPCGMTMuons;
      oFineHaloDTCSC <= sFineHaloDTCSC;
    end if;
  end process reg_outp;

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