----------------------------------------------------------------------------------
--									Test bench pro ip_core	  			  	  		  		  	  --
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use work.my_constants.all;
 
ENTITY ip_core_tb IS
END ip_core_tb;
 
ARCHITECTURE behavior OF ip_core_tb IS 
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT ip_core
    PORT(
         RX_CLK : IN  std_logic;
         TX_CLK : IN  std_logic;
         RX_DATA : OUT  std_logic_vector(7 downto 0);
         RX_DATA_VLD : OUT  std_logic;
         RX_DATA_BAD : OUT  std_logic;
         RX_DATA_GOOD : OUT  std_logic;
         TX_DATA : IN  std_logic_vector(7 downto 0);
			TX_DATA_LEN: in std_logic_vector(UDP_ADDR_WIDTH - 1 downto 0);	
         TX_DATA_VLD : IN  std_logic;
         TX_DATA_ACK : OUT  std_logic;
         DATA_TO_MAC : OUT  std_logic_vector(7 downto 0);
         DATA_TO_MAC_VLD : OUT  std_logic;
         DATA_FROM_MAC : IN  std_logic_vector(7 downto 0);
         DATA_FROM_MAC_VLD : IN  std_logic;
         DATA_FROM_MAC_BAD : IN  std_logic;
         DATA_FROM_MAC_GOOD : IN  std_logic;
         DATA_TO_MAC_ACK : IN  std_logic;
         SOURCE_IP : OUT  std_logic_vector(31 downto 0);
         SOURCE_PROTOCOL : OUT  std_logic_vector(7 downto 0);
         DESTINATION_IP : IN  std_logic_vector(31 downto 0);
         DESTINATION_PROTOCOL : IN  std_logic_vector(7 downto 0);
         RESET : IN  std_logic
        );
    END COMPONENT;
    

   --Inputs
   signal RX_CLK : std_logic := '0';
   signal TX_CLK : std_logic := '0';
   signal TX_DATA : std_logic_vector(7 downto 0) := (others => '0');
	signal TX_DATA_LEN: std_logic_vector(UDP_ADDR_WIDTH - 1 downto 0) := (others => '0');
   signal TX_DATA_VLD : std_logic := '0';
   signal DATA_FROM_MAC : std_logic_vector(7 downto 0) := (others => '0');
   signal DATA_FROM_MAC_VLD : std_logic := '0';
   signal DATA_FROM_MAC_BAD : std_logic := '0';
   signal DATA_FROM_MAC_GOOD : std_logic := '0';
   signal DATA_TO_MAC_ACK : std_logic := '0';
   signal DESTINATION_IP : std_logic_vector(31 downto 0) := (others => '0');
   signal DESTINATION_PROTOCOL : std_logic_vector(7 downto 0) := (others => '0');
   signal RESET : std_logic := '0';

 	--Outputs
   signal RX_DATA : std_logic_vector(7 downto 0);
   signal RX_DATA_VLD : std_logic;
   signal RX_DATA_BAD : std_logic;
   signal RX_DATA_GOOD : std_logic;
   signal TX_DATA_ACK : std_logic;
   signal DATA_TO_MAC : std_logic_vector(7 downto 0);
   signal DATA_TO_MAC_VLD : std_logic;
   signal SOURCE_IP : std_logic_vector(31 downto 0);
   signal SOURCE_PROTOCOL : std_logic_vector(7 downto 0);

   -- Clock period definitions
   constant RX_CLK_period : time := 8 ns;
   constant TX_CLK_period : time := 8 ns;

	-- Typ pro data 
	type data_typ is record
		data : bit_vector(7 downto 0); 
      valid : bit;                    
      error : bit;                    
	end record;
	type frame_typ is array (natural range <>) of data_typ;

	----------------------------------------------------------------------
	-- Definice link. ramcu s ARP a IP protokolem 
	----------------------------------------------------------------------
   constant arp_frame : frame_typ := (
   -- Frame 0   
        0      => ( DATA => X"FF", VALID => '1', ERROR => '0'), -- Destination Address (DA)
        1      => ( DATA => X"FF", VALID => '1', ERROR => '0'),
        2      => ( DATA => X"FF", VALID => '1', ERROR => '0'),
        3      => ( DATA => X"FF", VALID => '1', ERROR => '0'),
        4      => ( DATA => X"FF", VALID => '1', ERROR => '0'),
        5      => ( DATA => X"FF", VALID => '1', ERROR => '0'),
        6      => ( DATA => X"5A", VALID => '1', ERROR => '0'), -- Source Address	(5A)
        7      => ( DATA => X"02", VALID => '1', ERROR => '0'),
        8      => ( DATA => X"03", VALID => '1', ERROR => '0'),
        9      => ( DATA => X"04", VALID => '1', ERROR => '0'),
       10      => ( DATA => X"05", VALID => '1', ERROR => '0'),
       11      => ( DATA => X"06", VALID => '1', ERROR => '0'),
       12      => ( DATA => X"08", VALID => '1', ERROR => '0'), --
       13      => ( DATA => X"06", VALID => '1', ERROR => '0'), -- Length/Type = Length = 46
       14      => ( DATA => X"00", VALID => '1', ERROR => '0'), 
       15      => ( DATA => X"01", VALID => '1', ERROR => '0'), -- typ HW
       16      => ( DATA => X"08", VALID => '1', ERROR => '0'), 
       17      => ( DATA => X"00", VALID => '1', ERROR => '0'), -- protokol
       18      => ( DATA => X"06", VALID => '1', ERROR => '0'), -- delka MAC
       19      => ( DATA => X"04", VALID => '1', ERROR => '0'), -- delka IP
       20      => ( DATA => X"00", VALID => '1', ERROR => '0'),
       21      => ( DATA => X"01", VALID => '1', ERROR => '0'), -- operace
       22      => ( DATA => X"AB", VALID => '1', ERROR => '0'),
       23      => ( DATA => X"CD", VALID => '1', ERROR => '0'), 
       24      => ( DATA => X"EF", VALID => '1', ERROR => '0'),
       25      => ( DATA => X"AA", VALID => '1', ERROR => '0'),
       26      => ( DATA => X"BB", VALID => '1', ERROR => '0'),
       27      => ( DATA => X"CC", VALID => '1', ERROR => '0'), -- MAC zdroje
       28      => ( DATA => X"0A", VALID => '1', ERROR => '0'), 
       29      => ( DATA => X"14", VALID => '1', ERROR => '0'),
       30      => ( DATA => X"02", VALID => '1', ERROR => '0'),
       31      => ( DATA => X"BA", VALID => '1', ERROR => '0'), -- IP zdroje
       32      => ( DATA => X"00", VALID => '1', ERROR => '0'),
       33      => ( DATA => X"00", VALID => '1', ERROR => '0'),
       34      => ( DATA => X"00", VALID => '1', ERROR => '0'),
       35      => ( DATA => X"00", VALID => '1', ERROR => '0'),
       36      => ( DATA => X"00", VALID => '1', ERROR => '0'),
       37      => ( DATA => X"00", VALID => '1', ERROR => '0'),
       38      => ( DATA => X"0A", VALID => '1', ERROR => '0'),
       39      => ( DATA => X"14", VALID => '1', ERROR => '0'),
       40      => ( DATA => X"02", VALID => '1', ERROR => '0'),
       41      => ( DATA => X"D5", VALID => '1', ERROR => '0'),
       42      => ( DATA => X"1D", VALID => '1', ERROR => '0'),
       43      => ( DATA => X"1E", VALID => '1', ERROR => '0'),
       44      => ( DATA => X"1F", VALID => '1', ERROR => '0'),
       45      => ( DATA => X"20", VALID => '1', ERROR => '0'),
       46      => ( DATA => X"21", VALID => '1', ERROR => '0'),
       47      => ( DATA => X"22", VALID => '1', ERROR => '0'),
       48      => ( DATA => X"23", VALID => '1', ERROR => '0'),
       49      => ( DATA => X"24", VALID => '1', ERROR => '0'),
       50      => ( DATA => X"25", VALID => '1', ERROR => '0'),
       51      => ( DATA => X"26", VALID => '1', ERROR => '0'),
       52      => ( DATA => X"27", VALID => '1', ERROR => '0'),
       53      => ( DATA => X"28", VALID => '1', ERROR => '0'),
       54      => ( DATA => X"29", VALID => '1', ERROR => '0'),
       55      => ( DATA => X"2A", VALID => '1', ERROR => '0'),
       56      => ( DATA => X"2B", VALID => '1', ERROR => '0'),
       57      => ( DATA => X"2C", VALID => '1', ERROR => '0'),
       58      => ( DATA => X"2D", VALID => '1', ERROR => '0'),
       59      => ( DATA => X"2E", VALID => '1', ERROR => '0'));

  constant ip_frame : frame_typ := (
   -------------
   -- Frame 1
   -------------
        0      => ( DATA => X"AA", VALID => '1', ERROR => '0'), 	-- dest. MAC
        1      => ( DATA => X"BB", VALID => '1', ERROR => '0'),	
        2      => ( DATA => X"CC", VALID => '1', ERROR => '0'),	
        3      => ( DATA => X"DD", VALID => '1', ERROR => '0'),	
        4      => ( DATA => X"EE", VALID => '1', ERROR => '0'),	
        5      => ( DATA => X"FF", VALID => '1', ERROR => '0'),	
        6      => ( DATA => X"AB", VALID => '1', ERROR => '0'), 	-- src. MAC
        7      => ( DATA => X"CD", VALID => '1', ERROR => '0'),	
        8      => ( DATA => X"EF", VALID => '1', ERROR => '0'),	
        9      => ( DATA => X"AA", VALID => '1', ERROR => '0'),	
       10      => ( DATA => X"BB", VALID => '1', ERROR => '0'),	
       11      => ( DATA => X"CC", VALID => '1', ERROR => '0'),	
       12      => ( DATA => X"08", VALID => '1', ERROR => '0'), 	-- type/len
       13      => ( DATA => X"00", VALID => '1', ERROR => '0'), 	  
        14      => ( DATA => X"45", VALID => '1', ERROR => '0'), 	-- version + 
        15      => ( DATA => X"00", VALID => '1', ERROR => '0'),	-- TOS
        16      => ( DATA => X"00", VALID => '1', ERROR => '0'),	-- Total len H
        17     => ( DATA => X"50", VALID => '1', ERROR => '0'),	-- Total len L
        18     => ( DATA => X"00", VALID => '1', ERROR => '0'),	-- ID H
        19     => ( DATA => X"0A", VALID => '1', ERROR => '0'),	-- ID L
        20     => ( DATA => X"00", VALID => '1', ERROR => '0'), 	-- flags + fragmentation
        21     => ( DATA => X"00", VALID => '1', ERROR => '0'),	-- fragmentation
        22     => ( DATA => X"03", VALID => '1', ERROR => '0'),	-- TTL
        23     => ( DATA => X"11", VALID => '1', ERROR => '0'),	-- Protocol
       24     => ( DATA => X"62", VALID => '1', ERROR => '0'),		-- Checksum H
       25      => ( DATA => X"22", VALID => '1', ERROR => '0'),	-- Checksum L
       26      => ( DATA => X"0A", VALID => '1', ERROR => '0'), 	-- Source IP
       27      => ( DATA => X"14", VALID => '1', ERROR => '0'), 	-- Source IP
       28      => ( DATA => X"02", VALID => '1', ERROR => '0'), 	-- Source IP
       29      => ( DATA => X"BA", VALID => '1', ERROR => '0'), 	-- Source IP
       30      => ( DATA => X"0A", VALID => '1', ERROR => '0'), 	-- Dest. IP
       31      => ( DATA => X"14", VALID => '1', ERROR => '0'),	-- Dest. IP
       32      => ( DATA => X"02", VALID => '1', ERROR => '0'),	-- Dest. IP
       33      => ( DATA => X"D5", VALID => '1', ERROR => '0'), 	-- Dest. IP
       34      => ( DATA => X"DD", VALID => '1', ERROR => '0'),	-- data bajt 0 ------------------
       35      => ( DATA => X"01", VALID => '1', ERROR => '0'), 
       36      => ( DATA => X"AB", VALID => '1', ERROR => '0'),
       37      => ( DATA => X"CD", VALID => '1', ERROR => '0'), 
       38      => ( DATA => X"EF", VALID => '1', ERROR => '0'),
       39      => ( DATA => X"AA", VALID => '1', ERROR => '0'),
       40      => ( DATA => X"BB", VALID => '1', ERROR => '0'),
       41      => ( DATA => X"CC", VALID => '1', ERROR => '0'),
       42      => ( DATA => X"01", VALID => '1', ERROR => '0'), 
       43      => ( DATA => X"23", VALID => '1', ERROR => '0'),
       44      => ( DATA => X"45", VALID => '1', ERROR => '0'),
       45      => ( DATA => X"67", VALID => '1', ERROR => '0'), 
       46      => ( DATA => X"00", VALID => '1', ERROR => '0'),
       47      => ( DATA => X"14", VALID => '1', ERROR => '0'),
       48      => ( DATA => X"15", VALID => '1', ERROR => '0'),
       49      => ( DATA => X"16", VALID => '1', ERROR => '0'),
       50      => ( DATA => X"17", VALID => '1', ERROR => '0'),
       51      => ( DATA => X"18", VALID => '1', ERROR => '0'),
       52      => ( DATA => X"19", VALID => '1', ERROR => '0'),
       53      => ( DATA => X"1A", VALID => '1', ERROR => '0'),
       54      => ( DATA => X"1B", VALID => '1', ERROR => '0'),
       55      => ( DATA => X"1C", VALID => '1', ERROR => '0'),
       56      => ( DATA => X"1D", VALID => '1', ERROR => '0'),
       57      => ( DATA => X"1E", VALID => '1', ERROR => '0'),
       58      => ( DATA => X"1F", VALID => '1', ERROR => '0'),
       59      => ( DATA => X"20", VALID => '1', ERROR => '0'),
       60      => ( DATA => X"21", VALID => '1', ERROR => '0'),
       61      => ( DATA => X"22", VALID => '1', ERROR => '0'),
       62      => ( DATA => X"23", VALID => '1', ERROR => '0'),
       63      => ( DATA => X"24", VALID => '1', ERROR => '0'),
       64      => ( DATA => X"25", VALID => '1', ERROR => '0'),
       65      => ( DATA => X"26", VALID => '1', ERROR => '0'),
       66      => ( DATA => X"27", VALID => '1', ERROR => '0'),
       67      => ( DATA => X"28", VALID => '1', ERROR => '0'),
       68      => ( DATA => X"29", VALID => '1', ERROR => '0'),
       69      => ( DATA => X"2A", VALID => '1', ERROR => '0'),
       70      => ( DATA => X"2B", VALID => '1', ERROR => '0'),
       71      => ( DATA => X"2C", VALID => '1', ERROR => '0'),
       72      => ( DATA => X"2D", VALID => '1', ERROR => '0'),
       73      => ( DATA => X"2E", VALID => '1', ERROR => '0'));	 
 

