-- EMACS settings: -*-  tab-width: 2; indent-tabs-mode: t -*-
-- vim: tabstop=2:shiftwidth=2:noexpandtab
-- kate: tab-width 2; replace-tabs off; indent-width 2;
-- =============================================================================
-- Authors:				 	Patrick Lehmann
--
-- Entity:				 	TODO
--
-- Description:
-- 
-- .. TODO:: No documentation available.
--
-- License:
-- =============================================================================
-- Copyright 2007-2015 Technische Universitaet Dresden - Germany
--										 Chair of VLSI-Design, Diagnostics and Architecture
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--		http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-- =============================================================================

library IEEE;
use			IEEE.STD_LOGIC_1164.all;
use			IEEE.NUMERIC_STD.all;

library PoC;
use			PoC.utils.all;
use			PoC.vectors.all;
use			PoC.strings.all;
use			PoC.io.all;


package [docs]net is
	-- ==========================================================================================================================================================
	-- Ethernet: physical layer (PHY)
	-- ==========================================================================================================================================================
	type T_NET_ETH_PHY_DATA_INTERFACE is (
		NET_ETH_PHY_DATA_INTERFACE_MII,
		NET_ETH_PHY_DATA_INTERFACE_GMII,
		NET_ETH_PHY_DATA_INTERFACE_RGMII,
		NET_ETH_PHY_DATA_INTERFACE_SGMII
	);

	type T_NET_ETH_PHY_MANAGEMENT_INTERFACE is (
		NET_ETH_PHY_MANAGEMENT_INTERFACE_NONE,
		NET_ETH_PHY_MANAGEMENT_INTERFACE_MDIO,
		NET_ETH_PHY_MANAGEMENT_INTERFACE_MDIO_OVER_IIC
	);

	type T_NET_ETH_PCSCORE is (
		NET_ETH_PCSCORE_GENERIC_GMII,
		NET_ETH_PCSCORE_XILINX_HARDCORE,
		NET_ETH_PCSCORE_XILINX_PCSCORE
	);

	type T_NET_ETH_PHY_DEVICE is (
		NET_ETH_PHY_DEVICE_MARVEL_88E1111
	);

	subtype T_NET_ETH_PHY_DEVICE_ADDRESS is T_SLV_8;

	type T_NET_ETH_PHYCONTROLLER_COMMAND is (
		NET_ETH_PHYC_CMD_NONE,
		NET_ETH_PHYC_CMD_HARD_RESET,
		NET_ETH_PHYC_CMD_SOFT_RESET
	);

	type T_NET_ETH_PHYCONTROLLER_STATUS is (
		NET_ETH_PHYC_STATUS_POWER_DOWN,
		NET_ETH_PHYC_STATUS_RESETING,
		NET_ETH_PHYC_STATUS_CONNECTING,
		NET_ETH_PHYC_STATUS_CONNECTED,
		NET_ETH_PHYC_STATUS_DISCONNECTING,
		NET_ETH_PHYC_STATUS_DISCONNECTED,
		NET_ETH_PHYC_STATUS_ERROR
	);

	type T_NET_ETH_PHYCONTROLLER_ERROR is (
		NET_ETH_PHYC_ERROR_NONE,
		NET_ETH_PHYC_ERROR_NO_CABLE
	);

	-- FPGA <=> PHY physical interface: GMII (Gigabit Media Independant Interface)
	type T_NET_ETH_PHY_INTERFACE_GMII is record
		RX_RefClock						: std_logic;

		TX_Clock							: std_logic;
		TX_Valid							: std_logic;
		TX_Data								: T_SLV_8;
		TX_Error							: std_logic;

		RX_Clock							: std_logic;
		RX_Valid							: std_logic;
		RX_Data								: T_SLV_8;
		RX_Error							: std_logic;
	end record;

	-- FPGA <=> PHY physical interface: RGMII (Reduced Gigabit Media Independant Interface)
	type T_NET_ETH_PHY_INTERFACE_RGMII is record
		RX_RefClock						: std_logic;

		TX_Clock							: std_logic;
		TX_Data								: T_SLV_4;
		TX_Control						: std_logic;

		RX_Clock							: std_logic;
		RX_Data								: T_SLV_4;
		RX_Control						: std_logic;
	end record;

	-- FPGA <=> PHY physical interface: SGMII (Serial GMII)
	type T_NET_ETH_PHY_INTERFACE_SGMII is record
		DGB_SystemClock_In		: std_logic;
		DGB_AutoNeg_Restart		: std_logic;

		SGMII_RefClock_In			: std_logic;
		SGMII_TXRefClock_Out	: std_logic;
		SGMII_RXRefClock_Out	: std_logic;

		TX_n									: std_logic;
		TX_p									: std_logic;

		RX_n									: std_logic;
		RX_p									: std_logic;
	end record;

	-- FPGA <=> PHY management interface: MDIO (Management Data Input/Output)
	type T_NET_ETH_PHY_INTERFACE_MDIO is record
		Clock_ts							: T_IO_TRISTATE;	-- clock (MDC)
		Data_ts								: T_IO_TRISTATE;	-- data (MDIO)
	end record;

	type T_NET_ETH_PHY_INTERFACE_COMMON is record
		Reset									: std_logic;
		Interrupt							: std_logic;
	end record;

	-- combined interface definition - union-types are still not supported in VHDL
	type T_NET_ETH_PHY_INTERFACES is record
		GMII									: T_NET_ETH_PHY_INTERFACE_GMII;
		RGMII									: T_NET_ETH_PHY_INTERFACE_RGMII;
		SGMII									: T_NET_ETH_PHY_INTERFACE_SGMII;
		MDIO									: T_NET_ETH_PHY_INTERFACE_MDIO;
		Common								: T_NET_ETH_PHY_INTERFACE_COMMON;
	end record;

	-- ==========================================================================================================================================================
	-- Ethernet: physical coding sublayer (PCS)
	-- ==========================================================================================================================================================
	-- 1000BASE-X - synchronization
	type T_NET_ETH_PCS_1000BASE_X_SYNC_STATUS is (
		NET_ETH_PCS_1000BASE_X_SYNC_STATUS_FAIL,
		NET_ETH_PCS_1000BASE_X_SYNC_STATUS_OK
	);

	-- 1000BASE-X - autonegotiation
	type T_NET_ETH_PCS_1000BASE_X_AUTONEG_STATUS is (
		NET_ETH_PCS_1000BASE_X_AUTONEG_STATUS_IDLE,
		NET_ETH_PCS_1000BASE_X_AUTONEG_STATUS_CONFIG,
		NET_ETH_PCS_1000BASE_X_AUTONEG_STATUS_DATA
	);

	-- ==========================================================================================================================================================
	-- Ethernet: reconcilation sublayer (RS)
	-- ==========================================================================================================================================================
	type T_NET_ETH_RS_DATA_INTERFACE is (
		NET_ETH_RS_DATA_INTERFACE_MII,
		NET_ETH_RS_DATA_INTERFACE_GMII,
		NET_ETH_RS_DATA_INTERFACE_TRANSCEIVER
	);

	-- ==========================================================================================================================================================
	-- Ethernet: MAC Control-Layer
	-- ==========================================================================================================================================================
	type T_NET_ETH_COMMAND is (
		NET_ETH_CMD_NONE,
		NET_ETH_CMD_HARD_RESET,
		NET_ETH_CMD_SOFT_RESET--,
--		NET_ETH_CMD_POWER_DOWN,
--		NET_ETH_CMD_POWER_UP
	);

	type T_NET_ETH_STATUS is (
		NET_ETH_STATUS_POWER_DOWN,
		NET_ETH_STATUS_RESETING,
		NET_ETH_STATUS_CONNECTING,
		NET_ETH_STATUS_CONNECTED,
		NET_ETH_STATUS_DISCONNECTING,
		NET_ETH_STATUS_DISCONNECTED,
		NET_ETH_STATUS_ERROR
	);

	type T_NET_ETH_ERROR is (
		NET_ETH_ERROR_NONE,
		NET_ETH_ERROR_MAC_ERROR,
		NET_ETH_ERROR_PHY_ERROR,
		NET_ETH_ERROR_PCS_ERROR,
		NET_ETH_ERROR_NO_CABLE
	);

	-- ==========================================================================================================================================================
	-- Ethernet: ????????????????????
	-- ==========================================================================================================================================================
	function [docs]to_net_eth_RSDataInterface(str : string) return T_NET_ETH_RS_DATA_INTERFACE;
	function [docs]to_net_eth_PHYDataInterface(str : string) return T_NET_ETH_PHY_DATA_INTERFACE;
	function [docs]to_net_eth_PHYManagementInterface(str : string) return T_NET_ETH_PHY_MANAGEMENT_INTERFACE;
	function [docs]to_net_eth_PHYDevice(str : string) return T_NET_ETH_PHY_DEVICE;

	-- limitations
	constant C_NET_ETH_PREMABLE_LENGTH					: positive						:= 7;
	constant C_NET_ETH_INTER_FRAME_GAP_LENGTH		: positive						:= 12;
	constant C_NET_ETH_MIN_FRAME_LENGTH					: positive						:= 64;
	constant C_NET_ETH_MAX_NORMALFRAME_LENGTH		: positive						:= 1518;
	constant C_NET_ETH_MAX_TAGGEDFRAME_LENGTH		: positive						:= 1522;
	constant C_NET_ETH_MAX_JUMBOFRAME_LENGTH		: positive						:= 9018;

	-- ==========================================================================================================================================================
	-- Ethernet: MAC Data-Link-Layer
	-- ==========================================================================================================================================================
	-- types
	type T_NET_MAC_ADDRESS								is array (5 downto 0)				of T_SLV_8;
	type T_NET_MAC_ETHERNETTYPE						is array (1 downto 0)				of T_SLV_8;

	-- arrays
	type T_NET_MAC_ADDRESS_VECTOR					is array (natural range <>) of T_NET_MAC_ADDRESS;
	type T_NET_MAC_ETHERNETTYPE_VECTOR		is array (natural range <>)	of T_NET_MAC_ETHERNETTYPE;

	-- predefined constants
	constant C_NET_MAC_ADDRESS_EMPTY			: T_NET_MAC_ADDRESS					:= (others => (others => '0'));
	constant C_NET_MAC_ADDRESS_BROADCAST	: T_NET_MAC_ADDRESS					:= (others => (others => '1'));
	constant C_NET_MAC_MASK_EMPTY					: T_NET_MAC_ADDRESS					:= (others => (others => '0'));
	constant C_NET_MAC_MASK_DEFAULT				: T_NET_MAC_ADDRESS					:= (others => (others => '1'));
	constant C_NET_MAC_ETHERNETTYPE_EMPTY	: T_NET_MAC_ETHERNETTYPE		:= (others => (others => '0'));

	-- type conversion functions
	function [docs]to_net_mac_address(slv : T_SLV_48)						return T_NET_MAC_ADDRESS;
	function [docs]to_net_mac_address(slvv : T_SLVV_8)					return T_NET_MAC_ADDRESS;
	function [docs]to_net_mac_address(str : string)							return T_NET_MAC_ADDRESS;
	function [docs]to_net_mac_ethernettype(slv : T_SLV_16)			return T_NET_MAC_ETHERNETTYPE;

	function [docs]to_slv(mac : T_NET_MAC_ADDRESS) 							return std_logic_vector;
	function [docs]to_slv(Ethtype : T_NET_MAC_ETHERNETTYPE)			return std_logic_vector;

	function [docs]to_slvv_8(mac : T_NET_MAC_ADDRESS)						return T_SLVV_8;
	function [docs]to_slvv_8(Ethtype : T_NET_MAC_ETHERNETTYPE)	return T_SLVV_8;

	function [docs]to_string(mac : T_NET_MAC_ADDRESS)						return string;
	function [docs]to_string(Ethtype : T_NET_MAC_ETHERNETTYPE)	return string;

	-- ==========================================================================================================================================================
	-- ETH_Wrapper: configuration data structures
	-- ==========================================================================================================================================================
	type T_NET_MAC_INTERFACE is record
		Address							: T_NET_MAC_ADDRESS;
		Mask								: T_NET_MAC_ADDRESS;
	end record;

	type T_NET_MAC_INTERFACE_VECTOR is array(natural range <>) of T_NET_MAC_INTERFACE;

	constant C_NET_MAC_SOURCEFILTER_NONE	: T_NET_MAC_INTERFACE	:= (Address => to_net_mac_address("00:00:00:00:00:01"), Mask => C_NET_MAC_MASK_EMPTY);

	type T_NET_MAC_CONFIGURATION is record
		Interface						: T_NET_MAC_INTERFACE;
		SourceFilter				: T_NET_MAC_INTERFACE_VECTOR(0 to 7);
		TypeSwitch					: T_NET_MAC_ETHERNETTYPE_VECTOR(0 to 7);
	end record;

	-- arrays
	type T_NET_MAC_CONFIGURATION_VECTOR is array(natural range <>)	of T_NET_MAC_CONFIGURATION;

	-- functions
	function [docs]getPortCount(MACConfiguration : T_NET_MAC_CONFIGURATION_VECTOR) return positive;

	-- ==========================================================================================================================================================
	-- local network: sequence and flow control protocol (SFC)
	-- ==========================================================================================================================================================
	-- types
	subtype T_NET_MAC_SFC_TYPE										is T_SLV_16;

	-- arrays
	type		T_ETH_SFC_TYPE_VECTOR									is array (natural range <>) of T_NET_MAC_SFC_TYPE;

	-- predefined constants
	constant C_NET_MAC_SFC_TYPE_EMPTY							: T_NET_MAC_SFC_TYPE			:= (others => '0');

	-- ==========================================================================================================================================================
	-- internet layer: Internet Protocol - common
	-- ==========================================================================================================================================================
	subtype T_NET_IP_PROTOCOL											is T_SLV_8;


	-- ==========================================================================================================================================================
	-- internet layer: Internet Protocol Version 4 (IPv4)
	-- ==========================================================================================================================================================
	-- types
	type		T_NET_IPV4_ADDRESS										is array (3 downto 0)				of T_SLV_8;
	subtype T_NET_IPV4_PROTOCOL										is T_NET_IP_PROTOCOL;
	subtype T_NET_IPV4_TOS_PRECEDENCE							is std_logic_vector(2 downto 0);

	type T_NET_IPV4_TYPE_OF_SERVICE is record
		Precedence					: T_NET_IPV4_TOS_PRECEDENCE;
		Delay								: std_logic;
		Throughput					: std_logic;
		Relibility					: std_logic;
	end record;

	-- arrays
	type		T_NET_IPV4_ADDRESS_VECTOR							is array (natural range <>) of T_NET_IPV4_ADDRESS;
	type		T_NET_IPV4_PROTOCOL_VECTOR						is array (natural range <>) of T_NET_IPV4_PROTOCOL;
	type		T_NET_IPV4_TYPE_OF_SERVICE_VECTOR			is array (natural range <>) of T_NET_IPV4_TYPE_OF_SERVICE;

	-- predefined constants
	constant C_NET_IPV4_ADDRESS_EMPTY							: T_NET_IPV4_ADDRESS				:= (others => (others => '0'));
	constant C_NET_IPV4_PROTOCOL_EMPTY						: T_NET_IPV4_PROTOCOL				:= (others => '0');

	constant C_NET_IPV4_TOS_PRECEDENCE_ROUTINE								: T_NET_IPV4_TOS_PRECEDENCE			:= "000";
	constant C_NET_IPV4_TOS_PRECEDENCE_PRIORITY								: T_NET_IPV4_TOS_PRECEDENCE			:= "001";
	constant C_NET_IPV4_TOS_PRECEDENCE_IMMEDIATE							: T_NET_IPV4_TOS_PRECEDENCE			:= "010";
	constant C_NET_IPV4_TOS_PRECEDENCE_FLASH									: T_NET_IPV4_TOS_PRECEDENCE			:= "011";
	constant C_NET_IPV4_TOS_PRECEDENCE_FLASH_OVERRIDE					: T_NET_IPV4_TOS_PRECEDENCE			:= "100";
	constant C_NET_IPV4_TOS_PRECEDENCE_CRITIC_ECP							: T_NET_IPV4_TOS_PRECEDENCE			:= "101";
	constant C_NET_IPV4_TOS_PRECEDENCE_INTERNETWORK_CONTROL		: T_NET_IPV4_TOS_PRECEDENCE			:= "110";
	constant C_NET_IPV4_TOS_PRECEDENCE_NETWORK_CONTROL				: T_NET_IPV4_TOS_PRECEDENCE			:= "111";

	constant C_NET_IPV4_TOS_DEFAULT								: T_NET_IPV4_TYPE_OF_SERVICE		:= (Precedence => C_NET_IPV4_TOS_PRECEDENCE_ROUTINE, Delay => '0', Throughput => '0', Relibility => '0');

	-- type conversion functions
	function [docs]to_net_ipv4_address(slv : T_SLV_32)				return T_NET_IPV4_ADDRESS;
	function [docs]to_net_ipv4_address(str : string)					return T_NET_IPV4_ADDRESS;
	function [docs]to_net_ipv4_TYPE_of_service(slv : T_SLV_8)	return T_NET_IPV4_TYPE_OF_SERVICE;

	function [docs]to_slv(ip : T_NET_IPV4_ADDRESS)						return std_logic_vector;
