----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    17:45:42 02/04/2016 
-- Design Name: 
-- Module Name:    nexys3_phy - 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;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
library UNISIM;
use UNISIM.VComponents.all;


entity nexys3_phy is
	port (
		clk_in						: in    std_logic;
		board_id						: in    std_logic_vector(2 downto 0);
		
      -- GMII Interface
      -----------------     
      PhyRstn						: out   std_logic;
		PhyRxClk						: in    std_logic;
		PhyRxDv						: in    std_logic;
		PhyRxd						: in    std_logic_vector(3 downto 0);
		PhyRxEr						: in    std_logic;
		PhyTxClk						: in    std_logic;
		PhyTxEn						: out   std_logic;
      PhyTxd						: out   std_logic_vector(3 downto 0);
		PhyTxEr						: out   std_logic;
      PhyMdc						: out   std_logic;
      PhyMdio						: inout std_logic;
--		PhyCrs						: in    std_logic;
--		PhyCol						: in    std_logic;
		-----------------
		GPIO_LEDs					: out   std_logic_vector(7 downto 0);
		GPIO_Switches				: in    std_logic_vector(7 downto 0);
		GPIO_Buttons				: in    std_logic_vector(4 downto 0);
		Disp_seg						: out   std_logic_vector(7 downto 0);
		Disp_an						: out   std_logic_vector(3 downto 0)
	);
end nexys3_phy;


