----------------------------------------------------------------------------------
--											HLAVNI VRSTVA 			  	  		  		  			  --
----------------------------------------------------------------------------------

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 Eth0 is
	PORT (
		-------------------------------------------------
		-- taktovani 125Mhz
		GTXCLK: in std_logic;
		-------------------------------------------------
		-- Do PHY 
		PHY_COL: in std_logic;
		PHY_CS: in std_logic;

		PHY_TXD: out std_logic_vector(7 downto 0);
		PHY_TXEN: out std_logic;
		PHY_TXER: out std_logic;
		PHY_TXCLK: in std_logic;			 -- 100/10Mbit
		PHY_GTXCLK: out std_logic;			 -- 1Gbit

		PHY_RXD: in std_logic_vector(7 downto 0);
		PHY_RXDV: in std_logic;
		PHY_RXER: in std_logic;
		PHY_RXCLK: in std_logic;
	
		PHY_RESET: out std_logic;
		------------------------------------------------
		-- Signály pro přenos dat
		RX_CLK: out std_logic;
		RX_DATA: out std_logic_vector(7 downto 0);
		RX_DATA_VLD: out std_logic;
		RX_DATA_GOOD: out std_logic;		
		RX_DATA_BAD: out std_logic;

		TX_CLK: out std_logic;
		TX_DATA: in std_logic_vector(7 downto 0);
		TX_DATA_VLD: in std_logic;
		TX_DATA_ACK: out std_logic;
		TX_DATA_END: in std_logic;
		------------------------------------------------
		-- Smerovani IP / UDP
		DESTINATION_PORT : in std_logic_vector(15 downto 0);
		DESTINATION_IP: in std_logic_vector(31 downto 0);
		SOURCE_IP: out std_logic_vector(31 downto 0);
		------------------------------------------------
		-- MAC nastaveni / info
		SPEED1G: out std_logic;
		IFG: in std_logic_vector(7 downto 0);
		FULL_DUPLEX: in std_logic;	
		-- Ovládací/informační signály pro připojení ke vzdálenému PC
		CONNECT: in std_logic;
		CLOSE: in std_logic;
		CONNECTED: out std_logic;
		------------------------------------------------


		RESET: in std_logic
		
	);
end Eth0;


architecture Behavioral of Eth0 is
COMPONENT mac_core
PORT(
	-- taktovani 125Mhz
	GTXCLK: in std_logic;
	-------------------------------------------------
	-- GMII 
	PHY_COL: in std_logic;
	PHY_CS: in std_logic;

	PHY_TXD: out std_logic_vector(7 downto 0);
	PHY_TXEN: out std_logic;
	PHY_TXER: out std_logic;
	PHY_TXCLK: in std_logic;			 -- 100/10Mbit
	PHY_GTXCLK: out std_logic;

	PHY_RXD: in std_logic_vector(7 downto 0);
	PHY_RXDV: in std_logic;
	PHY_RXER: in std_logic;
	PHY_RXCLK: in std_logic;
	
	PHY_RESET: out std_logic;
	------------------------------------------------
	-- do vyssi vrstvy
	TX_CLK: out std_logic;
	TX_DATA: in std_logic_vector(7 downto 0);
	TX_DATA_VLD: in std_logic;
	TX_DATA_ACK: out std_logic;
	
	RX_CLK: out std_logic;
	RX_DATA: out std_logic_vector(7 downto 0);
	RX_DATA_VLD: out std_logic;
	RX_DATA_GOOD: out std_logic;
	RX_DATA_BAD: out std_logic;
	------------------------------------------------	
	-- Control / info pro MAC
	COLLISION: out std_logic;
	IFG: in std_logic_vector(7 downto 0);
	FULL_DUPLEX: std_logic;	
	SPEED1G: out std_logic;			-- 1 = 1Gb, 0 = 100/10Mb	
	--
	RESET: in std_logic
	);
END COMPONENT;

