-------------------------------------------------------------
-- MSS copyright 2011
--	Filename:  tbcom5402tcptx_5401mac.VHD
-- Author: Alain Zarembowitch / MSS
--	Version: 1
--	Date last modified: 8/20/11
-- Inheritance: 	N/A
--
-- description:  Test bench for the COM-5402.
-- Emphasis is on TCP tx streaming. Send 8-bit counter data as fast as possible.
-- The LAN receive side is based on reading a stimulus file named "input.cap" [Must be in the same directory as the ISE project]
-- (in the form of a Wireshark Libpcap file format, network capture)
-- and passes it to the COM5402 IP stack receive path.
-- The MAC is used for tx (so as to check the tx flow control)

---------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use work.com5402pkg.all;	-- defines global types, number of TCP streams, etc
 
ENTITY tbcom5402tcptx_5401mac IS
END tbcom5402tcptx_5401mac;
 
ARCHITECTURE behavior OF tbcom5402tcptx_5401mac IS 
 
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------
	COMPONENT TIMER_4US
	GENERIC (
		CLK_FREQUENCY: integer 
	);
	PORT(
		ASYNC_RESET : IN std_logic;
		CLK : IN std_logic;          
		TICK_4US : OUT std_logic;
		TICK_100MS: out std_logic
		);
	END COMPONENT;
 
	COMPONENT COM5402
	GENERIC (
		CLK_FREQUENCY: integer;
		SIMULATION: std_logic
	);	
	PORT(
		CLK : IN std_logic;
		ASYNC_RESET : IN std_logic;
		MAC_ADDR : IN std_logic_vector(47 downto 0);
		IPv4_ADDR : IN std_logic_vector(31 downto 0);
		IPv6_ADDR : IN std_logic_vector(127 downto 0);
		SUBNET_MASK: in std_logic_vector(31 downto 0);
		GATEWAY_IP_ADDR: in std_logic_vector(31 downto 0);
		MAC_TX_CTS : IN std_logic;
		MAC_RX_DATA : IN std_logic_vector(7 downto 0);
		MAC_RX_DATA_VALID : IN std_logic;
		MAC_RX_SOF : IN std_logic;
		MAC_RX_EOF : IN std_logic;          
		MAC_TX_DATA : OUT std_logic_vector(7 downto 0);
		MAC_TX_DATA_VALID : OUT std_logic;
		MAC_TX_EOF : OUT std_logic;
		UDP_RX_DATA: out std_logic_vector(7 downto 0);
		UDP_RX_DATA_VALID: out std_logic;
		UDP_RX_SOF: out std_logic;	
		UDP_RX_EOF: out std_logic;	
		UDP_RX_DEST_PORT_NO: in std_logic_vector(15 downto 0);
		UDP_TX_DATA : IN std_logic_vector(7 downto 0);
		UDP_TX_DATA_VALID : IN std_logic;
		UDP_TX_SOF : IN std_logic;
		UDP_TX_EOF : IN std_logic;
		UDP_TX_CTS: out std_logic;	
		UDP_TX_ACK: out std_logic;	
		UDP_TX_NAK: out std_logic;	
		UDP_TX_DEST_IP_ADDR: in std_logic_vector(127 downto 0);
		UDP_TX_DEST_PORT_NO: in std_logic_vector(15 downto 0);
		UDP_TX_SOURCE_PORT_NO: in std_logic_vector(15 downto 0);
		TCP_RX_DATA: out SLV8xNTCPSTREAMStype;
		TCP_RX_DATA_VALID: out std_logic_vector((NTCPSTREAMS-1) downto 0);
		TCP_RX_RTS: out std_logic;
		TCP_RX_CTS: in std_logic;
		TCP_TX_DATA: in SLV8xNTCPSTREAMStype;
		TCP_TX_DATA_VALID: in std_logic_vector((NTCPSTREAMS-1) downto 0);
		TCP_TX_CTS: out std_logic_vector((NTCPSTREAMS-1) downto 0);	
		CS1 : OUT std_logic_vector(7 downto 0);
		CS1_CLK : OUT std_logic;
		CS2 : OUT std_logic_vector(7 downto 0);
		CS2_CLK : OUT std_logic;
		TP : OUT std_logic_vector(10 downto 1)
		);
	END COMPONENT;

	COMPONENT COM5401
	GENERIC (
		MII_SEL: std_logic;  
		PHY_ADDR: std_logic_vector(4 downto 0);
		CLK_FREQUENCY: integer 
	);
	PORT(
		CLK : IN std_logic;
		ASYNC_RESET : IN std_logic;
		MAC_TX_CONFIG : IN std_logic_vector(15 downto 0);
		MAC_RX_CONFIG : IN std_logic_vector(15 downto 0);
		MAC_ADDR : IN std_logic_vector(47 downto 0);
		PHY_CONFIG_CHANGE : IN std_logic;
		PHY_RESET : IN std_logic;
		SPEED : IN std_logic_vector(1 downto 0);
		DUPLEX : IN std_logic;
		TEST_MODE : IN std_logic_vector(1 downto 0);
		POWER_DOWN : IN std_logic;
		CLK_SKEW : IN std_logic_vector(15 downto 0);
		MAC_TX_DATA : IN std_logic_vector(7 downto 0);
		MAC_TX_DATA_VALID : IN std_logic;
		MAC_TX_EOF : IN std_logic;
		MAC_RX_CTS : IN std_logic;
		RXC : IN std_logic;
		RXD : IN std_logic_vector(3 downto 0);
		RX_CTL : IN std_logic;
		MII_TX_CLK : IN std_logic;
		GMII_MII_CRS : IN std_logic;
		GMII_MII_COL : IN std_logic;
		GMII_MII_RX_CLK : IN std_logic;
		GMII_MII_RXD : IN std_logic_vector(7 downto 0);
		GMII_MII_RX_DV : IN std_logic;
		GMII_MII_RX_ER : IN std_logic;    
		MDIO : INOUT std_logic;      
		MAC_TX_CTS : OUT std_logic;
		MAC_RX_DATA : OUT std_logic_vector(7 downto 0);
		MAC_RX_DATA_VALID : OUT std_logic;
		MAC_RX_SOF : OUT std_logic;
		MAC_RX_EOF : OUT std_logic;
		TXC : OUT std_logic;
		TXD : OUT std_logic_vector(3 downto 0);
		TX_CTL : OUT std_logic;
		RESET_N : OUT std_logic;
		MCLK : OUT std_logic;
		GMII_TX_CLK : OUT std_logic;
		GMII_MII_TXD : OUT std_logic_vector(7 downto 0);
		GMII_MII_TX_EN : OUT std_logic;
		GMII_MII_TX_ER : OUT std_logic;
		LINK_STATUS : OUT std_logic;
		SPEED_STATUS : OUT std_logic_vector(1 downto 0);
		DUPLEX_STATUS : OUT std_logic;
		PHY_ID : OUT std_logic_vector(15 downto 0);
		CS1 : OUT std_logic_vector(7 downto 0);
		CS1_CLK : OUT std_logic;
		CS2 : OUT std_logic_vector(7 downto 0);
		CS2_CLK : OUT std_logic;
		CS_CLKG : OUT std_logic;
		TP : OUT std_logic_vector(10 downto 1)
		);
	END COMPONENT;
    
	COMPONENT PHYSIM_RGMII
	PORT(
		TXC : IN std_logic;
		TXD : IN std_logic_vector(3 downto 0);
		TX_CTL : IN std_logic;
		RESET_N : IN std_logic;
		MCLK : IN std_logic;    
		MDIO : INOUT std_logic;      
		RXC : OUT std_logic;
		RXD : OUT std_logic_vector(3 downto 0);
		RX_CTL : OUT std_logic;
		CLK125_NDO : OUT std_logic
		);
	END COMPONENT;

