-------------------------------------------------------------
-- MSS copyright 2011-2012
--	Filename:  tb5402udprx.VHD
-- Author: Alain Zarembowitch / MSS
--	Version: 1
--	Date last modified: 8/8/12
-- Inheritance: 	N/A
--
-- description:  Test UDP receiver. Receives UDP packets from a Wireshark .cap capture file.
-- Stitched together, the UDP packets make a PRBS-11 test sequence, which can be used to measure
-- bit error rate in the BER2 component.
-- Verify that BER2 is synchronized with the reconstructed stream (BER2_SYNC_LOCK = '1'),
-- that the BER2 matched filter detects the start of PRBS11 sequence periodically every 2047 bits (BER2_MF_DETECT),
-- and that no bit error occurs (BER2_BYTE_ERROR = '0').
--
-- Tested with NTCPSTREAMS = 1, NUDPTX = 1, NUDPRX = 1 
--
-- Test conditions: 
-- our IP address 172.16.1.44, tx port 5678
-- sender IP address 172.16.1.129, rx port 1234
--
-- Key ISIM waveforms are saved in tb5402udprx.wcfg (open with ISIM)

---------------------------------------------------------------
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 tb5402udprx IS
END tb5402udprx;
 
ARCHITECTURE behavior OF tb5402udprx IS 
 
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------

	COMPONENT COM5402
	GENERIC (
		NUDPTX: integer range 0 to 1:= 1;
		NUDPRX: integer range 0 to 1:= 0;
		NTCPSTREAMS: integer range 0 to 255 := 1;  
		CLK_FREQUENCY: integer := 120;
		TX_IDLE_TIMEOUT: integer range 0 to 50:= 50;	
		SIMULATION: std_logic := '0'
	);	
	PORT(
		CLK : IN std_logic;
		ASYNC_RESET : IN std_logic;
		SYNC_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);
		CONNECTION_RESET: in std_logic_vector((NTCPSTREAMS-1) 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_vector((NTCPSTREAMS-1) downto 0);	-- Ready To Send
		TCP_RX_CTS: in std_logic_vector((NTCPSTREAMS-1) downto 0);	-- Clear To Send
		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 PACKETS_2_STREAM
	generic (
		NBUFS: integer
	);
	PORT(
		ASYNC_RESET : IN std_logic;
		CLK : IN std_logic;
		PACKET_DATA_IN : IN std_logic_vector(7 downto 0);
		PACKET_DATA_VALID_IN : IN std_logic;
		PACKET_EOF_IN : IN std_logic;
		STREAM_CTS_IN : IN std_logic;          
		PACKET_CTS_OUT : OUT std_logic;
		STREAM_DATA_OUT : OUT std_logic_vector(7 downto 0);
		STREAM_DATA_VALID_OUT : OUT std_logic;
		BAD_PACKET : OUT std_logic;
		TP : OUT std_logic_vector(10 downto 1)
		);
	END COMPONENT;

	COMPONENT BER2
	PORT(
		CLK : IN std_logic;
		SYNC_RESET : IN std_logic;
		DATA_IN : IN std_logic_vector(7 downto 0);
		SAMPLE_CLK_IN : IN std_logic;
		CONTROL : IN std_logic_vector(7 downto 0);          
		MF_DETECT : OUT std_logic;
		MF_DETECT_CONFIRMED : OUT std_logic;
		SYNC_LOCK : OUT std_logic;
		BYTE_ERROR : OUT std_logic;
		DATA_REPLICA : OUT std_logic_vector(7 downto 0);
		SAMPLE_CLK_OUT : OUT std_logic;
		BER : OUT std_logic_vector(31 downto 0);
		BER_SAMPLE_CLK : OUT std_logic;
		TP : OUT std_logic_vector(10 downto 1)
		);
	END COMPONENT;

--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------
constant NTCPSTREAMS: integer range 0 to 255 := 1;  
signal CLK : std_logic := '0';
signal ASYNC_RESET : std_logic := '0';
signal SYNC_RESET : std_logic := '0';
signal SYNC_RESET_CNTR: std_logic_vector(3 downto 0) := (others => '0');
--signal MAC_ADDR : std_logic_vector(47 downto 0) := x"000102030405";
signal MAC_ADDR : std_logic_vector(47 downto 0) := x"88AE1D98F950";
--signal MAC_ADDR : std_logic_vector(47 downto 0) := x"004A4871B05C";
	-- must match Wireshark capture file
--signal IPv4_ADDR : std_logic_vector(31 downto 0) := x"AC100180";
signal IPv4_ADDR : std_logic_vector(31 downto 0) := x"AC10012C";
--signal IPv4_ADDR : std_logic_vector(31 downto 0) := x"0A0A0A10";
	-- 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');
signal TP : std_logic_vector(10 downto 1);
signal TCP_RX_CTS: std_logic;
signal TCP_TX_CTS: std_logic_vector((NTCPSTREAMS-1) downto 0);
signal TCP_TX_DATA_E: SLV8xNTCPSTREAMStype;

-- udp rx
signal UDP_RX_DATA: std_logic_vector(7 downto 0) := x"00";
signal UDP_RX_DATA_VALID: std_logic := '0';
signal UDP_RX_EOF: std_logic := '0';
signal UDP_BAD_PACKET: std_logic := '0';	

--//-- THROUGHPUT & BER TESTS ----------------------
signal RX_STREAM_DATA: std_logic_vector(7 downto 0) := (others => '0');
signal RX_STREAM_DATA_VALID: std_logic := '0';
signal BER2_MF_DETECT: std_logic := '0';
signal BER2_MF_DETECT_CONFIRMED: std_logic := '0';
signal BER2_SYNC_LOCK: std_logic := '0';
signal BER2_BYTE_ERROR: std_logic := '0';


-- Clock period definitions
constant CLK_period : time := 8 ns;	-- 125 MHz

constant SIM_LENGTH: integer := 1000000;	-- 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 := ".\sim\tbcom5402udprx.cap";	
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);
	
