----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    17:27:50 05/05/2015 
-- Design Name: 
-- Module Name:    udp_top - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

-- UDP/IP library
use work.data_IO.all;
use work.ipv4_types.all;

--WR library
use work.wr_fabric_pkg.all;
use work.genram_pkg.all;

entity udp_top is
	generic( 
				g_data_tx_width  		: natural := 16;
				g_add_data_tx_width 	: natural := 16;
				g_nb_data_packed 		: natural := 20;
				g_data_rx_width  		: natural := 16
				);
    Port ( 
			clk_sys_i : in std_logic;
			rst_n_i   : in std_logic;
					
      -- Endpoint/WRC interface - packet source
			src_i : in  t_wrf_source_in;
			src_o : out t_wrf_source_out;
			
		-- Endpoint/WRC interface - packet sink
			snk_i : in  t_wrf_sink_in;
			snk_o : out t_wrf_sink_out;
			
    ---------------------------------------------------------------------------
    -- User interface
    ---------------------------------------------------------------------------
		-----TX
		 -- Data word to be sent. 
         tx_data_i 			: in  STD_LOGIC_VECTOR (g_data_tx_width-1 downto 0);
		 -- 1 indicates that the tx_data_i contains a valid data word.
         tx_data_ready_i 	: in  STD_LOGIC;
		--additionnal information sent once with bunch
			add_tx_data			: in  STD_LOGIC_VECTOR (g_add_data_tx_width-1 downto 0);			
			
		----RX
		-- Data word received. 
         rx_data_o 			: out  STD_LOGIC_VECTOR (g_data_rx_width-1 downto 0);
		 -- 1 indicates that the rx_data_o contains a valid data word.
         rx_data_ready_o 	: out  STD_LOGIC;

			---------------------------------------------------------------------------
    -- Configuration
    ---------------------------------------------------------------------------

		-- Local MAC address. Leave at 0 when using with the WR MAC/Core, it will
		-- insert its own source MAC.
			cfg_mac_local_i : in std_logic_vector(47 downto 0) := x"000000000000";
		-- Destination MAC address.
			cfg_mac_target_i : in std_logic_vector(47 downto 0);
		--IP address. .
			cfg_ip_local_i  : in std_logic_vector(31 downto 0) := x"C0A80064"; 			--IP src 192.168.0.100
			cfg_ip_target_i : in std_logic_vector(31 downto 0) := x"C0A8000A";  			--IP dst 192.168.0.10
--		-- throttle value setting	
--			throttle_val_i			: in  std_logic_vector(15 downto 0);
--         set_throttle_val_i	: in  std_logic;

			-- Tx FIFO signals
			tx_almost_empty_o	: out  STD_LOGIC;
			tx_almost_full_o  : out  STD_LOGIC;
			 
		--Port
			cfg_port_i : in std_logic_vector (15 downto 0)  := x"D6D8"	--port 55000
			
			--------Debug-----
--			TRIG0 : out std_logic_vector(31 downto 0);
--			TRIG1 : out std_logic_vector(31 downto 0)
--			TRIG2 : out std_logic_vector(31 downto 0);
--			TRIG3 : out std_logic_vector(31 downto 0)
			);
end udp_top;

architecture Behavioral of udp_top is

 type t_pipe is record
    dvalid : std_logic;
    dreq   : std_logic;
    sof    : std_logic;
    eof    : std_logic;
    error  : std_logic;
    data   : std_logic_vector(15 downto 0);
  end record;
  
