---------|---------|---------|---------|---------|---------|---------|---------|
-- Author          :  Tom Vu                                     
-- Date            :  09/07/97                                  
-- Description	   :  Search Unit
--------------------------------------------------------------------------------
library ieee;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
--------------------------------------------------------------------------------
entity SEARCH_UNIT is

port(   CLK             : in     std_logic;
        RST_N           : in     std_logic;
        WRB             : in     std_logic;
        RDB             : in     std_logic;
        SEARCH          : in     std_logic;
        EXTRA_XOR       : in     std_logic;
        USE_CBC       	: in     std_logic;
        ADDR_KEY        : in     std_logic_vector(6  downto 0);

        DATAI       	: in  	 std_logic_vector(7 downto 0);
        PT_BYTE_MASK   	: in  	 std_logic_vector(7 downto 0);
        PT_XOR_MASK   	: in  	 std_logic_vector(63 downto 0);
        PT_VECTOR       : in     std_logic_vector(255 downto 0);
        C0              : in     std_logic_vector(63 downto 0);
        C1              : in     std_logic_vector(63 downto 0);
        KEY_OUT         : out     std_logic_vector(55 downto 0);
        DES_OUTPUT      : out     std_logic_vector(63 downto 0);
--       MATCH_OUT 	: out     std_logic;
        SELECT_ONE 	: out     std_logic;
        SEARCH_OUT 	: out     std_logic;
        CLEAR_SEARCH 	: out     std_logic;
        DATAO        	: out    std_logic_vector(7 downto 0)
    );


end SEARCH_UNIT;

--------------------------------------------------------------------------------
architecture beh of SEARCH_UNIT is
--------------------------------------------------------------------------------
type DATA8_ARRAY is array(7 downto 0) of std_logic_vector(7 downto 0);

signal MESSAGE   	: std_logic_vector(63 downto 0);
signal IP_KEY   	: std_logic_vector(63 downto 0);
signal DES_OUT   	: std_logic_vector(63 downto 0);
signal EXTRA_XOR_OUT   	: std_logic_vector(63 downto 0);
signal SHIFT_REG   	: DATA8_ARRAY;
signal KEY 		: std_logic_vector(55 downto 0);
signal D_KEY 		: std_logic_vector(31 downto 0);
signal MESG_LEFT 	: std_logic_vector(31 downto 0);
signal CNT		: std_logic_vector(4 downto 0);
signal BIT_SHIFT_REG 	: std_logic_vector(7  downto 0);
signal TEMP_VECTOR 	: std_logic_vector(3  downto 0);
signal WR1B 		: std_logic;
signal WR_STROBEB	: std_logic;
signal DONE 		: std_logic;
signal STARTDES 	: std_logic;
signal MATCH 		: std_logic;
signal MATCH_DLY_CYCLE1	: std_logic;
signal MATCH_DLY_CYCLE2	: std_logic;
signal FALSE_MATCH	: std_logic;
signal SEARCH_DLY1 	: std_logic;
signal SEARCH_DLY2 	: std_logic;
signal SEARCH_DLY3 	: std_logic;
signal SEARCHING 	: std_logic;
signal SEARCHING_DLY 	: std_logic;
signal LOAD 		: std_logic;
signal FIRST_TIME1 	: std_logic;
signal FIRST_TIME2 	: std_logic;
signal FIRST_LOAD 	: std_logic;
signal SELECT1 		: std_logic;
signal SELECT1_DLY	: std_logic;
signal KEY_ODD_DLY1	: std_logic_vector(1  downto 0);
signal KEY_ODD_DLY2	: std_logic_vector(1  downto 0);
signal CHECK_SAME_KEY	: std_logic;
signal KEY_INCR		: std_logic;
signal KEY_DECR		: std_logic;
signal PRE_DONE		: std_logic;
signal CNT_EQ_1		: std_logic;
signal CNT_GT_10	: std_logic;
signal CNT_EQ_10	: std_logic;
signal CNT_LE_10	: std_logic;
signal FIRST_DES	: std_logic;
signal RESET_SEARCHING	: std_logic;
signal CLEAR_SEARCH_BAK     : std_logic;