------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
begin

process
begin
	CLK <= '0';
	wait for CLK_period/2;
	CLK <= '1';
	wait for CLK_period/2;
end process;

-- sync reset
process(CLK)
begin
	if rising_edge(CLK) then
		if(SYNC_RESET_CNTR(3) = '0') then
			SYNC_RESET_CNTR <= SYNC_RESET_CNTR + 1;
		end if;
		if(SYNC_RESET_CNTR = "0111") then
			SYNC_RESET <= '1';
		else
			SYNC_RESET <= '0';
		end if;
	end if;
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);
		wait for 0 ns;	
		
		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;
			else
				-- packet
				if(byteCount2 < 4) then
					-- timestamp seconds
					MAC_RX_EOF0 <= '0';	-- clear EOF flag
					MAC_RX_DATA_VALID0 <= '0';
					byteCount2 <= byteCount2 + 1;
				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;
	

	
	-- 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;
	
 
	-- UDP receiver
   UDP_RX_001: COM5402 
	GENERIC MAP(
		NUDPTX => 1,
		NUDPRX  => 1,
		NTCPSTREAMS => 1,
		TX_IDLE_TIMEOUT => 50,
		CLK_FREQUENCY => 125,	
		SIMULATION => '1'
	)
	PORT MAP (
          CLK => CLK,
          ASYNC_RESET => SYNC_RESET,
          SYNC_RESET => SYNC_RESET,
			 MAC_ADDR => MAC_ADDR,	-- as per collected wireshark .cap file
			 IPv4_ADDR => IPv4_ADDR,-- as per collected wireshark .cap file
			 IPv6_ADDR => IPv6_ADDR,
			 SUBNET_MASK => x"FFFFFF00",
			 GATEWAY_IP_ADDR => GATEWAY_IP_ADDR,
			 CONNECTION_RESET => "0",
          MAC_TX_DATA => open,
          MAC_TX_DATA_VALID => open,
          MAC_TX_EOF => open,
          MAC_TX_CTS => '0',
          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 => UDP_RX_DATA,
			 UDP_RX_DATA_VALID => UDP_RX_DATA_VALID,
			 UDP_RX_SOF => open,
			 UDP_RX_EOF => UDP_RX_EOF,
--			 UDP_RX_DEST_PORT_NO => x"1234",	-- as per collected wireshark .cap file
			 UDP_RX_DEST_PORT_NO => x"0500",
			-- 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"000000000000000000000000AC100103",
			UDP_TX_DEST_PORT_NO => x"1234",
			UDP_TX_SOURCE_PORT_NO => x"5678",
			-- TCP rx
			 TCP_RX_DATA => open,
			 TCP_RX_DATA_VALID => open,
			 TCP_RX_RTS => open,
			 TCP_TX_DATA => TCP_TX_DATA,
			 TCP_TX_DATA_VALID => TCP_TX_DATA_VALID,
			 TCP_TX_CTS => open,
			 TCP_RX_CTS => "0",
          CS1 => open,
          CS1_CLK => open,
          CS2 => open,
          CS2_CLK => open,
          TP => open
        );



Inst_PACKETS_2_STREAM: PACKETS_2_STREAM 
GENERIC MAP(
	NBUFS => 1
)
PORT MAP(
	CLK => CLK,
	ASYNC_RESET => ASYNC_RESET,
	PACKET_DATA_IN => UDP_RX_DATA,
	PACKET_DATA_VALID_IN => UDP_RX_DATA_VALID,
	PACKET_EOF_IN => UDP_RX_EOF,
	PACKET_CTS_OUT => open,	-- no flow control (can't control the rate of arrival of UDP packets)
	STREAM_DATA_OUT => RX_STREAM_DATA,
	STREAM_DATA_VALID_OUT => RX_STREAM_DATA_VALID,
	STREAM_CTS_IN => '1',
	BAD_PACKET => UDP_BAD_PACKET,
	TP => open
);


-- detect errors
BER2_001: BER2 PORT MAP(
	CLK => CLK,
	SYNC_RESET => ASYNC_RESET,
	DATA_IN => RX_STREAM_DATA,
	SAMPLE_CLK_IN => RX_STREAM_DATA_VALID,
	CONTROL => x"03",	-- 1 million bit window
	MF_DETECT => BER2_MF_DETECT,
	MF_DETECT_CONFIRMED => BER2_MF_DETECT_CONFIRMED,
	SYNC_LOCK => BER2_SYNC_LOCK,
	BYTE_ERROR => BER2_BYTE_ERROR,
	DATA_REPLICA => open,
	SAMPLE_CLK_OUT => open,
	BER => open,
	BER_SAMPLE_CLK => open,
	TP => open
);


TCP_TX_DATA_VALID(0) <= '0';


END;