--	function to_slv(proto : T_NET_IPV4_PROTOCOL)				return STD_LOGIC_VECTOR;
	function [docs]to_slv(tos : T_NET_IPV4_TYPE_OF_SERVICE)		return std_logic_vector;

	function [docs]to_slvv_8(ip : T_NET_IPV4_ADDRESS)		return T_SLVV_8;

	function [docs]to_string(ip : T_NET_IPV4_ADDRESS)		return string;

	-- ==========================================================================================================================================================
	-- internet layer: Internet Protocol Version 6 (IPv6)
	-- ==========================================================================================================================================================
	-- types
	type		T_NET_IPV6_ADDRESS								is array (15 downto 0)				of T_SLV_8;
	type		T_NET_IPV6_PREFIX									is record
		Prefix				: T_NET_IPV6_ADDRESS;
		PrefixLength	: std_logic_vector(6 downto 0);
	end record;
	subtype T_NET_IPV6_NEXT_HEADER						is T_NET_IP_PROTOCOL;

	-- arrays
	type		T_NET_IPV6_ADDRESS_VECTOR					is array (natural range <>) of T_NET_IPV6_ADDRESS;
	type		T_NET_IPV6_PREFIX_VECTOR					is array (natural range <>) of T_NET_IPV6_PREFIX;
	type		T_NET_IPV6_NEXT_HEADER_VECTOR			is array (natural range <>) of T_NET_IPV6_NEXT_HEADER;

	-- predefined constants
	constant C_NET_IPV6_ADDRESS_EMPTY					: T_NET_IPV6_ADDRESS				:= (others => (others => '0'));
	constant C_NET_IPV6_NEXT_HEADER_EMPTY			: T_NET_IPV6_NEXT_HEADER		:= (others => '0');

	-- type conversion functions
	function [docs]to_net_ipv6_address(slv : T_SLV_128) 	return T_NET_IPV6_ADDRESS;
	function [docs]to_net_ipv6_address(str : string)			return T_NET_IPV6_ADDRESS;
	function [docs]to_net_ipv6_prefix(str : string)				return T_NET_IPV6_PREFIX;

	function [docs]to_slv(ip : T_NET_IPV6_ADDRESS)				return std_logic_vector;
	function [docs]to_slvv_8(ip : T_NET_IPV6_ADDRESS)			return T_SLVV_8;

	function [docs]to_string(IP : T_NET_IPV6_ADDRESS)			return string;
	function [docs]to_string(Prefix : T_NET_IPV6_PREFIX)	return string;

	-- ==========================================================================================================================================================
	-- internet layer: Address Resolution Protocol (ARP)
	-- ==========================================================================================================================================================

	-- commands
	type T_NET_ARP_ARPCACHE_COMMAND is (
		NET_ARP_ARPCACHE_CMD_NONE,
--		NET_ARP_ARPCACHE_CMD_CLEAR,
		NET_ARP_ARPCACHE_CMD_ADD
--		NET_ARP_ARPCACHE_CMD_INVALIDATE
	);

	-- status
	type T_NET_ARP_ARPCACHE_STATUS is (
		NET_ARP_ARPCACHE_STATUS_IDLE,
		NET_ARP_ARPCACHE_STATUS_UPDATING,
		NET_ARP_ARPCACHE_STATUS_UPDATE_COMPLETE
	);

	type T_NET_ARP_IPPOOL_COMMAND is (
		NET_ARP_IPPOOL_CMD_NONE,
		NET_ARP_IPPOOL_CMD_ADD,
		NET_ARP_IPPOOL_CMD_EDIT,
		NET_ARP_IPPOOL_CMD_REMOVE
	);

	type T_NET_ARP_ARPCACHE_LINE is record
		Tag				: T_NET_IPV4_ADDRESS;
		MAC				: T_NET_MAC_ADDRESS;
	end record;

	type T_NET_ARP_ARPCACHE_VECTOR		is array (natural range <>) of T_NET_ARP_ARPCACHE_LINE;

	-- commands
	type T_NET_ARP_TESTER_COMMAND is (
		NET_ARP_TESTER_CMD_NONE,
		NET_ARP_TESTER_CMD_LOOP
	);

	-- status
	type T_NET_ARP_TESTER_STATUS is (
		NET_ARP_TESTER_STATUS_IDLE,
		NET_ARP_TESTER_STATUS_TESTING,
		NET_ARP_TESTER_STATUS_TEST_COMPLETE
	);

	-- ==========================================================================================================================================================
	-- internet layer: Internet Control Message Protocol (ICMP)
	-- ==========================================================================================================================================================
	subtype T_NET_ICMPV4_TYPE						is T_SLV_8;
	subtype T_NET_ICMPV4_CODE						is T_SLV_8;

	-- commands
	type T_NET_ICMPV4_COMMAND is (
		NET_ICMPV4_CMD_NONE,
		NET_ICMPV4_CMD_ECHO_REQUEST
	);

	type T_NET_ICMPV4_TX_COMMAND is (
		NET_ICMPV4_TX_CMD_NONE,
		NET_ICMPV4_TX_CMD_ECHO_REQUEST,
		NET_ICMPV4_TX_CMD_ECHO_REPLY
	);

	type T_NET_ICMPV4_RX_COMMAND is (
		NET_ICMPV4_RX_CMD_NONE,
		NET_ICMPV4_RX_CMD_CLEAR
	);

	-- status
	type T_NET_ICMPV4_STATUS is (
		NET_ICMPV4_STATUS_IDLE,
		NET_ICMPV4_STATUS_SENDING,
		NET_ICMPV4_STATUS_SEND_COMPLETE,
		NET_ICMPV4_STATUS_ERROR
	);

	type T_NET_ICMPV4_TX_STATUS is (
		NET_ICMPV4_TX_STATUS_IDLE,
		NET_ICMPV4_TX_STATUS_SENDING,
		NET_ICMPV4_TX_STATUS_SEND_COMPLETE,
		NET_ICMPV4_TX_STATUS_ERROR
	);

	type T_NET_ICMPV4_RX_STATUS is (
		NET_ICMPV4_RX_STATUS_IDLE,
		NET_ICMPV4_RX_STATUS_RECEIVING,
		NET_ICMPV4_RX_STATUS_RECEIVED_ECHO_REQUEST,
		NET_ICMPV4_RX_STATUS_RECEIVED_ECHO_REPLY,
		NET_ICMPV4_RX_STATUS_ERROR
	);

	-- errors
	type T_NET_ICMPV4_ERROR is (
		NET_ICMPV4_ERROR_NONE,
		NET_ICMPV4_ERROR_TIMEOUT,
		NET_ICMPV4_ERROR_RECEIVED_CORRUPT_MESSAGE,
		NET_ICMPV4_ERROR_MESSAGE_NOT_SUPPORTED,
		NET_ICMPV4_ERROR_FSM
	);

	type T_NET_ICMPV4_TX_ERROR is (
		NET_ICMPV4_TX_ERROR_NONE,
		NET_ICMPV4_TX_ERROR_FSM
	);

	type T_NET_ICMPV4_RX_ERROR is (
		NET_ICMPV4_RX_ERROR_NONE,
		NET_ICMPV4_RX_ERROR_UNKNOWN_CODE,
		NET_ICMPV4_RX_ERROR_UNKNOWN_TYPE,
		NET_ICMPV4_RX_ERROR_CHECKSUM_ERROR,
		NET_ICMPV4_RX_ERROR_FSM
	);

	-- ==========================================================================================================================================================
	-- internet layer: Internet Control Message Protocol for IPv6 (ICMPv6)
	-- ==========================================================================================================================================================
	subtype T_NET_ICMPV6_TYPE						is T_SLV_8;
	subtype T_NET_ICMPV6_CODE						is T_SLV_8;

	-- ==========================================================================================================================================================
	-- internet layer: Neighbor Discovery Protocol (NDP)
	-- ==========================================================================================================================================================
	type T_NET_NDP_DESTINATIONCACHE_LINE is record
		Tag				: T_NET_IPV6_ADDRESS;
		NextHop		: T_NET_IPV6_ADDRESS;
	end record;

	type T_NET_NDP_NEIGHBORCACHE_LINE is record
		Tag				: T_NET_IPV6_ADDRESS;
		MAC				: T_NET_MAC_ADDRESS;
	end record;

	type T_NET_NDP_DESTINATIONCACHE_VECTOR	is array (natural range <>)	of T_NET_NDP_DESTINATIONCACHE_LINE;
	type T_NET_NDP_NEIGHBORCACHE_VECTOR			is array (natural range <>)	of T_NET_NDP_NEIGHBORCACHE_LINE;

	type T_NET_NDP_REACHABILITY_STATE is (
		NET_NDP_REACHABILITY_STATE_UNKNOWN,
		NET_NDP_REACHABILITY_STATE_INCOMPLETE,
		NET_NDP_REACHABILITY_STATE_REACHABLE,
		NET_NDP_REACHABILITY_STATE_STALE,
		NET_NDP_REACHABILITY_STATE_DELAY,
		NET_NDP_REACHABILITY_STATE_PROBE
	);

	-- ==========================================================================================================================================================
	-- transport layer: User Datagram Protocol (UDP)
	-- ==========================================================================================================================================================
	subtype T_NET_UDP_PORT								is T_SLV_16;


	type		T_NET_UDP_PORTPAIR is record
		Ingress			: T_NET_UDP_PORT;				-- incoming port number
		Egress			: T_NET_UDP_PORT;				-- outgoing port number
	end record;

	type		T_NET_UDP_PORTPAIR_VECTOR			is array(natural range <>) of T_NET_UDP_PORTPAIR;


	-- ==========================================================================================================================================================
	-- Ethernet: known Ethernet Types
	-- ==========================================================================================================================================================
	--	add user defined ethernet types here:
	constant C_NET_MAC_ETHERNETTYPE_SSFC						: T_NET_MAC_ETHERNETTYPE		:= to_net_mac_ethernettype(x"A987");		-- Andreas Hoeer - SFC Protocol - simple version (length-field, type-field)
	constant C_NET_MAC_ETHERNETTYPE_SWAP						: T_NET_MAC_ETHERNETTYPE		:= to_net_mac_ethernettype(x"FFFE");		-- Xilinx Ethernet Frame Swap Module
	constant C_NET_MAC_ETHERNETTYPE_LOOPBACK				: T_NET_MAC_ETHERNETTYPE		:= to_net_mac_ethernettype(x"FFFF");		-- Frame loopback module