BEGIN
 
	-- Instantiate the Unit Under Test (UUT)
   uut: ip_core PORT MAP (
          RX_CLK => RX_CLK,
          TX_CLK => TX_CLK,
          RX_DATA => RX_DATA,
          RX_DATA_VLD => RX_DATA_VLD,
          RX_DATA_BAD => RX_DATA_BAD,
          RX_DATA_GOOD => RX_DATA_GOOD,
          TX_DATA => TX_DATA,
          TX_DATA_LEN => TX_DATA_LEN,
          TX_DATA_VLD => TX_DATA_VLD,
          TX_DATA_ACK => TX_DATA_ACK,
          DATA_TO_MAC => DATA_TO_MAC,
          DATA_TO_MAC_VLD => DATA_TO_MAC_VLD,
          DATA_FROM_MAC => DATA_FROM_MAC,
          DATA_FROM_MAC_VLD => DATA_FROM_MAC_VLD,
          DATA_FROM_MAC_BAD => DATA_FROM_MAC_BAD,
          DATA_FROM_MAC_GOOD => DATA_FROM_MAC_GOOD,
          DATA_TO_MAC_ACK => DATA_TO_MAC_ACK,
          SOURCE_IP => SOURCE_IP,
          SOURCE_PROTOCOL => SOURCE_PROTOCOL,
          DESTINATION_IP => DESTINATION_IP,
          DESTINATION_PROTOCOL => DESTINATION_PROTOCOL,
          RESET => RESET
        );

   -- Clock process definitions
   RX_CLK_process :process
   begin
		RX_CLK <= '0';
		wait for RX_CLK_period/2;
		RX_CLK <= '1';
		wait for RX_CLK_period/2;
   end process;
 
   TX_CLK_process :process
   begin
		TX_CLK <= '0';
		wait for TX_CLK_period/2;
		TX_CLK <= '1';
		wait for TX_CLK_period/2;
   end process;
 

   -- Stimulus process
   stim_proc: process
   begin		
      -- hold reset state for 100 ns.
      wait for 100 ns;	

      wait for RX_CLK_period*10;
		wait for 4 ns;
		
		-------------------
		-- ARP dotaz PC
		-------------------
		for i in  0 to 58 loop
			DATA_FROM_MAC <= to_stdlogicvector(arp_frame(i).data);
			DATA_FROM_MAC_VLD	<= to_stdUlogic(arp_frame(i).valid);
			wait for 8ns;
		end loop;
		DATA_FROM_MAC_VLD <= '0';
		DATA_FROM_MAC <= x"00";
		DATA_FROM_MAC_GOOD <= '1';
		wait for 8ns;
		DATA_FROM_MAC_GOOD <= '0';
		
		wait for 240ns;
		DATA_TO_MAC_ACK <= '1';
		wait for 8ns;
		DATA_TO_MAC_ACK <= '0';

		-------------------------------
		-- Cekat az se odesle reply do PC
		-------------------------------
		wait until DATA_TO_MAC_VLD = '0';
		wait for 24 ns;
		----------------------------
		-- Prijem a odeslani IP dat 
		----------------------------

		TX_DATA <= x"ab";		-- odesilani
		TX_DATA_VLD <= '1';
		DESTINATION_IP <= x"0A1402BA";
		TX_DATA_LEN <= conv_std_logic_vector(70,UDP_ADDR_WIDTH);
		wait for 48ns;
		DATA_TO_MAC_ACK <= '1';		
		wait for 8ns;
		DATA_TO_MAC_ACK <= '0';

		for i in  0 to 60 loop	-- prijem
			DATA_FROM_MAC <= to_stdlogicvector(ip_frame(i).data);
			DATA_FROM_MAC_VLD	<= to_stdUlogic(ip_frame(i).valid);
			wait for 8ns;
		end loop;
		DATA_FROM_MAC_VLD <= '0';
		TX_DATA_VLD <= '0';
		TX_DATA <= x"00";
		
		wait;
   end process;

END;