--------------------------------------------
-- UDP/IP stack without MAC, use WR core MAC
--------------------------------------------
	component UDP_Complete_nomac is
    port (
			-- UDP TX signals
			udp_tx_start			: in std_logic;							-- indicates req to tx UDP
			udp_txi					: in udp_tx_type;							-- UDP tx cxns
			udp_tx_result			: out std_logic_vector (1 downto 0);-- tx status (changes during transmission)
			udp_tx_data_out_ready: out std_logic;							-- indicates udp_tx is ready to take data
			-- UDP RX signals
			udp_rx_start			: out std_logic;							-- indicates receipt of udp header
			udp_rxo					: out udp_rx_type;
			-- IP RX signals
			ip_rx_hdr				: out ipv4_rx_header_type;
			-- system signals
			rx_clk					: in  STD_LOGIC;
			tx_clk					: in  STD_LOGIC;
			reset 					: in  STD_LOGIC;
			our_ip_address 		: in STD_LOGIC_VECTOR (31 downto 0);
			our_mac_address 		: in std_logic_vector (47 downto 0);
			dst_mac_address    	: in  std_logic_vector (47 downto 0);
--			control					: in udp_control_type;
			-- status signals
--			arp_pkt_count			: out STD_LOGIC_VECTOR(7 downto 0);			-- count of arp pkts received
			ip_pkt_count			: out STD_LOGIC_VECTOR(7 downto 0);			-- number of IP pkts received for us
			-- MAC Transmitter
			mac_tx_tdata         : out  std_logic_vector(15 downto 0);	-- data byte to tx
			mac_tx_tvalid        : out  std_logic;							-- tdata is valid
			mac_tx_tready        : in std_logic;							-- mac is ready to accept data
			mac_tx_tfirst        : out  std_logic;							-- indicates first byte of frame
			mac_tx_tlast         : out  std_logic;							-- indicates last byte of frame
			-- MAC Receiver
			mac_rx_tdata         : in std_logic_vector(15 downto 0);	-- data byte received
			mac_rx_tvalid        : in std_logic;							-- indicates tdata is valid
			mac_rx_tready        : out  std_logic;							-- tells mac that we are ready to take data
			mac_rx_tlast         : in std_logic								-- indicates last byte of the trame
			----debug----
--			TRIG0 : out std_logic_vector(31 downto 0);
--			TRIG2 : out std_logic_vector(31 downto 0);
--			TRIG3 : out std_logic_vector(31 downto 0)			
			);
	end component;
	
	component xwb_fabric_source
    port (
      clk_i     : in  std_logic;
      rst_n_i   : in  std_logic;
      src_i     : in  t_wrf_source_in;
      src_o     : out t_wrf_source_out;
      addr_i    : in  std_logic_vector(1 downto 0);
      data_i    : in  std_logic_vector(15 downto 0);
      dvalid_i  : in  std_logic;
      sof_i     : in  std_logic;
      eof_i     : in  std_logic;
      error_i   : in  std_logic;
      bytesel_i : in  std_logic;
      dreq_o    : out std_logic);
	end component;
	
	component xwb_fabric_sink 
	  port (
		 clk_i   : in std_logic;
		 rst_n_i : in std_logic;
		 snk_i : in  t_wrf_sink_in;
		 snk_o : out t_wrf_sink_out;
		 addr_o    : out std_logic_vector(1 downto 0);
		 data_o    : out std_logic_vector(15 downto 0);
		 dvalid_o  : out std_logic;
		 sof_o     : out std_logic;
		 eof_o     : out std_logic;
		 error_o   : out std_logic;
		 bytesel_o : out std_logic;
		 dreq_i    : in  std_logic);
	end component;

COMPONENT udp_tx_fsm
	generic(
		 g_data_tx_width  	: natural := 16;
		 g_nb_data_packed 	: natural := 20;		--number of data packets in one UDP frame
		 g_add_data_tx_width : natural := 16;
		 g_tx_timeout 			: integer := 655000 --	~10ms
		 );
    Port (
		clk_i				: in std_logic;
		rst_i				: in std_logic;
		--- configuration
		port_dstsrc 		: in std_logic_vector(15 downto 0);
		cfg_ip_target_i 	: in std_logic_vector(31 downto 0) := x"C0A80010";  			--IP dst 192.168.0.10
		-- UDP TX 
		udp_tx_start				: out std_logic;								-- indicates req to tx UDP
		udp_txi						: out udp_tx_type;							-- UDP tx cxns
		udp_tx_result				: in std_logic_vector(1 downto 0);		-- tx status (changes during transmission)
		udp_tx_data_out_ready	: in std_logic;								-- indicates udp_tx is ready to take data		
		busy_o						: out std_logic;	
		add_tx_data					: in std_logic_vector(g_add_data_tx_width-1 downto 0);	
		--- FIFO interface	
		data4tx_i			: in std_logic_vector(g_data_tx_width-1 downto 0);     -- data for tx
		rd_en_o				: out std_logic;	
--		fifo_empty_i 		: in std_logic;
--		data_valid_i		: in std_logic;
		data_cnt_i  		: in std_logic_vector(f_log2_size(2*g_nb_data_packed)-1 downto 0);
		almost_full_i  	: in std_logic
--		rd_data_cnt_i  	: in std_logic_VECTOR(9 downto 0);
		--wr_data_cnt_i  	: in std_logic_VECTOR(6 downto 0)
		--------Debug-----
--		TRIG0 : out std_logic_vector(31 downto 0);
--		TRIG1 : out std_logic_vector(31 downto 0)
	 );
