--******************************************************************************
--* @short      Pair Logic for matching units 
--******************************************************************************
--* @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 STD.TEXTIO.all;

entity LFPairLogic is
  port (
    iMQMatrix   : in TMQMatrix;
    oPairMatrix : out TPairMatrix;

    clk : in std_logic
    );  
  
end entity LFPairLogic;



architecture behavioral of LFPairLogic is

-- Greater-Equal Matrix A >= B: first two indices A, second two indices B 
  type TGEMatrix is array (integer range 0 to 3, integer range 0 to 3,
                           integer range 0 to 3, integer range 0 to 3) of std_logic;

  type TMaxMatrix is array (integer range 0 to 3, integer range 0 to 3) of std_logic;

  function calc_pair_matrix (
    constant GEMatrix : TGEMatrix;
    constant MQMatrix : TMQMatrix)
    return TPairMatrix is

    variable MaxMatrix : TMaxMatrix;
    variable DisMatrix : TMaxMatrix;
    variable PairMatrix_v : TPairMatrix;
    
    variable isMax  : std_logic;                
    variable isDis  : std_logic;                
    variable isPair : std_logic;                
    
    --    variable lo : line;
  begin  
    --
    -- Calculate Max Matrix
    --      
    for i in 0 to 3 loop
      for j in 0 to 3 loop
        isMax := '1';
        -- check in 1st dimension
        for i1 in 0 to i-1 loop
          if ( GEMatrix(i1,j,i,j) = '1') then
            isMax := '0';             -- current has to be gt values on the left
          end if;
        end loop;  -- i1
        for i1 in i+1 to 3 loop
          if ( not GEMatrix(i,j,i1,j) = '1') then
            isMax := '0';             -- current has to be ge values on the right
          end if;
        end loop;  -- i1
        
        -- check in 2nd dimension
        for j1 in 0 to j-1 loop
          if ( GEMatrix(i,j1,i,j) = '1') then
            isMax := '0';             -- current has to be gt values above
          end if;
        end loop;  -- j1
        for j1 in j+1 to 3 loop
          if ( not GEMatrix(i,j,i,j1) = '1') then
            isMax := '0';             -- current has to be ge values below
          end if;
        end loop;  -- j1

        -- MQ has to be non-zero
        if (MQMatrix(i,j) = "000000") then
          isMax := '0';
        end if;


        -- check that not empty??
        MaxMatrix(i,j) := isMax;
      end loop;  -- j
    end loop;  -- i