COMPONENT ip_core
PORT(
	RX_CLK : 					in std_logic;
	TX_CLK: 						in std_logic;

	-- do transportni vrstvy
	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;

	-- z transportni vrsvy
	TX_DATA : 					in std_logic_vector(7 downto 0);
	TX_DATA_LEN: 				in std_logic_vector(UDP_ADDR_WIDTH - 1 downto 0);	-- delka IP dat
	TX_DATA_VLD: 				in std_logic;								-- impulz H pro poslani dat 
	TX_DATA_ACK : 				out std_logic;

	-- do MAC 
	DATA_TO_MAC : 				out std_logic_vector(7 downto 0);
	DATA_TO_MAC_vld : 		out std_logic;

	-- z MAC vrstvy
	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;

	-- Info / smerovani
	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);	-- cilova IP adresa z IP vrstvy
	DESTINATION_PROTOCOL:   in std_logic_vector(7 downto 0);

	-- reset
	RESET : 						in std_logic 

	);
END COMPONENT;
		

	COMPONENT icmp_core
	PORT(
		CLK_RX : IN std_logic;
		CLK_TX : IN std_logic;
		DATA_TO_IP_ACK : IN std_logic;
		DATA_FROM_IP : IN std_logic_vector(7 downto 0);
		DATA_FROM_IP_VLD : IN std_logic;
		DATA_FROM_IP_BAD : IN std_logic;
		DATA_FROM_IP_GOOD : IN std_logic;
		SOURCE_ADDRESS : IN std_logic_vector(31 downto 0);
		RESET : IN std_logic;          
		DATA_TO_IP : OUT std_logic_vector(7 downto 0);
		DATA_TO_IP_LEN : OUT std_logic_vector(UDP_ADDR_WIDTH - 1 downto 0);
		DATA_TO_IP_VLD : OUT std_logic;
		DESTINATION_ADDRESS : OUT std_logic_vector(31 downto 0)
		);
	END COMPONENT;
	
COMPONENT udp_core
PORT(
	TX_CLK : IN std_logic;
	RX_CLK : IN std_logic;
		
	-- z IP vrstvy
	DATA_FROM_IP : IN std_logic_vector(7 downto 0);
	DATA_FROM_IP_VLD : IN std_logic;
	DATA_FROM_IP_GOOD : IN std_logic;
	DATA_FROM_IP_BAD : IN std_logic;
	SOURCE_IP : IN std_logic_vector(31 downto 0);
		
	-- do IP vrsty
	DATA_TO_IP : OUT std_logic_vector(7 downto 0);
	DATA_TO_IP_VLD : OUT std_logic;
	DATA_TO_IP_LEN: out std_logic_vector(UDP_ADDR_WIDTH - 1 downto 0);
	DATA_TO_IP_ACK : IN std_logic;

	-- do vyssi vrstvy
	RX_DATA : OUT std_logic_vector(7 downto 0);
	RX_DATA_VLD : OUT std_logic;
	RX_DATA_GOOD : OUT std_logic;
	RX_DATA_BAD : OUT std_logic;
		
	-- z vyssi vrstvy
	TX_DATA : IN std_logic_vector(7 downto 0);
	TX_DATA_VLD : IN std_logic;
	TX_DATA_EN : OUT std_logic;
	
	DESTINATION_PORT : IN std_logic_vector(15 downto 0);
	DESTINATION_IP : IN std_logic_vector(31 downto 0);

	-- reset
	RESET : IN std_logic                  
);
END COMPONENT;