signal EXTRA_SELECT	: std_logic_vector(2 downto 0);

signal BIT_MUX		: std_logic;

component DES
port(   CLK             : in     std_logic;
        RST_N           : in     std_logic;
        START           : in     std_logic;
        MESSAGE         : in     std_logic_vector(63 downto 0);
        KEY             : in     std_logic_vector(55 downto 0);
        DONE            : out     std_logic;
        CNT         	: out     std_logic_vector(4 downto 0);
        DES_OUT         : out    std_logic_vector(63 downto 0)
    );
end component;


component MUX256
port(   

        SHIFT_OUT       : in     std_logic_vector(7 downto 0);
        PT_VECTOR       : in     std_logic_vector(255 downto 0);
        BIT_MUX         : out     std_logic
    );
end component;

begin
M256: MUX256
port map(   	SHIFT_OUT   	=> SHIFT_REG(7),
	        PT_VECTOR   	=> PT_VECTOR,
      	 	BIT_MUX  	=> BIT_MUX
    );

DES1: DES
port map(   	CLK             => CLK,
        	RST_N           => RST_N,
	        START           => STARTDES,
      	 	MESSAGE         => MESSAGE,
      		KEY             => KEY,
        	DONE            => DONE,
        	CNT         	=> CNT,
        	DES_OUT         => DES_OUT
    );
MESSAGE 	<= C0 when (SELECT1 = '0') else C1;
--------------------------------------------------------------------------------
PCSETSEARCH_PR: process(RST_N,CLK)
--------------------------------------------------------------------------------
begin   
if RST_N = '0' then
        FIRST_TIME1 <= '0';
        FIRST_TIME2 <= '0';
        SEARCH_DLY1 <= '0';
        SEARCH_DLY2 <= '0';
        SEARCH_DLY3 <= '0';
	for i in 0 to 7 loop
        SHIFT_REG(i) <= (others => '0');
	end loop;
elsif CLK'event and CLK = '1' then

	
        FIRST_TIME2 <= FIRST_TIME1;
	if (DONE = '1') then

		if (SEARCH = '1') then
       	 	FIRST_TIME1 <= '1';
		end if;

        SEARCH_DLY1 <= SEARCH;
        SEARCH_DLY2 <= SEARCH_DLY1 ;
        SEARCH_DLY3 <= SEARCH_DLY2 ;
	end if;
	if (CNT_EQ_1 = '1') then
		SHIFT_REG(7) <= EXTRA_XOR_OUT(63 downto 56);
		SHIFT_REG(6) <= EXTRA_XOR_OUT(55 downto 48);
		SHIFT_REG(5) <= EXTRA_XOR_OUT(47 downto 40);
		SHIFT_REG(4) <= EXTRA_XOR_OUT(39 downto 32);
		SHIFT_REG(3) <= EXTRA_XOR_OUT(31 downto 24);
		SHIFT_REG(2) <= EXTRA_XOR_OUT(23 downto 16);
		SHIFT_REG(1) <= EXTRA_XOR_OUT(15 downto  8);
		SHIFT_REG(0) <= EXTRA_XOR_OUT( 7 downto  0);
	else
		for i in 0 to 6 loop
		SHIFT_REG(i+1) <= SHIFT_REG(i);		
		end loop;
	end if;
end if;  
 
end process PCSETSEARCH_PR;


--------------------------------------------------------------------------------
---- Use to clear away invalid matches before PC loads   -----------------------
FIRST_LOAD <= FIRST_TIME1 and not(FIRST_TIME2);
--------------------------------------------------------------------------------


BIT_SHIFT_PR: process(RST_N,CLK)
--------------------------------------------------------------------------------
begin
if RST_N = '0' then
	BIT_SHIFT_REG <= (others => '1');
elsif CLK'event and CLK = '1' then

-------	 SHIFT --------------------------
	if (CNT_LE_10 = '1') then
		for i in 0 to 6 loop
		BIT_SHIFT_REG(i+1) <= BIT_SHIFT_REG(i);		
		end loop;
		BIT_SHIFT_REG(0) <= BIT_MUX;
	end if;
