OpenCores
URL https://opencores.org/ocsvn/gigabit_udp_mac/gigabit_udp_mac/trunk

Subversion Repositories gigabit_udp_mac

[/] [gigabit_udp_mac/] [trunk/] [MAC/] [MAC_Controller.vhd] - Rev 2

Compare with Previous | Blame | View Log

-------------------------------------------------------------
--	Filename:  MAC_Controller.VHD
--	Version: 5
--	Date last modified: 9/16/11
-- Inheritance: COM5401.VHD, rev5, 9/16/11
--
-- description:  10/100/1000 MAC
-- Features include
-- (a) Automatic appending of 32-bit CRC to tx packets. Users don't have to.
-- (b) discarding of rx packets with bad CRC.
-- 
-- Usage: the following KSZ9021RN strapping options MUST be set in the .ucf file
-- pin35 RX_CLK/PHYAD2 pull-down  LEFT_CONNECTOR_A(1),A(19),B(1),B(21)
-- pins32,31,28,27 RXDx/MODEx  pull-up, advertise all modes
-- 	LEFT_CONNECTOR_A(2,4,5,6,21,22,23,24),B(3,4,6,7,23,24,25,26)
-- pin33 RX_DV(RX_CTL)/CLK125_EN	
-- 	pull-down on all ICs. No need for an external 125 MHz clock (not very clean).
-- 	LEFT_CONNECTOR_A(2) pullup, LEFT_CONNECTOR_A(20),B(2),B(22) pull-down
-- pin41 CLK125_NDO/LED_MODE pulldown dual leds, tri-color.
-- 	LEFT_CONNECTOR_A(13,31),_B(14,34)
-- 
-- The transmit elastic buffer is large enough for 2 maximum size frame. The tx Clear To Send (MAC_TX_CTS)
-- signal is raised when the the MAC is ready to accept one complete frame without interruption.
-- In this case, MAC_TX_CTS may go low while the frame transfer has started, but there is guaranteed
-- space for the entire frame.  
--
---------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
library UNISIM;
use UNISIM.VComponents.all;
 
entity MAC_Controller is
	generic (
		PHY_ADDR: std_logic_vector(4 downto 0) := "00001";	
			-- PHY_AD0/1 pulled-down by 1KOhm, PHY_AD2 pulled-up in .ucf file.
		CLK_FREQUENCY: integer := 125
			-- CLK frequency in MHz. Needed to compute actual delays.
	);
    Port ( 
		--// CLK, RESET
		CLK: in std_logic;
			-- USER-side GLOBAL CLOCK
		IDELAYREFCLK200MHZ: in std_logic;
			-- 190-210 MHz clock required for implementing IO delay(s).
		ASYNC_RESET: in std_logic;
			-- reset pulse must be > slowest clock period  (>400ns)
			-- minimum width 50ns for Virtex 5 (IDELAYCTRL contraint)
			-- MANDATORY at power up.
 
		--// MAC CONFIGURATION
		-- configuration signals are synchonous with the user-side CLK
		MAC_TX_CONFIG: in std_logic_vector(15 downto 0);
			-- bit 0: (1) Automatic padding of short frames. Requires that auto-CRC insertion be enabled too. 
			--			 (0) Skip padding. User is responsible for adding padding to meet the minimum 60 byte frame size
			-- bit 1: (1) Automatic appending of 32-bit CRC at the end of the frame
			--			 (0) Skip CRC32 insertion. User is responsible for including the frame check sequence
			-- Note: use 0x03 when interfacing with COM-5402 IP/UDP/TCP stack.
		MAC_RX_CONFIG: in std_logic_vector(15 downto 0);
			-- bit 0: (1) promiscuous mode enabled (0) disabled, i.e. destination address is verified for each incoming packet 
			-- bit 1: (1) accept broadcast rx packets (0) reject
			-- bit 2: (1) accept multi-cast rx packets (0) reject
			-- bit 3: (1) filter out the 4-byte CRC field (0) pass along the CRC field.
			-- Note2: use 0x0F when interfacing with COM-5402 IP/UDP/TCP stack.
		MAC_ADDR: in std_logic_vector(47 downto 0);
			-- This network node 48-bit MAC address. The receiver checks incoming packets for a match between 
			-- the destination address field and this MAC address.
			-- The user is responsible for selecting a unique ‘hardware’ address for each instantiation.
			-- Natural bit order: enter x0123456789ab for the MAC address 01:23:45:67:89:ab
 
		--// PHY CONFIGURATION
		-- configuration signals are synchonous with the user-side CLK.
		PHY_CONFIG_CHANGE: in std_logic;
			-- optional pulse to activate any configuration change below.
			-- Not needed if the default values are acceptable.
			-- Ignored if sent during the initial PHY reset (10ms after power up)
		PHY_RESET: in std_logic; 
			-- 1 = PHY software reset (default), 0 = no reset
		SPEED: in std_logic_vector(1 downto 0);
			-- 00 = force 10 Mbps
			-- 01 = force 100 Mbps
			-- 10 = force 1000 Mbps
			-- 11 = auto-negotiation (default)
		DUPLEX: in std_logic;
			-- 1 = full-duplex (default), 0 = half-duplex
		TEST_MODE: in std_logic_vector(1 downto 0);
			-- 00 = normal mode (default)
			-- 01 = loopback mode (at the phy)
			-- 10 = remote loopback
			-- 11 = led test mode
		POWER_DOWN: in std_logic;
			-- software power down mode. 1 = enabled, 0 = disabled (default).
 
		--// USER -> Transmit MAC Interface
		-- 32-bit CRC is automatically appended. User should not supply it.
		-- Synchonous with the user-side CLK
		MAC_TX_DATA: in std_logic_vector(7 downto 0);
			-- MAC reads the data at the rising edge of CLK when MAC_TX_DATA_VALID = '1'
		MAC_TX_DATA_VALID: in std_logic;
			-- data valid
		MAC_TX_EOF: in std_logic;
			-- '1' when sending the last byte in a packet to be transmitted. 
			-- Aligned with MAC_TX_DATA_VALID
		MAC_TX_CTS: out std_logic;
			-- MAC-generated Clear To Send flow control signal, indicating room in the 
			-- tx elastic buffer for a complete maximum size frame 1518B. 
			-- The user should check that this signal is high before deciding to send
			-- sending the next frame. 
			-- Note: MAC_TX_CTS may go low while the frame is transfered in. Ignore it.
 
		--// Receive MAC -> USER Interface
		-- Valid rx packets only: packets with bad CRC or invalid address are discarded.
		-- Synchonous with the user-side CLK
		-- The short-frame padding is included .
		MAC_RX_DATA: out std_logic_vector(7 downto 0);
			-- USER reads the data at the rising edge of CLK when MAC_RX_DATA_VALID = '1'
		MAC_RX_DATA_VALID: out std_logic;
			-- data valid
		MAC_RX_SOF: out std_logic;
			-- '1' when sending the first byte in a received packet. 
			-- Aligned with MAC_RX_DATA_VALID
		MAC_RX_EOF: out std_logic;
			-- '1' when sending the last byte in a received packet. 
			-- Aligned with MAC_RX_DATA_VALID
		MAC_RX_CTS: in std_logic;
			-- User-generated Clear To Send flow control signal. The receive MAC checks that this 
			-- signal is high before sending the next MAC_RX_DATA byte. 
 
 
 
		--// RGMII PHY Interface (when RGMII is enabled. See MII_SEL generic flag above)
		RESET_N: out std_logic;
			-- PHY reset
		MCLK: out std_logic;
		MDIO: inout std_logic:='0';  -- (tri-state)
			-- serial interface
 
		--// GMII/MII PHY Interface (when GMII/MII is enabled.  See MII_SEL generic flag above)
		MII_TX_CLK: in std_logic:='0';
			-- MII tx clock from PHY. Continuous clock. (10/100 Mbps only) 
			-- 25 MHz (100 Mbps), or 2.5 MHz (10 Mbps) depending on speed
			-- accuracy: +/- 100ppm (MII)
			-- duty cycle between 35% and 65% inclusive (MII).
		GMII_TX_CLK: out std_logic;
			-- GMII tx clock to PHY. Continuous clock. 125MHz (1000 Mbps only)
			-- 2ns delay inside (user adjustable).
		GMII_MII_TXD: out std_logic_vector(7 downto 0);  -- tx data
			-- tx data (when TX_EN = '1' and TX_ER = '0') or special codes otherwise (carrier extend, 
			-- carrier extend error, transmit error propagation). See 802.3 table 35-1 for definitions.
		GMII_MII_TX_EN: out std_logic;
		GMII_MII_TX_ER: out std_logic;
			-- to deliberately corrupt the contents of the frame (so as to be detected as such by the receiver)
		GMII_MII_CRS: in std_logic:='0';
		GMII_MII_COL: in std_logic:='0';
 
		GMII_MII_RX_CLK: in std_logic;  
			-- continuous receive reference clock recovered by the PHY from the received signal
			-- 125/25/2.5 MHz +/- 50 ppm. 
			-- Duty cycle better than 35%/65% (MII)
			-- 125 MHz must be delayed by 1.5 to 2.1 ns to prevent glitches (TBC. true for RGMII, but for GMII TOO???)
 
		GMII_MII_RXD: in std_logic_vector(7 downto 0);  
			-- rx data. 8-bit when 1000 Mbps. 4-bit nibble (3:0) when 10/100 Mbps.
		GMII_MII_RX_DV: in std_logic;  
		GMII_MII_RX_ER: in std_logic;  
 
 
		--// PHY status
		-- The link, speed and duplex status are read from the RXD when RX_CTL is inactive
		-- synchronous with RXCG global clock
		LINK_STATUS: out std_logic;
			-- 0 = link down, 1 = link up
		SPEED_STATUS: out std_logic_vector(1 downto 0);
			-- RXC clock speed, 00 = 2.5 MHz, 01 = 25 MHz, 10 = 125 MHz, 11 = reserved
		DUPLEX_STATUS: out std_logic;
			-- 0 = half duplex, 1 = full duplex
		PHY_ID: out std_logic_vector(15 downto 0)
 
 );
end entity;
 