END COMPONENT;

--COMPONENT tx_fifo		--independent clocks
--  PORT (
--    rst : IN STD_LOGIC;
--    wr_clk : IN STD_LOGIC;
--    rd_clk : IN STD_LOGIC;
--    din : IN STD_LOGIC_VECTOR(95 DOWNTO 0);
--    wr_en : IN STD_LOGIC;
--    rd_en : IN STD_LOGIC;
--    dout : OUT STD_LOGIC_VECTOR(95 DOWNTO 0);
--    full : OUT STD_LOGIC;
--    empty : OUT STD_LOGIC;
--    almost_empty : OUT STD_LOGIC;
--    rd_data_count : OUT STD_LOGIC_VECTOR(5 DOWNTO 0);
--    prog_full : OUT STD_LOGIC
--  );
--END COMPONENT;


	COMPONENT tx_fifo
  PORT (
    clk : IN STD_LOGIC;
    rst : IN STD_LOGIC;
    din : IN STD_LOGIC_VECTOR(95 DOWNTO 0);
    wr_en : IN STD_LOGIC;
    rd_en : IN STD_LOGIC;
    dout : OUT STD_LOGIC_VECTOR(95 DOWNTO 0);
    full : OUT STD_LOGIC;
    empty : OUT STD_LOGIC;
    almost_empty : OUT STD_LOGIC;
    data_count : OUT STD_LOGIC_VECTOR(5 DOWNTO 0)
  );
END COMPONENT;

	component udp_rx_fsm
		generic(
			g_data_rx_width  : natural := 16;
			g_padding_length : natural := 32 );
		 port(
			rst_i 			: IN std_logic;
			clk_i 			: IN std_logic;
			udp_rx_start_i : IN std_logic;
			udp_rx_i 		: IN udp_rx_type;          
			udp_rx_data_o 	: OUT STD_LOGIC_VECTOR (g_data_rx_width-1 downto 0);
			data_valid_o 	: OUT std_logic
		);
	end component;
	
	signal fab_src, fab_snk   	: t_pipe;
	signal udp_src_i 				: t_wrf_source_in;
   signal udp_src_o 				: t_wrf_source_out;
	signal rst_p, delay_eof		: std_logic;
	signal  data_fifo2udptx 	: std_logic_vector(g_data_tx_width-1 downto 0);
	--fifo tx signals
	signal  tx_rd_en, busy, tx_data_valid, tx_almost_full : std_logic;		--tx_almost_empty,
	signal datatx_count : std_logic_vector(f_log2_size(2*g_nb_data_packed)-1 downto 0);	
--	signal datatx_count : std_logic_vector(f_log2_size(4*g_nb_data_packed)-1 downto 0);	

	signal stop_trig, wr_en_fifo : std_logic;	
	
	---RX signals 
	signal rx_data  			: std_logic_vector(g_data_rx_width-1 downto 0);
	signal rx_data_ready 	: std_logic;
-- UDP signals
	signal udp_tx_result 	: std_logic_vector(1 downto 0);
	signal udp_txi				: udp_tx_type;
	signal udp_rx				: udp_rx_type;
--	signal control_udp		: udp_control_type;
	signal ip_pkt_count : std_logic_vector(7 downto 0);
	signal udp_tx_start, udp_rx_start, udp_tx_data_out_ready		: std_logic;
	
begin
	
	  --------active high reset----
	rst_p <= not rst_n_i; 		-- !!!! Active high reset on UDP ip !!!!!
	
	udp_src_i 			<= src_i;
	src_o 				<= udp_src_o;
	rx_data_o 			<= rx_data;
	rx_data_ready_o 	<= rx_data_ready;
	