-------	
end if;
end process BIT_SHIFT_PR;

--------------------------------------------------------------------------------
MATCH_PR: process(RST_N,CLK)
--------------------------------------------------------------------------------
begin
if RST_N = '0' then
        MATCH <= '0';
 	MATCH_DLY_CYCLE1 <= '0';
 	MATCH_DLY_CYCLE2 <= '0';
 	KEY_ODD_DLY1     <= "00";
 	KEY_ODD_DLY2     <= "00";
elsif CLK'event and CLK = '1' then
	if (CNT = 10) then
		if ((BIT_SHIFT_REG(0) = '1' or (PT_BYTE_MASK(0) = '1')) and
		    (BIT_SHIFT_REG(1) = '1' or (PT_BYTE_MASK(1) = '1')) and
		    (BIT_SHIFT_REG(2) = '1' or (PT_BYTE_MASK(2) = '1')) and
		    (BIT_SHIFT_REG(3) = '1' or (PT_BYTE_MASK(3) = '1')) and
		    (BIT_SHIFT_REG(4) = '1' or (PT_BYTE_MASK(4) = '1')) and
		    (BIT_SHIFT_REG(5) = '1' or (PT_BYTE_MASK(5) = '1')) and
		    (BIT_SHIFT_REG(6) = '1' or (PT_BYTE_MASK(6) = '1')) and
		    (BIT_SHIFT_REG(7) = '1' or (PT_BYTE_MASK(7) = '1'))) then

		MATCH <= '1';
		else
		MATCH <= '0';
		end if;
	end if;
---------------------
	if (FIRST_LOAD = '1') then
		MATCH <= '0';
	end if;
---------------------
	if (CNT = 10) then
		MATCH_DLY_CYCLE2 <= MATCH_DLY_CYCLE1;
		MATCH_DLY_CYCLE1 <= MATCH ;
	end if;
---------------------
	if (PRE_DONE = '1') then
	 	KEY_ODD_DLY2     <= KEY_ODD_DLY1;
 		KEY_ODD_DLY1     <= KEY(1 downto 0);
	end if;
end if;
end process MATCH_PR;

--------------------------------------------------------------------------------
WRITE_STROBE_PR: process(RST_N,CLK)
--------------------------------------------------------------------------------
begin
if RST_N = '0' then
        WR1B <= '1';
        WR_STROBEB <= '1';
elsif CLK'event and CLK = '1' then
        WR_STROBEB <= WR1B;
        WR1B <= WRB;
end if;
end process WRITE_STROBE_PR;

--------------------------------------------------------------------------------
KEY_PR: process(RST_N,CLK)
--------------------------------------------------------------------------------
begin
if (RST_N = '0')then
        KEY <= (others => '0');
elsif CLK'event and CLK = '1' then
        if (WR1B = '0'and ADDR_KEY(0) = '1') then
                KEY(7  downto  0) <= DATAI;
        elsif (PRE_DONE = '1') then
                KEY(7  downto 0) <= D_KEY(7  downto 0);
        end if;
-----
        if (WR1B = '0'and ADDR_KEY(1) = '1') then
                KEY(15 downto  8) <= DATAI;
        elsif (PRE_DONE = '1') then
                KEY(15 downto  8) <= D_KEY(15 downto  8);
        end if;
-----
        if (WR1B = '0'and ADDR_KEY(2) = '1') then
                KEY(23 downto 16) <= DATAI;
        elsif (PRE_DONE = '1') then
                KEY(23 downto 16) <= D_KEY(23 downto 16);
        end if;
-----
        if (WR1B = '0'and ADDR_KEY(3) = '1') then
                KEY(31 downto 24) <= DATAI;
        elsif (PRE_DONE = '1') then
                KEY(31 downto 24) <= D_KEY(31 downto 24);
        end if;
-----
        if (WR1B = '0'and ADDR_KEY(4) = '1') then
                KEY(39 downto 32) <= DATAI;
        end if;
-----
        if (WR1B = '0'and ADDR_KEY(5) = '1') then
                KEY(47 downto 40) <= DATAI;
        end if;