architecture Behavioral of MAC_Controller is
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------
	COMPONENT RESET_TIMER
	GENERIC (
		CLK_FREQUENCY: in integer
	);	
	PORT(
		CLK : IN std_logic;
		RESET_START : IN std_logic;          
		RESET_COMPLETE : OUT std_logic;
		INITIAL_CONFIG_PULSE : OUT std_logic;
		RESET_N : OUT std_logic
		);
	END COMPONENT;
 
	COMPONENT PHY_CONFIG
	GENERIC (
		PHY_ADDR: std_logic_vector(4 downto 0)
	);	
	PORT(
		SYNC_RESET : IN std_logic;
		CLK : IN std_logic;
		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);
		SREG_READ_START : IN std_logic;
		SREG_REGAD : IN std_logic_vector(8 downto 0);    
		LINK_STATUS: out std_logic;  
		MDI: in std_logic;  -- MDIO input
		MDO: out std_logic;  -- MDIO output
		MDT: out std_logic;  -- MDIO tri-state
		SREG_DATA : OUT std_logic_vector(15 downto 0);
		SREG_SAMPLE_CLK : OUT std_logic;
		MCLK : OUT std_logic
		);
	END COMPONENT;
 
	COMPONENT RGMII_WRAPPER_V6
	GENERIC (
		CLK_FREQUENCY: in integer
	);	
	PORT(
		SYNC_RESET : IN std_logic;
		CLK : IN std_logic;
		IDELAYREFCLK200MHZ: in std_logic;
		RXC : IN std_logic;
		RXD : IN std_logic_vector(3 downto 0);
		RX_CTL : IN std_logic;
		MAC_TXD : IN std_logic_vector(7 downto 0);
		MAC_TX_EN : IN std_logic;
		MAC_TX_ER : IN std_logic;
		MAC_TX_SAMPLE_CLK : IN std_logic;
		TX_SPEED : IN std_logic_vector(1 downto 0);          
		TXC : OUT std_logic;
		TXD : OUT std_logic_vector(3 downto 0);
		TX_CTL : OUT std_logic;
		MAC_RXD : OUT std_logic_vector(7 downto 0);
		MAC_RX_SAMPLE_CLK: OUT std_logic;
		MAC_RX_DV : OUT std_logic;
		MAC_RX_ER : OUT std_logic;
		RXCG_OUT : OUT std_logic;
		CRS : OUT std_logic;
		COL : OUT std_logic;
		LINK_STATUS : OUT std_logic;
		SPEED_STATUS : OUT std_logic_vector(1 downto 0);
		DUPLEX_STATUS : OUT std_logic;
		TP: out std_logic_vector(10 downto 1)
		);
	END COMPONENT;
 
	COMPONENT GMII_MII_WRAPPER_V6
	PORT(
		SYNC_RESET : IN std_logic;
		CLK : IN std_logic;
		IDELAYREFCLK200MHZ: in std_logic;
		TX_CLK : IN std_logic;
		RX_CLK : IN std_logic;
		RXD : IN std_logic_vector(7 downto 0);
		RX_DV : IN std_logic;
		RX_ER : IN std_logic;
		CRS : IN std_logic;
		COL : IN std_logic;
		MAC_TXD : IN std_logic_vector(7 downto 0);
		MAC_TX_EN : IN std_logic;
		MAC_TX_ER : IN std_logic;
		MAC_TX_SAMPLE_CLK : IN std_logic;
		MAC_TX_SPEED : IN std_logic_vector(1 downto 0);          
		GTX_CLK : OUT std_logic;
		TXD : OUT std_logic_vector(7 downto 0);
		TX_EN : OUT std_logic;
		TX_ER : OUT std_logic;
		MAC_RX_CLK : OUT std_logic;
		MAC_RXD : OUT std_logic_vector(7 downto 0);
		MAC_RX_DV : OUT std_logic;
		MAC_RX_ER : OUT std_logic;
		MAC_RX_SAMPLE_CLK : OUT std_logic;
		MAC_CRS : OUT std_logic;
		MAC_COL : OUT std_logic;
		LINK_STATUS : OUT std_logic;
		SPEED_STATUS : OUT std_logic_vector(1 downto 0);
		DUPLEX_STATUS : OUT std_logic
		);
	END COMPONENT;
 
	COMPONENT CRC32_8B
	PORT(
		SYNC_RESET : IN std_logic;
		CLK : IN std_logic;
		CRC32_IN : IN std_logic_vector(31 downto 0);
		DATA_IN : IN std_logic_vector(7 downto 0);
		SAMPLE_CLK_IN : IN std_logic;          
		CRC32_OUT : OUT std_logic_vector(31 downto 0);
		CRC32_VALID : OUT std_logic
		);
	END COMPONENT;
 
	COMPONENT LFSR11C
	PORT(
		ASYNC_RESET : IN std_logic;
		CLK : IN std_logic;
		BIT_CLK_REQ : IN std_logic;
		SYNC_RESET : IN std_logic;
		SEED : IN std_logic_vector(10 downto 0);          
		LFSR_BIT : OUT std_logic;
		BIT_CLK_OUT : OUT std_logic;
		SOF_OUT : OUT std_logic;
		LFSR_REG_OUT: OUT std_logic_vector(10 downto 0)
		);
	END COMPONENT;
 
--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------
-- NOTATIONS: 
-- _E as one-CLK early sample
-- _D as one-CLK delayed sample
-- _D2 as two-CLKs delayed sample
 
--// CLK & RESETS ---------
signal RESETFLAG_D: std_logic := '0';
signal RESETFLAG_D2: std_logic := '0';
signal SYNC_RESET: std_logic := '0';
signal SYNC_RESETRX: std_logic := '0';
signal RESETRX_FLAG_D: std_logic := '0';
signal RESETRX_FLAG_D2: std_logic := '0';
 
 
--// PHY RESET AND CONFIGURATION ----------------------------------------------------------
signal RESET_N_LOCAL: std_logic := '0';
signal INITIAL_CONFIG_PULSE: std_logic := '1';
signal PHY_CONFIG_CHANGE_A: std_logic := '0';
signal PHY_RESET_A: std_logic := '0';
signal SPEED_A: std_logic_vector(1 downto 0);
signal DUPLEX_A: std_logic := '0';
signal TEST_MODE_A: std_logic_vector(1 downto 0);
signal POWER_DOWN_A: std_logic := '0';
signal CLK_SKEW_A: std_logic_vector(15 downto 0);
signal MDI: std_logic := '0';
signal MDO: std_logic := '0';
signal MDT: std_logic := '0';
signal RESET_COMPLETE: std_logic := '0';
signal PHY_IF_WRAPPER_RESET: std_logic := '0';
signal SREG_READ_START: std_logic := '0';
signal SREG_SAMPLE_CLK: std_logic := '0';
signal PHY_ID_LOCAL: std_logic_vector(15 downto 0);
signal LINK_STATUS_local: std_logic := '0';
signal DUPLEX_STATUS_local: std_logic := '0';
signal SPEED_STATUS_LOCAL: std_logic_vector(1 downto 0) := (others => '0');
signal TP_RGMII_WRAPPER: std_logic_vector(10 downto 1) := (others => '0');
 
--//  PHY INTERFACE: GMII to RGMII CONVERSION ----------------------------------------------------------
signal CRS: std_logic := '0';
signal CRS_D: std_logic := '0';
signal COL: std_logic := '0';
signal MAC_TXD: std_logic_vector(7 downto 0) := (others => '0');
signal MAC_TX_EN: std_logic := '0';
signal MAC_TX_ER: std_logic := '0';
signal MAC_TX_SAMPLE_CLK: std_logic := '0';
signal MAC_RXD0: std_logic_vector(7 downto 0);
signal MAC_RX_DV0: std_logic := '0';
signal MAC_RX_ER0: std_logic := '0';
signal MAC_RX_SAMPLE_CLK0: std_logic := '0'; 
signal MAC_RXD: std_logic_vector(7 downto 0);
signal MAC_RX_DV: std_logic := '0';
signal MAC_RX_ER: std_logic := '0';
signal MAC_RX_SAMPLE_CLK: std_logic := '0';
 
 
--//  TX ELASTIC BUFFER ----------------------------------------------------------
signal MAC_TX_DIA: std_logic_vector(31 downto 0) := (others => '0');
signal MAC_TX_DIPA: std_logic_vector(0 downto 0) := (others => '0');
signal MAC_TX_WPTR: std_logic_vector(11 downto 0) := (others => '0');
signal MAC_TX_WPTR_D: std_logic_vector(11 downto 0) := (others => '0');
signal MAC_TX_WPTR_D2: std_logic_vector(11 downto 0) := (others => '0');
signal MAC_TX_WPTR_D3: std_logic_vector(11 downto 0) := (others => '0');
signal MAC_TX_WPTR_STABLE: std_logic := '0';
signal MAC_TX_WPTR_STABLE_D: std_logic := '0';
signal TX_COUNTER8: std_logic_vector(2 downto 0) :=(others => '0');
signal MAC_TX_WEA: std_logic_vector(1 downto 0) := (others => '0');
signal MAC_TX_BUF_SIZE: std_logic_vector(11 downto 0) := (others => '0');
signal MAC_TX_RPTR: std_logic_vector(11 downto 0) := (others => '1');
signal MAC_TX_RPTR_D: std_logic_vector(11 downto 0) := (others => '1');
signal MAC_TX_RPTR_CONFIRMED: std_logic_vector(11 downto 0) := (others => '1');
signal MAC_TX_RPTR_CONFIRMED_D: std_logic_vector(11 downto 0) := (others => '1');
signal MAC_TX_SAMPLE2_CLK_E: std_logic := '0';
signal MAC_TX_SAMPLE2_CLK: std_logic := '0';
type DOBtype is array(integer range 0 to 1) of std_logic_vector(7 downto 0);
signal MAC_TX_DOB: DOBtype;
type DOPBtype is array(integer range 0 to 1) of std_logic_vector(0 downto 0);
signal MAC_TX_DOPB: DOPBtype;
signal MAC_TX_DATA2: std_logic_vector(7 downto 0) := (others => '0');
signal MAC_TX_EOF2: std_logic := '0';
signal MAC_TX_EOF2_D: std_logic := '0';
signal COMPLETE_TX_FRAMES_INBUF: std_logic_vector(7 downto 0) := x"00";  -- can't have more than 147 frames in a 16k buffer
signal ATLEAST1_COMPLETE_TX_FRAME_INBUF: std_logic := '0';
signal MAC_TX_EOF_TOGGLE: std_logic := '0';
signal MAC_TX_EOF_TOGGLE_D: std_logic := '0';
signal MAC_TX_EOF_TOGGLE_D2: std_logic := '0';
signal MAC_TX_CTS_local: std_logic := '0';
 
--//-- TX FLOW CONTROL --------------------------------
signal TX_SUCCESS_TOGGLE: std_logic := '0';
signal TX_SUCCESS_TOGGLE_D: std_logic := '0';
signal TX_SUCCESS_TOGGLE_D2: std_logic := '0';
signal MAC_TX_BUF_FREE: std_logic_vector(11 downto 0) := (others => '0');
 
 
--// MAC TX STATE MACHINE ----------------------------------------------------------
signal TX_SPEED: std_logic_vector(1 downto 0) := (others => '0');
signal TX_CLK: std_logic := '0';
signal TX_BYTE_CLK: std_logic := '0';
signal TX_BYTE_CLK_D: std_logic := '0';
signal TX_HALF_BYTE_FLAG: std_logic := '0';
signal IPG: std_logic := '0';
signal IPG_CNTR: std_logic_vector(7 downto 0) := (others => '0');  -- TODO CHECK CONSISTENCY WITH TIMER VALUES
signal TX_EVENT1: std_logic := '0';
signal TX_EVENT2: std_logic := '0';
signal TX_EVENT3: std_logic := '0';
signal TX_STATE: integer range 0 to 15 := 0;
signal TX_BYTE_COUNTER: std_logic_vector(18 downto 0) := (others => '0');  -- large enough for counting 2000 bytes in max size packet
signal TX_BYTE_COUNTER2: std_logic_vector(2 downto 0) := (others => '0');  -- small auxillary byte counter for small fields
signal TX_PREAMBLE: std_logic_vector(7 downto 0) := (others => '0');
signal MAC_TX_SAMPLE4_CLK: std_logic := '0';
signal MAC_TX_DATA4: std_logic_vector(7 downto 0) := (others => '0');
signal MAC_TX_DATA4_D: std_logic_vector(7 downto 4) := (others => '0');
signal RETX_ATTEMPT_COUNTER: std_logic_vector(4 downto 0) := (others => '0'); -- re-transmission attempts counter
signal RAND: std_logic_vector(10 downto 0) := (others => '0');
signal RETX_RANDOM_BKOFF: std_logic_vector(9 downto 0) := (others => '0');
signal TX_SUCCESS: std_logic := '0';
signal TX_EN: std_logic := '0';
signal TX_ER: std_logic := '0';
 