-- Ethernet Types, see:			http://en.wikipedia.org/wiki/EtherType
-- for complete liste see:	http://standards.ieee.org/develop/regauth/ethertype/eth.txt
-- see also:								http://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xml
	constant C_NET_MAC_ETHERNETTYPE_IPV4						: T_NET_MAC_ETHERNETTYPE		:= to_net_mac_ethernettype(x"0800");		-- Internet Protocol, Version 4 (IPv4)
	constant C_NET_MAC_ETHERNETTYPE_ARP							: T_NET_MAC_ETHERNETTYPE		:= to_net_mac_ethernettype(x"0806");		-- Address Resolution Protocol (ARP)
	constant C_NET_MAC_ETHERNETTYPE_WOL							: T_NET_MAC_ETHERNETTYPE		:= to_net_mac_ethernettype(x"0842");		-- Wake-on-LAN Magic Packet, as used by ether-wake and Sleep Proxy Service
	constant C_NET_MAC_ETHERNETTYPE_VLAN						: T_NET_MAC_ETHERNETTYPE		:= to_net_mac_ethernettype(x"8100");		-- VLAN-tagged frame (IEEE 802.1Q) & Shortest Path Bridging IEEE 802.1aq[3]
	constant C_NET_MAC_ETHERNETTYPE_SNMP						: T_NET_MAC_ETHERNETTYPE		:= to_net_mac_ethernettype(x"814C");		-- Simple Network Management Protocol (SNMP)[4]
	constant C_NET_MAC_ETHERNETTYPE_IPV6						: T_NET_MAC_ETHERNETTYPE		:= to_net_mac_ethernettype(x"86DD");		-- Internet Protocol, Version 6 (IPv6)
	constant C_NET_MAC_ETHERNETTYPE_MACCONTROL			: T_NET_MAC_ETHERNETTYPE		:= to_net_mac_ethernettype(x"8808");		-- MAC Control
	constant C_NET_MAC_ETHERNETTYPE_JUMBOFRAMES			: T_NET_MAC_ETHERNETTYPE		:= to_net_mac_ethernettype(x"8870");		-- Jumbo Frames
	constant C_NET_MAC_ETHERNETTYPE_QINQ						: T_NET_MAC_ETHERNETTYPE		:= to_net_mac_ethernettype(x"9100");		-- Q-in-Q

	-- ==========================================================================================================================================================
	-- Internet Layer: known Upper-Layer Protocols for Internet Protocol
	-- ==========================================================================================================================================================
	constant C_NET_IP_PROTOCOL_LOOPBACK							: T_NET_IP_PROTOCOL					:= x"FF";		-- 					(255) - IANA reserved (used for loopback)

	constant C_NET_IP_PROTOCOL_IPV4									: T_NET_IP_PROTOCOL					:= x"04";		-- 					(	 4) - IPv4 Header																	RFC 2003
	constant C_NET_IP_PROTOCOL_IPv6									: T_NET_IP_PROTOCOL					:= x"29";		-- 					(	41) - IPv6 Header - IPv6 Encapsulation						RFC 2473
	constant C_NET_IP_PROTOCOL_IPV6_HOP_BY_HOP			: T_NET_IP_PROTOCOL					:= x"00";		-- 					(	 0) - IPv6 Ext. Header - Hop-by-Hop Option				RFC 2460
	constant C_NET_IP_PROTOCOL_IPV6_ROUTING					: T_NET_IP_PROTOCOL					:= x"2B";		-- 					(	43) - IPv6 Ext. Header - Routing Header						RFC 2460
	constant C_NET_IP_PROTOCOL_IPV6_FRAGMENTATION		: T_NET_IP_PROTOCOL					:= x"2C";		-- 					(	44) - IPv6 Ext. Header - Fragmentation Header			RFC 2460
	constant C_NET_IP_PROTOCOL_IPV6_ICMP						: T_NET_IP_PROTOCOL					:= x"3A";		-- ICMPv6		(	58) - Internet Control Message Protocol for IPv6	RFC ----
	constant C_NET_IP_PROTOCOL_IPV6_NO_NEXT_HEADER	: T_NET_IP_PROTOCOL					:= x"3B";		-- 					(	59) - IPv6 Ext. Header - No Next Header						RFC 2460
	constant C_NET_IP_PROTOCOL_IPV6_DEST_OPTIONS		: T_NET_IP_PROTOCOL					:= x"3C";		-- 					(	60) - IPv6 Ext. Header - Destination Options			RFC 2460

	constant C_NET_IP_PROTOCOL_ICMP									: T_NET_IP_PROTOCOL					:= x"01";		-- ICMP			(	 1)	- Internet Control Message Protocol						RFC	 792
	constant C_NET_IP_PROTOCOL_IGMP									: T_NET_IP_PROTOCOL					:= x"02";		-- IGMP			(	 2)	- Internet Group Management Protocol					RFC	1112

	constant C_NET_IP_PROTOCOL_TCP									: T_NET_IP_PROTOCOL					:= x"06";		-- TCP			(	 6)	- Transmission Control Protocol								RFC	 793
	constant C_NET_IP_PROTOCOL_SCTP									: T_NET_IP_PROTOCOL					:= x"84";		-- SCTP 		(132) - Stream Control Transmission Protocol				RFC	----
	constant C_NET_IP_PROTOCOL_UDP									: T_NET_IP_PROTOCOL					:= x"11";		-- UDP			(	17)	- User Datagram Protocol											RFC	 768
	constant C_NET_IP_PROTOCOL_UDP_LITE							: T_NET_IP_PROTOCOL					:= x"88";		-- UDPLite	(136) - UDP Lite																		RFC	3828

	constant C_NET_IP_PROTOCOL_L2TP									: T_NET_IP_PROTOCOL					:= x"73";		-- L2TP			(115) - Layer Two Tunneling Protocol								RFC	3931

	-- ==========================================================================================================================================================
	-- Internet Layer: known Internet Control Message Protocol Types and Codes
	-- ==========================================================================================================================================================
	-- ICMPv4 Types
	constant C_NET_ICMPV4_TYPE_EMPTY										: T_NET_ICMPV4_TYPE	:= x"00";		-- empty type field
	constant C_NET_ICMPV4_TYPE_ECHO_REPLY								: T_NET_ICMPV4_TYPE	:= x"00";		-- Echo-Reply
	constant C_NET_ICMPV4_TYPE_DEST_UNREACHABLE					: T_NET_ICMPV4_TYPE	:= x"03";		-- Destination unreachable
	constant C_NET_ICMPV4_TYPE_SOURCE_QUENCH						: T_NET_ICMPV4_TYPE	:= x"04";		-- Source Quench
	constant C_NET_ICMPV4_TYPE_REDIRECT									: T_NET_ICMPV4_TYPE	:= x"05";		-- Redirect
	constant C_NET_ICMPV4_TYPE_ECHO_REQUEST							: T_NET_ICMPV4_TYPE	:= x"08";		-- Echo-Request
	constant C_NET_ICMPV4_TYPE_TIME_EXCEEDED						: T_NET_ICMPV4_TYPE	:= x"0B";		-- Time Exceeded
	constant C_NET_ICMPV4_TYPE_PARAMETER_PROBLEM				: T_NET_ICMPV4_TYPE	:= x"0C";		-- Parameter Problem

	-- ICMPv4 Codes
	constant C_NET_ICMPV4_CODE_EMPTY										: T_NET_ICMPV4_CODE	:= x"00";		-- empty code field

	-- ICMPv4 Codes for type Destination Unreachable
	constant C_NET_ICMPV4_CODE_NET_UNREACHABLE					: T_NET_ICMPV4_CODE	:= x"00";		-- Network unreachable
	constant C_NET_ICMPV4_CODE_HOST_UNREACHABLE					: T_NET_ICMPV4_CODE	:= x"01";		-- Host unreachable
	constant C_NET_ICMPV4_CODE_PROTOCOL_UNREACHABLE			: T_NET_ICMPV4_CODE	:= x"02";		-- Protocol unreachable
	constant C_NET_ICMPV4_CODE_PORT_UNREACHABLE					: T_NET_ICMPV4_CODE	:= x"03";		-- Port unreachable
	constant C_NET_ICMPV4_CODE_FRAGMENTATION_NEEDED			: T_NET_ICMPV4_CODE	:= x"04";		-- Fragmentation needed, but DF set
	constant C_NET_ICMPV4_CODE_SOURCE_ROUTE_FAILED			: T_NET_ICMPV4_CODE	:= x"05";		-- Source route failed

	-- ICMPv4 Codes for type Time Exceeded
	constant C_NET_ICMPV4_CODE_TIME_TO_LIVE_EXCEEDED		: T_NET_ICMPV4_CODE	:= x"00";		-- Hop limit exceeded in transit
	constant C_NET_ICMPV4_CODE_FRAG_REASS_TIME_EXCEEDED	: T_NET_ICMPV4_CODE	:= x"01";		-- Fragment reassembly time exceeded

	-- ICMPv4 Codes for type Echo Request
	constant C_NET_ICMPV4_CODE_ECHO_REQUEST							: T_NET_ICMPV4_CODE	:= x"00";		-- Echo Request

	-- ICMPv4 Codes for type Echo Reply
	constant C_NET_ICMPV4_CODE_ECHO_REPLY								: T_NET_ICMPV4_CODE	:= x"00";		-- Echo Reply


	-- ==========================================================================================================================================================
	-- Internet Layer: known Internet Control Message Protocol (for IPv6) Types and Codes
	-- ==========================================================================================================================================================
	-- ICMPv6 Types - Errors
	constant C_NET_ICMPV6_TYPE_DEST_UNREACHABLE				: T_NET_ICMPV6_TYPE	:= x"01";		-- Destination unreachable
	constant C_NET_ICMPV6_TYPE_PACKET_TOO_BIG					: T_NET_ICMPV6_TYPE	:= x"02";		-- Packet Too Big
	constant C_NET_ICMPV6_TYPE_TIME_EXCEEDED					: T_NET_ICMPV6_TYPE	:= x"03";		-- Time Exceeded
	constant C_NET_ICMPV6_TYPE_PARAMETER_PROBLEM			: T_NET_ICMPV6_TYPE	:= x"04";		-- Parameter Problem
	constant C_NET_ICMPV6_TYPE_ERROR_EXP							: T_NET_ICMPV6_TYPE	:= x"7F";		--
	-- ICMPv6 Types - Information
	constant C_NET_ICMPV6_TYPE_ECHO_REQUEST						: T_NET_ICMPV6_TYPE	:= x"80";		-- Echo Request
	constant C_NET_ICMPV6_TYPE_ECHO_REPLY							: T_NET_ICMPV6_TYPE	:= x"81";		-- Echo Reply
	constant C_NET_ICMPV6_TYPE_INFORMANTION_EXP				: T_NET_ICMPV6_TYPE	:= x"FF";		--

	-- ICMPv6 Codes
	constant C_NET_ICMPV6_CODE_EMPTY									: T_NET_ICMPV6_CODE	:= x"00";		-- empty code field

	-- ICMPv6 Codes for type Destination Unreachable
	constant C_NET_ICMPV6_CODE_NO_ROUTE_TO_DEST				: T_NET_ICMPV6_CODE	:= x"00";		-- No route to destination
	constant C_NET_ICMPV6_CODE_COM_PROHIBITED					: T_NET_ICMPV6_CODE	:= x"01";		-- Communication with destination administratively prohibited
	constant C_NET_ICMPV6_CODE_BEYOND_SCOPE						: T_NET_ICMPV6_CODE	:= x"02";		-- Beyond scope of source address
	constant C_NET_ICMPV6_CODE_ADDRESS_UNREACHABLE		: T_NET_ICMPV6_CODE	:= x"03";		-- Address unreachable
	constant C_NET_ICMPV6_CODE_PORT_UNREACHABLE				: T_NET_ICMPV6_CODE	:= x"04";		-- Port unreachable
	constant C_NET_ICMPV6_CODE_ADDRESS_FAILED_POLICY	: T_NET_ICMPV6_CODE	:= x"05";		-- Source address failed ingress/egress policy
	constant C_NET_ICMPV6_CODE_REJECT_ROUTE_TO_DEST		: T_NET_ICMPV6_CODE	:= x"06";		-- Reject route to destination

	-- ICMPv6 Codes for type Packet Too Big
	constant C_NET_ICMPV6_CODE_PACKET_TOO_BIG					: T_NET_ICMPV6_CODE	:= x"00";		-- Packet Too Big

	-- ICMPv6 Codes for type Time Exceeded
	constant C_NET_ICMPV6_CODE_HOP_LIMIT_EXCEEDED			: T_NET_ICMPV6_CODE	:= x"00";		-- Hop limit exceeded in transit
	constant C_NET_ICMPV6_CODE_REASS_TIME_EXCEEDED		: T_NET_ICMPV6_CODE	:= x"01";		-- Fragment reassembly time exceeded

	-- ICMPv6 Codes for type Parameter Problem
	constant C_NET_ICMPV6_CODE_HEADER_FIELD_ERROR			: T_NET_ICMPV6_CODE	:= x"00";		-- Erroneous header field encountered
	constant C_NET_ICMPV6_CODE_NEXT_HEADER_ERROR			: T_NET_ICMPV6_CODE	:= x"01";		-- Unrecognized Next Header type encountered
	constant C_NET_ICMPV6_CODE_IPV6_OPTION_ERROR			: T_NET_ICMPV6_CODE	:= x"02";		-- Unrecognized IPv6 option encountered

	-- ICMPv6 Codes for type Echo Request
	constant C_NET_ICMPV6_CODE_ECHO_REQUEST						: T_NET_ICMPV6_CODE	:= x"00";		-- Echo Request

	-- ICMPv6 Codes for type Echo Reply
	constant C_NET_ICMPV6_CODE_ECHO_REPLY							: T_NET_ICMPV6_CODE	:= x"00";		-- Echo Reply


	-- ==========================================================================================================================================================
	-- Transport Layer: known User Datagramm Protocol (UDP) Types, Ports and Codes
	-- ==========================================================================================================================================================
	subtype T_NET_TCP_PORT	is T_NET_UDP_PORT;		-- TODO: if TCP is added, move this to the TCP section in this file!

	constant C_NET_TCP_PORTNUMBER_ECHO								: T_NET_TCP_PORT		:= x"0007";		-- Echo Protocol (7) - RFC 862
	constant C_NET_TCP_PORTNUMBER_FTP_DATA						: T_NET_TCP_PORT		:= x"0014";		-- FTP Protocol (20) - RFC 765
	constant C_NET_TCP_PORTNUMBER_FTP_CONTROL					: T_NET_TCP_PORT		:= x"0015";		-- FTP Protocol (21) - RFC 765

	constant C_NET_TCP_PORTNUMBER_LOOPBACK						: T_NET_TCP_PORT		:= x"FFFF";