--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------
   signal CLK : std_logic := '0';
   signal ASYNC_RESET : std_logic := '0';
	signal TICK_4US: std_logic := '0';
   signal MAC_ADDR : std_logic_vector(47 downto 0) := x"000102030405";
		-- must match Wireshark capture file
   signal IPv4_ADDR : std_logic_vector(31 downto 0) := x"AC100180";
		-- must match Wireshark capture file
   signal GATEWAY_IP_ADDR : std_logic_vector(31 downto 0) := x"AC100103";
		-- must match Wireshark capture file
   signal IPv6_ADDR : std_logic_vector(127 downto 0) := x"0123456789ABCDEF00112233AC100180";
   signal MAC_TX_CTS : std_logic := '1';
   signal MAC_RX_DATA : std_logic_vector(7 downto 0) := (others => '0');
   signal MAC_RX_DATA_VALID : std_logic := '0';
   signal MAC_RX_SOF : std_logic := '0';
   signal MAC_RX_EOF : std_logic := '0';
   signal MAC_RX_DATA0 : std_logic_vector(7 downto 0) := (others => '0');
   signal MAC_RX_DATA_VALID0 : std_logic := '0';
   signal MAC_RX_SOF0 : std_logic := '0';
   signal MAC_RX_EOF0 : std_logic := '0';
	signal TCP_TX_DATA: SLV8xNTCPSTREAMStype := (others => (others => '0'));
	signal TCP_TX_DATA_VALID: std_logic_vector((NTCPSTREAMS-1) downto 0) := (others => '0');

 	--Outputs
   signal MAC_TX_DATA : std_logic_vector(7 downto 0);
   signal MAC_TX_DATA_VALID : std_logic;
   signal MAC_TX_EOF : std_logic;
   signal CS1 : std_logic_vector(7 downto 0);
   signal CS1_CLK : std_logic;
   signal CS2 : std_logic_vector(7 downto 0);
   signal CS2_CLK : std_logic;
   signal TP : std_logic_vector(10 downto 1);
	signal TCP_TX_CTS: std_logic_vector((NTCPSTREAMS-1) downto 0);
	signal TCP_TX_DATA_E: SLV8xNTCPSTREAMStype;
	signal TCP_TX_DATA_VALID_E: std_logic_vector((NTCPSTREAMS-1) downto 0);
	

	-- PRBS-11 test sequence
	signal PRBS11_DATA: std_logic_vector(7 downto 0) := x"00";
	signal PRBS11_DATA_VALID: std_logic := '0';
	signal PRBS11_SOF: std_logic := '0';
	signal PRBS11_CTS: std_logic := '0';
	signal STREAM_EN: std_logic := '0';


   -- Clock period definitions
   constant CLK_period : time := 8 ns;
	
	constant SIM_LENGTH: integer := 100000;	-- simulation length expressed in number of bytes read from the libpcap stimulus file
	
	type char_file is file of character; -- one byte each
	file libpcap_file: char_file;
	constant file_name: string := "input.cap";	-- file must be located in same directory as this testbench.
	signal byteCount1: std_logic_vector(7 downto 0) := x"00";
	signal byteCount2: std_logic_vector(15 downto 0) := x"0000";
	signal messageLength: std_logic_vector(31 downto 0) := x"00000000";
