--******************************************************************************
--* @short      Sort Rank Unit. Assigns sort ranks to all input muons.
--******************************************************************************
--* @author  SAKULIN Hannes  <hsakulin@dsy-srv3.cern.ch>
--* @date    $Date: 2005/01/31 15:17:30 $
--* @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.LFVMERegDefaults.all;
use work.LFTiming.all;
use work.VMEMux.all;

entity LFSortRankUnit is
  
  generic (
    sort_rank_unit_idx       : integer := 0;   -- 0: brl, 1:fwd
    sort_rank_unit_lat_start : integer := 0);  -- start latency

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

    -- OUTPUTS after 1/2 bx => check this.
    oDisableDTCSC : out std_logic_vector(0 to 3);
    oDisableRPC   : out std_logic_vector(0 to 3);  

    -- OUTPUTS after 1 bx
    oSortRankDTCSC        : out TSortRank_vector(0 to 3);  
    oSortRankRPC          : out TSortRank_vector(0 to 3);
    oVLQbitsDTCSC        : out TVLQbits_vector(0 to 3);
    oVLQbitsRPC          : out TVLQbits_vector(0 to 3);

    -- OUTPUTS 1 bx later
    oSortRankMatchedDTCSC : out TSortRank_vector(0 to 3);
    oSortRankMatchedRPC   : out TSortRank_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 LFSortRankUnit;

architecture behavioral of LFSortRankUnit is

  function add (
    constant rank : TSortRank;
    constant ofs  : TSortRank)
    return TSortRank is

    variable vSum : unsigned(8 downto 0);
  begin
    vSum := UNSIGNED(resize (UNSIGNED(rank),9)) + UNSIGNED(resize(UNSIGNED(ofs),9));
    if vSum(8) = '0' then
      return (std_logic_vector(vSum(7 downto 0)));
    else
      return "11111111";
    end if;    
  end;  

  signal vme_data_out_i   : TVMEData_vec (0 to 8);
  signal vme_en_out_i     : TVMEEnable_vec (0 to 8);
  
  signal sSortRankRPC     : TSortRank_vector(0 to 3);
  signal sSortRankDTCSC   : TSortRank_vector(0 to 3);
  
  signal sOffset          : std_logic_vector(15 downto 0);
  
begin  -- architecture behavioral

  -----------------------------------------------------------------------------
  -- instantiate rank assignment units
  -----------------------------------------------------------------------------
  
  sort_rank_DTCSC: for i in 0 to 3 generate
  begin  -- generate sort_rank_DTCSC
    DTCSC: entity work.LFRankAssUnit
      generic map (
        rank_ass_unit_idx       => 2*sort_rank_unit_idx,
        idxmuon                 => i,
        rank_ass_unit_lat_start => sort_rank_unit_lat_start)
      port map (
        iMuon        => iDTCSCMuons(i),
        oSortRank    => sSortRankDTCSC(i),
        oVLQ         => oVLQbitsDTCSC(i),
        oDisableHot  => oDisableDTCSC(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 sort_rank_DTCSC;


  sort_rank_RPC: for i in 0 to 3 generate
  begin  -- generate sort_rank_RPC
    RPC: entity work.LFRankAssUnit
      generic map (
        rank_ass_unit_idx       => 2*sort_rank_unit_idx+1,
        idxmuon                 => i,
        rank_ass_unit_lat_start => sort_rank_unit_lat_start)
      port map (
        iMuon        => iRPCMuons(i),
        oSortRank    => sSortRankRPC(i),
        oVLQ         => oVLQbitsRPC(i),
        oDisableHot  => oDisableRPC(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+4),
        vme_en_out   => vme_en_out_i(i+4),
        clk          => clk,
        sinit        => sinit);
  end generate sort_rank_RPC;

  -----------------------------------------------------------------------------
  -- sort rank offset register
  -----------------------------------------------------------------------------

  -- set default offset, here
  sort_rank_offset: entity work.VMEReg
    generic map (
      init_val            => std_logic_vector(TO_UNSIGNED(LF_SortRankOffset_defaults(sort_rank_unit_idx),16)), 
      my_vme_base_address => LF_SortRankOffset_addr)
    port map (
      data         => sOffset,
      reset        => sinit,
      
      vme_addr     => vme_addr,
      vme_data     => vme_data,
      vme_en       => vme_en,
      vme_wr       => vme_wr,
      vme_data_out => vme_data_out_i(8),
      vme_en_out   => vme_en_out_i(8),
      vme_clk      => clk);
  
  -----------------------------------------------------------------------------
  -- sort rank offset adder
  -----------------------------------------------------------------------------

  add_ofs: process (clk) is
    variable vSum : unsigned(8 downto 0);
  begin  -- process add_ofs
    if clk'event and clk=calc_lf_edge(sort_rank_unit_lat_start + LF_RLAT_SRU_OFFSADD) then
      for i in 0 to 3 loop
        oSortRankMatchedDTCSC(i) <= add(sSortRankDTCSC(i), sOffset(7 downto 0));
        oSortRankMatchedRPC(i) <= add(sSortRankRPC(i), sOffset(7 downto 0));

      end loop;  -- i
      oSortRankDTCSC <= sSortRankDTCSC;
      oSortRankRPC <= sSortRankRPC  ;
    end if;
  end process add_ofs;
  
  
  -- multiplex vme_data_output
  mux_vme(vme_data_out_i, vme_en_out_i, vme_data_out, vme_en_out);
  
end architecture behavioral;