COMPONENT app_core
	port (
		GTX_CLK				: in std_logic;
		TX_CLK				: in std_logic;
		RX_CLK				: in std_logic;		
		-- uzivatelske rozhrani vstup
		TX_DATA				: in std_logic_vector(7 downto 0);
		TX_DATA_VLD			: in std_logic;
		TX_DATA_ACK			: out std_logic;
		TX_DATA_END			: in std_logic;
		-- uzivatelske rozhrani výstup
		RX_DATA				: out std_logic_vector(7 downto 0);
		RX_DATA_VLD			: out std_logic;
		RX_DATA_GOOD		: out std_logic;
		RX_DATA_BAD			: out std_logic;		
		-- do UDP vrstvy
		DATA_TO_UDP			: out std_logic_vector(7 downto 0);
		DATA_TO_UDP_VLD	: out std_logic;
		DATA_TO_UDP_EN		: in std_logic;	
		-- z UDP vrstvy
		DATA_FROM_UDP		: in std_logic_vector(7 downto 0);
		DATA_FROM_UDP_VLD	: in std_logic;
		DATA_FROM_UDP_GOOD: in std_logic;
		DATA_FROM_UDP_BAD	: in std_logic;
		------------------------------------------------
		-- Ovládací/informační signály pro připojení ke vzdálenému PC
		CONNECT				: in std_logic;
		CLOSE					: in std_logic;
		CONNECTED			: out std_logic;
		------------------------------------------------
		-- reset
		RESET					: in std_logic
	);
END COMPONENT;

signal destination_protocol: std_logic_vector(7 downto 0);
signal destination_ip_i: std_logic_vector(31 downto 0);
-- signaly pro pristup do IP modulu
signal d_from_ip, d_to_ip: std_logic_vector(7 downto 0);
signal d_from_ip_vld, d_to_ip_vld: std_logic;
-- multiplexovane signaly do / z ICMP modulu
signal d_to_icmp, d_from_icmp: std_logic_vector(7 downto 0);
signal d_to_icmp_vld, d_from_icmp_vld: std_logic;
-- multiplexovane signaly do / z UDP modulu
signal d_to_UDP, d_from_UDP: std_logic_vector(7 downto 0);
signal d_to_UDP_vld, d_from_UDP_vld: std_logic;
--
signal d_to_IP_lenght, d_from_icmp_lenght, d_from_udp_lenght: std_logic_vector(UDP_ADDR_WIDTH - 1 downto 0);
--
signal d_from_ip_good, d_from_ip_bad: std_logic;
signal d_to_ip_ack, d_from_udp_ack, d_from_icmp_ack: std_logic;

signal source_ip_i, icmp_adress: std_logic_vector(31 downto 0); 
signal source_protocol: std_logic_vector(7 downto 0);

-- 
signal d_from_mac, d_to_mac: std_logic_vector(7 downto 0);
signal d_from_mac_vld, d_to_mac_vld, d_to_mac_ack, d_from_mac_good, d_from_mac_bad: std_logic;
--
signal d_from_app_vld, d_to_app_vld, d_from_app_en, d_to_app_good, d_to_app_bad: std_logic;
signal d_from_app, d_to_app: std_logic_vector(7 downto 0);

signal rx_clk_i, tx_clk_i: std_logic;

