-----------------------------------------------------------------------
-- Demonstracni modul pouziti jádra Eth0 pro prenos udp dat  			--
-- Funkce: 
-- 1/ ASCII data prijata z PC zobrazi na displeji
-- 2/ Po stisku tlacitka bude odesilat "nahodna" UDP data do pc		-- 
-- Ovládani: button SW13 - posilat udp data
-- 			 button SW14 - globalni reset
-----------------------------------------------------------------------

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;

library UNISIM;
use UNISIM.VComponents.all;

entity Ethernet is
PORT (
		-- 100Mhz externi oscilator
		CLK100MHZ : IN std_logic;
		-- do PHY cipu
		PHY_COL : IN std_logic;
		PHY_CS : IN std_logic;
		PHY_TXCLK : IN 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_TXD : OUT std_logic_vector(7 downto 0);
		PHY_TXEN : OUT std_logic;
		PHY_TXER : OUT std_logic;
		PHY_GTXCLK : OUT std_logic;
		PHY_RESET : OUT std_logic;
		-- pripojeni displeje 
		LCD_FPGA_DB : INOUT std_logic_vector(3 downto 0);      
		LCD_FPGA_E : OUT std_logic;
		LCD_FPGA_RS : OUT std_logic;
		LCD_FPGA_RW : OUT std_logic;
		-- tlacitka pro reset / send 
		SEND: IN std_logic;		
		RESET : IN std_logic          
		);

end Ethernet;

architecture Behavioral of Ethernet is

COMPONENT Eth0
	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_EN: out 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);
		------------------------------------------------
		--
		SPEED1G: out std_logic;
		IFG: in std_logic_vector(7 downto 0);

		RESET: in std_logic
);
END COMPONENT;
	
COMPONENT lcd
	port
		( 
			-- Interface pro pripojeni k řadiči na ML506
			USER_CLK    : in    std_logic;
         LCD_FPGA_DB	: inout std_logic_vector(3 downto 0);
         LCD_FPGA_E	: out	  std_logic;
         LCD_FPGA_RS	: out	  std_logic;
		   LCD_FPGA_RW	: out	  std_logic;
         -- interface pro RAM
			WRITE_CLK	: in std_logic;							-- hodny pro zapis
			WRITE_ADDR	: in std_logic_vector(4 downto 0);	-- adresa zapisu 
			WE       	: in std_logic;							-- write enable
			DATA_IN		: in std_logic_vector(7 downto 0);	-- vstupni data
			RESET			: in std_logic								-- reset
		);
END COMPONENT;

signal clk_fb_emac1, clk100_emac1, gtx_clk_0_i, GTX_CLK_0, reset_i: std_logic;

signal tx_data, rx_data: std_logic_vector(7 downto 0);
signal tx_data_vld, rx_data_vld: std_logic;
signal tx_data_en, rx_data_good, rx_data_bad, rx_clk, tx_clk: std_logic;

signal disp_adress: std_logic_vector(4 downto 0);
signal disp_data: std_logic_vector(7 downto 0);
signal disp_write, disp_clk: std_logic;

signal ram_in: std_logic_vector(7 downto 0);

signal cnt: std_logic_vector(9 downto 0);