--//  TX 32-BIT CRC COMPUTATION -------------------------------------------------------
signal TX_CRC32: std_logic_vector(31 downto 0) := (others => '0');
signal TX_CRC32_FLIPPED_INV: std_logic_vector(31 downto 0) := (others => '0');
signal TX_CRC32_RESET: std_logic := '0';
signal TX_FCS: std_logic_vector(7 downto 0) := (others => '0');
signal MAC_TX_SAMPLE3_CLK: std_logic := '0';
signal MAC_TX_DATA3: std_logic_vector(7 downto 0) := (others => '0');
 
--// MAC RX STATE MACHINE ----------------------------------------------------------
signal RX_CLKG: std_logic := '0';
signal RX_STATE: integer range 0 to 15 := 0;
signal RX_EVENT1: std_logic := '0';
--signal RX_EVENT2: std_logic := '0';
signal RX_EVENT3: std_logic := '0';
signal RX_EVENT4: std_logic := '0';
signal RX_EVENT5: std_logic := '0';
signal RX_BYTE_COUNTER: std_logic_vector(18 downto 0);  -- large enough for counting 2000 bytes in max size packet
signal RX_BYTE_COUNTER_INC: std_logic_vector(18 downto 0);  -- large enough for counting 2000 bytes in max size packet
signal RX_TOO_SHORT: std_logic := '0';
signal RX_TOO_LONG: std_logic := '0';
signal RX_VALID_ADDR: std_logic := '0';
signal RX_LENGTH_ERR: std_logic := '0';
signal LAST6B: std_logic_vector(47 downto 0) := (others => '0');
signal RX_LENGTH: std_logic_vector(10 downto 0) := (others => '0');
signal RX_LENGTH_TYPEN: std_logic := '0';
signal RX_DIFF: std_logic_vector(11 downto 0) := (others => '0');
signal MAC_RXD_D: std_logic_vector(7 downto 0) := (others => '0');
signal MAC_RX_SAMPLE2_CLK: std_logic := '0';
 
--//  RX 32-BIT CRC COMPUTATION -------------------------------------------------------
signal RX_CRC32_RESET: std_logic := '0';
signal RX_CRC32: std_logic_vector(31 downto 0) := (others => '0');
signal RX_CRC32_VALID: std_logic := '0';
signal RX_BAD_CRC: std_logic := '0';
 
--// PARSE RX DATA -------------------------------------------------------------------
signal MAC_RXD3: std_logic_vector(7 downto 0);
signal MAC_RX_SAMPLE3_CLK: std_logic := '0';
--signal MAC_RX_SOF3: std_logic := '0';
signal MAC_RX_EOF3A: std_logic := '0';
signal MAC_RX_EOF3B: std_logic := '0';
signal MAC_RX_EOF3B_D: std_logic := '0';
signal MAC_RX_EOF3: std_logic := '0';
signal RX_FRAME_EN3: std_logic := '0';
 
--//  RX INPUT ELASTIC BUFFER ----------------------------------------------------------
signal MAC_RX_DIPA: std_logic_vector(0 downto 0);
signal MAC_RX_DOPB: std_logic_vector(0 downto 0);
signal MAC_RX_WPTR: std_logic_vector(10 downto 0);
signal MAC_RX_WPTR_D: std_logic_vector(10 downto 0);
signal MAC_RX_WPTR_D2: std_logic_vector(10 downto 0);
signal MAC_RX_WPTR_D3: std_logic_vector(10 downto 0);
signal MAC_RX_WPTR_CONFIRMED: std_logic_vector(10 downto 0) := (others => '0');
signal MAC_RX_WPTR_STABLE: std_logic := '0';
signal MAC_RX_WPTR_STABLE_D: std_logic := '0';
signal RX_COUNTER8: std_logic_vector(2 downto 0) := "000";
signal MAC_RX_RPTR: std_logic_vector(10 downto 0);
signal MAC_RXD4: std_logic_vector(7 downto 0);
signal MAC_RX_SAMPLE4_CLK: std_logic := '0';
signal MAC_RX_SAMPLE4_CLK_E: std_logic := '0';
signal MAC_RX_EOF4: std_logic := '0';
signal MAC_RX_BUF_SIZE: std_logic_vector(10 downto 0);
signal MAC_RX_EOF4_FLAG: std_logic := '1';
 
signal PHY_CONFIG_TP: std_logic_vector(10 downto 1);
 
 
--------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
begin
 
 
-- PHY-supplied RX global clock
RECLOCK_003: process(ASYNC_RESET, RX_CLKG)
begin	
	if rising_edge(RX_CLKG) then
		RESETRX_FLAG_D <= ASYNC_RESET;
		RESETRX_FLAG_D2 <= RESETRX_FLAG_D;
 
		-- 1-CLK clock synchronous reset pulse at the end of the async pulse
		if(RESETRX_FLAG_D = '0') and (RESETRX_FLAG_D2 = '1') then
			-- end of external reset pulse. generate a CLK synchronous reset
			SYNC_RESETRX <= '1';
		else 
			SYNC_RESETRX <= '0';
		end if;
	end if;
end process;
 
 
--// PHY RESET AND CONFIGURATION ----------------------------------------------------------
-- First generate a RESET_N pulse 10ms long, then wait 50ms before programming the PHY
-- We cannot assume that the 125 MHz reference clock is present. 
 
-- convert ASYNC_RESET to a CLK-synchronous RESET pulse
RECLOCK_002: process(ASYNC_RESET, CLK)
begin	
	if rising_edge(CLK) then
		RESETFLAG_D <= ASYNC_RESET;
		RESETFLAG_D2 <= RESETFLAG_D;
 
		-- 1-CLK clock synchronous reset pulse at the end of the async pulse
		if(RESETFLAG_D = '0') and (RESETFLAG_D2 = '1') then
			-- end of external reset pulse. generate a CLK synchronous reset
			SYNC_RESET <= '1';
		else 
			SYNC_RESET <= '0';
		end if;
	end if;
end process;
 
-- PHY reset at power up or SYNC_RESET
-- Generates a 10ms RESET_N pulse followed by a TBD ms delay and a INITIAL_CONFIG_PULSE.
-- The delay between RESET_N de-assertion and config pulse is 50ms (conservative. It takes time for PHY to configure.
-- even though the specs states 100us is sufficient, we find that 40ms min is needed).
Inst_RESET_TIMER: RESET_TIMER 
GENERIC MAP(
	CLK_FREQUENCY => CLK_FREQUENCY	-- user clock frequency in MHz
)
PORT MAP(
	CLK => CLK,	-- user clock, always present
	RESET_START => SYNC_RESET,
	RESET_COMPLETE => RESET_COMPLETE,
	INITIAL_CONFIG_PULSE => INITIAL_CONFIG_PULSE,  -- config pulse 50ms after RESET_N deassertion
	RESET_N => RESET_N_LOCAL
);
 
RESET_N <= RESET_N_LOCAL;
 
--
---- enact the configuration
PHY_CONFIG_CHANGE_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(INITIAL_CONFIG_PULSE = '1') then
			-- A default configuration is loaded automatically after power up. 
			PHY_CONFIG_CHANGE_A <= '1';
			PHY_RESET_A <= '0';	-- no software PHY reset, we just did a hardware reset
			SPEED_A <= "11";		-- auto
			DUPLEX_A <= '1';		
			TEST_MODE_A <= "00";
			POWER_DOWN_A <= '0';
		elsif(PHY_CONFIG_CHANGE = '1') then
			-- PHY_CONFIG_CHANGE indicates a user-triggered configuration change.
			PHY_CONFIG_CHANGE_A <= '1';
			PHY_RESET_A <= PHY_RESET;
			SPEED_A <= SPEED;
			DUPLEX_A <= DUPLEX;
			TEST_MODE_A <= TEST_MODE;
			POWER_DOWN_A <= POWER_DOWN;
		else
			PHY_CONFIG_CHANGE_A <= '0';
		end if;
	end if;
end process;
 
 
-- PHY monitoring and control
Inst_PHY_CONFIG: PHY_CONFIG 
GENERIC MAP(
	PHY_ADDR => PHY_ADDR
)
PORT MAP(
	SYNC_RESET => SYNC_RESET,  
	CLK => CLK,
	CONFIG_CHANGE => PHY_CONFIG_CHANGE_A,
	PHY_RESET => PHY_RESET_A,
	SPEED => SPEED_A,
	DUPLEX => DUPLEX_A,
	TEST_MODE => TEST_MODE_A,
	POWER_DOWN => POWER_DOWN_A,
	CLK_SKEW => CLK_SKEW_A,
	SREG_READ_START => SREG_READ_START,
	SREG_REGAD => "000000010",	-- register 2: PHY Identifier 1
	SREG_DATA => PHY_ID_LOCAL,
	SREG_SAMPLE_CLK => SREG_SAMPLE_CLK,
	LINK_STATUS => LINK_STATUS_local,
	MCLK => MCLK,
	MDI => MDI,
	MDO => MDO,
	MDT => MDT
	);
PHY_ID <= PHY_ID_LOCAL;
 
---- tri-state MDIO port
--IOBUF_inst : IOBUF
--generic map (
--	DRIVE => 12,
--	IOSTANDARD => "DEFAULT",
--	SLEW => "SLOW")
--port map (
--	O => MDI,     -- Buffer output
--	IO => MDIO,   -- Buffer inout port (connect directly to top-level port)
--	I => MDO,     -- Buffer input
--	T => MDT      -- 3-state enable input, high=input, low=output 
--);
 
 
-- read PHY identification once at power-up or reset (hardware self-test)
PHY_STATUS_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(PHY_CONFIG_CHANGE_A = '1') then	-- power-up/reset
			SREG_READ_START <= '1';				-- start asking for status register
		elsif(SREG_SAMPLE_CLK = '1') then
			SREG_READ_START <= '0';
		end if;
	end if;
