-------------------------------------------------------------
-- MSS copyright 2011-2013
--	Filename:  tbCOM5401_testTXCTS.vhd
-- Author: Alain Zarembowitch / MSS
--	Version: 10
--	Date last modified: 8/21/13
-- Inheritance: 	N/A
-- 
-- description:  this testbench sends 512-byte frames as fast as possible to the COM5401 Ethernet MAC.
-- This allows one to test the flow control. 
-- The simple PHY simulator just loops back tx to rx. Therefore frames are also received by the Ethernet MAC.
-- At the time of simulation, one can select the PHY interface (RGMII or GMII),
-- and various MAC configuration parameters (MAC_TX_CONFIG, MAC_RX_CONFIG, MAC_ADDR).
--
-- Usage: 
-- Set the LAN speed in PHYSIM_GMII_MII as if the PHY completed the autonegotiation. For example      
-- SPEED => "10",  for 100 Mbps (25 MHz clock).
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;
 
ENTITY tbCOM5401_testTXCTS IS
END tbCOM5401_testTXCTS;
 
ARCHITECTURE behavior OF tbCOM5401_testTXCTS IS 
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------
	COMPONENT COM5401
	GENERIC (
		MII_SEL: std_logic;  
		PHY_ADDR: std_logic_vector(4 downto 0);
		CLK_FREQUENCY: integer;
		SIMULATION: std_logic
	);
	PORT(
		CLK : IN std_logic;
		SYNC_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(9 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);
		N_RX_FRAMES: out  std_logic_vector(15 downto 0);
		N_RX_BAD_CRCS: out  std_logic_vector(15 downto 0);
		N_RX_FRAMES_TOO_SHORT: out  std_logic_vector(15 downto 0);
		N_RX_FRAMES_TOO_LONG: out  std_logic_vector(15 downto 0);
		N_RX_WRONG_ADDR: out  std_logic_vector(15 downto 0);
		N_RX_LENGTH_ERRORS: 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;

	COMPONENT PHYSIM_GMII_MII
	PORT(
		GTX_CLK : IN std_logic;
		TXD : IN std_logic_vector(7 downto 0);
		TX_EN : IN std_logic;
		TX_ER : IN std_logic;
		RESET_N : IN std_logic;
		SPEED : IN std_logic_vector(1 downto 0);
		MCLK : IN std_logic;    
		MDIO : INOUT std_logic;      
		TX_CLK : OUT std_logic;
		RX_CLK : OUT std_logic;
		RXD : OUT std_logic_vector(7 downto 0);
		RX_DV : OUT std_logic;
		RX_ER : OUT std_logic;
		CRS : OUT std_logic;
		COL : OUT std_logic;
		CLK125_NDO : OUT std_logic
		);
	END COMPONENT;


--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------
-- Suffix _D indicates a one CLK delayed version of the net with the same name
-- Suffix _X indicates an extended precision version of the net with the same name
-- Suffix _N indicates an inverted version of the net with the same name

   signal CLK : std_logic := '0';
   signal CLK125G : std_logic := '0';
	signal SYNC_RESET : std_logic := '0';
	signal SYNC_RESET_CNTR: std_logic_vector(3 downto 0) := (others => '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 MAC_ADDR: std_logic_vector(47 downto 0);
   signal MAC_TX_DATA : std_logic_vector(7 downto 0) := (others => '0');
	signal TX_COUNTER: std_logic_vector(10 downto 0) := "00000000000";			
   signal MAC_TX_DATA_VALID : std_logic := '0';
   signal MAC_TX_EOF : std_logic := '0';
   signal MAC_RX_CTS : std_logic := '0';
   signal RXC : std_logic := '0';
   signal RXD : std_logic_vector(3 downto 0) := (others => '0');
   signal RX_CTL : std_logic := '0';
   signal CLK125_NDO : std_logic := '0';
	signal MII_TX_CLK: std_logic;
	signal GMII_MII_RX_CLK: std_logic;
	signal GMII_MII_RXD : std_logic_vector(7 downto 0);
	signal GMII_MII_RX_DV : std_logic;
	signal GMII_MII_RX_ER : std_logic;    

	--BiDirs
   signal MDIO : std_logic;

 	--Outputs
   signal MAC_TX_CTS : std_logic;
   signal MAC_RX_DATA : std_logic_vector(7 downto 0);
   signal MAC_RX_DATA_VALID : std_logic;
   signal MAC_RX_SOF : std_logic;
   signal MAC_RX_EOF : std_logic;
   signal TXC : std_logic;
   signal TXD : std_logic_vector(3 downto 0);
   signal TX_CTL : std_logic;
   signal RESET_N : std_logic;
   signal MCLK : std_logic;
   signal LINK_STATUS : std_logic;
   signal SPEED_STATUS : std_logic_vector(1 downto 0);
   signal DUPLEX_STATUS : std_logic;
	signal GMII_TX_CLK: std_logic;
	signal GMII_MII_TXD: std_logic_vector(7 downto 0);
	signal GMII_MII_TX_EN: std_logic;
	signal GMII_MII_TX_ER: std_logic;
	signal GMII_MII_CRS: std_logic;
	signal GMII_MII_COL: std_logic;
	signal N_RX_FRAMES: std_logic_vector(15 downto 0) := (others => '0');
	signal N_RX_BAD_CRCS: std_logic_vector(15 downto 0) := (others => '0');
	signal N_RX_FRAMES_TOO_SHORT: std_logic_vector(15 downto 0) := (others => '0');
	signal N_RX_FRAMES_TOO_LONG: std_logic_vector(15 downto 0) := (others => '0');
	signal N_RX_LENGTH_ERRORS: std_logic_vector(15 downto 0) := (others => '0');
	signal N_RX_WRONG_ADDR: std_logic_vector(15 downto 0) := (others => '0');
	signal TP: std_logic_vector(10 downto 1);
	signal DELAY_START: std_logic := '1';

   -- Clock period definitions
   constant CLK_period : time := 8 ns;  -- 125 MHz user clock
	
	
	
--// CONFIGURATION ------------------------------------------------
constant MII_SEL: std_logic := '1';   -- select which MII interface: 0 = RGMII, 1 = GMII/MII
	
 
BEGIN

--// USER CONFIGURATIONS -----------------------------------------------------

-- Generate user-side clock
CLK_process :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;

CLK125G <= CLK125_NDO;
	-- 125 MHz clock from PHY

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
MAC_ADDR <= x"D0D1D2D3D4D5";
--MAC_ADDR <= x"A0A1A2A3A4A5";
--MAC_ADDR <= x"01000CCCCCCC";  -- Cisco Delivery Protocol, Ethernet multicast address example.
	
--// USER TX DATA -----------------------------------------------------
-- send byte count
-- transmit 512-byte packets continuously and as fast as possible
-- delay start by 400ns
process
begin
	DELAY_START <= '1';
	wait for 400 ns;
	DELAY_START <= '0';
	wait;
end process;

TX_PACKET_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(SYNC_RESET = '1') then
			TX_COUNTER <= (others => '0');
			MAC_TX_EOF <= '0';
			MAC_TX_DATA_VALID <= '0';
		elsif(MAC_TX_CTS = '1') and (DELAY_START = '0') then
			MAC_TX_DATA_VALID <= '1';
			if(TX_COUNTER >= 511) then
				MAC_TX_EOF <= '1';
				TX_COUNTER <= (others => '0');
				MAC_TX_DATA <= TX_COUNTER(7 downto 0);
			else
				TX_COUNTER <= TX_COUNTER + 1;
				MAC_TX_DATA <= TX_COUNTER(7 downto 0);
				MAC_TX_EOF <= '0';
			end if;
		else
			MAC_TX_EOF <= '0';
			MAC_TX_DATA_VALID <= '0';
		end if;
	end if;
end process;

--// Instantiate the Unit Under Test (UUT) -----------------------------------------------------
MAC_RX_CTS <= '1'; -- read rx data as fast as possible.

	LAN_001: COM5401 
	GENERIC MAP(
		MII_SEL => MII_SEL,
		PHY_ADDR => "00100",	-- PHY_AD0/1 pulled-down by 1KOhm, PHY_AD2 pulled-up in .ucf file.
		CLK_FREQUENCY => 125,
		SIMULATION => '1'
	)
	PORT MAP(
		 CLK => CLK,
		 SYNC_RESET => SYNC_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 => "1111111111",	-- 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 => MAC_RX_DATA,
		 MAC_RX_DATA_VALID => MAC_RX_DATA_VALID,
		 MAC_RX_SOF => MAC_RX_SOF,
		 MAC_RX_EOF => MAC_RX_EOF,
		 MAC_RX_CTS => MAC_RX_CTS,
		 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 => MII_TX_CLK, -- MII interface  -----
		 GMII_TX_CLK => GMII_TX_CLK,
		 GMII_MII_TXD => GMII_MII_TXD,
		 GMII_MII_TX_EN => GMII_MII_TX_EN,
		 GMII_MII_TX_ER => GMII_MII_TX_ER,
		 GMII_MII_CRS => GMII_MII_CRS,
		 GMII_MII_COL => GMII_MII_COL,
		 GMII_MII_RX_CLK => GMII_MII_RX_CLK,
		 GMII_MII_RXD => GMII_MII_RXD,
		 GMII_MII_RX_DV => GMII_MII_RX_DV,
		 GMII_MII_RX_ER => GMII_MII_RX_ER, -- end of MII interface ------
		 LINK_STATUS => LINK_STATUS,
		 SPEED_STATUS => SPEED_STATUS,
		 DUPLEX_STATUS => DUPLEX_STATUS,
		 PHY_ID => open,
		 N_RX_FRAMES => N_RX_FRAMES,
		 N_RX_BAD_CRCS => N_RX_BAD_CRCS,
		 N_RX_FRAMES_TOO_SHORT => N_RX_FRAMES_TOO_SHORT,
		 N_RX_FRAMES_TOO_LONG => N_RX_FRAMES_TOO_LONG,
		 N_RX_WRONG_ADDR => N_RX_WRONG_ADDR,
		 N_RX_LENGTH_ERRORS => N_RX_LENGTH_ERRORS,
		 CS_CLKG => open,
		 CS1 => open,
		 CS1_CLK => open,
		 CS2 => open,
		 CS2_CLK => open,
		 TP => TP
		 
	  );


--// PHY EMULATION ----------------------------------------------
IF_SEL_000: if(MII_SEL = '0') generate
	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 generate;	

IF_SEL_001: if(MII_SEL = '1') generate
   -- PHY loopback emulation
	Inst_PHYSIM_GMII_MII: PHYSIM_GMII_MII PORT MAP(
		TX_CLK => MII_TX_CLK,
		GTX_CLK => GMII_TX_CLK,
		TXD => GMII_MII_TXD,
		TX_EN => GMII_MII_TX_EN,
		TX_ER =>GMII_MII_TX_ER,
		RX_CLK => GMII_MII_RX_CLK,
		RXD => GMII_MII_RXD,
		RX_DV => GMII_MII_RX_DV,
		RX_ER => GMII_MII_RX_ER,
		CRS => GMII_MII_CRS,
		COL => GMII_MII_COL,
		 RESET_N => RESET_N,
--       SPEED => "01",  -- define PHY-negotiated speed as 100 Mbps (as if after autonegotiation)
       SPEED => "10",  -- define PHY-negotiated speed 1Gbps (as if after autonegotiation)
		 MCLK => MCLK,
		 MDIO => MDIO,
		 CLK125_NDO => CLK125_NDO
	);
end generate;	

END;