architecture Behavioral of nexys3_phy is

	component clock_wiz
	port (
		CLK_IN1		: in  std_logic;
		CLK_OUT1		: out std_logic;
		RESET			: in  std_logic;
		LOCKED		: out std_logic
	);
	end component;


	component phy_controller
	port (
		clk									: in    std_logic;
		phy_reset_done						: in    std_logic;
		phy_cmd_available					: in    std_logic;
		phy_command							: in    std_logic_vector(31 downto 0);
		phy_cmd_busy						: out   std_logic;
		phy_reply							: out   std_logic_vector(31 downto 0);
      PhyMdc								: out   std_logic;
      PhyMdio								: inout std_logic
	);
	end component;


	component phy_io
	port (
		PhyRxClk						: in  std_logic;
		PhyRxDv						: in  std_logic;
		PhyRxd						: in  std_logic_vector(3 downto 0);
		PhyRxEr						: in  std_logic;
		rx_clk						: out std_logic;
		rx_data_valid				: out std_logic;
		rx_data						: out std_logic_vector(3 downto 0);
		rx_data_error				: out std_logic;
		PhyTxClk						: in  std_logic;
		PhyTxEn						: out std_logic;
      PhyTxd						: out std_logic_vector(3 downto 0);
		PhyTxEr						: out std_logic;
		tx_clk						: out std_logic;
		tx_data_enable				: in  std_logic;
		tx_data						: in  std_logic_vector(3 downto 0)
	);
	end component;
	
	signal rx_error_counter						: unsigned(31 downto 0) := (others => '0');
	
	
	component packet_parser
	port (
      clk									: in  std_logic;
		reset_enet_counters				: in  std_logic;
      rx_clk								: in  std_logic;
      rx_data_in							: in  std_logic_vector(3 downto 0);
      rx_data_valid						: in  std_logic;
		tx_clk								: in  std_logic;
      tx_data_out							: out std_logic_vector(3 downto 0);
      tx_data_enable						: out std_logic;
		message_fifo_in_wr_en			: out std_logic;
		message_fifo_in_din				: out std_logic_vector(8 downto 0);
		num_good_pkts_counter			: out std_logic_vector(31 downto 0);
		num_bad_pkts_counter				: out std_logic_vector(31 downto 0);
		board_id								: in  std_logic_vector(2 downto 0);
		message_fifo_out_rd_en			: out std_logic;
		message_fifo_out_dout			: in  std_logic_vector(63 downto 0);
		message_fifo_out_empty			: in  std_logic;
		send_reply							: in  std_logic;
		reply_busy							: out std_logic;
		pkt_rx_busy							: out std_logic;
		pkt_tx_arp_busy					: out std_logic;
		pkt_tx_udp_busy					: out std_logic;
		debug									: out std_logic_vector(1 downto 0)
	);
	end component;


	component message_parser
	port (
		clk									: in  std_logic;
		reset_enet_counters				: out std_logic;
		message_fifo_in_wr_en			: in  std_logic;
		message_fifo_in_din				: in  std_logic_vector(8 downto 0);
		message_fifo_in_full				: out std_logic;
		message_fifo_out_rd_en			: in  std_logic;
		message_fifo_out_dout			: out std_logic_vector(63 downto 0);
		message_fifo_out_empty			: out std_logic;
		command_available					: out std_logic;
		command_contents					: out std_logic_vector(31 downto 0);
		command_reply_available			: in  std_logic;
		command_reply_contents			: in  std_logic_vector(31 downto 0);
		num_good_pkts_counter			: in  std_logic_vector(31 downto 0);
		num_bad_pkts_counter				: in  std_logic_vector(31 downto 0);
		firmware_version					: in  std_logic_vector(15 downto 0);
		send_reply							: out std_logic;
		reply_busy							: in  std_logic;
		phy_cmd_available					: out std_logic;
		phy_command							: out std_logic_vector(31 downto 0);
		phy_cmd_busy						: in  std_logic;
		phy_reply							: in  std_logic_vector(31 downto 0);
		rx_error_counter					: in  unsigned(31 downto 0);
--		rx_data_error						: in  std_logic;
--		tx_data_error						: out std_logic;
		unused_inputs						: in  std_logic_vector(1 downto 0)
	);
	end component;


	component command_processor
	port (
		clk									: in  std_logic;
		command_available					: in  std_logic;
		command_contents					: in  std_logic_vector(31 downto 0);
		command_reply_available			: out std_logic;
		command_reply_contents			: out std_logic_vector(31 downto 0);
		firmware_version					: in  std_logic_vector(15 downto 0);
		hdw_cmd_busy						: out std_logic;
		command_busy						: out std_logic;
		GPIO_Switches						: in  std_logic_vector(7 downto 0);
		GPIO_Buttons						: in  std_logic_vector(4 downto 0);
		Disp_seg								: out std_logic_vector(7 downto 0);
		Disp_an								: out std_logic_vector(3 downto 0)
	);
	end component;
	
	signal clk_i										: std_logic;
	
	signal phy_reset									: std_logic;
	signal phy_reset_done							: std_logic := '0';
	signal phy_reset_count							: unsigned(11 downto 0) := (others => '0');

	signal tx_clock_counter							: unsigned(23 downto 0) := (others => '0');
	signal rx_clock_counter							: unsigned(23 downto 0) := (others => '0');
	
	signal tx_data_i									: std_logic_vector(3 downto 0);
	signal tx_data_enable_i							: std_logic;