--            write(lo, string'("[[[[Max Matrix]]]]"));
--            writeline(output, lo);
--            for r in 0 to 3 loop
--              for c in 0 to 3 loop
-- --                write (LO,string'(" "));
-- --                write (LO,r);
-- --                write (LO,string'(" "));
-- --                write (LO,c);
--                write (LO,string'(" "));
--                write (LO, TO_BIT(MaxMatrix(r,c)));
--              end loop;  -- c
--                writeline (OUTPUT, LO);      
--            end loop;  -- r
--            writeline (OUTPUT, LO);      
    
    --
    -- Calculate DIS Matrix
    --
    for i in 0 to 3 loop
      for j in 0 to 3 loop
        isDis := '0';

        -- check for a max in the same row
        for i1 in 0 to i-1 loop
          if (  MaxMatrix(i1,j) = '1') then
            isDis := '1';     
          end if;
        end loop;  -- i1
        for i1 in i+1 to 3 loop
          if ( MaxMatrix(i1,j) = '1') then
            isDis := '1';  
          end if;
        end loop;  -- i1
        
        -- check in 2nd dimension
        for j1 in 0 to j-1 loop
          if ( MaxMatrix(i,j1) = '1') then
            isDis := '1';
          end if;
        end loop;  -- j1
        for j1 in j+1 to 3 loop
          if ( MaxMatrix(i,j1) = '1') then
            isDis := '1';
          end if;
        end loop;  -- j1

        DisMatrix(i,j) := isDis;
        
      end loop;  -- j
    end loop;  -- i

--            write(lo, string'("[[[[Dis Matrix]]]]"));
--            writeline(output, lo);
--            for r in 0 to 3 loop
--              for c in 0 to 3 loop
-- --                write (LO,string'(" "));
-- --                write (LO,r);
-- --                write (LO,string'(" "));
-- --                write (LO,c);
--                write (LO,string'(" "));
--                write (LO, TO_BIT(DisMatrix(r,c)));
--              end loop;  -- c
--                writeline (OUTPUT, LO);      
--            end loop;  -- r
--            writeline (OUTPUT, LO);      

    --
    -- Calculate Pair Matrix
    -- 
    for i in 0 to 3 loop
      for j in 0 to 3 loop
        isPair := '1';
        -- check in 1st dimension
        for i1 in 0 to i-1 loop
          if ( GEMatrix(i1,j,i,j) = '1') and ( DisMatrix(i1,j) = '0') then
            isPair := '0';             -- current has to be gt values on the left
          end if;
        end loop;  -- i1
        for i1 in i+1 to 3 loop
          if ( not GEMatrix(i,j,i1,j) = '1')  and ( DisMatrix(i1,j) = '0') then
            isPair := '0';             -- current has to be ge values on the right
          end if;
        end loop;  -- i1
        
        -- check in 2nd dimension
        for j1 in 0 to j-1 loop
          if ( GEMatrix(i,j1,i,j) = '1')  and ( DisMatrix(i,j1) = '0') then
            isPair := '0';             -- current has to be gt values above
          end if;
        end loop;  -- j1
        for j1 in j+1 to 3 loop
          if ( not GEMatrix(i,j,i,j1) = '1')  and ( DisMatrix(i,j1) = '0') then
            isPair := '0';             -- current has to be ge values below
          end if;
        end loop;  -- j1

        -- MQ has to be non-zero
        if (MQMatrix(i,j) = "000000") then
          isPair := '0';
        end if;

        -- check that not empty??
        PairMatrix_v(i,j) := isPair;
      end loop;  -- j
    end loop;  -- i


--            write(lo, string'("[[[[Pair Matrix]]]]"));
--            writeline(output, lo);
--            for r in 0 to 3 loop
--              for c in 0 to 3 loop
-- --                write (LO,string'(" "));
-- --                write (LO,r);
-- --                write (LO,string'(" "));
-- --                write (LO,c);
--                write (LO,string'(" "));
--                write (LO, TO_BIT(PairMatrix_v(r,c)));
--              end loop;  -- c
--                writeline (OUTPUT, LO);      
--            end loop;  -- r
--            writeline (OUTPUT, LO);      
    return PairMatrix_v;
  end;
  

  
  component comp6
    port (
      A: IN std_logic_VECTOR(5 downto 0);
      B: IN std_logic_VECTOR(5 downto 0);
      A_GE_B: OUT std_logic);
  end component;

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

--
-- GE, MAX, DIS and PAIR Matrix based on a design by N.Neumeister, A.Taurok 10/97
--

  signal GEMatrix : TGEMatrix;

begin  -- architecture behavioral

  -- Matrix of comparators to compare
  -- if MQ(i,j) >= MQ(i1,j1)
  -- 
  -- this results in 16x16=256 comparators (6 LUTs each if optimally implemented)
  --
  -- could save half of the comparators by avoiding comparisons taht have been
  -- done with the inputs swapped
  -- and comparisons of one element with itself
  --


  g1:    for i in 0 to 3 generate
    g2:   for j in 0 to 3 generate
      g3:  for i1 in 0 to 3 generate
        g4:  for j1 in 0 to 3 generate
          x: comp6
            port map (
              A => iMQMatrix(i,j),
              B => iMQMatrix(i1,j1),
              A_GE_B => GEMatrix(i, j, i1, j1));
        end generate;
      end generate;
    end generate;
  end generate;

  oPairMatrix <= calc_pair_matrix(GEMatrix, iMQMatrix);


end architecture behavioral;