end process;
--//  PHY INTERFACE: RGMII FORMATTING ----------------------------------------------------------
 
-- Translation RGMII (PHY interface) - GMII (MAC interface)
-- Adjust the TXC and RXC clock 2ns delays within as needed.
PHY_IF_WRAPPER_RESET <= SYNC_RESETRX;	
 
LINK_STATUS <= LINK_STATUS_local;
DUPLEX_STATUS <= DUPLEX_STATUS_local;
SPEED_STATUS <= SPEED_STATUS_LOCAL;
 
--//  PHY INTERFACE: GMII/MII FORMATTING ----------------------------------------------------------
-- TODO: make tx clk the same as rx clk (same RGMII_WRAPPER).
	Inst_GMII_MII_WRAPPER: GMII_MII_WRAPPER_V6 PORT MAP(
		SYNC_RESET => PHY_IF_WRAPPER_RESET,
		CLK => CLK,	
		IDELAYREFCLK200MHZ => IDELAYREFCLK200MHZ,
		TX_CLK => MII_TX_CLK,  -- MII tx clock from PHY
		GTX_CLK => GMII_TX_CLK, -- GMII tx clock to PHY
		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, 
		MAC_RX_CLK => RX_CLKG,
		MAC_RXD => MAC_RXD0,
		MAC_RX_DV => MAC_RX_DV0,
		MAC_RX_ER => MAC_RX_ER0,
		MAC_RX_SAMPLE_CLK => MAC_RX_SAMPLE_CLK0,
		MAC_TXD => MAC_TXD,
		MAC_TX_EN => MAC_TX_EN,
		MAC_TX_ER => MAC_TX_ER,
		MAC_TX_SAMPLE_CLK => MAC_TX_SAMPLE_CLK,
		MAC_TX_SPEED => TX_SPEED,
		MAC_CRS => CRS,
		MAC_COL => COL,
		LINK_STATUS => open,--LINK_STATUS_local,
		SPEED_STATUS => SPEED_STATUS_LOCAL,
		DUPLEX_STATUS => DUPLEX_STATUS_local
	);
 
	-- Vodoo code (Isim simulator is confused otherwise). Reclock RX signals.
	-- My guess: simulator does not like the BUFG or delay within the GMII_MII_WRAPPER.
	-- Small penalty: just a few Flip Flops. 
	RX_RECLOCK_001: process(RX_CLKG)
	begin
		if rising_edge(RX_CLKG) then
			MAC_RXD <= MAC_RXD0;
			MAC_RX_DV <= MAC_RX_DV0;
			MAC_RX_ER <= MAC_RX_ER0;
			MAC_RX_SAMPLE_CLK <= MAC_RX_SAMPLE_CLK0;
		end if;
	end process;
 
--//  TX ELASTIC BUFFER ----------------------------------------------------------
-- The purpose of the elastic buffer is two-fold:
-- (a) a transition between the CLK-synchronous user side, and the RX_CLKG synchronous PHY side
-- (b) storage for Ethernet transmit frames, to absorb traffic peaks, minimize the number of 
-- UDP packets lost at high throughput.
-- The tx elastic buffer is 16Kbits, large enough for TWO complete maximum size 
-- (14addr+1500data+4FCS = 1518B) frames.
 
-- write pointer management
MAC_TX_WPTR_001: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		MAC_TX_WPTR <= (others => '0');
	elsif rising_edge(CLK) then
		TX_COUNTER8 <= TX_COUNTER8 + 1;
 
		if (SYNC_RESET = '1') then
			MAC_TX_WPTR <= (others => '0');
		elsif(MAC_TX_DATA_VALID = '1') then
			MAC_TX_WPTR <= MAC_TX_WPTR + 1;
		end if;
 
		-- update WPTR_D once every 8 clocks.
		if(TX_COUNTER8 = 7) then
			MAC_TX_WPTR_D <= MAC_TX_WPTR;
		end if;
 
		-- allow WPTR reclocking with another clock, as long as it is away from the transition area
		if(TX_COUNTER8 < 6) then
			MAC_TX_WPTR_STABLE <= '1';
		else 
			MAC_TX_WPTR_STABLE <= '0';
		end if;
 
 
	end if;
end process;
 
MAC_TX_DIPA(0) <= MAC_TX_EOF;  -- indicates last byte in the tx packet
 
-- select which RAMBlock to write to.
MAC_TX_WEA(0) <= MAC_TX_DATA_VALID and (not MAC_TX_WPTR(11));
MAC_TX_WEA(1) <= MAC_TX_DATA_VALID and MAC_TX_WPTR(11);
 
-- No need for initialization
RAMB16_X: for I in 0 to 1 generate
	RAMB16_001: RAMB16_S9_S9 
	port map(
		DIA => MAC_TX_DATA,
		DIB => x"00",
		DIPA => MAC_TX_DIPA(0 downto 0),
		DIPB => "0",
		DOPA => open,
		DOPB => MAC_TX_DOPB(I)(0 downto 0),	
		ENA => '1',
		ENB => '1',
		WEA => MAC_TX_WEA(I),
		WEB => '0',
		SSRA => '0',
		SSRB => '0',
		CLKA => CLK,   
		CLKB => RX_CLKG,     
		ADDRA => MAC_TX_WPTR(10 downto 0),
		ADDRB => MAC_TX_RPTR(10 downto 0),
		DOA => open,
		DOB => MAC_TX_DOB(I)
	);
end generate;
 
MAC_TX_DATA2 <= MAC_TX_DOB(conv_integer(MAC_TX_RPTR_D(11)));
MAC_TX_EOF2 <= MAC_TX_DOPB(conv_integer(MAC_TX_RPTR_D(11)))(0); 
 
-- RX_CLKG zone. Reclock WPTR
MAC_TX_WPTR_002: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		MAC_TX_WPTR_STABLE_D <= MAC_TX_WPTR_STABLE;
		MAC_TX_WPTR_D2 <= MAC_TX_WPTR_D;
 
		if(MAC_TX_WPTR_STABLE_D = '1') then
			-- WPTR is stable. OK to resample with the RX_CLKG clock.
			MAC_TX_WPTR_D3 <= MAC_TX_WPTR_D2;
		end if;
	end if;
end process;
 