--	signal tx_data_error_i							: std_logic;
	signal rx_data_i									: std_logic_vector(3 downto 0);
	signal rx_data_valid_i							: std_logic;
	signal rx_data_error_i							: std_logic;
	signal rx_phy_crs_i								: std_logic;
	signal rx_phy_col_i								: std_logic;
	signal pkt_debug									: std_logic_vector(1 downto 0);
	
	signal rx_clk_i									: std_logic;
	signal phytxclk_buf								: std_logic;
	signal tx_clk_i									: std_logic;
		
	signal message_fifo_in_wr_en_i				: std_logic;
	signal message_fifo_in_din_i					: std_logic_vector(8 downto 0);
	signal message_fifo_in_full_i					: std_logic;
		
	signal message_fifo_out_rd_en_i				: std_logic;
	signal message_fifo_out_dout_i				: std_logic_vector(63 downto 0);
	signal message_fifo_out_empty_i				: std_logic;
	
	signal reset_enet_counters_i					: std_logic;
	signal num_good_pkts_counter_i				: std_logic_vector(31 downto 0);
	signal num_bad_pkts_counter_i					: std_logic_vector(31 downto 0);
	
	signal send_reply_i								: std_logic;
	signal reply_busy_i								: std_logic;
	signal pkt_rx_busy								: std_logic;
	signal pkt_tx_arp_busy							: std_logic;
	signal pkt_tx_udp_busy							: std_logic;
	
	signal phy_cmd_available						: std_logic;
	signal phy_command								: std_logic_vector(31 downto 0);
	signal phy_cmd_busy								: std_logic;
	signal phy_reply									: std_logic_vector(31 downto 0);
	
	signal command_available_i						: std_logic;
	signal command_contents_i						: std_logic_vector(31 downto 0);
	signal command_reply_available_i				: std_logic;
	signal command_reply_contents_i				: std_logic_vector(31 downto 0);
	
	signal hdw_cmd_busy_i							: std_logic;
	signal command_busy_i							: std_logic;
	
	
 constant firmware_version_i						: std_logic_vector(15 downto 0) := x"0100";
 