-----
        if (WR1B = '0'and ADDR_KEY(6) = '1') then
                KEY(55 downto 48) <= DATAI;
        end if;



end if;
end process KEY_PR;

--------------------------------------------------------------------------------
READ_KEY_PR: process(ADDR_KEY, RDB, KEY)
--------------------------------------------------------------------------------
begin
if (RDB = '0') then

	if (ADDR_KEY(0) = '1') then
	DATAO <= KEY(7  downto  0) ;
	elsif (ADDR_KEY(1) = '1') then
	DATAO <= KEY(15 downto  8) ;
	elsif (ADDR_KEY(2) = '1') then
	DATAO <= KEY(23 downto 16) ;
	elsif (ADDR_KEY(3) = '1') then
	DATAO <= KEY(31 downto 24) ;
	elsif (ADDR_KEY(4) = '1') then
	DATAO <= KEY(39 downto 32) ;
	elsif (ADDR_KEY(5) = '1') then
	DATAO <= KEY(47 downto 40) ;
	elsif (ADDR_KEY(6) = '1') then
	DATAO <= KEY(55 downto 48) ;
	else
	DATAO <= (others  => 'Z');
	end if;
else
	DATAO <= (others  => 'Z');
end if;
end process READ_KEY_PR;


--------------------------------------------------------------------------------
KEY_ALU_PR: process(KEY_DECR,KEY_INCR,KEY)
--------------------------------------------------------------------------------
begin


if (KEY_INCR = '1') and (KEY_DECR = '0')then
	D_KEY <= KEY(31 downto 0) + 1;
elsif (KEY_DECR = '1')  and (KEY_INCR = '0') then
	D_KEY <= KEY(31 downto 0) - 1;
else
	D_KEY <= KEY(31 downto 0);
end if;

end process KEY_ALU_PR;

--------------------------------------------------------------------------------
EXTRA_XOR_PR: process(PT_XOR_MASK,EXTRA_SELECT, DES_OUT, C0)
--------------------------------------------------------------------------------
begin
case EXTRA_SELECT is
when "000" => 
        EXTRA_XOR_OUT <= DES_OUT xor PT_XOR_MASK;
when "001" => 
        EXTRA_XOR_OUT <= DES_OUT xor PT_XOR_MASK;
when "010" => 
        EXTRA_XOR_OUT <= ((DES_OUT(63 downto 56)  xor DES_OUT(31 downto 24)) &
			  (DES_OUT(55 downto 48)  xor DES_OUT(23 downto 16)) &
			  (DES_OUT(47 downto 40)  xor DES_OUT(15 downto  8)) &
			  (DES_OUT(39 downto 32)  xor DES_OUT( 7 downto  0)) &
			   DES_OUT(31 downto  0)) xor PT_XOR_MASK; 
-----------------------------
when "101" => 
        EXTRA_XOR_OUT <= DES_OUT xor C0;
when "110" => 
        EXTRA_XOR_OUT <= (DES_OUT(63 downto 56) xor DES_OUT(31 downto 24)) &
			 (DES_OUT(55 downto 48) xor DES_OUT(23 downto 16)) &
			 (DES_OUT(47 downto 40) xor DES_OUT(15 downto  8)) &
			 (DES_OUT(39 downto 32) xor DES_OUT( 7 downto  0)) &
			 DES_OUT(31 downto  0) ; 


when others => 
	EXTRA_XOR_OUT <= DES_OUT;

end case;
end process EXTRA_XOR_PR;
EXTRA_SELECT <= SELECT1_DLY & EXTRA_XOR & USE_CBC;
--EXTRA_SELECT <= SELECT1 & EXTRA_XOR & USE_CBC;
--------------------------------------------------------------------------------
STARTDES_PR: process(RST_N,CLK)
--------------------------------------------------------------------------------
begin
if RST_N = '0' then
	STARTDES <= '0';
elsif CLK'event and CLK = '1' then
--	STARTDES <= DONE or LOAD;  --  17 clocks
	STARTDES <= PRE_DONE or LOAD;  --  16 clocks

end if;
end process STARTDES_PR;