MAC_TX_BUF_SIZE <= MAC_TX_WPTR_D3 + not(MAC_TX_RPTR);
-- occupied tx buffer size for reading purposes (CLKG clock domain)(
-- always lags, could be a bit more, never less.
 
--//-- TX FLOW CONTROL --------------------------------
-- ask for more input data if there is room for at least 1K more input bytes
-- Never write past the last confirmed read pointer location.
 
-- read the last confirmed read pointer location and reclock in CLK domain when stable
MAC_TX_CTS_001: process(CLK)
begin
	if rising_edge(CLK) then
		TX_SUCCESS_TOGGLE_D <= TX_SUCCESS_TOGGLE;
		TX_SUCCESS_TOGGLE_D2 <= TX_SUCCESS_TOGGLE_D;
		if(TX_SUCCESS_TOGGLE_D2 /= TX_SUCCESS_TOGGLE_D) then
			-- shortly after successful packet transmission. 
			MAC_TX_RPTR_CONFIRMED_D <= MAC_TX_RPTR_CONFIRMED;
		end if;
	end if;
end process;
 
-- Compute available room for more tx data
MAC_TX_CTS_002: process(CLK)
begin
	if rising_edge(CLK) then
		MAC_TX_BUF_FREE <= not (MAC_TX_WPTR_D2 + not MAC_TX_RPTR_CONFIRMED_D);
	end if;
end process;
-- Is there enough room for a complete max size frame?
-- Don't cut it too close because user interface can flood the buffer very quickly (CLK @ 125 MHz clock)
-- while we compute the buffer size with the possibly much slower RX_CLG (could be 2.5 MHz for 10Mbps).
MAC_TX_CTS_003: process(CLK)
begin
	if rising_edge(CLK) then
		if(SYNC_RESETRX = '1') then
			MAC_TX_CTS_local <= '0';	-- reset
		elsif(LINK_STATUS_local = '0') then
			-- don't ask the stack for data if there is no link
			MAC_TX_CTS_local <= '0';	-- reset
		elsif(MAC_TX_BUF_FREE(11) = '0') then
			-- room for less than 2KB. Activate flow control
			MAC_TX_CTS_local <= '0';
		else
			MAC_TX_CTS_local <= '1';
		end if;
	end if;
end process;
MAC_TX_CTS <=  LINK_STATUS_local;--LINK_STATUS_local;--MAC_TX_CTS_local;
 
 
-- manage read pointer
MAC_TX_RPTR_001: process(ASYNC_RESET, RX_CLKG)
begin
	if(ASYNC_RESET = '1') then
		MAC_TX_RPTR <= (others => '1');
		MAC_TX_RPTR_D <= (others => '1');
	elsif rising_edge(RX_CLKG) then
		MAC_TX_RPTR_D <= MAC_TX_RPTR;
 
		if(TX_STATE = 2) and (TX_BYTE_CLK = '1') and (MAC_TX_EOF2 = '1') then
			-- special case. Immediately block output sample clk because we have just read past the end of 
			-- packet (nothing we could do about it).
			MAC_TX_SAMPLE2_CLK <= '0';
		else
			-- regular case:  1 clk delay to extract data from ramb.
			-- aligned with MAC_TX_DATA2 byte.
			MAC_TX_SAMPLE2_CLK <= MAC_TX_SAMPLE2_CLK_E;  
		end if;
 
		if(SYNC_RESETRX = '1') then
			MAC_TX_RPTR <= (others => '1');
		elsif(TX_STATE = 1) and (TX_BYTE_CLK = '1') and (TX_BYTE_COUNTER2(2 downto 0) <= 1) then
			-- read the first byte(s) in advance (need 2 RX_CLKG to get the data out)
			-- Note: we may temporarily read past the write pointer (by one location) 
			-- but will rewind immediately thereafter
			MAC_TX_SAMPLE2_CLK_E <= '1';
			MAC_TX_RPTR <= MAC_TX_RPTR + 1;
		elsif(TX_STATE = 2) and (TX_EVENT3 = '1') then
			-- we are done reading the packet. rewind the read pointer, as we went past the end of packet.
			MAC_TX_SAMPLE2_CLK_E <= '0';
			MAC_TX_RPTR <= MAC_TX_RPTR - 1;
		elsif(TX_STATE = 2) and (TX_BYTE_CLK = '1') then
			-- read the rest of the packet
			-- forward data from input elastic buffer to RGMII interface
			-- Note: we may temporarily read past the write pointer (by one location) 
			-- but will rewind immediately thereafter
			MAC_TX_SAMPLE2_CLK_E <= '1';
			MAC_TX_RPTR <= MAC_TX_RPTR + 1;
		elsif(TX_STATE = 6) then
			-- collision detected. rewind read pointer to the start of frame.
			MAC_TX_RPTR <= MAC_TX_RPTR_CONFIRMED;
		else
			MAC_TX_SAMPLE2_CLK_E <= '0';
		end if;
	end if;
end process;
 
-- update confirmed read pointer after successful frame transmission
MAC_TX_RPTR_002: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		if(SYNC_RESETRX = '1') then
			MAC_TX_RPTR_CONFIRMED <= (others => '1');
			TX_SUCCESS_TOGGLE <= '0';
		elsif(TX_SUCCESS = '1') then
			MAC_TX_RPTR_CONFIRMED <= MAC_TX_RPTR;
			TX_SUCCESS_TOGGLE <= not TX_SUCCESS_TOGGLE;
		end if;
	end if;
end process;
 
-- How many COMPLETE tx frames are available for transmission in the input elastic buffer?
-- Transmission is triggered by the availability of a COMPLETE frame in the buffer (not just a few frame bytes)
-- It is therefore important to keep track of the number of complete frames.
-- At the elastic buffer input, a new complete frame is detected upon receiving the EOF pulse.
COMPLETE_TX_FRAMES_001: process(ASYNC_RESET, CLK)
begin
	if (ASYNC_RESET = '1') then
		MAC_TX_EOF_TOGGLE <= '0';
	elsif rising_edge(CLK) then
		if(MAC_TX_DATA_VALID = '1') and (MAC_TX_EOF = '1') then
			MAC_TX_EOF_TOGGLE <= not MAC_TX_EOF_TOGGLE;  -- Need toggle signal to generate copy in RX_CLKG clock domain
		end if;
	end if;
end process;
 
 
COMPLETE_TX_FRAMES_002: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		MAC_TX_EOF_TOGGLE_D <= MAC_TX_EOF_TOGGLE;	-- reclock in RX_CLKG clock domain (to prevent glitches)
		MAC_TX_EOF_TOGGLE_D2 <= MAC_TX_EOF_TOGGLE_D;
 
		if (SYNC_RESETRX = '1') then
			COMPLETE_TX_FRAMES_INBUF <= (others => '0');
 
		elsif(MAC_TX_EOF_TOGGLE_D2 /= MAC_TX_EOF_TOGGLE_D) and (TX_SUCCESS = '0') then
			-- just added another complete frame into the tx buffer (while no successful transmission concurrently)
			COMPLETE_TX_FRAMES_INBUF <= COMPLETE_TX_FRAMES_INBUF + 1;
		elsif(MAC_TX_EOF_TOGGLE_D2 = MAC_TX_EOF_TOGGLE_D) and (TX_SUCCESS = '1') 
				and (ATLEAST1_COMPLETE_TX_FRAME_INBUF = '1') then
			-- a frame was successfully transmitted (and none was added at the very same instant)
			COMPLETE_TX_FRAMES_INBUF <= COMPLETE_TX_FRAMES_INBUF - 1;
		end if;
	end if;
end process;
 
-- Flag to indicate at least one complete tx frame in buffer.
ATLEAST1_COMPLETE_TX_FRAME_INBUF <= '0' when (COMPLETE_TX_FRAMES_INBUF = 0) else '1';
 
 
DELAY_EOF2: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		if(TX_BYTE_CLK = '1') then
			-- delay by one byte
			MAC_TX_EOF2_D <= MAC_TX_EOF2;
		end if;
	end if;
end process;
 
 
--// MAC TX STATE MACHINE ----------------------------------------------------------
TX_SPEED <= SPEED_STATUS_LOCAL;  -- transmit speed is as auto-negotiated by the rx PHY.
-- test test test simulation at various LAN speeds
--TX_SPEED <= "01";  
 
-- Tx timers ------------------------
-- Generate transmit clock. Depends on the tx_speed.
-- Clock is always enabled, even when not transmitting (reason: we need to be
-- able to convey to the RGMII wrapper when to stop, etc).
-- Important distinction between TX_CLK and TX_BYTE_CLK because GMII interface is 4-bit wide
-- for 10/100 Mbps and 8-bit wide for 1000 Mbps.
-- Thus, TX_BYTE_CLK is half the frequency of TX_CLK, but pulses are aligned.
TX_CLK_GEN_001: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		if (SYNC_RESETRX = '1') then
			TX_BYTE_CLK <= '0';
			TX_HALF_BYTE_FLAG <= '0';
		elsif (TX_SPEED = "10") then
			-- 1000 Mbps
			TX_BYTE_CLK <= '1';
		elsif (TX_SPEED = "01") or (TX_SPEED = "00") then
			-- 10/100 Mbps. 
			-- divide by two to get the byte clock when 10/100 Mbps
			TX_HALF_BYTE_FLAG <= not TX_HALF_BYTE_FLAG;
			if(TX_HALF_BYTE_FLAG = '1') then
				TX_BYTE_CLK <= '1';
			else
				TX_BYTE_CLK <= '0';
			end if;
		else
			TX_BYTE_CLK <= '0';
		end if;	
	end if;
end process;
 
 
-- 96-bit InterPacketGap (Interframe Delay) timer
IPG_001: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		if (SYNC_RESETRX = '1') then
			IPG_CNTR <= (others => '0');
			CRS_D <= '0';
		else
			CRS_D <= CRS;  -- reclock with RX_CLKG
 
			if((CRS_D = '1') and (DUPLEX = '0')) or (TX_EN = '1') or (TX_STATE = 5) then
				-- detected passing packet (half-duplex only) or transmission is in progress 
				-- or carrier extension in progress
				-- Arm InterPacketGap timer
				IPG_CNTR <= x"0C"  ; -- 96 bits = 12 bytes  802.3 section 4.4.2
			elsif(IPG_CNTR > 0) and (TX_BYTE_CLK = '1') then
				-- after end of passing packet, decrement counter downto to zero (InterPacketGap).
				IPG_CNTR <= IPG_CNTR - 1;
			end if;
		end if;
	end if;
end process;
IPG <= '1' when (IPG_CNTR = 0) else '0';  -- '1' last passing packet was more than InterPacketGap ago. OK to start tx.
 
-- Events ------------------------
-- First tx packet trigger
TX_EVENT1 <= '0' when (ATLEAST1_COMPLETE_TX_FRAME_INBUF = '0') else -- no COMPLETE frame in tx input buffer
				 '0' when (MAC_TX_BUF_SIZE = 0) else -- no data in tx input buffer
				 '0' when (IPG = '0') else -- medium is not clear. need to wait after the InterPacketGap. Deferring on.
				 '0' when (TX_SUCCESS = '1') else  -- don't act too quickly. It takes one RX_CLKG to update the complete_tx_frame_inbuf counter.
				 '0' when (PHY_IF_WRAPPER_RESET = '1') else -- PHY/RGMII wrapper are being reset. Do not start tx.
				 TX_BYTE_CLK;  -- go ahead..start transmitting. align event pulse with TX_BYTE_CLK
 
-- collision detection, half-duplex mode, within the timeSlot
-- Timeslot is 64 bytes for 10/100 Mbps and 512 bytes for 1000 Mbps, starting at the preamble.
TX_EVENT2 <= '1' when ((COL = '1') and (DUPLEX = '0') and (TX_SPEED = "10") and (TX_BYTE_COUNTER(10 downto 0) < 503)) else
				 '1' when ((COL = '1') and (DUPLEX = '0') and (TX_SPEED(1) = '0') and (TX_BYTE_COUNTER(10 downto 0) < 55)) else
				 '0';
 
-- end of frame detected at tx buffer output. 
-- Timing depends on the TX_SPEED (because of the delay in reading data from tx buffer output)
TX_EVENT3 <= '1' when (TX_BYTE_CLK = '1') and (MAC_TX_EOF2 = '1') and (TX_SPEED = "10") else
			    '1' when (TX_BYTE_CLK = '1') and (MAC_TX_EOF2_D = '1') and (TX_SPEED(1) = '0') else
				 '0';
 
-- Tx state machine ------------------------
TX_STATE_GEN_001: process(RX_CLKG, MAC_ADDR)
begin
	if rising_edge(RX_CLKG) then
		if (SYNC_RESETRX = '1') or (LINK_STATUS_local = '0') then
			TX_STATE <= 0;	-- idle state
			TX_SUCCESS <= '0'; 
			TX_BYTE_CLK_D <= '0';
			RETX_ATTEMPT_COUNTER <= (Others => '0');  -- re-transmission attempts counter
		else
 
			TX_BYTE_CLK_D <= TX_BYTE_CLK;  -- output byte ready one RX_CLKG later 
 
			if(TX_STATE = 0) then
				TX_SUCCESS <= '0'; 
				RETX_ATTEMPT_COUNTER <= (Others => '0');  -- reset re-transmission attempts counter
				if (TX_EVENT1 = '1') then
					-- start tx packet: send 1st byte of preamble
					TX_STATE <= 1; 
					TX_BYTE_COUNTER2 <= "111"; -- 8-byte preamble + start of frame sequence
				end if;
			elsif(TX_STATE = 1) and (DUPLEX = '0') and (COL = '1')  then
				-- collision sensing while in half-duplex mode. 
				-- The packet header being transmitted is well within the slot time limit.
				TX_STATE <= 6;  -- send jam
				TX_BYTE_COUNTER2 <= "011"; -- jamSize = 32 bits = 4 Bytes
			elsif(TX_STATE = 1) and (TX_BYTE_CLK = '1') and (TX_BYTE_COUNTER2(2 downto 0) /= 0) then
				-- counting through the preamble + start frame sequence
				TX_BYTE_COUNTER2 <= TX_BYTE_COUNTER2 - 1;
			elsif(TX_STATE = 1) and (TX_BYTE_CLK = '1') and (TX_BYTE_COUNTER2(2 downto 0) = 0) then
				-- end of preamble. start forwarding data from elastic buffer to RGMII wrapper
				TX_STATE <= 2; 
				TX_BYTE_COUNTER <= (others => '0');
			elsif(TX_STATE = 2) and (TX_EVENT2 = '1') then
				-- collision sensing while in half-duplex mode and within the specified slot time (starting at the preamble)
				TX_STATE <= 6;  -- send jam
				TX_BYTE_COUNTER2 <= "011"; -- jamSize = 32 bits = 4 Bytes
			elsif(TX_STATE = 2) and (TX_BYTE_CLK = '1') and (TX_EVENT3 = '0') then
				-- keep track of the payload byte count (to detect the need for padding)
				TX_BYTE_COUNTER <= TX_BYTE_COUNTER + 1;
			elsif(TX_STATE = 2) and (TX_BYTE_CLK = '1') and (TX_EVENT3 = '1')  then
				-- found end of frame
				TX_BYTE_COUNTER <= TX_BYTE_COUNTER + 1;
				if (TX_BYTE_COUNTER(10 downto 0) < 59) then 
					if (MAC_TX_CONFIG(1 downto 0) = "11") then
						-- frame is too short: payload data does not meet minimum 60-byte size.
						-- user enabled automatic padding and automatic CRC32 insertion
						TX_STATE <= 3;
					else
						-- error: frame is too short. abort.
						TX_STATE <= 10;
					end if;
				elsif (MAC_TX_CONFIG(1) = '1') then
					-- user enabled auto-CRC32 insertion. Start inserting CRC
					TX_STATE <= 4;
					TX_BYTE_COUNTER2 <= "011";	-- 4-byte CRC(FCS)
				elsif (TX_BYTE_COUNTER(10 downto 0) >= 63) then
					-- complete packet (including user-supplied CRC)
					-- Carrier Extension?  Applicable to 1000 Mbps half-duplex
					if(TX_SPEED = "10") and (DUPLEX = '0') and (TX_BYTE_COUNTER(10 downto 0) < 511) then
						-- Carrier extension to slotTime (512 bytes) as per 802.3 Section 4.2.3.4
						TX_STATE <= 5;
					else
						-- we are done here
						TX_STATE <= 0;
						TX_SUCCESS <= '1'; -- completed frame transmission
					end if;
				else
					-- error. frame is too short (< 64 bytes including 4-byte CRC). abort.
					TX_STATE <= 10;
				end if;
			elsif(TX_STATE = 3) and (TX_EVENT2 = '1') then
				-- collision sensing while in half-duplex mode and within the specified slot time (starting at the preamble)
				TX_STATE <= 6;  -- send jam
				TX_BYTE_COUNTER2 <= "011"; -- jamSize = 32 bits = 4 Bytes
			elsif(TX_STATE = 3) and (TX_BYTE_CLK = '1') then
				TX_BYTE_COUNTER <= TX_BYTE_COUNTER + 1;
				if(TX_BYTE_COUNTER(10 downto 0) < 59) then
					-- padding payload field to the minimum size.
					-- keep track of the byte count 
				elsif (MAC_TX_CONFIG(1) = '1') then
					-- Completed padding. User enabled CRC32 insertion. Start inserting CRC
					TX_STATE <= 4;
					TX_BYTE_COUNTER2 <= "011";	-- 4-byte CRC(FCS)
				else
					-- error. Illegal user configuration. auto-pad requires auto-CRC. abort.
					TX_STATE <= 10;
				end if;
			elsif(TX_STATE = 4) and (TX_EVENT2 = '1') then
				-- collision sensing while in half-duplex mode and within the specified slot time (starting at the preamble)
				TX_STATE <= 6;  -- send jam
				TX_BYTE_COUNTER2 <= "011"; -- jamSize = 32 bits = 4 Bytes
			elsif(TX_STATE = 4) and (TX_BYTE_CLK = '1') and (TX_BYTE_COUNTER2(1 downto 0) /= 0) then
				-- counting through the CRC/FCS sequence
				TX_BYTE_COUNTER2 <= TX_BYTE_COUNTER2 - 1;
				TX_BYTE_COUNTER <= TX_BYTE_COUNTER + 1;
			elsif(TX_STATE = 4) and (TX_BYTE_CLK = '1') and (TX_BYTE_COUNTER2(1 downto 0) = 0) then
				-- end of CRC/FCS. Packet is now complete. 
				TX_BYTE_COUNTER <= TX_BYTE_COUNTER + 1;
				-- Carrier Extension?  Applicable to 1000 Mbps half-duplex
				if(TX_SPEED = "10") and (DUPLEX = '0') and (TX_BYTE_COUNTER(10 downto 0) < 511) then
					-- Carrier extension to slotTime (512 bytes) as per 802.3 Section 4.2.3.4
					TX_STATE <= 5;
				else
					-- we are done here
					TX_STATE <= 0;
					TX_SUCCESS <= '1'; -- completed frame transmission
				end if;
			elsif(TX_STATE = 5) and (TX_EVENT2 = '1') then
				-- collision sensing while in half-duplex mode and within the specified slot time (starting at the preamble)
				TX_STATE <= 6;  -- send jam
				TX_BYTE_COUNTER2 <= "011"; -- jamSize = 32 bits = 4 Bytes
			elsif(TX_STATE = 5) and (TX_BYTE_CLK = '1') then
				-- Carrier extension
				TX_BYTE_COUNTER <= TX_BYTE_COUNTER + 1;
				if(TX_BYTE_COUNTER(10 downto 0) >= 511) then
					-- met slotTime requirement.
					TX_STATE <= 0;
					TX_SUCCESS <= '1'; -- completed frame transmission
				end if;
			elsif(TX_STATE = 6) and (TX_BYTE_CLK = '1') and (TX_BYTE_COUNTER2(1 downto 0) /= 0) then
				-- Jam . counting through the 4-byte jam
				TX_BYTE_COUNTER2 <= TX_BYTE_COUNTER2 - 1;
			elsif(TX_STATE = 6) and (TX_BYTE_CLK = '1') and (TX_BYTE_COUNTER2(1 downto 0) = 0) then
				-- end of Jam
 
				-- re-transmit?
				if(RETX_ATTEMPT_COUNTER < 16) then
					-- we have not yet reached the attemptLimit
					TX_STATE <= 7;  -- backoff 
					RETX_ATTEMPT_COUNTER <= RETX_ATTEMPT_COUNTER + 1;
					-- set backoff
					if(TX_SPEED = "10") then
						-- 1000 Mbps. Backoff is an integer multiple of slotTime: 
						-- random * slotTime. slotTime = 512 Bytes
						TX_BYTE_COUNTER(8 downto 0) <= (others => '1');
						TX_BYTE_COUNTER(18 downto 9) <= RETX_RANDOM_BKOFF;  -- uniform random variable. range 0 - 1023
					elsif(TX_SPEED(1) = '0') then
						-- 10/100 Mbps. Backoff is an integer multiple of slotTime:
						-- random * slotTime. slotTime = 64 Bytes
						TX_BYTE_COUNTER(5 downto 0) <= (others => '1');
						TX_BYTE_COUNTER(15  downto 6) <= RETX_RANDOM_BKOFF;  -- uniform random variable. range 0 - 1023;
						TX_BYTE_COUNTER(18 downto 16) <= (others => '0');
					end if;
				else
					TX_STATE <= 10;	-- error. could not transmit packet
				end if;
			elsif(TX_STATE = 7) and (TX_BYTE_CLK = '1') and (TX_BYTE_COUNTER /= 0) then
				-- backoff timer
				TX_BYTE_COUNTER <= TX_BYTE_COUNTER - 1;
			elsif(TX_STATE = 7) and (TX_BYTE_CLK = '1') and (TX_BYTE_COUNTER = 0) then
				-- backoff timer expired. try sending again
				-- start tx packet: send 1st byte of preamble
				TX_STATE <= 1; 
				TX_BYTE_COUNTER2 <= "111"; -- 8-byte preamble + start of frame sequence
			end if;
		end if;
	end if;
end process;
 
-- Tx packet assembly ------------------------
-- generate 7-byte preamble, 1-byte start frame sequence
-- TX_PREAMBLE is aligned with TX_BYTE_CLK_D
PREAMBLE_GEN_001: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		if(TX_STATE = 1) and (TX_BYTE_CLK = '1') and (TX_BYTE_COUNTER2(2 downto 0) = 1) then
			TX_PREAMBLE <= "11010101";  -- start frame delimiter (SFD). 
			-- [note: standard shows LSb D0 to the left, MSb D7 to the right, as per serial transmission sequence.]
		elsif(TX_BYTE_CLK = '1') then
			-- new packet or re-transmission
			TX_PREAMBLE <= "01010101";  -- preamble
			-- [note: standard shows LSb to the left, MSb to the right, as per serial transmission sequence.]
		end if;
	end if;
end process;
 
-- mux 4-byte frame check sequence
-- TX_FCS is aligned with TX_BYTE_CLK_D
FCS_GEN_001: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		-- send MSB first (802.11 Section 3.2.9).
		-- Don't have time to reclock TX_CRC32_FLIPPED_INV(31 downto 24): will be muxed without reclocking.
		if(TX_STATE = 4) and (TX_BYTE_CLK = '1') and (TX_BYTE_COUNTER2(1 downto 0) = 3) then
			TX_FCS <= TX_CRC32_FLIPPED_INV(23 downto 16);	
		elsif(TX_STATE = 4) and (TX_BYTE_CLK = '1') and (TX_BYTE_COUNTER2(1 downto 0) = 2) then
			TX_FCS <= TX_CRC32_FLIPPED_INV(15 downto 8);	
		elsif(TX_STATE = 4) and (TX_BYTE_CLK = '1') and (TX_BYTE_COUNTER2(1 downto 0) = 1) then
			TX_FCS <= TX_CRC32_FLIPPED_INV(7 downto 0);
		end if;
	end if;
end process;
 
 
TX_EN <= '0' when (TX_STATE = 0) else  -- idle
			'1' when (TX_STATE < 5) else  -- normal transmission
			'1' when (TX_STATE = 6) else  -- 32-bit jam after collision detection
			'0';
 
TX_ER <= '1' when (TX_STATE = 5) else  -- carrier extension
			'0';
 
-- mux preamble, start frame sequence, data, fcs, etc and forward to GMII tx interface
-- MAC_TX_DATA4 is aligned with TX_BYTE_CLK_D
TX_MUX_001: process(TX_STATE, TX_BYTE_COUNTER2, TX_PREAMBLE, MAC_TX_DATA2, TX_CRC32_FLIPPED_INV, TX_FCS)
begin
	if(TX_STATE = 1) then
		-- 7-byte preamble and 1-byte start frame sequence
		MAC_TX_DATA4 <= TX_PREAMBLE;
	elsif(TX_STATE = 2) then
		-- payload data
		MAC_TX_DATA4 <= MAC_TX_DATA2;
	elsif(TX_STATE = 3) then
		-- padding
		MAC_TX_DATA4 <= x"00";  -- padding with zeros.
	elsif(TX_STATE = 4) and (TX_BYTE_COUNTER2(1 downto 0) = 3) then
		-- Frame Check Sequence
		MAC_TX_DATA4 <= TX_CRC32_FLIPPED_INV(31 downto 24);	-- no time to reclock. need it now
	elsif(TX_STATE = 4) and (TX_BYTE_COUNTER2(1 downto 0) < 3) then
		-- Frame Check Sequence
		MAC_TX_DATA4 <= TX_FCS;
	elsif(TX_STATE = 5) then
		-- carrier extend
		MAC_TX_DATA4 <= x"0F";  
	else
	-- TODO tail end
		MAC_TX_DATA4 <= x"00";
	end if;
end process;
 
MAC_TX_SAMPLE4_CLK <= TX_BYTE_CLK_D when (TX_STATE /= 0) else '0';
 
-- signal conditioning for the TX GMII interface
GMII_TX_GEN: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		if (SYNC_RESETRX = '1') then
			MAC_TXD <= (others => '0');
			MAC_TX_EN <= '0';
			MAC_TX_ER <= '0';
			MAC_TX_SAMPLE_CLK <= '0';
			MAC_TX_DATA4_D <= (others => '0');
		elsif(TX_BYTE_CLK_D = '1') then
			MAC_TXD <= MAC_TX_DATA4;
			MAC_TX_EN <= TX_EN;
			MAC_TX_ER <= TX_ER;
			MAC_TX_SAMPLE_CLK <= '1';
		else
			MAC_TX_SAMPLE_CLK <= '0';
		end if;
	end if;
end process;
 
 
-- Tx random backoff ------------------------
-- Use LFSR11 as generator of a uniform random distribution of numbers between 0 and 2047
Inst_LFSR11C: LFSR11C PORT MAP(
	ASYNC_RESET => '0',
	CLK => RX_CLKG,
	BIT_CLK_REQ => TX_BYTE_CLK,	-- keep generating new random number
	SYNC_RESET => SYNC_RESETRX,   
	SEED => "00000000001",
	LFSR_BIT => open,
	BIT_CLK_OUT => open,
	SOF_OUT => open,
	LFSR_REG_OUT => RAND
);
 
 
 
-- limit the random number range depending on the number of transmission attempts
-- see 802.3 standard section 4.2.3.2.5 for details.
RETX_RAND_BKOFF_GEN: process(RAND, RETX_ATTEMPT_COUNTER)
begin
	case RETX_ATTEMPT_COUNTER is
		when "00000" => RETX_RANDOM_BKOFF <= RAND(9 downto 0) and "0000000001";  -- first attempt: r = 0,1	
		when "00001" => RETX_RANDOM_BKOFF <= RAND(9 downto 0) and "0000000011";  -- second attempt: r = 0-3
		when "00010" => RETX_RANDOM_BKOFF <= RAND(9 downto 0) and "0000000111";  -- third attempt: r = 0-7	
		when "00011" => RETX_RANDOM_BKOFF <= RAND(9 downto 0) and "0000001111";  -- etc	
		when "00100" => RETX_RANDOM_BKOFF <= RAND(9 downto 0) and "0000011111";  	
		when "00101" => RETX_RANDOM_BKOFF <= RAND(9 downto 0) and "0000111111";  	
		when "00110" => RETX_RANDOM_BKOFF <= RAND(9 downto 0) and "0001111111";  
		when "00111" => RETX_RANDOM_BKOFF <= RAND(9 downto 0) and "0011111111";  	
		when "01000" => RETX_RANDOM_BKOFF <= RAND(9 downto 0) and "0111111111";  	
		when others => RETX_RANDOM_BKOFF <= RAND(9 downto 0);   -- cap range to r = 0-1023  	
	end case;
end process;
 
 
--//  TX 32-BIT CRC COMPUTATION -------------------------------------------------------
-- 802.3 section 3.2.9: 
-- protected fields: payload data + padding (excludes preamble and start of frame sequence)
MAC_TX_DATA3 <= MAC_TX_DATA2 when (TX_STATE = 2) else x"00";  -- padding with zeros
MAC_TX_SAMPLE3_CLK <= TX_BYTE_CLK_D when ((TX_STATE = 2) or (TX_STATE = 3)) else '0'; 
 
TX_CRC32_RESET <= '1' when (TX_STATE = 1) else '0';  -- reset CRC2 during the packet preamble (covers the re-transmission case)
 
-- latency 1 RX_CLKG
TX_CRC32_8B: CRC32_8B PORT MAP(
	SYNC_RESET => TX_CRC32_RESET,
	CLK => RX_CLKG,
	CRC32_IN => TX_CRC32,  -- feedback previous iteration
	DATA_IN => MAC_TX_DATA3,	
	SAMPLE_CLK_IN => MAC_TX_SAMPLE3_CLK,
	CRC32_OUT => TX_CRC32,
	CRC32_VALID => open
);
 
-- flip LSb<->MSb and invert
TX_CRC32_002: process(TX_CRC32)
begin
	for I in 0 to 7 loop
		TX_CRC32_FLIPPED_INV(I) <= not TX_CRC32(7 - I);
		TX_CRC32_FLIPPED_INV(I + 8) <= not TX_CRC32(15 - I);
		TX_CRC32_FLIPPED_INV(I + 16) <= not TX_CRC32(23 - I);
		TX_CRC32_FLIPPED_INV(I + 24) <= not TX_CRC32(31 - I);
	end loop;
end process;
 
--// MAC RX STATE MACHINE ----------------------------------------------------------
-- remember the last rx byte
RX_DELAY_001: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		if (MAC_RX_SAMPLE_CLK = '1') then
			MAC_RXD_D <= MAC_RXD;
		end if;
	end if;
end process;
 
 
-- Rx events ------------------------
-- new packet. RX_DV is asserted and detected start of frame delimiter (SFD)
RX_EVENT1 <= '1' when (MAC_RX_SAMPLE_CLK = '1') and (MAC_RX_DV = '1') and (MAC_RX_ER = '0') 
							and (MAC_RXD_D = x"D5")  else '0';	
-- false carrier indication  (TODO: what for???)  xE for 10/1000, x0E for 1000 Mbps
--RX_EVENT2 <= '1' when (MAC_RX_SAMPLE_CLK = '1') and (MAC_RX_DV = '0') and (MAC_RX_ER = '1') 
--							and (MAC_RXD(3 downto 0) = x"E")  else '0';	
 
-- end of frame delimiter
RX_EVENT3 <= '1' when (MAC_RX_SAMPLE_CLK = '1') and (MAC_RX_DV = '0') else
				 '0';
 
-- valid frame byte (data, padding, crc)
RX_EVENT4 <= '1' when (MAC_RX_SAMPLE_CLK = '1') and (MAC_RX_DV = '1') and (MAC_RX_ER = '0') else
				 '0';
 
-- frame complete, all checks complete
RX_EVENT5 <= MAC_RX_EOF3B_D;
 
 
 
-- Rx state machine ------------------------
RX_BYTE_COUNTER_INC <= RX_BYTE_COUNTER + 1;
 
RX_STATE_GEN_001: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		if (SYNC_RESETRX = '1') then
			RX_STATE <= 0;
		elsif(RX_STATE = 0) and (RX_EVENT1 = '1') then
			-- RX_DV is asserted and detected start of frame delimiter (SFD)
			-- Note: the preamble could be full, partial or entirely missing.
			RX_STATE <= 1;
			RX_BYTE_COUNTER <= (others => '0');
		elsif(RX_STATE = 1) and (RX_EVENT3 = '1') then
			-- end of frame delimiter
			RX_STATE <= 2;
		elsif(RX_STATE = 1) and (RX_EVENT4 = '1') then
			-- count bytes within frame
			RX_BYTE_COUNTER <= RX_BYTE_COUNTER_INC;
			-- shift-in the last 6 bytes (efficient when decoding address field or length/type field)
			-- MSB (47 downto 40) is received first.
			LAST6B(47 downto 8) <= LAST6B(39 downto 0);
			LAST6B(7 downto 0) <= MAC_RXD_D;
		elsif(RX_STATE = 2) and (RX_EVENT5 = '1') then
			-- frame complete, all checks complete
			RX_STATE <= 0;
		end if;
	end if;
end process;
 
-- Assess whether rx frame is too short (collision) or too long?
-- ready at RX_STATE 2
RX_TOO_SHORT_GEN: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		if(RX_STATE = 1) and (RX_EVENT3 = '1') then
			-- end of frame delimiter
			if(RX_BYTE_COUNTER_INC(18 downto 6) = 0) then  -- < 64 bytes
				-- too short 6+6+2+46+4 = 64
				RX_TOO_SHORT <= '1';
				RX_TOO_LONG <= '0';
			elsif(RX_BYTE_COUNTER_INC(18 downto 11) /= 0) or 
				(RX_BYTE_COUNTER_INC(10 downto 0)> 1518) then  -- > 1518 bytes
				-- too long. 6+6+2+1500+4 = 1418
				RX_TOO_SHORT <= '0';
				RX_TOO_LONG <= '1';
			else
				RX_TOO_SHORT <= '0';
				RX_TOO_LONG <= '0';
			end if;
		end if;
	end if;
end process;
 
-- Destination address check
ADDR_CHECK_GEN: process(RX_CLKG, MAC_RX_CONFIG, MAC_ADDR)
begin
	if rising_edge(RX_CLKG) then
		if(MAC_RX_CONFIG(0) = '1') then
			-- promiscuous mode. No destination address check
			RX_VALID_ADDR <= '1';
		elsif(RX_STATE = 1) and (RX_EVENT4 = '1') and (RX_BYTE_COUNTER = 6) then
			-- end of destination address field. Check address
			if(LAST6B = MAC_ADDR) then
				-- destination address matches
				RX_VALID_ADDR <= '1';
			elsif (LAST6B = x"FFFFFFFFFFFF") and (MAC_RX_CONFIG(1) = '1') then
				-- accepts broadcast packets with the broadcast destination address FF:FF:FF:FF:FF:FF. 
				RX_VALID_ADDR <= '1';
			elsif (LAST6B(42) = '1') and (MAC_RX_CONFIG(2) = '1') then
				-- accept multicast packets with the multicast bit set in the destination address. 
				-- '1' in the LSb of the first address byte.
				RX_VALID_ADDR <= '1';
		   else
				RX_VALID_ADDR <= '0';
			end if;
		end if;
	end if;
end process;
 
-- Length/type field check
LENGTH_CHECK_GEN: process(RX_CLKG, MAC_RX_CONFIG, MAC_ADDR)
begin
	if rising_edge(RX_CLKG) then
		if(RX_EVENT1 = '1') then
			-- assume type field by default at the start of frame
			RX_LENGTH_TYPEN <= '0';  -- length/type field represents a type. ignore the length value.
		elsif(RX_STATE = 1) and (RX_EVENT4 = '1') and (RX_BYTE_COUNTER = 14) then
			-- end of length/type field
			if(LAST6B(15 downto 11) = 0) and (LAST6B(10 downto 0) <= 1500) then
				-- this field is interpreted as "Length" = client data field size
				-- MSB first (802.3 section 3.2.6)
				RX_LENGTH <= LAST6B(10 downto 0);  
				RX_LENGTH_TYPEN <= '1';  -- length/type field represents a length
			else
				RX_LENGTH_TYPEN <= '0';  -- length/type field represents a type. ignore the length value.
			end if;
		end if;
	end if;
end process;
 
-- compute the difference between RX_BYTE_COUNTER and RX_LENGTH (meaningless, but help minimize gates)
RX_DIFF <= RX_BYTE_COUNTER(11 downto 0) - ('0' & RX_LENGTH);
 
-- Length field consistency with actual rx frame length. Check if the length/type field is 'length'
RX_LENGTH_ERR_GEN: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		if(RX_LENGTH_TYPEN = '0') then
			-- type field. No explicit length info. Can't validate actual length.
			RX_LENGTH_ERR <= '0'; 
		elsif(MAC_RX_EOF3B = '1') then
			if(RX_LENGTH <= 46) then
				-- short rx frame is padded to the minimum size of 60 bytes + 4 CRC
				if(RX_BYTE_COUNTER = 63) then
					-- correct answer.
					RX_LENGTH_ERR <= '0'; 
				else
					-- inconsistency
					RX_LENGTH_ERR <= '1'; 
				end if;
			else
				-- normal size frame. no pad.
				if(RX_DIFF = 17) then
					-- correct answer.
					RX_LENGTH_ERR <= '0'; 
				else
					-- inconsistency
					RX_LENGTH_ERR <= '1'; 
				end if;
			end if;
		end if;
	end if;
end process;
 
 
 
--//  RX 32-BIT CRC COMPUTATION -------------------------------------------------------
-- 802.3 section 3.2.9: 
-- protected fields: payload data + optional pad + CRC (excludes preamble and start of frame sequence)
MAC_RX_SAMPLE2_CLK <= '1' when (RX_STATE = 1) and (MAC_RX_SAMPLE_CLK = '1')  else '0'; 
 
RX_CRC32_RESET <= '1' when (RX_STATE = 0) else '0';  -- reset CRC2 during the packet preamble 
 
-- latency 1 RX_CLKG
RX_CRC32_8B: CRC32_8B PORT MAP(
	SYNC_RESET => RX_CRC32_RESET,
	CLK => RX_CLKG,
	CRC32_IN => RX_CRC32,  -- feedback previous iteration
	DATA_IN => MAC_RXD_D,	
	SAMPLE_CLK_IN => MAC_RX_SAMPLE2_CLK,
	CRC32_OUT => RX_CRC32,
	CRC32_VALID => RX_CRC32_VALID
);
 
-- assess whether the frame check sequence is valid
-- ready one RX_CLKG after the start of RX_STATE 2
RX_BAD_CRC_GEN: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		if(RX_STATE = 2) then
			-- end of frame delimiter
			RX_BAD_CRC <= not RX_CRC32_VALID;
		end if;
	end if;
end process;
 
--// PARSE RX DATA -------------------------------------------------------------------
-- Delay data by 1 byte (otherwise we will only know about EOF AFTER the last byte is received)
MAC_RXD3 <= MAC_RXD_D;
 
-- SOF
--MAC_RX_SOF3 <= MAC_RX_SAMPLE_CLK when (RX_STATE = 1) and (RX_BYTE_COUNTER = 0) else '0';
 
-- EOF based on the length field (does not include pad nor CRC). Meaningless when the type/length field 
-- is used as type. 
MAC_RX_EOF3A <= '1' when (RX_STATE = 1) and (RX_EVENT4 = '1') and (RX_DIFF = 13) else '0';
 
-- EOF based on the RX_DV deassertion.
MAC_RX_EOF3B <= '1' when (RX_STATE = 1) and (RX_EVENT3 = '1') else '0';
 
MAC_RX_EOF3 <=  MAC_RX_EOF3B when (RX_LENGTH_TYPEN = '0') else MAC_RX_EOF3A;
MAC_RX_SAMPLE3_CLK <= MAC_RX_SAMPLE_CLK and RX_FRAME_EN3;
 
RX_FILTEROUT_001: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		if (SYNC_RESETRX = '1') then
			RX_FRAME_EN3 <= '0';
		elsif(RX_STATE = 0) and (RX_EVENT1 = '1') then
			RX_FRAME_EN3 <= '1';
		elsif(MAC_RX_EOF3 = '1') then
			RX_FRAME_EN3 <= '0';
		end if;
	end if;
end process;
 
--//  VALID RX FRAME? ----------------------------------------------------------
-- Is the rx frame valid? If so, confirm the wptr location.
 
MAC_RX_VALID_001: process(RX_CLKG)
begin
	if rising_edge(RX_CLKG) then
		-- wait one more CLK period until all validity checks are complete
		MAC_RX_EOF3B_D <= MAC_RX_EOF3B;
 
		if(SYNC_RESETRX = '1') then
			MAC_RX_WPTR_CONFIRMED <= (others => '0');
		else 
			if(RX_EVENT5 = '1') then
				-- frame complete, all checks complete
				if(RX_CRC32_VALID = '0') then
					-- BAD_CRC
					-- TODO error counter
				elsif(RX_TOO_SHORT = '1') then
					-- frame is too short (<64B)
					-- TODO error counter
				elsif(RX_TOO_LONG = '1') then
					-- frame is too long (>1518B)
					-- TODO error counter
				elsif(RX_VALID_ADDR = '0') then
					-- address does not match (and promiscuous mode is off)
					-- TODO counter
				elsif(RX_LENGTH_ERR = '1') then
					-- length field is inconsistent with actual rx frame length
					-- TODO counter
				else
					-- passed all checks
					-- update confirmed value for MAC_RX_WPTR
					if(MAC_RX_CONFIG(3) = '1') then
						-- filter out 4-byte CRC-32
						MAC_RX_WPTR_CONFIRMED <= MAC_RX_WPTR - 4;
					else
						-- include 4-byte CRC-32
						MAC_RX_WPTR_CONFIRMED <= MAC_RX_WPTR;
					end if;
				end if;
 
			end if;
		end if;
	end if;
end process;
 
 
 
--//  RX INPUT ELASTIC BUFFER ----------------------------------------------------------
-- The purpose of the elastic buffer is two-fold:
-- (a) a transition between the RX_CLKG synchronous PHY side and the CLK-synchronous user side.
-- (b) storage for receive packets, to absorb traffic peaks, minimize the number of 
-- UDP packets lost at high throughput.
-- The rx elastic buffer is 16Kbits, large enough for a complete maximum size (14addr+1500data+4FCS = 1518B) frame.
 
-- write pointer management
MAC_RX_WPTR_001: process(ASYNC_RESET, RX_CLKG)
begin
	if(ASYNC_RESET = '1') then
		MAC_RX_WPTR <= (others => '0');
		MAC_RX_WPTR_D <= (others => '0');
	elsif rising_edge(RX_CLKG) then
		RX_COUNTER8 <= RX_COUNTER8 + 1;
 
		if(SYNC_RESETRX = '1') then
			MAC_RX_WPTR <= (others => '0');
		elsif(RX_STATE = 0) then
			-- re-position the write pointer (same or rewind if previous frame was invalid
			MAC_RX_WPTR <= MAC_RX_WPTR_CONFIRMED;
		elsif(MAC_RX_SAMPLE3_CLK = '1') then
			MAC_RX_WPTR <= MAC_RX_WPTR + 1;
		end if;
 
		-- update WPTR_D once every 8 clocks.
		if(SYNC_RESETRX = '1') then
			MAC_RX_WPTR_D <= (others => '0');
		elsif(RX_COUNTER8 = 7) then
			MAC_RX_WPTR_D <= MAC_RX_WPTR_CONFIRMED;
		end if;
 
		-- allow WPTR reclocking with another clock, as long as it is away from the transition area
		if(RX_COUNTER8 < 6) then
			MAC_RX_WPTR_STABLE <= '1';
		else 
			MAC_RX_WPTR_STABLE <= '0';
		end if;
 
 
	end if;
end process;
 
 
 
MAC_RX_DIPA(0) <= MAC_RX_EOF3;  -- indicates last byte in the rx packet
 
-- No need for initialization
RAMB16_002: RAMB16_S9_S9 
port map(
	DIA => MAC_RXD3,
	DIB => x"00",
	DIPA => MAC_RX_DIPA(0 downto 0),
	DIPB => "0",
	DOPA => open,
	DOPB => MAC_RX_DOPB(0 downto 0),	
	ENA => '1',
	ENB => '1',
	WEA => MAC_RX_SAMPLE3_CLK,
	WEB => '0',
	SSRA => '0',
	SSRB => '0',
	CLKA => RX_CLKG,
	CLKB => CLK,
	ADDRA => MAC_RX_WPTR,
	ADDRB => MAC_RX_RPTR,
	DOA => open,
	DOB => MAC_RXD4
);
 
 
-- CLK zone. Reclock WPTR
MAC_RX_WPTR_002: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		MAC_RX_WPTR_D2 <= (others => '0');
		MAC_RX_WPTR_D3 <= (others => '0');
		MAC_RX_WPTR_STABLE_D <= '0';
	elsif rising_edge(CLK) then
		MAC_RX_WPTR_STABLE_D <= MAC_RX_WPTR_STABLE;
		MAC_RX_WPTR_D2 <= MAC_RX_WPTR_D;
 
		if(MAC_RX_WPTR_STABLE_D = '1') then
			-- WPTR is stable. OK to resample with the RX_CLKG clock.
			MAC_RX_WPTR_D3 <= MAC_RX_WPTR_D2;
		end if;
	end if;
end process;
 
MAC_RX_BUF_SIZE <= MAC_RX_WPTR_D3 + not(MAC_RX_RPTR);
-- occupied tx buffer size
 
-- manage read pointer
MAC_RX_RPTR_001: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		MAC_RX_RPTR <= (others => '1');
	elsif rising_edge(CLK) then
		MAC_RX_SAMPLE4_CLK <= MAC_RX_SAMPLE4_CLK_E;  -- it takes one CLK to read data from the RAMB
 
		if(SYNC_RESET = '1') then
			MAC_RX_RPTR <= (others => '1');
			MAC_RX_SAMPLE4_CLK_E <= '0';
			MAC_RX_SAMPLE4_CLK <= '0';
		elsif(MAC_RX_CTS = '1') and (MAC_RX_BUF_SIZE /= 0) then
			-- user requests data and the buffer is not empty
			MAC_RX_RPTR <= MAC_RX_RPTR + 1;
			MAC_RX_SAMPLE4_CLK_E <= '1';
		else
			MAC_RX_SAMPLE4_CLK_E <= '0';
		end if;
	end if;
end process;
 
-- reconstruct an EOF aligned with the last output byte
EOF_GEN_001: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		MAC_RX_EOF4 <= '0';
	elsif rising_edge(CLK) then
		if(SYNC_RESET = '1') then
			MAC_RX_EOF4 <= '0';
		elsif(MAC_RX_SAMPLE4_CLK_E = '1') and  (MAC_RX_BUF_SIZE = 0)then
			MAC_RX_EOF4 <= '1';
		else
			MAC_RX_EOF4 <= '0';
		end if;
	end if;
end process;
-- alternate code (does not work when CRC32 is stripped)
-- MAC_RX_EOF4 <= MAC_RX_DOPB(0) and MAC_RX_SAMPLE4_CLK; -- reconstruct EOF pulse (1 CLK wide)
 
-- reconstruct a SOF
SOF_GEN_001: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		MAC_RX_EOF4_FLAG <= '1';
	elsif rising_edge(CLK) then
		if(SYNC_RESET = '1') then
			MAC_RX_EOF4_FLAG <= '1';
		elsif(MAC_RX_EOF4 = '1') then
			MAC_RX_EOF4_FLAG <= '1';
		elsif(MAC_RX_SAMPLE4_CLK = '1') then
			MAC_RX_EOF4_FLAG <= '0';
		end if;
	end if;
end process;
 
-- output to user
MAC_RX_DATA <= MAC_RXD4;
MAC_RX_DATA_VALID <= MAC_RX_SAMPLE4_CLK;
MAC_RX_EOF <= MAC_RX_EOF4;
MAC_RX_SOF <= MAC_RX_EOF4_FLAG and MAC_RX_SAMPLE4_CLK;
 
end Behavioral;
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.