end package;


package body net is

	function to_net_eth_RSDataInterface(str : string) return T_NET_ETH_RS_DATA_INTERFACE is
	begin
		for i in T_NET_ETH_RS_DATA_INTERFACE'pos(T_NET_ETH_RS_DATA_INTERFACE'low) to T_NET_ETH_RS_DATA_INTERFACE'pos(T_NET_ETH_RS_DATA_INTERFACE'high) loop
			if str_match(str_toUpper(str), str_toUpper(T_NET_ETH_RS_DATA_INTERFACE'image(T_NET_ETH_RS_DATA_INTERFACE'val(i)))) then
				return T_NET_ETH_RS_DATA_INTERFACE'val(i);
			end if;
		end loop;
		report "Unknown RS_DATA_INTERFACE: " & str severity FAILURE;
	end function;

	function to_net_eth_PHYDataInterface(str : string) return T_NET_ETH_PHY_DATA_INTERFACE is
	begin
		for i in T_NET_ETH_PHY_DATA_INTERFACE'pos(T_NET_ETH_PHY_DATA_INTERFACE'low) to T_NET_ETH_PHY_DATA_INTERFACE'pos(T_NET_ETH_PHY_DATA_INTERFACE'high) loop
			if str_match(str_toUpper(str), str_toUpper(T_NET_ETH_PHY_DATA_INTERFACE'image(T_NET_ETH_PHY_DATA_INTERFACE'val(i)))) then
				return T_NET_ETH_PHY_DATA_INTERFACE'val(i);
			end if;
		end loop;
		report "Unknown PHY_DATA_INTERFACE: " & str severity FAILURE;
	end function;

	function to_net_eth_PHYManagementInterface(str : string) return T_NET_ETH_PHY_MANAGEMENT_INTERFACE is
	begin
		for i in T_NET_ETH_PHY_MANAGEMENT_INTERFACE'pos(T_NET_ETH_PHY_MANAGEMENT_INTERFACE'low) to T_NET_ETH_PHY_MANAGEMENT_INTERFACE'pos(T_NET_ETH_PHY_MANAGEMENT_INTERFACE'high) loop
			if str_match(str_toUpper(str), str_toUpper(T_NET_ETH_PHY_MANAGEMENT_INTERFACE'image(T_NET_ETH_PHY_MANAGEMENT_INTERFACE'val(i)))) then
				return T_NET_ETH_PHY_MANAGEMENT_INTERFACE'val(i);
			end if;
		end loop;
		report "Unknown PHY_MANAGEMENT_INTERFACE: " & str severity FAILURE;
	end function;

	function to_net_eth_PHYDevice(str : string) return T_NET_ETH_PHY_DEVICE is
	begin
		for i in T_NET_ETH_PHY_DEVICE'pos(T_NET_ETH_PHY_DEVICE'low) to T_NET_ETH_PHY_DEVICE'pos(T_NET_ETH_PHY_DEVICE'high) loop
			if str_match(str_toUpper(str), str_toUpper(T_NET_ETH_PHY_DEVICE'image(T_NET_ETH_PHY_DEVICE'val(i)))) then
				return T_NET_ETH_PHY_DEVICE'val(i);
			end if;
		end loop;
		report "Unknown PHY_DEVICE: " & str severity FAILURE;
	end function;


	function getPortCount(MACConfiguration : T_NET_MAC_CONFIGURATION_VECTOR) return positive is
		variable count : natural := 0;
	begin
		for i in MACConfiguration'range loop
			for j in MACConfiguration(i).TypeSwitch'range loop
				if (MACConfiguration(i).TypeSwitch(j) /= C_NET_MAC_ETHERNETTYPE_EMPTY) then
					count := count + 1;
				end if;
			end loop;
		end loop;

		return count;
	end function;

	-- ==========================================================================================================================================================
	-- Ethernet: MAC Data-Link-Layer
	-- ==========================================================================================================================================================
	function to_net_mac_address(slv : T_SLV_48) return T_NET_MAC_ADDRESS is
		variable mac					: T_NET_MAC_ADDRESS;
	begin
		for i in 0 to 5 loop
			mac(i)	:=	slv(((i * 8) + 7) downto (i * 8));
		end loop;
		return mac;
	end function;

	function to_net_mac_address(slvv : T_SLVV_8) return T_NET_MAC_ADDRESS is
		variable mac					: T_NET_MAC_ADDRESS;
	begin
		if (slvv'length /= 6) then report "to_net_mac_address: vector-length mismatch - slvv'length=" & integer'image(slvv'length) severity ERROR; end if;
		for i in slvv'range loop
			mac(i)	:=	slvv(i);
		end loop;
		return mac;
	end function;

	subtype MAC_ADDRESS_SEGMENT					is string(1 to 2);
	type		MAC_ADDRESS_SEGMENT_VECTOR	is array (natural range <>) of MAC_ADDRESS_SEGMENT;

	function mac_split(str : string) return MAC_ADDRESS_SEGMENT_VECTOR is
		variable input								: string(str'range)											:= str_toUpper(str);
		variable Segments							: MAC_ADDRESS_SEGMENT_VECTOR(0 to 5)		:= (others => (others => '0'));
		variable SegmentPointer				: natural																:= 0;
		variable CharPointer					: natural																:= 2;
	begin
--		report "mac_split of " & str severity NOTE;
		for i in str'reverse_range loop
--			report "  char=" & input(i) severity NOTE;
			if (to_digit(input(i), 'h') /= -1) then
				Segments(SegmentPointer)(CharPointer)	:= input(i);
--				report "    copy to seg=" & INTEGER'image(SegmentPointer) & "  pos=" & INTEGER'image(CharPointer) severity NOTE;
				CharPointer					:= CharPointer - 1;
			elsif ((input(i) = ':') or (input(i) = '-')) then
				SegmentPointer		:= SegmentPointer + 1;
				CharPointer				:= 2;
			else
				report "ERROR - unknown char [" & input(i) & "]" severity ERROR;
			end if;
		end loop;

		return Segments;
	end function;

	-- converts MAC address strings to T_NET_MAC_ADDRESS
	-- allowed delimiter signs: ':' or '-'
	function to_net_mac_address(str : string) return T_NET_MAC_ADDRESS is
		variable Segments				: MAC_ADDRESS_SEGMENT_VECTOR(0 to 5)	:= mac_split(str);
		variable MAC						: T_NET_MAC_ADDRESS;
	begin
		for i in Segments'range loop
			MAC(i)	:= to_slv(to_natural_hex(Segments(i)), 8);
		end loop;
		return MAC;
	end function;

	function to_net_mac_ethernettype(slv : T_SLV_16) return T_NET_MAC_ETHERNETTYPE is
		variable EthType					: T_NET_MAC_ETHERNETTYPE;
	begin
		for i in 0 to 1 loop
			EthType(i)	:=	slv(((i * 8) + 7) downto (i * 8));
		end loop;
		return EthType;
	end function;

	function to_slv(mac : T_NET_MAC_ADDRESS) return std_logic_vector is
		variable slv		: T_SLV_48;
	begin
		for i in 0 to 5 loop
			slv(((i * 8) + 7) downto (i * 8))		:= mac(i);
		end loop;
		return slv;
	end function;

	function to_slv(EthType : T_NET_MAC_ETHERNETTYPE) return std_logic_vector is
		variable slv		: T_SLV_16;
	begin
		for i in 0 to 1 loop
			slv(((i * 8) + 7) downto (i * 8))		:= EthType(i);
		end loop;
		return slv;
	end function;

	function to_slvv_8(mac : T_NET_MAC_ADDRESS) return T_SLVV_8 is
		variable slvv : T_SLVV_8(mac'range);
	begin
		for i in mac'range loop
			slvv(i)	:= mac(i);
		end loop;
		return slvv;
	end function;

	function to_slvv_8(EthType : T_NET_MAC_ETHERNETTYPE) return T_SLVV_8 is
		variable slvv : T_SLVV_8(EthType'range);
	begin
		for i in EthType'range loop
			slvv(i)	:= EthType(i);
		end loop;
		return slvv;
	end function;

	function to_string(mac : T_NET_MAC_ADDRESS) return string is
		variable str		: string(1 to 18)		:= (others => ':');
	begin
		for i in 0 to 5 loop
			str((i * 3) + 1 to (i * 3) + 2)	:= to_string(mac(5 - i), 'h');
		end loop;
		return str(1 to 17);
	end function;

	function to_string(EthType : T_NET_MAC_ETHERNETTYPE) return string is
	begin
		-- TODO: replace this case-statement by substring(image(EthType), 10,0)
		case to_slv(EthType) is
			when to_slv(C_NET_MAC_ETHERNETTYPE_EMPTY) =>				return "Empty";
			when to_slv(C_NET_MAC_ETHERNETTYPE_ARP) =>					return "ARP";
			when to_slv(C_NET_MAC_ETHERNETTYPE_IPV4) =>					return "IPv4";
			when to_slv(C_NET_MAC_ETHERNETTYPE_IPV6) =>					return "IPv6";
			when to_slv(C_NET_MAC_ETHERNETTYPE_JUMBOFRAMES) =>	return "Jumbo";
			when to_slv(C_NET_MAC_ETHERNETTYPE_MACCONTROL) =>		return "MACControl";
			when to_slv(C_NET_MAC_ETHERNETTYPE_QINQ) =>					return "QinQ";
			when to_slv(C_NET_MAC_ETHERNETTYPE_SNMP) =>					return "SNMP";
			when to_slv(C_NET_MAC_ETHERNETTYPE_VLAN) =>					return "VLAN";
			when to_slv(C_NET_MAC_ETHERNETTYPE_WOL) =>					return "WOL";

			when to_slv(C_NET_MAC_ETHERNETTYPE_SWAP) =>					return "Swap";
			when to_slv(C_NET_MAC_ETHERNETTYPE_LOOPBACK) =>			return "LoopBack";
			when others =>																			return "0x" & to_string(to_slv(EthType), 'h');
		end case;
	end function;

	-- ==========================================================================================================================================================
	-- internet layer: Internet Protocol Version 4 (IPv4)
	-- ==========================================================================================================================================================
	function to_net_ipv4_address(slv : T_SLV_32) return T_NET_IPV4_ADDRESS is
		variable ip					: T_NET_IPV4_ADDRESS;
	begin
		for i in 0 to 3 loop
			ip(i)	:=	slv(((i * 8) + 7) downto (i * 8));
		end loop;
		return ip;
	end function;

	subtype IPV4_ADDRESS_SEGMENT					is string(1 to 3);
	type		IPV4_ADDRESS_SEGMENT_VECTOR		is array (natural range <>) of IPV4_ADDRESS_SEGMENT;

	function ipv4_split(str : string) return IPV4_ADDRESS_SEGMENT_VECTOR is
		variable input								: string(str'range)											:= str_toUpper(str);
		variable Segments							: IPV4_ADDRESS_SEGMENT_VECTOR(0 to 3)		:= (others => (others => '0'));
		variable SegmentPointer				: natural																:= 0;
		variable CharPointer					: natural																:= 3;
	begin
--		report "ipv4_split of " & str severity NOTE;
		for i in str'reverse_range loop
--			report "  char=" & input(i) severity NOTE;
			if (to_digit(input(i), 'd') /= -1) then
				Segments(SegmentPointer)(CharPointer)	:= input(i);
--				report "    copy to seg=" & INTEGER'image(SegmentPointer) & "  pos=" & INTEGER'image(CharPointer) severity NOTE;
				CharPointer					:= CharPointer - 1;
			elsif (input(i) = '.') then
				SegmentPointer		:= SegmentPointer + 1;
				CharPointer				:= 3;
			else
				report "ERROR - unknown char" severity ERROR;
			end if;
		end loop;

		return Segments;
	end function;

	-- converts MAC address strings to T_NET_MAC_ADDRESS
	--	allowed delimiter sign: '.'
	function to_net_ipv4_address(str : string) return T_NET_IPV4_ADDRESS is
		variable Segments				: IPV4_ADDRESS_SEGMENT_VECTOR(0 to 3)	:= ipv4_split(str);
		variable Segment				: T_SLV_8;
		variable IP							: T_NET_IPV4_ADDRESS;
	begin
		for i in Segments'range loop
			IP(i) := to_slv(to_natural_dec(Segments(i)), 8);
		end loop;
		return IP;
	end function;

	function to_net_ipv4_TYPE_of_service(slv : T_SLV_8)	return T_NET_IPV4_TYPE_OF_SERVICE is
		variable tos			: T_NET_IPV4_TYPE_OF_SERVICE;
	begin
		tos.Precedence		:= slv(2 downto 0);
		tos.Delay					:= slv(3);
		tos.Throughput		:= slv(4);
		tos.Relibility		:= slv(5);
		return tos;
	end function;

	function to_slv(ip : T_NET_IPV4_ADDRESS) return std_logic_vector is
		variable slv						: T_SLV_32;
	begin
		for i in 0 to 3 loop
			slv(((i * 8) + 7) downto (i * 8))		:= ip(i);
		end loop;
		return slv;
	end function;
--
--	function to_slv(proto : T_NET_IPV4_PROTOCOL) return STD_LOGIC_VECTOR is
--		variable slv						: T_SLV_8;
--	begin
--		slv := proto;
--		return slv;
--	end function;

	function to_slv(tos : T_NET_IPV4_TYPE_OF_SERVICE)	return std_logic_vector is
		variable slv						: T_SLV_8;
	begin
		slv(2 downto 0)		:= tos.Precedence;
		slv(3)						:= tos.Delay;
		slv(4)						:= tos.Throughput;
		slv(5)						:= tos.Relibility;
		slv(7 downto 6)		:= "00";
		return slv;
	end function;

	function to_slvv_8(ip : T_NET_IPV4_ADDRESS) return T_SLVV_8 is
		variable slvv						: T_SLVV_8(ip'range);
	begin
		for i in ip'range loop
			slvv(i)	:= ip(i);
		end loop;
		return slvv;
	end function;

	function to_string(IP : T_NET_IPV4_ADDRESS) return string is
		variable temp						: string(1 to 16)			:= (others => '.');
		variable str						: string(1 to 3);
		variable len						: positive;
		variable CharPointer		: natural							:= 1;

	begin
--		report "converting IPv4 address" severity NOTE;
		for i in 3 downto 0 loop
--			report "  I=" & INTEGER'image(i) & "  IP(i)=" & INTEGER'image(to_integer(unsigned(IP(i)))) & "  CP=" & INTEGER'image(CharPointer) severity NOTE;

			str := resize(integer'image(to_integer(unsigned(IP(i)))), str'length);
			len	:= str_length(str);
			temp(CharPointer to CharPointer + len - 1)	:= str(1 to len);
			CharPointer := CharPointer + len + 1;
		end loop;

		return temp(1 to CharPointer - 2);
	end function;

	-- ==========================================================================================================================================================
	-- internet layer: Internet Protocol Version 6 (IPv6)
	-- ==========================================================================================================================================================
	function to_net_ipv6_address(slv : T_SLV_128) return T_NET_IPV6_ADDRESS is
		variable ip					: T_NET_IPV6_ADDRESS;
	begin
		for i in 0 to 15 loop
			ip(i)	:=	slv(((i * 8) + 7) downto (i * 8));
		end loop;

		return ip;
	end function;

	subtype IPV6_ADDRESS_SEGMENT					is string(1 to 4);
	type		IPV6_ADDRESS_SEGMENT_VECTOR		is array (natural range <>) of IPV6_ADDRESS_SEGMENT;

	function ipv6_split(str : string) return IPV6_ADDRESS_SEGMENT_VECTOR is
		variable input								: string(str'range)											:= str_toUpper(str);
		variable Segments							: IPV6_ADDRESS_SEGMENT_VECTOR(0 to 7)		:= (others => (others => '0'));
		variable DelimiterPointer			: natural																:= 0;
		variable SegmentPointer				: natural																:= 0;
		variable CharPointer					: natural																:= 4;
		variable RemainingDelimiters	: natural																:= 0;
	begin
--		report "ipv6_split of " & str severity NOTE;

		for i in str'reverse_range loop
--			report "  char=" & input(i) severity NOTE;
			if (to_digit(input(i), 'h') /= -1) then
				Segments(SegmentPointer)(CharPointer)	:= input(i);
--				report "    copy to seg=" & INTEGER'image(SegmentPointer) & "  pos=" & INTEGER'image(CharPointer) severity NOTE;
				CharPointer					:= CharPointer - 1;
				DelimiterPointer		:= 0;
			elsif (input(i) = ':') then
				if (DelimiterPointer = 0) then
					SegmentPointer		:= SegmentPointer + 1;
					CharPointer				:= 4;
					DelimiterPointer	:= i;
				else
					-- count remaining segments-delimiters
					for j in i - 1 downto input'low loop
						if (input(j) = ':') then
							RemainingDelimiters	:= RemainingDelimiters + 1;
						end if;
					end loop;
--					report "    lookahead rem-del=" & INTEGER'image(RemainingDelimiters) severity NOTE;
					SegmentPointer		:= 7 - RemainingDelimiters;
					CharPointer				:= 4;
					DelimiterPointer	:= 0;
				end if;
			else
				report "    ERROR - unknown char" severity ERROR;
			end if;
		end loop;

		return Segments;
	end function;

	function to_net_ipv6_address(str : string) return T_NET_IPV6_ADDRESS is
		variable Segments				: IPV6_ADDRESS_SEGMENT_VECTOR(0 to 7)	:= ipv6_split(str);
		variable Segment				: T_SLV_16;
		variable IP							: T_NET_IPV6_ADDRESS;
	begin
		for i in Segments'range loop
			Segment								:= to_slv(to_natural_hex(Segments(i)), 16);
			IP(i * 2)							:= Segment(7 downto 0);
			IP((i * 2) + 1)				:= Segment(15 downto 8);
		end loop;
		return IP;
	end function;

	function to_net_ipv6_prefix(str : string) return T_NET_IPV6_PREFIX is
		variable Pos						: positive;
		variable Prefix					: T_NET_IPV6_PREFIX;
		variable IPv6Address		: T_NET_IPV6_ADDRESS;
		variable Len						: natural;
	begin
		for i in str'reverse_range loop
			if (str(i) = '/') then
				Pos := i;
				exit;
			end if;
		end loop;

		if (Pos = str'high) then report "syntax error in IPv6 prefix: " & str severity ERROR;		end if;

		IPv6Address							:= to_net_ipv6_address(str(str'low to Pos - 1));
		Len											:= integer'value(str(Pos + 1 to str'high));

		if (not ((0 < Len) and (Len < 128))) then																								report "IPv6 prefix length is out of range: IPv6=" & str & " Length=" & integer'image(Len) severity ERROR;	end if;
		if ((to_slv(IPv6Address) and genmask_low(128 - Len, 128)) /= (127 downto 0 => '0')) then report "IPv6 prefix is longer then it's mask: IPv6=" & str severity ERROR;																	end if;

		Prefix.Prefix						:= IPv6Address;
		Prefix.PrefixLength			:= to_slv(Len, Prefix.PrefixLength'length);
		return Prefix;
	end function;

	function to_slv(ip : T_NET_IPV6_ADDRESS) return std_logic_vector is
		variable slv						: T_SLV_128;
	begin
		for i in 0 to 15 loop
			slv(((i * 8) + 7) downto (i * 8))		:= ip(i);
		end loop;
		return slv;
	end function;

	function to_slvv_8(ip : T_NET_IPV6_ADDRESS) return T_SLVV_8 is
		variable slvv						: T_SLVV_8(ip'range);
	begin
		for i in ip'range loop
			slvv(i)	:= ip(i);
		end loop;
		return slvv;
	end function;

	function to_string(IP : T_NET_IPV6_ADDRESS) return string is
		variable temp						: string(1 to 40)			:= (others => ':');
		variable CharPointer		: natural							:= 1;
		variable Char						: character;

		variable copy						: boolean							:= FALSE;
	begin
		for i in 7 downto 0 loop
			temp(CharPointer + 0 to CharPointer + 1)	:= to_string(IP((i * 2) + 1), 'h');
			temp(CharPointer + 2 to CharPointer + 3)	:= to_string(IP( i * 2), 'h');
			CharPointer																:= CharPointer + 5;
		end loop;

		-- compress string - remove leading zeros
--		report "compressing IPv6 address" severity NOTE;
		CharPointer			:= 1;
		for i in temp'range loop
--			report "  I=" & INTEGER'image(i) & "  char=" & temp(i) & "  CP=" & INTEGER'image(CharPointer) & "  copy=" & to_string(copy) severity NOTE;

			if (copy = FALSE) then
				if ((temp(i) = '0') and (temp(i + 1) /= ':')) then
					null;
				else
					temp(CharPointer)	:= temp(i);
					CharPointer				:= CharPointer + 1;
					copy							:= TRUE;
				end if;
			else
				if (temp(i) = ':') then
					copy							:= FALSE;
				end if;
				temp(CharPointer)		:= temp(i);
				CharPointer					:= CharPointer + 1;
			end if;
		end loop;

		return temp(1 to CharPointer - 2);
	end function;

	function to_string(Prefix : T_NET_IPV6_PREFIX)	return string is
	begin
		return to_string(Prefix.Prefix) & "/" & to_string(Prefix.PrefixLength, 'd');
	end function;
end package body;