--	signal byteRead: std_logic_vector(7 downto 0);
	
 --//-- LAN PHY --------------------------------------------------------------------
signal CLK125_NDO : std_logic := '0';
signal MAC_TX_CONFIG : std_logic_vector(15 downto 0) := (others => '0');
signal MAC_RX_CONFIG: std_logic_vector(15 downto 0) := (others => '0');
signal TXC : std_logic;
signal TXD : std_logic_vector(3 downto 0);
signal TX_CTL : std_logic;
signal RXC : std_logic := '0';
signal RXD : std_logic_vector(3 downto 0) := (others => '0');
signal RX_CTL : std_logic := '0';
signal MCLK : std_logic;
signal MDIO : std_logic;
signal RESET_N : std_logic;
signal MII_TX_CLK: std_logic;

------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
begin

TIMER_4US_001: TIMER_4US 
GENERIC MAP(
	CLK_FREQUENCY => 120		-- 120 MHz, as time reference
)
PORT MAP(
	ASYNC_RESET => ASYNC_RESET,
	CLK => CLK,
	TICK_4US => TICK_4US,
	TICK_100MS => open
);


-- enable stream to packet after a delay (after ARP is complete for example)
process
begin
	STREAM_EN <= '0';
	wait for 30000 ns;
	STREAM_EN <= '1';
	wait;
end process;