begin

	main_clock_gen : clock_wiz
	port map (
		CLK_IN1	=> clk_in,
		CLK_OUT1	=> clk_i,
		RESET		=> '0',
		LOCKED	=> open
	);

	PhyRstn <= not phy_reset;

	gen_phy_reset : process (clk_i)
	begin
		if rising_edge(clk_i) then
			if (phy_reset_count = x"FFF") then
				phy_reset <= '0';
				phy_reset_done <= '1';
			else
				phy_reset <= '1';
				phy_reset_count <= phy_reset_count + 1;
			end if;
		end if;
	end process gen_phy_reset;


	phy_controller_0 : phy_controller
	port map (
		clk						=> clk_i,
		phy_reset_done			=> phy_reset_done,
		phy_cmd_available		=> phy_cmd_available,
		phy_command				=> phy_command,
		phy_cmd_busy			=> phy_cmd_busy,
		phy_reply				=> phy_reply,
      PhyMdc					=> PhyMdc,
      PhyMdio					=> PhyMdio
	);
	
	
	GPIO_Leds(0) <= rx_clock_counter(23);
	GPIO_Leds(1) <= tx_clock_counter(23);
	GPIO_Leds(2) <= reply_busy_i;
	GPIO_Leds(3) <= pkt_rx_busy;
	GPIO_Leds(4) <= pkt_tx_arp_busy;
	GPIO_Leds(5) <= pkt_tx_udp_busy;
	GPIO_Leds(6) <= command_busy_i;
	GPIO_Leds(7) <= hdw_cmd_busy_i;
	
	
	rx_clk_ctr_proc : process(rx_clk_i)
	begin
		if rising_edge(rx_clk_i) then
			rx_clock_counter <= rx_clock_counter + 1;
		end if;
	end process rx_clk_ctr_proc;
	
	tx_clk_ctr_proc : process(tx_clk_i)
	begin
		if rising_edge(tx_clk_i) then
			tx_clock_counter <= tx_clock_counter + 1;
		end if;
	end process tx_clk_ctr_proc;
	
	
	phy_io_0 : phy_io
	port map (
		PhyRxClk				=> PhyRxClk,
		PhyRxDv				=> PhyRxDv,
		PhyRxd				=> PhyRxd,
		PhyRxEr				=> PhyRxEr,
		rx_clk				=> rx_clk_i,
		rx_data_valid		=> rx_data_valid_i,
		rx_data				=> rx_data_i,
		rx_data_error		=> rx_data_error_i,
		PhyTxClk				=> PhyTxClk,
		PhyTxEn				=> PhyTxEn,
		PhyTxd				=> PhyTxd,
		PhyTxEr				=> PhyTxEr,
		tx_clk				=> tx_clk_i,
		tx_data_enable		=> tx_data_enable_i,
		tx_data				=> tx_data_i
	);



	rx_error_counter_proc : process (reset_enet_counters_i, rx_clk_i)
	begin
		if (reset_enet_counters_i = '1') then
			rx_error_counter <= (others => '0');
		elsif rising_edge(rx_clk_i) then
			if (rx_data_error_i = '1') then
				rx_error_counter <= rx_error_counter + 1;
			end if;
		end if;
	end process rx_error_counter_proc;


	packet_parser_0 : packet_parser
	port map (
		clk									=> clk_i,
		reset_enet_counters				=> reset_enet_counters_i,
      rx_clk								=> rx_clk_i,
      rx_data_in							=> rx_data_i,
      rx_data_valid						=> rx_data_valid_i,
      tx_clk								=> tx_clk_i,
      tx_data_out							=> tx_data_i,
      tx_data_enable						=> tx_data_enable_i,
		message_fifo_in_wr_en			=> message_fifo_in_wr_en_i,
		message_fifo_in_din				=> message_fifo_in_din_i,
		num_good_pkts_counter			=> num_good_pkts_counter_i,
		num_bad_pkts_counter				=> num_bad_pkts_counter_i,
		board_id								=> board_id,
		message_fifo_out_rd_en			=> message_fifo_out_rd_en_i,
		message_fifo_out_dout			=> message_fifo_out_dout_i,
		message_fifo_out_empty			=> message_fifo_out_empty_i,
		send_reply							=> send_reply_i,
		reply_busy							=> reply_busy_i,
		pkt_rx_busy							=> pkt_rx_busy,
		pkt_tx_arp_busy					=> pkt_tx_arp_busy,
		pkt_tx_udp_busy					=> pkt_tx_udp_busy,
		debug									=> pkt_debug
	);
	
	 
	message_parser_0: message_parser
	port map (
		clk									=> clk_i,
		reset_enet_counters				=> reset_enet_counters_i,
		message_fifo_in_wr_en			=> message_fifo_in_wr_en_i,
		message_fifo_in_din				=> message_fifo_in_din_i,
		message_fifo_in_full				=> message_fifo_in_full_i,
		message_fifo_out_rd_en			=> message_fifo_out_rd_en_i,
		message_fifo_out_dout			=> message_fifo_out_dout_i,
		message_fifo_out_empty			=> message_fifo_out_empty_i,
		command_available					=> command_available_i,
		command_contents					=> command_contents_i,
		command_reply_available			=> command_reply_available_i,
		command_reply_contents			=> command_reply_contents_i,
		num_good_pkts_counter			=> num_good_pkts_counter_i,
		num_bad_pkts_counter				=> num_bad_pkts_counter_i,
		firmware_version					=> firmware_version_i,
		send_reply							=> send_reply_i,
		reply_busy							=> reply_busy_i,
		phy_cmd_available					=> phy_cmd_available,
		phy_command							=> phy_command,
		phy_cmd_busy						=> phy_cmd_busy,
		phy_reply							=> phy_reply,
		rx_error_counter					=> rx_error_counter,
--		rx_data_error						=> rx_data_error_i,
--		tx_data_error						=> tx_data_error_i,
		unused_inputs						=> pkt_debug
	);
	

	command_processor_0 : command_processor
	port map (
		clk									=> clk_i,
		command_available					=> command_available_i,
		command_contents					=> command_contents_i,
		command_reply_available			=> command_reply_available_i,
		command_reply_contents			=> command_reply_contents_i,
		firmware_version					=> firmware_version_i,
		hdw_cmd_busy						=> hdw_cmd_busy_i,
		command_busy						=> command_busy_i,
		GPIO_Switches						=> GPIO_Switches,
		GPIO_Buttons						=> GPIO_Buttons,
		Disp_seg								=> Disp_seg,
		Disp_an								=> Disp_an
	);

end Behavioral;