--	wr_en_fifo <= tx_data_ready_i and (not stop_trig);
	wr_en_fifo <= tx_data_ready_i;
	tx_almost_full_o <= tx_almost_full;

	UDP_Complete_nomac_i : UDP_Complete_nomac	
	port map (
		-- UDP TX signals
		udp_tx_start				=>	udp_tx_start,				-- indicates req to tx UDP
		udp_txi						=>	udp_txi,
		udp_tx_result				=> udp_tx_result,				-- tx status (changes during transmission)
		udp_tx_data_out_ready	=> udp_tx_data_out_ready,	-- indicates udp_tx is ready to take data
		-- UDP RX signals
		udp_rx_start				=> udp_rx_start,				-- indicates receipt of udp header
		udp_rxo						=> udp_rx,
		-- IP RX signals
		ip_rx_hdr					=> open,
		-- system signals
		rx_clk						=>	clk_sys_i,			--62,5MHZ				--Clk_125_Mhz,
		tx_clk						=>	clk_sys_i,			--62,5MHZ				--Clk_125_Mhz,
		reset 						=> rst_p,
		our_ip_address 			=>	cfg_ip_local_i, 					
		our_mac_address 			=>	cfg_mac_local_i,	
		dst_mac_address			=>	cfg_mac_target_i,
--		control						=> control_udp,
		-- status signals
		ip_pkt_count				=> ip_pkt_count,		-- number of IP pkts received for us
		-- MAC Transmitter
		mac_tx_tdata         	=> fab_src.data,		-- data to tx
		mac_tx_tvalid        	=> fab_src.dvalid,	-- tdata is valid
		mac_tx_tready        	=>	fab_src.dreq,		-- mac is ready to accept data
		mac_tx_tfirst        	=> fab_src.sof,		-- indicates first byte of frame
		mac_tx_tlast         	=> fab_src.eof,		--delay_eof,		-- indicates last byte of frame
		-- MAC Receiver
		mac_rx_tdata         	=>	fab_snk.data,		-- data byte received
		mac_rx_tvalid        	=>	fab_snk.dvalid,	-- indicates tdata is valid
		mac_rx_tready        	=> fab_snk.dreq,		-- tells mac that we are ready to take data
		mac_rx_tlast         	=> fab_snk.eof			-- indicates last byte of the trame
--		TRIG2 						=> TRIG2,
--		TRIG3 						=> TRIG3
		);
			
			
	U_Fab_Source : xwb_fabric_source
    port map(
      clk_i     => clk_sys_i,
      rst_n_i   => rst_n_i,
      src_i     => udp_src_i,
      src_o     => udp_src_o,
      addr_i    => c_WRF_DATA,		-- "00"
      data_i    => fab_src.data, 	-- 16bits
      dvalid_i  => fab_src.dvalid,
      sof_i     => fab_src.sof,
      eof_i     => fab_src.eof,
      error_i   => '0',
      bytesel_i => '0',
      dreq_o    => fab_src.dreq
		);
		
		
	U_Fab_Sink : xwb_fabric_sink 
	  port map(
		 clk_i     => clk_sys_i,
       rst_n_i   => rst_n_i,
		 snk_i 	  => snk_i,
		 snk_o 	  => snk_o,
		 addr_o    => open,
		 data_o    => fab_snk.data,
		 dvalid_o  => fab_snk.dvalid,
		 sof_o     => open,
		 eof_o     => fab_snk.eof,
		 error_o   => open,
		 bytesel_o => open,
		 dreq_i    => fab_snk.dreq);		 
		 
--U_TX_Buffer : tx_fifo
--  PORT MAP (
--    rst => rst_p,
--    wr_clk => clk_sys_i,
--    rd_clk => clk_sys_i,
--    din => tx_data_i,
--    wr_en => wr_en_fifo,
--    rd_en => tx_rd_en,
--    dout => data_fifo2udptx,
--    full => open,		--full,
--    empty => open,	--empty,
--    almost_empty => tx_almost_empty_o,
--    rd_data_count => datatx_count,
--    prog_full => tx_almost_full
--  );


--U_TX_Buffer : tx_fifo
--  PORT MAP (
--    rst => rst_p,
--    clk => clk_sys_i,
--    din => tx_data_i,
--    wr_en => wr_en_fifo,
--    rd_en => tx_rd_en,
--    dout => data_fifo2udptx,
--    full => open,		--full,
--    empty => open,	--empty,
--    almost_empty => tx_almost_empty_o,
--    data_count => datatx_count
--  );

		 
 U_TX_Buffer : generic_sync_fifo
    generic map (
      g_data_width             => g_data_tx_width,
      g_size                   => 2*g_nb_data_packed,
      g_with_almost_full       => true,
		g_with_almost_empty      => true,
      g_almost_empty_threshold => 1,
      g_almost_full_threshold  => g_nb_data_packed,
		g_with_count        	 	 => true,
      g_show_ahead         	 => true
		)
    port map (
      rst_n_i        => rst_n_i,
      clk_i          => clk_sys_i,
      d_i            => tx_data_i,
      we_i           => wr_en_fifo,
      q_o            => data_fifo2udptx,
      rd_i           => tx_rd_en,
      empty_o        => open,
      full_o         => open,
      almost_empty_o => tx_almost_empty_o,
      almost_full_o  => tx_almost_full,
		count_o			=> datatx_count
      );