-- read and decode a libpcap file
	process is
		variable c : character;
		variable byteRead: std_logic_vector(7 downto 0) := x"00";
		
	begin
		file_open(libpcap_file, file_name, read_mode);
		
		for i in 0 to SIM_LENGTH loop
			if(not endfile(libpcap_file)) then
				read(libpcap_file, c);
			else
				c := 'z';	-- continue simulation past the end of the stimulus file.
			end if;
			byteRead := std_logic_vector(to_unsigned(character'pos(c),8));
			if(byteCount1 < 24) then
				-- global header
				byteCount1 <= byteCount1 + 1;
				byteCount2 <= (others => '0');
				wait for 0.01ns;	-- delay start of wireshark simulation
			else
				-- packet
				if(byteCount2 < 4) then
					-- timestamp seconds
					MAC_RX_EOF0 <= '0';	-- clear EOF flag
					MAC_RX_DATA_VALID0 <= '0';
					byteCount2 <= byteCount2 + 1;
					wait for 500*CLK_period;	-- slow down the rate at which we read the wireshark file
				elsif(byteCount2 < 8) then
					-- timetamp microseconds
					byteCount2 <= byteCount2 + 1;
				elsif(byteCount2 < 12) then
					-- packet length
					messageLength(23 downto 0) <= messageLength(31 downto 8);
					messageLength(31 downto 24) <= std_logic_vector(to_unsigned(character'pos(c),8));	-- LSB first
					byteCount2 <= byteCount2 + 1;
				elsif(byteCount2 < 16) then
					-- actual packet length on network
					byteCount2 <= byteCount2 + 1;
				else
					-- packet data
					MAC_RX_DATA0 <= byteRead;
					if(byteCount2 = 16) then
						MAC_RX_SOF0 <= '1';
						MAC_RX_DATA_VALID0 <= '1';
						byteCount2 <= byteCount2 + 1;
					elsif(byteCount2 = messageLength + 15) then
						-- reached end of packet, reset counter
						MAC_RX_EOF0 <= '1';
						byteCount2 <= (others => '0');	
					else
						MAC_RX_SOF0 <= '0';
						byteCount2 <= byteCount2 + 1;
					end if;
				end if;
				wait for CLK_period;	
			end if;
			
		end loop;
		
	end process;
	
	process
	begin
		CLK <= '0';
		wait for CLK_period/2;
		CLK <= '1';
		wait for CLK_period/2;
	end process;
	
	-- reclock data for clean interface
	RECLOCK_001: process(CLK)
	begin
		if rising_edge(CLK) then
			MAC_RX_DATA <= MAC_RX_DATA0;
			MAC_RX_DATA_VALID <= MAC_RX_DATA_VALID0;
			MAC_RX_SOF <= MAC_RX_SOF0;
			MAC_RX_EOF <= MAC_RX_EOF0;
		end if;
	end process;
	
 
	-- Instantiate the Unit Under Test (UUT)
   uut: COM5402 
	GENERIC MAP(
		CLK_FREQUENCY => 125,	-- 125 MHz clock (8ns simulation period), use for time and frequency
		SIMULATION => '1'
	)
	PORT MAP (
          CLK => CLK,
          ASYNC_RESET => ASYNC_RESET,
			 MAC_ADDR => MAC_ADDR,
			 IPv4_ADDR => IPv4_ADDR,
			 IPv6_ADDR => IPv6_ADDR,
			 SUBNET_MASK => x"FFFFFF00",
			 GATEWAY_IP_ADDR => GATEWAY_IP_ADDR,
          MAC_TX_DATA => MAC_TX_DATA,
          MAC_TX_DATA_VALID => MAC_TX_DATA_VALID,
          MAC_TX_EOF => MAC_TX_EOF,
          MAC_TX_CTS => MAC_TX_CTS,
          MAC_RX_DATA => MAC_RX_DATA,
          MAC_RX_DATA_VALID => MAC_RX_DATA_VALID,
          MAC_RX_SOF => MAC_RX_SOF,
          MAC_RX_EOF => MAC_RX_EOF,
			-- UDP rx
			UDP_RX_DATA => open,
			UDP_RX_DATA_VALID => open,
			UDP_RX_SOF => open,
			UDP_RX_EOF => open,
			UDP_RX_DEST_PORT_NO => x"0000",
			-- UDP tx
			UDP_TX_DATA => x"00",
			UDP_TX_DATA_VALID => '0',
			UDP_TX_SOF => '0',
			UDP_TX_EOF => '0',
			UDP_TX_CTS => open,
			UDP_TX_ACK => open,
			UDP_TX_NAK => open,
			UDP_TX_DEST_IP_ADDR => x"00000000000000000000000000000000",
			UDP_TX_DEST_PORT_NO => x"0000",
			UDP_TX_SOURCE_PORT_NO => x"0000",
			-- TCP rx streams
			 TCP_RX_DATA => open,
			 TCP_RX_DATA_VALID => open,
			 TCP_RX_RTS => open,
			 TCP_RX_CTS => '1',
			-- TCP tx streams
			 TCP_TX_DATA => TCP_TX_DATA,
			 TCP_TX_DATA_VALID => TCP_TX_DATA_VALID,
			 TCP_TX_CTS => TCP_TX_CTS,
			-- Monitoring
          CS1 => CS1,
          CS1_CLK => CS1_CLK,
          CS2 => CS2,
          CS2_CLK => CS2_CLK,
          TP => TP
        );


-- data stream is TCP stream #0
-- tx throughput test on stream #0
LAN_TX_GEN: process(CLK)
begin
	if rising_edge(CLK) then
		if(TCP_TX_CTS(0) = '1') then
			TCP_TX_DATA(0) <= TCP_TX_DATA(0) + 1;
			TCP_TX_DATA_VALID(0) <= '1';
		else
			TCP_TX_DATA_VALID(0) <= '0';
		end if;
	end if;
end process;

--//-- LAN PHY --------------------------------------------------------------------
-- User commands
MAC_TX_CONFIG <= x"0003"; -- enable padding, crc32
--MAC_TX_CONFIG <= x"0000"; -- user is responsible for padding and crc32
--MAC_RX_CONFIG <= x"0001"; -- promiscuous mode
MAC_RX_CONFIG <= x"0006"; -- check address, allow broadcast and multicast rx packets
--MAC_RX_CONFIG <= x"0008"; -- check address, no broadcast nor multicast rx packets, filter out crc field

	LAN_001: COM5401 
	GENERIC MAP(
		MII_SEL => '0',	-- RGMII
		PHY_ADDR => "00100",	-- PHY_AD0/1 pulled-down by 1KOhm, PHY_AD2 pulled-up in .ucf file.
		CLK_FREQUENCY => 120
	)
	PORT MAP(
		 CLK => CLK,
		 ASYNC_RESET => ASYNC_RESET,
		 MAC_TX_CONFIG => MAC_TX_CONFIG,
		 MAC_RX_CONFIG => MAC_RX_CONFIG,
		 MAC_ADDR => MAC_ADDR, 
		 PHY_CONFIG_CHANGE => '0',
		 PHY_RESET => '0',
		 SPEED => "11",	-- unused here. Use defaults within.
		 DUPLEX => '1',	-- unused here. Use defaults within.
		 TEST_MODE => "00",	-- unused here. Use defaults within.
		 CLK_SKEW => x"7777",	-- unused here. Use defaults within
		 POWER_DOWN => '0', -- unused here. Use defaults within.
		 MAC_TX_DATA => MAC_TX_DATA,
		 MAC_TX_DATA_VALID => MAC_TX_DATA_VALID,
		 MAC_TX_EOF => MAC_TX_EOF,
		 MAC_TX_CTS => MAC_TX_CTS,
		 MAC_RX_DATA => open,	-- 5402 reads data from the input.cap Wireshark capture file, not from this MAC
		 MAC_RX_DATA_VALID => open,
		 MAC_RX_SOF => open,
		 MAC_RX_EOF => open,
		 MAC_RX_CTS => '1',
		 TXC => TXC,	-- RGMII interface ----------------
		 TXD => TXD,
		 TX_CTL => TX_CTL,
		 RXC => RXC,
		 RXD => RXD,
		 RX_CTL => RX_CTL,
		 RESET_N => RESET_N,
		 MCLK => MCLK,
		 MDIO => MDIO,
		 MII_TX_CLK => '0', -- MII interface  -----
		 GMII_TX_CLK => open,
		 GMII_MII_TXD => open,
		 GMII_MII_TX_EN => open,
		 GMII_MII_TX_ER => open,
		 GMII_MII_CRS => '0',
		 GMII_MII_COL => '0',
		 GMII_MII_RX_CLK => '0',
		 GMII_MII_RXD => x"00",
		 GMII_MII_RX_DV => '0',
		 GMII_MII_RX_ER => '0', -- end of MII interface ------
		 LINK_STATUS => open,
		 SPEED_STATUS => open,
		 DUPLEX_STATUS => open,
		 PHY_ID => open,
		 CS_CLKG => open,
		 CS1 => open,
		 CS1_CLK => open,
		 CS2 => open,
		 CS2_CLK => open,
		 TP => open
		 
	  );


--// PHY EMULATION ----------------------------------------------
PHYSIM_RGMII_001: PHYSIM_RGMII PORT MAP(
	 TXC => TXC,
	 TXD => TXD,
	 TX_CTL => TX_CTL,
	 RXC => RXC,
	 RXD => RXD,
	 RX_CTL => RX_CTL,
	 RESET_N => RESET_N,
	 MCLK => MCLK,
	 MDIO => MDIO,
	 CLK125_NDO => CLK125_NDO
);


END;
