--******************************************************************************
--* @short      8->4 Sorter based on sort ranks
--******************************************************************************
--* @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.LFTiming.all;
use work.SorterUnit.all;

entity LFSortStage1 is
  generic (
    sorter_lat_start : integer := 6);  -- start latency
  port (iSortRanksOther : in TSortRank_vector(0 to 3);
        iSortRanksRPC   : in TSortRank_vector(0 to 3);
        
        iEmptyOther    : in std_logic_vector(0 to 3);  -- arrive 1/2 bx later
        iEmptyRPC      : in std_logic_vector(0 to 3);  -- arrive 1/2 bx later

        iCancelOther_A : in std_logic_vector(0 to 3);  -- arrive 1/2 bx later
        iCancelRPC_A   : in std_logic_vector(0 to 3);  -- arrive 1/2 bx later

        iCancelOther_B : in std_logic_vector(0 to 3);  -- arrive 1/2 bx later
        iCancelRPC_B   : in std_logic_vector(0 to 3);  -- arrive 1/2 bx later
        
        iMuonsOther    : in TGMTMu_vector(0 to 3);  -- arrive 1/2 bx later
        iMuonsRPC      : in TGMTMu_vector(0 to 3);  -- arrive 1/2 bx later 
                                                    -- 
        iIdxBitsOther  : in TIndexBits_vector(0 to 3);  -- arrive 1/2 bx later
--        iIdxBitsRPC    : in TIndexBits_vector(0 to 3);  -- arrive 1/2 bx later 
--        (generate RPC indices, automatically)
        
        oMuons         : out TGMTMu_vector(0 to 3);
        oSortRanks     : out TSortRank_vector(0 to 3);
        oIdxBits       : out TIndexBits_vector(0 to 3);
        oIsRPCMu          : out std_logic_vector(0 to 3); 
        
        -- Clock and control
        clk            : in    std_logic;
        sinit          : in    std_logic);
end;
  

architecture behavioral of LFSortStage1 is
  attribute syn_useioff : boolean;
  attribute syn_useioff of behavioral : architecture is true;
  
  component comp8
	port (
	A: IN std_logic_VECTOR(7 downto 0);
	B: IN std_logic_VECTOR(7 downto 0);
	A_GE_B: OUT std_logic);
  end component;

-- Synplicity black box declaration
attribute syn_black_box : boolean;
attribute syn_black_box of comp8: component is true;

  signal GEMatrix, GEMatrix_reg : TGEMatrix;

  signal sSortRanks : TSortRank_vector(0 to 7);
  signal sSortRanks_reg : TSortRank_vector(0 to 7);

  signal sDisable : std_logic_vector(0 to 7);

  signal sSelBits : TSelBits_1_of_8_vec (0 to 3);                       
begin  -- architecture behavioral

  sSortRanks(0 to 3) <= iSortRanksOther;
  sSortRanks(4 to 7) <= iSortRanksRPC;

  sDisable(0 to 3) <= iEmptyOther or iCancelOther_A or iCancelOther_B;
  sDisable(4 to 7) <= iEmptyRPC or iCancelRPC_A or iCancelRPC_B;
  
  -----------------------------------------------------------------------------
  -- calculate GE Matrix
  -----------------------------------------------------------------------------  
  g1: for i in 0 to 7 generate
    g2: for j in i+1 to 7 generate
      x: comp8
        port map (
          A => sSortRanks(i),
          B => sSortRanks(j),
          A_GE_B => GEMatrix(i,j));

        -- in case of equal ranks the lower index muon wins
        GEMatrix(j,i) <= not GEMatrix(i,j);
    end generate;
  end generate;

  -----------------------------------------------------------------------------
  -- register the result and the empty inputs
  -----------------------------------------------------------------------------
  reg_ge: process (clk) is
  begin  -- process reg_ge
    if clk'event and clk = calc_lf_edge(sorter_lat_start + LF_RLAT_SORT_GEMatrix) then
      GEMatrix_reg <= GEMatrix;
      sSortRanks_reg <= sSortRanks;     
    end if;
  end process reg_ge;

  -----------------------------------------------------------------------------
  -- sort and four 8 to 1 Muxes
  -----------------------------------------------------------------------------  
  count_wins(GEMatrix_reg, sDisable, sSelBits);

  mux: process (clk) is
  begin  
    if clk'event and clk = calc_lf_edge(sorter_lat_start + LF_RLAT_SORT_DONE)  then
      
      
      for iplace in 0 to 3 loop
        case sSelBits(iplace) is
          when  "10000000" => oMuons(iplace) <= iMuonsOther(0);
          when  "01000000" => oMuons(iplace) <= iMuonsOther(1);
          when  "00100000" => oMuons(iplace) <= iMuonsOther(2);
          when  "00010000" => oMuons(iplace) <= iMuonsOther(3);
          when  "00001000" => oMuons(iplace) <= iMuonsRPC(0);
          when  "00000100" => oMuons(iplace) <= iMuonsRPC(1);
          when  "00000010" => oMuons(iplace) <= iMuonsRPC(2);
          when  "00000001" => oMuons(iplace) <= iMuonsRPC(3);
          when others => oMuons(iplace) <= ( "00", '0', '0', "000000", "000", "00000", "00000000" );
        end case;
        case sSelBits(iplace) is
          when  "10000000" => oSortRanks(iplace) <= sSortRanks_reg(0);
          when  "01000000" => oSortRanks(iplace) <= sSortRanks_reg(1);
          when  "00100000" => oSortRanks(iplace) <= sSortRanks_reg(2);
          when  "00010000" => oSortRanks(iplace) <= sSortRanks_reg(3);
          when  "00001000" => oSortRanks(iplace) <= sSortRanks_reg(4);
          when  "00000100" => oSortRanks(iplace) <= sSortRanks_reg(5);
          when  "00000010" => oSortRanks(iplace) <= sSortRanks_reg(6);
          when  "00000001" => oSortRanks(iplace) <= sSortRanks_reg(7);
          when others => oSortRanks(iplace) <= (others => '0');
        end case;
        case sSelBits(iplace) is
          when  "10000000" => oIdxBits(iplace) <= iIdxBitsOther(0);
          when  "01000000" => oIdxBits(iplace) <= iIdxBitsOther(1);
          when  "00100000" => oIdxBits(iplace) <= iIdxBitsOther(2);
          when  "00010000" => oIdxBits(iplace) <= iIdxBitsOther(3);
          when  "00001000" => oIdxBits(iplace) <= "0000";
          when  "00000100" => oIdxBits(iplace) <= "0100";
          when  "00000010" => oIdxBits(iplace) <= "1000";
          when  "00000001" => oIdxBits(iplace) <= "1100";
          when others => oIdxBits(iplace) <= (others => '0');
        end case;
        case sSelBits(iplace) is
          when  "10000000" => oIsRPCMu(iplace) <= '0';
          when  "01000000" => oIsRPCMu(iplace) <= '0';
          when  "00100000" => oIsRPCMu(iplace) <= '0';
          when  "00010000" => oIsRPCMu(iplace) <= '0';
          when  "00001000" => oIsRPCMu(iplace) <= '1';
          when  "00000100" => oIsRPCMu(iplace) <= '1'; 
          when  "00000010" => oIsRPCMu(iplace) <= '1';
          when  "00000001" => oIsRPCMu(iplace) <= '1';
          when others => oIsRPCMu(iplace) <= '0';
        end case;
      end loop;  -- iplace
    end if;
  end process mux;
  
end architecture behavioral;