U_udp_tx_fsm : udp_tx_fsm 
	generic map(
		 g_data_tx_width  	=> g_data_tx_width,
		 g_add_data_tx_width => g_add_data_tx_width,
		 g_nb_data_packed 	=> g_nb_data_packed, --number of g_data_tx_width data packed in one UDP frame 
		 g_tx_timeout 			=> 13100000		-- 200ms		--6550000 --	~100ms					--3275000			-- ~50ms	13100000
		 )	
    port map(
		clk_i					=> clk_sys_i,
		rst_i					=>  rst_p,
		--- configuration
		port_dstsrc 		=> cfg_port_i,
		cfg_ip_target_i 	=> cfg_ip_target_i, 				
		-- UDP TX 
		udp_tx_start				=>	udp_tx_start,				-- indicates req to tx UDP
		udp_txi						=> udp_txi,						-- UDP tx cxns
		udp_tx_result				=> udp_tx_result,				-- tx status (changes during transmission)
		udp_tx_data_out_ready	=> udp_tx_data_out_ready,	-- indicates udp_tx is ready to take data		
		busy_o						=> busy,	
		add_tx_data					=> add_tx_data,
		--- FIFO interface	
		data4tx_i			=> data_fifo2udptx,    -- data for tx
		rd_en_o				=> tx_rd_en,
--		fifo_empty_i 		=> open--,
		--data_valid_i		=> tx_data_valid,
		data_cnt_i 			=> datatx_count,
		almost_full_i  	=> tx_almost_full 		
		--------Debug-----
--		TRIG0 => TRIG0,
--		TRIG1 => TRIG1
	 );

-----------------------------------------
		 
----RX FIFO		 
--U_FIFO_Rxdata : fifo_data16b64b
--  PORT MAP (
--    rst => rst_p,
--    wr_clk => clk_sys_i,
--    rd_clk => clk_sys_i,
--    din => rx_data,
--    wr_en => wr_en,
--    rd_en => rd_en,
--    dout => rx_data_o,
--    full => full,
--    empty => empty,
--    valid => valid,
--    prog_full => prog_full
--  );	 
		 
		 
--- Extract RXdata	 
	U_udp_rx_fsm: udp_rx_fsm 
	generic map(
		g_data_rx_width => g_data_rx_width) 
	port map(
		rst_i 			=> rst_p,
		clk_i 			=> clk_sys_i,
		udp_rx_start_i => udp_rx_start,
		udp_rx_i 		=> udp_rx,
		udp_rx_data_o 	=> rx_data,
		data_valid_o 	=> rx_data_ready 
	);
		 
	
	-----DEBUG-----
--	TRIG0(31 downto 16)	<= udp_txi.data.data_out; 
--	TRIG0(15 downto 0)	<= data_fifo2udptx;	
--	
--	TRIG1(31 downto 20)	<= tx_data_i(123 downto 112); 	--SPI data trigger counter
--	TRIG1(19 downto 4)	<= tx_data_i(111 downto 96);		--event counter
--	TRIG1(3)					<= tx_data_ready_i;
--	TRIG1(2)					<= tx_rd_en;
--	TRIG1(1)					<= tx_fifo_empty;
--	TRIG1(0)					<= tx_data_valid;
--	
--	--TRIG2(31 downto 25) 	<= rd_datatx_count;
--	TRIG2(24 downto 9) 	<= udp_txi.hdr.data_length; 
--	
--	TRIG1(22) 				<= udp_src_i.ack;
--	TRIG1(23) 				<= udp_src_i.err;
--	TRIG1(24) 				<= udp_src_i.stall;
	
--	TRIG1(15 downto 0) 	<= udp_txi.data.data_out;
--	TRIG1(30) 				<= udp_tx_start;
--	TRIG1(31) 				<= udp_tx_data_out_ready;
--	TRIG2(15 downto 0) 	<= fab_src.data;
--	TRIG2(28) 				<= fab_src.dreq;
--	TRIG2(29) 				<= fab_src.dvalid;
--	TRIG2(30) 				<= fab_src.eof;
--	TRIG2(31) 				<= fab_src.sof;
--	TRIG3(15 downto 0) 	<= udp_txi.hdr.data_length;
--	TRIG3(31 downto 16) 	<= udp_txi.hdr.dst_ip_addr(31 downto 16);
		
end Behavioral;