--------------------------------------------------------------------------------
KEY_INCR_DECR_PR: process(RST_N,CLK)
--------------------------------------------------------------------------------
begin
if RST_N = '0' then
	KEY_INCR <= '0';
	KEY_DECR <= '0';
elsif CLK'event and CLK = '1' then
--
KEY_INCR  <=  (CNT_GT_10 and not(DONE) and SEARCHING_DLY) and (
	not(MATCH)  or  --- normal case
	SELECT1 or  	--- false match
	FIRST_DES);
KEY_DECR <= 	(CNT_GT_10 and not(DONE) and SEARCHING_DLY) and  --timing
		(MATCH and not(SELECT1))  -- only backup if match on C0
		and not(FIRST_DES);  

end if;
end process KEY_INCR_DECR_PR;

FALSE_MATCH  <= '1' when (MATCH_DLY_CYCLE2 = '1') and (MATCH = '0') and (SEARCHING_DLY = '1')
			else '0';
-------------------------------------------------
---- timing block, sensitive to START  ----------
-------------------------------------------------
PRE_DONE <= '1' when (CNT = "01111") else '0';
RESET_SEARCHING <= '1' when (CNT = "01100") else '0';

CNT_EQ_1  <= '1' when (CNT = 1 ) else '0';
CNT_LE_10 <= '1' when (CNT > 1 and CNT < 10) else '0';
CNT_EQ_10 <= '1' when (CNT = 10) else '0';
CNT_GT_10 <= '1' when (CNT > 10) else '0';
--------------------------------------------------------------------------------
SEARCHING_PR: process(RST_N,CLK)
--------------------------------------------------------------------------------
begin
if RST_N = '0' then
        SEARCHING <= '0';
        SEARCHING_DLY <= '0';
        CLEAR_SEARCH        <= '0';
elsif CLK'event and CLK = '1' then
        SEARCHING_DLY <= SEARCHING;

--------------- search active -------------------
	if ((LOAD = '1') or (SEARCHING = '1')) then
		SEARCHING  <= '1';
	end if;

--------------- found C1 ------------------------
	if (CLEAR_SEARCH_BAK = '1') then
		SEARCHING  <= '0';
	end if;

---------------
	CLEAR_SEARCH        <= CLEAR_SEARCH_BAK;
end if;
 
end process SEARCHING_PR;
	CHECK_SAME_KEY <= '1' when (KEY(1 downto 0) = KEY_ODD_DLY2) else '0';

--------------------------------------------------------------------------------
SELECT1_PR: process(RST_N,CLK)
--------------------------------------------------------------------------------
begin
if RST_N = '0' then
        SELECT1 <= '1';
elsif CLK'event and CLK = '1' then

--------------- found C0, look for C1  ----------
	if ((MATCH = '1') and (SELECT1 = '0') and (PRE_DONE = '1'))  then
		SELECT1  <= '1';
	end if;

--------------- Restart by PC or C1 is not a match ----------
	if  -- (LOAD = '1')  or  
	((SELECT1 = '1') and (PRE_DONE = '1') and (SEARCHING_DLY = '1')) then
		SELECT1  <= '0';
	end if;
---------------
	if (PRE_DONE = '1') then
		SELECT1_DLY <= SELECT1 ;
	end if;
end if;
 
end process SELECT1_PR;
--------------------------------------------------------------------------------
SEARCH_OUT 	<= SEARCHING;
LOAD 		<= SEARCH_DLY1 and PRE_DONE and not(SEARCH_DLY2); -- 17 clocks
FIRST_DES 	<= SEARCH_DLY2 and not(SEARCH_DLY3); 
CLEAR_SEARCH_BAK 	<= 
		'1' when ((MATCH = '1') and (SELECT1 = '0') 
                and (SELECT1_DLY = '1') and (RESET_SEARCHING = '1') 
		and (SEARCHING = '1')) else '0';

SELECT_ONE	<= SELECT1;
 KEY_OUT 	<= KEY;
 DES_OUTPUT	<= DES_OUT;
-- MATCH_OUT	<= MATCH;
--------------------------------------------------------------------------------
end beh;
--------------------------------------------------------------------------------