begin
	------------------------------------------------------------------------
	-------------------------- Ethernetove jadro ---------------------------
	------------------------------------------------------------------------	
	Inst_Eth0: Eth0 PORT MAP(
		GTXCLK => gtx_clk_0,
		-- do 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,
		
		-- Uzivatelske rozhrani
		RX_CLK => rx_clk,
		RX_DATA => rx_data,
		RX_DATA_VLD => rx_data_vld,
		RX_DATA_GOOD => rx_data_good,
		RX_DATA_BAD => rx_data_bad,
		
		TX_CLK => tx_clk,
		TX_DATA => tx_data,
		TX_DATA_VLD => tx_data_vld,
		TX_DATA_EN => tx_data_en,
		
		DESTINATION_PORT => x"7DDE",		-- Cílový UDP port
		DESTINATION_IP => x"0A1402BA",	-- Cílová adresa
		SOURCE_IP => open,					-- Zdrojová IP adresa
		IFG => x"03",							-- Zvetseni mezery kvuli mrznuti PC pri 1Gb/s
		
		-- Globalni reset
		RESET => reset_i
	);

	------------------------------------------------------------------------
	------------------------------ LCD -------------------------------------
	------------------------------------------------------------------------
	Inst_lcd: lcd PORT MAP(
		USER_CLK => CLK100MHZ,
		LCD_FPGA_DB => LCD_FPGA_DB,
		LCD_FPGA_E => LCD_FPGA_E,
		LCD_FPGA_RS => LCD_FPGA_RS,
		LCD_FPGA_RW => LCD_FPGA_RW,
		-- Zapis do ram 
		WRITE_CLK => disp_clk,
		DATA_IN => ram_in,
		WRITE_ADDR => disp_adress,
		WE => disp_write,
		RESET => reset_i
	);

	-----------------------------------------------------------------------
	-- Generator 125MHz (gtx_clk) ze vstupniho 100MHz
	-----------------------------------------------------------------------
   clk125_dcm : DCM_BASE
   generic map (
      CLKFX_DIVIDE   => 4,
      CLKFX_MULTIPLY => 5)
   port map (
		CLKIN      => CLK100MHZ,
		CLK0       => clk_fb_emac1,
		CLK180     => open,
		CLK270     => open,
		CLK2X      => open,
		CLK2X180   => open,
		CLK90      => open,
		CLKDV      => open,
		CLKFX      => gtx_clk_0_i,
		CLKFX180   => open,
		LOCKED     => open,
		CLKFB      => clk100_emac1,
		RST        => reset_i);

   fb_bufg      : BUFG port map (I => clk_fb_emac1, O => clk100_emac1);
 	gtx_clk_bufg : BUFG port map (I => gtx_clk_0_i, O => gtx_clk_0);
	reset_ibuf 	 : IBUF port map (I => RESET, O => reset_i);
	-----------------------------------------------------------------------
	disp_clk <= rx_clk;	-- taktovani pameti displeje

	-----------------------------------------------------------------------
	-- Zobrazeni prijatych dat na displeji
	-----------------------------------------------------------------------	
	process (rx_clk)
	begin
		if rising_edge(rx_clk) then
			if rx_data_vld = '1' then 
				disp_write <= '1';
				disp_adress <= disp_adress + 1;			 
				disp_data <= rx_data;			-- vypos prijatych dat na displej
			elsif rx_data_good = '1' then 	-- Prenos byl OK 
				disp_write <= '0';				-- moznost vypsat na displej, zapsat do ram apod.
			elsif rx_data_bad = '1' then 		-- Spatna data
				disp_write <= '0';				-- moznost doplnit smazani, vypis chyby apod. 
			else 
				disp_adress <= (others => '0'); 
				disp_write <= '0'; 
			end if;
		end if;
	end process;

	ram_in <= disp_data;

-- prevod z HEXA na ASCII tvar
--	ram_in <= "0000"&disp_data(3 downto 0) + 48 when (disp_data(3 downto 0) < x"A") and hex = '1' else 
--				 "0000"&disp_data(3 downto 0) + 55 when ((disp_data(3 downto 0) >= x"A") and hex = '1') else
--				 disp_data;
	
	---------------------------------------------------------------------
	-- Odeslani vygenerovanych dat pri stisku tlacitka SW13		
	---------------------------------------------------------------------	
	process (tx_clk)
	begin
		
		if rising_edge(tx_clk) then 
			tx_data_vld <= '0';
			tx_data <= (others => '0');
			
			if SEND = '1' and tx_data_en = '1' then 				
				-- odeslat udp paket dlouhy 950B
				if cnt /= 949 then 
					cnt <= cnt + 1;
					tx_data <= cnt(7 downto 0);
					tx_data_vld <= '1';					
				end if;
			else 
				cnt <= (others => '0');
			end if;
	
		end if;
	end process;
		
end Behavioral;