begin
	SOURCE_IP <= source_ip_i;

	------------------------------------------------------------------------
	------------------------------ MAC vrstva ------------------------------
	------------------------------------------------------------------------
	Inst_mac_core: mac_core PORT MAP(
		GTXCLK => GTXCLK,
		
		-- PHY
		PHY_COL => PHY_COL,
		PHY_CS => PHY_CS,
		PHY_TXD => PHY_TXD,
		PHY_TXEN => PHY_TXEN,
		PHY_TXER => PHY_TXER,
		PHY_TXCLK => PHY_TXCLK,
		PHY_GTXCLK => PHY_GTXCLK,
		PHY_RXD => PHY_RXD,
		PHY_RXDV => PHY_RXDV,
		PHY_RXER => PHY_RXER,
		PHY_RXCLK => PHY_RXCLK,
		PHY_RESET => PHY_RESET,
		
		TX_CLK => tx_clk_i,
		TX_DATA => d_to_mac,
		TX_DATA_VLD => d_to_mac_vld,
		TX_DATA_ACK => d_to_mac_ack,

		RX_CLK => rx_clk_i,
		RX_DATA => d_from_mac,
		RX_DATA_VLD => d_from_mac_vld,
		RX_DATA_GOOD => d_from_mac_good,
		RX_DATA_BAD => d_from_mac_bad,
		
		COLLISION => open,
		IFG => IFG,
		FULL_DUPLEX => FULL_DUPLEX,
		SPEED1G => SPEED1G,
		RESET => RESET
	);
	------------------------------------------------------------------------
	------------------------------- IP vrstva ------------------------------
	------------------------------------------------------------------------
	Inst_ip_core: ip_core PORT MAP(
		-- taktovani
		TX_CLK => tx_clk_i,
		RX_CLK => rx_clk_i,
		-- z / do vyssi vrstvy
		TX_DATA => d_to_ip,
		TX_DATA_VLD => d_to_ip_vld,
		TX_DATA_LEN => d_to_IP_lenght(UDP_ADDR_WIDTH - 1 downto 0),
		TX_DATA_ACK => d_to_ip_ack,
		
		RX_DATA => d_from_ip,
		RX_DATA_VLD => d_from_ip_vld,
		RX_DATA_BAD => d_from_ip_bad,
		RX_DATA_GOOD => d_from_ip_good,
		
		-- z / do MAC jadra
		DATA_TO_MAC => d_to_mac,
		DATA_TO_MAC_VLD => d_to_mac_vld,
		DATA_TO_MAC_ACK => d_to_mac_ack,
		
		DATA_FROM_MAC => d_from_mac,
		DATA_FROM_MAC_VLD => d_from_mac_vld,
		DATA_FROM_MAC_BAD => d_from_mac_bad,
		DATA_FROM_MAC_GOOD => d_from_mac_good,
		
		-- cilova IP a protokol
		DESTINATION_IP => destination_ip_i,
		DESTINATION_PROTOCOL => destination_protocol,
		
		-- info o prijatem paketu
		SOURCE_IP => source_ip_i,
		SOURCE_PROTOCOL => source_protocol,
		
		-- reset
		RESET => RESET
	);
	------------------------------------------------------------------------
	----------------------------- ICMP vrstva ------------------------------
	------------------------------------------------------------------------

		Inst_icmp_core: icmp_core PORT MAP(
		CLK_RX => rx_clk_i,
		CLK_TX => tx_clk_i,
		DATA_TO_IP => d_from_icmp,
		DATA_TO_IP_ACK => d_from_icmp_ack,
		DATA_TO_IP_LEN => d_from_icmp_lenght(UDP_ADDR_WIDTH - 1 downto 0),
		DATA_TO_IP_VLD => d_from_icmp_vld,
		DATA_FROM_IP => d_to_icmp,
		DATA_FROM_IP_VLD => d_to_icmp_vld,
		DATA_FROM_IP_BAD => d_from_ip_bad,
		DATA_FROM_IP_GOOD => d_from_ip_good,
		SOURCE_ADDRESS => source_ip_i,
		DESTINATION_ADDRESS => icmp_adress,
		RESET => reset
	);
	
	------------------------------------------------------------------------
	------------------------------ UDP vrstva ------------------------------
	------------------------------------------------------------------------
	Inst_udp_core: udp_core PORT MAP(
		RX_CLK => rx_clk_i,
		TX_CLK => tx_clk_i,
		
		DATA_FROM_IP => d_to_udp,
		DATA_FROM_IP_VLD => d_to_udp_vld,
		DATA_FROM_IP_GOOD => d_from_ip_good,
		DATA_FROM_IP_BAD => d_from_ip_bad,
		
		DATA_TO_IP_ACK => d_from_UDP_ack,
		DATA_TO_IP => d_from_udp,
		DATA_TO_IP_VLD => d_from_udp_vld,
		DATA_TO_IP_LEN => d_from_udp_lenght(UDP_ADDR_WIDTH - 1 downto 0),
		
		RX_DATA => d_to_app,
		RX_DATA_VLD => d_to_app_vld,
		RX_DATA_GOOD => d_to_app_good,
		RX_DATA_BAD => d_to_app_bad,
		
		TX_DATA => d_from_app,
		TX_DATA_VLD => d_from_app_vld,
		TX_DATA_EN => d_from_app_en,

		DESTINATION_PORT => DESTINATION_PORT,
		DESTINATION_IP => DESTINATION_IP,
		SOURCE_IP => source_ip_i,
		
		RESET => RESET
	);
	
	------------------------------------------------------------------------
	-------------------------- Aplikacni  vrstva ---------------------------
	------------------------------------------------------------------------
	inst_app_core: app_core PORT MAP(
		GTX_CLK => GTXCLK,
		TX_CLK => tx_clk_i,
		RX_CLK => rx_clk_i,
		
		TX_DATA => TX_DATA,
		TX_DATA_VLD => TX_DATA_VLD,
		TX_DATA_ACK => TX_DATA_ACK,
		TX_DATA_END => TX_DATA_END,
		RX_DATA => RX_DATA,
		RX_DATA_VLD => RX_DATA_VLD,
		RX_DATA_GOOD => RX_DATA_GOOD,
		RX_DATA_BAD => RX_DATA_BAD,
		
		DATA_TO_UDP => d_from_app,
		DATA_TO_UDP_VLD => d_from_app_vld,
		DATA_TO_UDP_EN => d_from_app_en,
		DATA_FROM_UDP => d_to_app,
		DATA_FROM_UDP_VLD => d_to_app_vld,
		DATA_FROM_UDP_GOOD => d_to_app_good,
		DATA_FROM_UDP_BAD => d_to_app_bad,
		
		CONNECT => CONNECT,
		CLOSE => CLOSE,
		CONNECTED => CONNECTED,
		
		RESET => RESET
	);

	RX_CLK <= rx_clk_i;
	TX_CLK <= tx_clk_i;

	-- RX cast - smerovani do ruznych transportnich protokolu demultiplexem
	RX_DMUX: process (source_protocol, d_from_ip, d_from_ip_vld)
	begin
		d_to_icmp <= x"00";
		d_to_icmp_vld <= '0';	
		d_to_udp <= x"00";
		d_to_udp_vld <= '0';

		case source_protocol is 
			when x"01" =>		-- icmp	
				d_to_icmp <= d_from_ip;
				d_to_icmp_vld <= d_from_ip_vld;	
				
			when x"11" =>		-- UDP
				d_to_udp <= d_from_ip;
				d_to_udp_vld <= d_from_ip_vld;	
			when others =>		-- necinny stav
		end case;
	end process;

	-- směrování z vrstev s aktivním signálem #_snd do IP bloku multiplexerem
	TX_MUX: process (d_from_icmp_vld, d_from_icmp, d_from_icmp_lenght, d_from_udp_vld, d_to_ip_ack, icmp_adress, DESTINATION_IP, d_from_udp, d_from_udp_lenght)
	begin
		-- necinny stav
		destination_protocol <= x"00";
		destination_ip_i	<= (others => '0');
		d_to_IP_lenght <= (others => '0');
		d_to_IP <= x"00";
		destination_protocol <= x"11";
		d_to_ip_vld <= '0';
		d_from_icmp_ack <= '0';
		d_from_udp_ack <= '0';
		
		if d_from_icmp_vld = '1' then 
			destination_protocol <= x"01";
			destination_ip_i <= icmp_adress;
			d_to_IP <= d_from_icmp;
			d_to_IP_lenght <= d_from_icmp_lenght;
			d_to_ip_vld <= '1';
			d_from_icmp_ack <= d_to_ip_ack;
			
		elsif d_from_udp_vld = '1' then 
			destination_protocol <= x"11";
			destination_ip_i <= DESTINATION_IP;
			d_to_IP <= d_from_udp;
			d_to_IP_lenght <= d_from_udp_lenght;
			d_to_ip_vld <= '1';
			d_from_udp_ack <= d_to_ip_ack;
		end if;
	end process;

end Behavioral;

