-------------------------------------------------------------
-- MSS copyright 2014-2018
-- Filename:  COM7003_TOP.VHD
-- Authors: 
--		Alain Zarembowitch / MSS
-- Version: Rev 003x
-- Last modified: 5/19/18

-- Inheritance: 	N/A
--
-- description:  Top level for DVB-RCS2 turbo code encoder and decoder 
--
-- Rev 003x 5/19/18
-- Editorial + corrected bug rate 7/8 encoding (puncturing)
-------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use work.com5402pkg.all;	-- defines global types, number of TCP streams, etc
library UNISIM;
use UNISIM.VComponents.all;

entity COM7003_TOP is
	generic (
       OPTION: std_logic_vector(7 downto 0) := x"20";    -- ' '    -- no option
       REVISION: std_logic_vector(7 downto 0) := x"33";    -- '3'
            --// FPGA option and revision (ASCII format '0' = x30, 'A' = x41)
            -- These two ASCII characters appear in the Comblock Control Center.
            -- Helpful in identifying which firmware version is currently running in the FPGA. 
		SIMULATION: std_logic := '0'
			-- '1' during simulation, '0' for synthesis	
	);
    Port ( 
		--GLOBAL CLOCKS
	   CLKREF_TCXO : in std_logic;	
			-- 19.2MHz reference clock. Generated by the VCTCXO on this board.

        --// GbE LAN. 
        -- connects to RGMII PHY (Micrel KSZ9031)
		  LAN_TXC: out std_logic;  -- tx clock
        LAN_TXD: out std_logic_vector(3 downto 0);  -- tx data
        LAN_TX_CTL: out std_logic;  -- tx control: combines TX_EN and TX_ER
            -- valid at the falling clock edge
        LAN_RXC: in std_logic;  -- receive clock
            -- must be delayed by 1.5 to 2.1 ns to prevent glitches
            -- Set the strapping options in the .ucf constraint file.
        LAN_RXD: in std_logic_vector(3 downto 0);  
            -- receive data
            -- Set the strapping options in the .ucf constraint file.
        LAN_RX_CTL: in std_logic;  -- receive control. combines RX_DV and RX_ER
            -- valid at the falling clock edge
            -- Note: Micrel KSZ9021RN PHY defines these as dual-function signals.
            -- Set the strapping options in the .ucf constraint file.
        LAN_RESET_N: out std_logic;
            -- PHY reset
        LAN_MCLK: out std_logic;
        LAN_MDIO: inout std_logic;  -- (tri-state)
        LAN_CLK125: in std_logic;   -- optional 125 MHz from PHY
        LAN_INT_N: in std_logic;    -- unused interrupt
        
		--// Left connector, 98 pin PCIe female connector. 
		-- Pins B5,B20,B31,B42 reserved for Ground
		-- Pins A49/B49 reserved for ComBlock Monitoring and Control.
		-- Place B13 in high-impedance when using the 12-bit DAC or vice versa.
		LEFT_CONNECTOR_A: inout std_logic_vector(38 downto 1);
		LEFT_CONNECTOR_B1: inout std_logic_vector(4 downto 1);
		LEFT_CONNECTOR_B2: inout std_logic_vector(16 downto 6);

		--// Right connector: 98 pin PCIe female connector.   
		-- Pins B5,B20,B31,B42 reserved for Ground
		-- Pins A49/B49 reserved for ComBlock Monitoring and Control.
		-- Connector pins A39 - A48, B40,B41,B43-B48 can be used by 
		-- re-routing LEFT_CONNECTOR signals using a resistor array (requires soldering)
		-- See schematics for details.
		RIGHT_CONNECTOR_A: inout std_logic_vector(38 downto 1);
		RIGHT_CONNECTOR_B1: inout std_logic_vector(4 downto 1);
		RIGHT_CONNECTOR_B2: inout std_logic_vector(19 downto 6);
		RIGHT_CONNECTOR_B3: inout std_logic_vector(30 downto 21);
		RIGHT_CONNECTOR_B4: inout std_logic_vector(39 downto 32);

		--// Monitoring & Control: ARM Cortex M3 microcontroller interface
		-- asynchronous bus (shared with NAND flash)
		-- set address at the rising edge of UC_WEB_IN when UC_CSIB_IN = '0' and UC_ALE_IN = '1'
		-- write data the rising edge of UC_WEB_IN when UC_CSIB_IN = '0'
		-- read data when  UC_CSIB_IN = '0' and UC_REB_IN = '0'
		UC_CSIB_IN: in std_logic;  -- chip select. active low.
		UC_ALE_IN: in std_logic;  -- address latch enable. active high.
		UC_REB_IN: in std_logic;  -- read enable #
		UC_WEB_IN: in std_logic;	-- write enable #
		UC_AD: inout std_logic_vector(7 downto 0)  -- shared address/data bus

		  
			  );
end entity;

architecture Behavioral of COM7003_TOP is
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------
-- Comment in/out components/drivers as needed
	COMPONENT CLKGEN7_MMCM_ADJ
	GENERIC (
        CLKFBOUT_MULT_F: real;
        CLKOUT0_DIVIDE_F: real;
        CLKIN1_PERIOD: real
    );    
    PORT(
        CLK_IN1 : IN std_logic;
        CLK_OUT1 : OUT std_logic;
		  PHASE_SHIFT_VAL: in std_logic_vector(7 downto 0);
		  PHASE_SHIFT_TRIGGER_TOGGLE: in std_logic;
        INPUT_CLK_STOPPED : OUT std_logic;
        LOCKED : OUT std_logic;
		  TP: out std_logic_vector(10 downto 1)
        );
    END COMPONENT;

	COMPONENT CROSS_CLK_DOMAINS_NODATALOSS
	PORT(
		CLK_A : IN std_logic;
		CLK_B : IN std_logic;
		ASYNC_RESET : IN std_logic;
		DATA_IN : IN std_logic_vector(7 downto 0);
		SAMPLE_CLK_IN : IN std_logic;
		SOF_IN : IN std_logic;
		EOF_IN : IN std_logic;
		SAMPLE_CLK_OUT_REQ : IN std_logic;          
		SAMPLE_CLK_IN_REQ : OUT std_logic;
		DATA_OUT : OUT std_logic_vector(7 downto 0);
		SAMPLE_CLK_OUT : OUT std_logic;
		SOF_OUT : OUT std_logic;
		EOF_OUT : OUT std_logic
		);
	END COMPONENT;

	COMPONENT BRAM_DP2
	GENERIC(
		DATA_WIDTHA: integer;
		ADDR_WIDTHA: integer;
		DATA_WIDTHB: integer;
		ADDR_WIDTHB: integer
	);
	PORT(
		CLKA   : in  std_logic;
		CSA: in std_logic;	
		WEA    : in  std_logic;	
		OEA : in std_logic;	
		ADDRA  : in  std_logic_vector(ADDR_WIDTHA-1 downto 0);
		DIA   : in  std_logic_vector(DATA_WIDTHA-1 downto 0);
		DOA  : out std_logic_vector(DATA_WIDTHA-1 downto 0);
		CLKB   : in  std_logic;
		CSB: in std_logic;	-- chip select, active high
		WEB    : in  std_logic;	-- write enable, active high
		OEB : in std_logic;	-- output enable, active high
		ADDRB  : in  std_logic_vector(ADDR_WIDTHB-1 downto 0);
		DIB   : in  std_logic_vector(DATA_WIDTHB-1 downto 0);
		DOB  : out std_logic_vector(DATA_WIDTHB-1 downto 0)
		);
	END COMPONENT;

	COMPONENT COM5401
	GENERIC (
		MII_SEL: std_logic;  
		PHY_ADDR: std_logic_vector(4 downto 0);
		CLK_FREQUENCY: integer; 
		PLATFORM: integer;
		TARGET_PHY: integer;
		NO_1000: std_logic;	
		INTERNAL_PHY_TX_CLKS_DELAYS: std_logic;
		INTERNAL_PHY_RX_CLKS_DELAYS: std_logic;
		SIMULATION: std_logic
	);
	PORT(
		CLK : IN std_logic;
		SYNC_RESET : IN std_logic;
		CLK125_0: in std_logic;
		CLK125_1: in std_logic;
		CLK25: 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_SKEW1: in std_logic_vector(15 downto 0);
		CLK_SKEW2: 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);
		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);
		CS_CLKG: out std_logic;	
		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;
		CT1: out std_logic;
		CT1_CLK: out std_logic;
		TP: out std_logic_vector(10 downto 1)
		);
	END COMPONENT;

	COMPONENT COM5402
	GENERIC (
		NUDPTX: integer range 0 to 1;
		NUDPRX: integer range 0 to 1;
		NTCPSTREAMS: integer range 0 to 255;  
		CLK_FREQUENCY: integer;
		TX_IDLE_TIMEOUT: integer range 0 to 50;	
		SIMULATION: std_logic
	);	
	PORT(
		CLK : 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);
		MULTICAST_IP_ADDR: in std_logic_vector(31 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_SOF : 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: in std_logic_vector(15 downto 0);
		CHECK_UDP_RX_DEST_PORT_NO: in std_logic;
		UDP_RX_DEST_PORT_NO_OUT: out 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);	
		TCP_CONNECTED_FLAG: 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(
		CLK : IN std_logic;
		ASYNC_RESET : 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;
	    STREAM_SOF_OUT: out std_logic;
        STREAM_EOF_OUT: out std_logic;
		BAD_PACKET : OUT std_logic;
		TP : OUT std_logic_vector(10 downto 1)
		);
	END COMPONENT;

	COMPONENT ELASTIC_BUFFER_NRAMB2
	GENERIC (
		DATA_WIDTH: integer;
		ADDR_WIDTH: integer;
		READ_AHEAD_1ADDRESS: std_logic
	);	
	PORT(
		CLK : IN std_logic;
		SYNC_RESET : IN std_logic;
		DATA_IN: in std_logic_vector((DATA_WIDTH-1) downto 0);
		SAMPLE_CLK_IN : IN std_logic;
		SAMPLE_CLK_IN_REQ : OUT std_logic;
		DATA_OUT: out std_logic_vector((DATA_WIDTH-1) downto 0);
		SAMPLE_CLK_OUT : OUT std_logic;
		SAMPLE_CLK_OUT_E : OUT std_logic;
		SAMPLE_CLK_OUT_REQ : IN std_logic;          
		BUFFER_EMPTY: out std_logic;
		USED: out std_logic_vector((ADDR_WIDTH-1) downto 0)
		);
	END COMPONENT;

	COMPONENT P8_TO_S1_CONVERSION
	PORT(
		CLK : IN std_logic;
		SYNC_RESET : IN std_logic;
		DATA8_IN : IN std_logic_vector(7 downto 0);
		SAMPLE8_CLK_IN : IN std_logic;
		SAMPLE1_CLK_OUT_REQ : IN std_logic;          
		SAMPLE8_CLK_IN_REQ : OUT std_logic;
		DATA1_OUT : OUT std_logic;
		SAMPLE1_CLK_OUT : OUT std_logic;
		BUF_EMPTY : OUT std_logic
		);
	END COMPONENT;

	COMPONENT LFSR11C
	PORT(
		CLK : IN std_logic;
		SYNC_RESET : IN std_logic;
		BIT_CLK_REQ : 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;

	COMPONENT ELASTIC_BUFFER16b
	PORT(
		CLK : IN std_logic;
		SYNC_RESET: in std_logic;
		DATA_IN : IN std_logic;
		SAMPLE_CLK_IN : IN std_logic;
		SAMPLE_CLK_OUT_REQ : IN std_logic;          
		SAMPLE_CLK_IN_REQ : OUT std_logic;
		DATA_OUT : OUT std_logic;
		SAMPLE_CLK_OUT : OUT std_logic
		);
	END COMPONENT;

	COMPONENT TC_ENCODER_DVB_RCS2
	generic (
		SIMULATION: std_logic
	);
	PORT(
		CLK : IN std_logic;
		SYNC_RESET : IN std_logic;
		DATA_IN : IN std_logic_vector(1 downto 0);
		DATA_IN_VALID : IN std_logic;
		SOF_IN : IN std_logic;
		CTS_OUT : OUT std_logic;
		BURST_PAYLOAD_SIZE : IN std_logic_vector(9 downto 0);
		R1: in std_logic_vector(2 downto 0);
		R2: in std_logic_vector(3 downto 0);
		P : IN std_logic_vector(6 downto 0);
		Q0 : IN std_logic_vector(3 downto 0);
		Q1 : IN std_logic_vector(3 downto 0);
		Q2 : IN std_logic_vector(3 downto 0);
		Q3 : IN std_logic_vector(2 downto 0);
		Y_PUNCTURING_PERIOD : IN std_logic_vector(4 downto 0);
		Y_PUNCTURING_PATTERN : IN std_logic_vector(27 downto 0);
		W_PUNCTURING_PATTERN : IN std_logic;          
		CRC16_EN: in std_logic;
		DATA_OUT: out std_logic_vector(1 downto 0);
		DATA_OUT_VALID: out std_logic;
		SOF_OUT: out std_logic;
		EOF_OUT: out std_logic;
		CTS_IN: in std_logic;
		N_PARITY_BITS: out std_logic_vector(11 downto 0);
		N_PARITY_BITS_RDY: out std_logic;
		TP: out std_logic_vector(10 downto 1)  
		);
	END COMPONENT;

    component SOF_SYNC is
    port (
        CLK: in std_logic;	
        ASYNC_RESET: in  std_logic;
        DATA_IN: in std_logic_vector(3 downto 0);     
        BIT_CLK_IN: in std_logic;
        FRAME_LENGTH: in std_logic_vector(12 downto 0);
        BIT_CLK_OUT: out std_logic;
        SOF: out std_logic;
        SOF_LOCK_DETECT: out std_logic;
        PHASE: out std_logic_vector(1 downto 0);
        DATA_ENABLE: out std_logic;
        DATA_OUT: out std_logic_vector(3 downto 0);
        BER: out std_logic_vector(16 downto 0);
        TP_MRC_SOF: out std_logic_vector(3 downto 0)
        );
 end component;

	COMPONENT TC_DECODER_DVB_RCS2
	generic (
		NQBITS: integer range 3 to 8;
		NADDRBITS: integer range 5 to 10;
		SIMULATION: std_logic
	);
	PORT(
		CLK : IN std_logic;
		SYNC_RESET : IN std_logic;
		DATA_A_IN: in std_logic_vector((NQBITS-1) downto 0);
		DATA_B_IN: in std_logic_vector((NQBITS-1) downto 0);
		DATA_IN_VALID : IN std_logic;
		SOF_IN : IN std_logic;
		EOF_IN: in std_logic;
		BURST_PAYLOAD_SIZE: in std_logic_vector((NADDRBITS-1) downto 0);
		P : IN std_logic_vector(6 downto 0);
		Q0 : IN std_logic_vector(3 downto 0);
		Q1 : IN std_logic_vector(3 downto 0);
		Q2 : IN std_logic_vector(3 downto 0);
		Q3 : IN std_logic_vector(2 downto 0);
		Y_PUNCTURING_PERIOD : IN std_logic_vector(4 downto 0);
		Y_PUNCTURING_PATTERN : IN std_logic_vector(27 downto 0);
		W_PUNCTURING_PATTERN : IN std_logic;
		N_ITER: in std_logic_vector(3 downto 0);
		CRC16_EN: in std_logic;
		CTS_IN : IN std_logic;          
		CTS_OUT : OUT std_logic;
		DATA_OUT : OUT std_logic_vector(1 downto 0);
		DATA_OUT_VALID : OUT std_logic;
		SOF_OUT : OUT std_logic;
		CRC_VALID: out std_logic;
		BAD_CRC: out std_logic;
		FRAME_CNTR: out std_logic_vector(31 downto 0);
		FRAME_ERROR_CNTR: out std_logic_vector(31 downto 0)
		);
	END COMPONENT;

	COMPONENT S1_TO_P8_CONVERSION
	PORT(
		CLK : IN std_logic;
		SYNC_RESET : IN std_logic;
		DATA1_IN : IN std_logic;
		SAMPLE1_CLK_IN : IN std_logic;
		SOF1_IN : IN std_logic;
		EOF1_IN : IN std_logic;          
		DATA8_OUT : OUT std_logic_vector(7 downto 0);
		SAMPLE8_CLK_OUT : OUT std_logic;
		SOF8_OUT : OUT std_logic;
		EOF8_OUT : OUT std_logic
		);
	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;

 	COMPONENT DNA_ID
	GENERIC (
		CLK_FREQUENCY: integer
	);	
	PORT(
		CLK : IN std_logic;
		SYNC_RESET : IN std_logic;          
		ID_OUT : OUT std_logic_vector(56 downto 0) := (others => '0');
		ID_VALID_OUT : OUT std_logic;
		ID_SAMPLE_CLK_OUT : 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


--// CLOCKS, RESETS
signal CLKREF_TCXOg: std_logic := '0';
signal CLKGEN7C_INPUT_CLK_STOPPED: std_logic := '0';
signal CLKGEN7C_LOCKED: std_logic := '0';
signal CLKGEN7D_INPUT_CLK_STOPPED: std_logic := '0';
signal CLKGEN7D_LOCKED: std_logic := '0';
signal CLK125_0: std_logic := '0';
signal CLK125_1: std_logic := '0';
signal CLK125_2: std_logic := '0';
signal CLK25: std_logic := '0';
signal CLK25_RST: std_logic := '0';
signal CLK10: std_logic := '0';
signal CLK10g: std_logic := '0';
constant CLK_FREQUENCY: integer := 125; -- processing clock frequency CLK_P in MHz, as time reference
signal RESET_COUNTER: unsigned(23 downto 0) := x"000000";	-- initialize for simulations
	-- spans 2^23/10MHz = 838ms
signal RESET_STATE: integer range 0 to 1 := 0;
signal ASYNC_RESET: std_logic := '1';
signal CLK_P: std_logic := '0';
signal CLK_P_FB: std_logic := '0';
signal SYNC_RESET_CLK_P: std_logic := '0';
signal ASYNC_RESET_D: std_logic := '0';
signal ASYNC_RESET_D2: std_logic := '0';
	-- asynchronous reset
signal READY_FLAG_CLK_P: std_logic := '0';
signal READY_FLAG_CLK_Pn: std_logic := '0';

--//-- LEFT CONNECTOR ----------------------------------
signal CLK_IN_LCg: std_logic := '0';
signal LEFT_CONNECTOR_A_D: std_logic_vector(17 downto 2) := (others => '0');
signal LEFT_CONNECTOR_B_D: std_logic_vector(16 downto 1) := (others => '0');
signal CCD1_DATA_IN: std_logic_vector(7 downto 0) := (others => '0');
signal CCD1_DATA_OUT: std_logic_vector(7 downto 0) := (others => '0');
signal CCD1_SAMPLE_CLK_OUT: std_logic:= '0';
signal CCD1_SAMPLE_CLK_OUT_REQ: std_logic:= '0';
signal CCD1_SAMPLE_CLK_OUT_REQA: std_logic:= '0';
signal CCD1_SAMPLE_CLK_OUT_REQB: std_logic:= '0';

--//-- RIGHT CONNECTOR ----------------------------------
signal CLK_IN_RCg: std_logic := '0';
signal RIGHT_CONNECTOR_A_D: std_logic_vector(17 downto 2) := (others => '0');
signal RIGHT_CONNECTOR_B_D: std_logic_vector(16 downto 1) := (others => '0');
signal CCD2_DATA_IN: std_logic_vector(7 downto 0) := (others => '0');
signal CCD2_DATA_OUT: std_logic_vector(7 downto 0) := (others => '0');
signal CCD2_SAMPLE_CLK_OUT: std_logic:= '0';
signal CCD2_SAMPLE_CLK_OUT_REQ: std_logic:= '0';
signal CCD2_SAMPLE_CLK_OUT_REQA: std_logic:= '0';
signal CCD2_SAMPLE_CLK_OUT_REQB: std_logic:= '0';

--//-- ETHERNET MAC#1-----------------------------------
signal CLK_SKEW21: std_logic_vector(15 downto 0) := (others => '0');
signal CLK_SKEW22: std_logic_vector(15 downto 0) := (others => '0');
signal LAN1_MAC_ADDR: std_logic_vector(47 downto 0) := (others => '0');
signal LAN1_TP: std_logic_vector(10 downto 1) := (others => '0');
signal LAN1_PHY_ID: std_logic_vector(15 downto 0) := (others => '0');
signal LAN1_MAC_RX_DATA: std_logic_vector(7 downto 0) := (others => '0');
signal LAN1_MAC_RX_DATA_VALID: std_logic:= '0';
signal LAN1_MAC_RX_SOF: std_logic:= '0';
signal LAN1_MAC_RX_EOF: std_logic:= '0';
signal LAN1_MAC_TX_DATA: std_logic_vector(7 downto 0) := (others => '0');
signal LAN1_MAC_TX_DATA_VALID: std_logic:= '0';
signal LAN1_MAC_TX_EOF: std_logic:= '0';
signal LAN1_MAC_TX_CTS: std_logic:= '0';
signal LAN1_LINK_STATUS: std_logic:= '0';
signal LAN1_SPEED_STATUS: std_logic_vector(1 downto 0) := (others => '0');
signal LAN1_DUPLEX_STATUS: std_logic:= '0';
signal LAN1_N_RX_FRAMES:  std_logic_vector(15 downto 0);
signal LAN1_N_RX_BAD_CRCS:  std_logic_vector(15 downto 0);
signal LAN1_N_RX_FRAMES_TOO_SHORT:  std_logic_vector(15 downto 0);
signal LAN1_N_RX_FRAMES_TOO_LONG:  std_logic_vector(15 downto 0);
signal LAN1_N_RX_WRONG_ADDR:  std_logic_vector(15 downto 0);
signal LAN1_N_RX_LENGTH_ERRORS:  std_logic_vector(15 downto 0);

--//-- IP STACK, TCP SERVER -----------------------------------
constant NTCPSTREAMS1: integer := 2;  -- number of concurrent TCP streams handled by this component
signal IP1_ADDRv4: std_logic_vector(31 downto 0) := (others => '0');	
signal SUBNET_MASK: std_logic_vector(31 downto 0) := (others => '0');	
signal GATEWAY_IP_ADDR: std_logic_vector(31 downto 0) := (others => '0');	
signal IPSTACK1_TP: std_logic_vector(10 downto 1) := (others => '0');
signal LAN1_UDP_RX_DATA: std_logic_vector(7 downto 0) := (others => '0');
signal LAN1_UDP_RX_DATA_VALID: std_logic := '0';
signal LAN1_UDP_RX_SOF: std_logic := '0';
signal LAN1_UDP_RX_EOF: std_logic := '0';
signal LAN1_UDP_RX_DATA2: std_logic_vector(7 downto 0) := (others => '0');
signal LAN1_UDP_RX_DATA2_VALID: std_logic := '0';
signal LAN1_TCP_RX_DATA: SLV8xNTCPSTREAMStype;
signal LAN1_TCP_RX_DATA_VALID: std_logic_vector((NTCPSTREAMS1-1) downto 0) := (others => '0');
--signal LAN1_TCP_RX_RTS: std_logic_vector((NTCPSTREAMS1-1) downto 0) := (others => '0');
signal LAN1_TCP_RX_CTS: std_logic_vector((NTCPSTREAMS1-1) downto 0) := (others => '0');
signal LAN1_TCP_TX_DATA: SLV8xNTCPSTREAMStype;
signal LAN1_TCP_TX_DATA_VALID: std_logic_vector((NTCPSTREAMS1-1) downto 0) := (others => '0');
signal LAN1_TCP_TX_CTS: std_logic_vector((NTCPSTREAMS1-1) downto 0) := (others => '0');
signal LAN1_TCP_CONNECTED_FLAG: std_logic_vector((NTCPSTREAMS1-1) downto 0) := (others => '0');
signal LAN1_RX_DATA0: std_logic_vector(7 downto 0) := (others => '0');
signal LAN1_RX_SAMPLE0_CLK: std_logic := '0';

--// LAN#1 TCP-IP Interface for M&C (TCP server port 1028)
signal EB1_SAMPLE_CLK_OUT_E: std_logic := '0';
signal RX_LAN: std_logic_vector(7 downto 0) := (others => '0'); 
signal RX_LAN_SAMPLE_CLK_REQ: std_logic;
signal RX_LAN_BUFFER_EMPTY: std_logic := '1';
signal RX_LAN_BUFFER_EMPTY_D: std_logic := '1';
signal RX_LAN_BUFFER_EMPTY_D2: std_logic := '1';
signal TX_LAN_TOGGLE: std_logic;
signal TX_LAN_TOGGLE_D: std_logic;
signal TX_LAN_TOGGLE_D2: std_logic;

--// LAN#1 TCP-IP Interface for payload data (TCP server port 1024)
signal TCP_RX_DATA1b1: std_logic := '0';
signal TCP_RX_SAMPLE1b1_CLK: std_logic := '0';
signal TCP_RX_SAMPLE1b1_CLK_REQ: std_logic := '0';

--//-- PRBS-11 TEST SEQUENCE ----------------------------------
signal PRBS11_BIT: std_logic := '0';
signal PRBS11_SOF: std_logic := '0';
signal PRBS11_SAMPLE_CLK: std_logic := '0';
signal PRBS11_SAMPLE_CLK_REQ: std_logic := '0';

--//-- 0-255 COUNTING TEST SEQUENCE ----------------------------------
signal TEST_COUNT_SEQ8b: unsigned(7 downto 0) := x"00";
signal TEST_COUNT_SEQ8b_VALID: std_logic := '0';
signal TEST_COUNT_SEQ8b_CTS: std_logic := '0';
signal TEST_COUNT_SEQ1b: std_logic := '0';
signal TEST_COUNT_SEQ1b_VALID: std_logic := '0';
signal TEST_COUNT_SEQ1b_CTS: std_logic := '0';

--// TURBO CODE ENCODER -----------------------------------------------------------
-- encoder configuration
signal TC_ENC_R1: std_logic_vector(2 downto 0) := (others => '0');
signal TC_ENC_R2: std_logic_vector(3 downto 0) := (others => '0');
signal TC_ENC_BURST_PAYLOAD_SIZE : std_logic_vector(7 downto 0) := (others => '0');
signal TC_ENC_BURST_PAYLOAD_SIZEx : std_logic_vector(9 downto 0) := (others => '0');
signal TC_E_BLOCK_SIZE : std_logic_vector(14 downto 0) := (others => '0');
signal TC_ENC_N: unsigned(9 downto 0):= (others => '0');
signal TC_ENC_P : std_logic_vector(6 downto 0) := (others => '0');
signal TC_ENC_Q0 : std_logic_vector(3 downto 0) := (others => '0');
signal TC_ENC_Q1 : std_logic_vector(3 downto 0) := (others => '0');
signal TC_ENC_Q2 : std_logic_vector(3 downto 0) := (others => '0');
signal TC_ENC_Q3 : std_logic_vector(2 downto 0) := (others => '0');
signal TC_ENC_Y_PUNCTURING_PERIOD : std_logic_vector(4 downto 0) := (others => '0');
signal TC_ENC_Y_PUNCTURING_PATTERN : std_logic_vector(27 downto 0) := (others => '0');
signal TC_ENC_W_PUNCTURING_PATTERN : std_logic := '0';
signal TC_ENC_CRC16_EN : std_logic := '0';

signal TC_ENC_SYNC_RESET: std_logic := '0';

signal ENC_DATA_IN2: std_logic := '0';
signal ENC_SAMPLE_CLK_IN2: std_logic := '0';
signal ENC_SAMPLE_CLK_IN2_REQ: std_logic := '0';
signal TC_ENC_CNTR: unsigned(10 downto 0):= (others => '0');
signal TC_U_DATA : std_logic_vector(1 downto 0) := (others => '0');
signal TC_U_DATA_VALID : std_logic := '0';
signal TC_U_SOF : std_logic := '0';
signal TC_U_EOF_E : std_logic := '0';
signal TC_U_EOF : std_logic := '0';
signal TC_U_CTS : std_logic := '0';

signal ENCODER_ENABLED: std_logic := '0';
signal ENC_DATA_IN: std_logic := '0';
signal ENC_SAMPLE_CLK_IN: std_logic := '0';
signal ENC_SAMPLE_CLK_IN_REQ: std_logic := '0';
signal ENC_SAMPLE_CLK_IN_REQB: std_logic := '0';


signal TC_E_DATA: std_logic_vector(1 downto 0) := (others => '0');
signal TC_E_DATA_D1: std_logic := '0';
signal TC_E_DATA_VALID: std_logic := '0';
signal TC_E_DATA_VALID_D: std_logic := '0';
signal TC_E_SOF: std_logic := '0';
signal TC_E_EOF: std_logic := '0';
signal TC_E_CTS: std_logic := '0';
signal TC_E_CTS_D: std_logic := '0';
signal TC_ENC_N_PARITY_BITS: std_logic_vector(11 downto 0) := (others => '0'); 
signal TC_ENC_N_PARITY_BITS_RDY: std_logic := '0';
signal TC_TP: std_logic_vector(10 downto 1) := (others => '0');

--//-- INSERT SYNC WORD ------------------------------
signal UW_GEN_STATE: integer range 0 to 2 := 0;
signal UW_GEN_STATE_D: integer range 0 to 2 := 0;
signal UW_GEN_CNTR: unsigned(5 downto 0) := (others => '0');
signal TC_ENC_FRAME_CNTR: unsigned(2 downto 0) := (others => '0');
signal TC_ENC_FRAME_CNTR_MAX: unsigned(2 downto 0) := (others => '0');
signal UW_BIT: std_logic := '0';
signal UW_REG: std_logic_vector(31 downto 0) := x"5a0fbe66";

signal TX_DATA1b1: std_logic := '0';
signal TX_SAMPLE1b1_CLK: std_logic := '0';
signal TX_SOF1b1: std_logic := '0';
signal TX_SAMPLE1b1_CLK_REQ : std_logic := '0';	-- TODO FLOW CONTROL FROM AFTER TC ENCODER
signal TX_SAMPLE1b1_CLK_REQA : std_logic := '0';	

signal DATA11: std_logic_vector(3 downto 0) := (others => '0');
signal SAMPLE11_CLK: std_logic := '0';
signal SOF11: std_logic := '0';

--// LIMIT ENCODER THROUGHPUT  -------------------------
signal NCO1_ACC: unsigned(23 downto 0) := (others => '0');
signal NCO1_VAL: std_logic_vector(23 downto 0) := (others => '0');
signal NCO1_MSB_D: std_logic := '0';
signal TX_SAMPLE1b1_CLK_REQB: std_logic := '0';

--// TC DECODER SOURCE SELECTION -------------------------
signal DEC_DATA_IN: std_logic_vector(3 downto 0) := (others => '0');
signal DEC_SAMPLE_CLK_IN: std_logic := '0';
signal DEC_SOF_IN: std_logic := '0';
signal DEC_SAMPLE_CLK_IN_REQ: std_logic := '0';
signal DEC_SAMPLE_CLK_IN_REQB: std_logic := '0';


--// TURBO CODE DECODER -----------------------------------------------------------
constant NADDRBITS: integer := 8;  -- ceiling(log2(maximum burst payload size in bytes))
signal DECODER_ENABLED: std_logic := '0';
-- decoder configuration
signal TC_DEC_BURST_PAYLOAD_SIZE: unsigned((NADDRBITS-1) downto 0) := (others => '0');
signal TC_C_BLOCK_SIZE: std_logic_vector(12 downto 0) := (others => '0');
signal TC_DEC_N_ITER: std_logic_vector(3 downto 0) := "0111";
signal TC_DEC_P : std_logic_vector(6 downto 0) := (others => '0');
signal TC_DEC_Q0 : std_logic_vector(3 downto 0) := (others => '0');
signal TC_DEC_Q1 : std_logic_vector(3 downto 0) := (others => '0');
signal TC_DEC_Q2 : std_logic_vector(3 downto 0) := (others => '0');
signal TC_DEC_Q3 : std_logic_vector(2 downto 0) := (others => '0');
signal TC_DEC_Y_PUNCTURING_PERIOD : std_logic_vector(4 downto 0) := (others => '0');
signal TC_DEC_Y_PUNCTURING_PATTERN : std_logic_vector(27 downto 0) := (others => '0');
signal TC_DEC_W_PUNCTURING_PATTERN : std_logic := '0';
signal UW1_PERIOD: unsigned(12 downto 0) := (others => '0');
signal TC_DEC_CRC16_EN : std_logic := '0';
signal TC_DEC_SYNC_RESET: std_logic := '0';

signal TDEC_DATA12: std_logic_vector(3 downto 0) := (others => '0');
signal TDEC_SAMPLE12_CLK: std_logic := '0';
signal TDEC_SOF12: std_logic := '0';
signal TDEC_SOF_LOCK_DETECT12: std_logic := '0';
signal TDEC_PHASE12: std_logic_vector(1 downto 0) := (others => '0');
signal TDEC_DATA_ENABLE12: std_logic := '0';
signal TDEC_BER12: std_logic_vector(16 downto 0) := (others => '0');
signal TP_MRC_SOF12: std_logic_vector(3 downto 0) := (others => '0');
-- reconstruct implied SOFs/EOFs, serial to parallel conversion
signal TC_C_BIT_CNTR: unsigned(12 downto 0) := (others => '0');
signal TC_C_BIT_CNTR_INC: unsigned(12 downto 0) := (others => '0');
signal TC_C_DATA: std_logic_vector(7 downto 0) := x"00";
signal TC_C_DATA_VALID: std_logic := '0';
signal TC_C_SOF: std_logic := '0';
signal TC_C_EOF: std_logic := '0';
signal TC_C_SOFEOF: std_logic_vector(1 downto 0) := "00";
-- Received data dual port RAM
signal TC_C_DATA2: std_logic_vector(7 downto 0) := (others => '0');
signal TC_C_DATA2_VALID_E: std_logic := '0';
signal TC_C_DATA2_VALID: std_logic := '0';
signal TC_C_SOFEOF2: std_logic_vector(1 downto 0) := "00";
signal TC_C_SOF2: std_logic := '0';
signal TC_C_EOF2: std_logic := '0';
signal TC_C_WPTR: unsigned(11 downto 0) := (others => '0');
signal TC_C_RPTR: unsigned(11 downto 0) := (others => '0');
signal TC_DEC_BUF_SIZE: unsigned(11 downto 0) := (others => '0');
signal TC_DEC_BUF_EMPTY: std_logic := '0';
signal TC_C_CTS: std_logic := '0';

signal TC_D_DATA: std_logic_vector(1 downto 0) := "00";
signal TC_D_DATA_VALID: std_logic := '0';
signal TC_D_DATA_VALID_D: std_logic := '0';
signal TC_D_SOF: std_logic := '0';
signal TC_D_CTS: std_logic := '0';
signal TC_D_CRC_VALID: std_logic := '0';
signal TC_D_BAD_CRC: std_logic := '0';
signal TC_D_FRAME_CNTR: std_logic_vector(31 downto 0) := (others => '0');
signal TC_D_FRAME_ERROR_CNTR: std_logic_vector(31 downto 0) := (others => '0');

signal RX_DATA1b2: std_logic := '0';
signal RX_SAMPLE1b2_CLK: std_logic := '0';
signal RX_SOF1b2: std_logic := '0';
signal RX_SAMPLE1b2_CLK_REQ: std_logic := '0';

--//-- BER MEASUREMENT  ---------------------------------------------------------
signal RX_DATA8b1: std_logic_vector(7 downto 0) := x"00";
signal RX_SAMPLE8b1_CLK: std_logic := '0';
signal BER_CONTROL: std_logic_vector(7 downto 0) := (others => '0');
signal BER_MF_DETECT: std_logic := '0';
signal BER_MF_DETECT_CONFIRMED: std_logic := '0';
signal BER_SYNC: std_logic := '0';
signal BER_BYTE_ERROR: std_logic := '0';
signal BER_ERROR_COUNT: std_logic_vector(31 downto 0) := (others => '0');
signal BER_TEST_POINT: std_logic_vector(10 downto 1) := (others => '0');

--//-- DNA Port ------------------------------------
signal DNA_ID_DATA: std_logic_vector(56 downto 0) := (others => '0');
signal DNA_ID_SAMPLE_CLK: std_logic := '0';

--// ARM co-processor interface
signal UC_WEBG: std_logic := '0';  -- WE# through global buffer
signal UC_REBG: std_logic := '0';	-- RE# through global buffer
signal UC_ADDRESS: unsigned(7 downto 0) := (others => '0');
signal UC_AD_local: std_logic_vector(7 downto 0) := (others => '0');
signal UC_RDN_D: std_logic := '0';
signal UC_RDN_D2: std_logic := '0';
signal CONFIG_CHANGE_TOGGLE: std_logic := '0';
signal CONFIG_CHANGE_TOGGLE_D: std_logic := '0';
signal CONFIG_CHANGE_TOGGLE_D2: std_logic := '0';
signal CONFIG_CHANGE_PULSE_CLK_P: std_logic := '0';
signal CONFIG_CHANGE_PULSE_CLK_P_D: std_logic := '0';
signal CONFIG_CHANGE_PULSE_CLK_P_D2: std_logic := '0';
signal UC_CONFIGURATION_DONE: std_logic := '0';
signal LAN_ADDR_CHANGE_TOGGLE: std_logic := '0';
signal LAN_ADDR_CHANGE_TOGGLE_D: std_logic := '0';
signal LAN_ADDR_CHANGE_TOGGLE_D2: std_logic := '0';
signal LAN_ADDR_CHANGE_PULSE: std_logic := '0';

--// Control Registers
constant NCREGS: integer := 27;	-- number of control registers.
constant NCREG_IMIN: integer := 0;	-- starting at this index
constant NCREG_IMAX: integer := (NCREG_IMIN+NCREGS-1);
type SLV8xNCREGStype is array (integer range NCREG_IMIN to NCREG_IMAX) of std_logic_vector(7 downto 0);
signal CREG: SLV8xNCREGStype;
signal REG255: std_logic_vector(7 downto 0) := (others => '0');
signal REG236: std_logic_vector(7 downto 0) := (others => '0');	-- MAC address LSB (to be defined at manufacturing)

--// Status Registers
constant NSREGS: integer := 25;	-- number of status registers.
constant NSREG_IMIN: integer := 7;	-- starting at this index
constant NSREG_IMAX: integer := (NSREG_IMIN+NSREGS-1);
type SLV8xNSREGStype is array (integer range NSREG_IMIN to NSREG_IMAX) of std_logic_vector(7 downto 0);
signal SREG: SLV8xNSREGStype := (others => (others => '0'));
signal SREG7_READ_TOGGLE: std_logic := '0';
signal SREG7_READ_TOGGLE_D: std_logic := '0';
signal SREG7_READ_TOGGLE_D2: std_logic := '0';
signal LATCH_MONITORING_PULSE: std_logic := '0';
signal SREG254_READ_TOGGLE: std_logic := '0';			
signal SREG254_READ_TOGGLE_D: std_logic := '0';
signal SREG254_READ_TOGGLE_D2: std_logic := '0';

--// ComScope control registers
--signal REG237: std_logic_vector(7 downto 0):= "00000000";
signal REG238: std_logic_vector(7 downto 0):= "00000000";
signal REG239: std_logic_vector(7 downto 0):= "00000000";
signal REG240: std_logic_vector(7 downto 0):= "00001101";	-- Trace 1 signal selection
signal REG241: std_logic_vector(7 downto 0):= "00000000";	-- Trigger position, decimation
signal REG242: std_logic_vector(7 downto 0):= "00001110";	-- Trace 2 signal selection
signal REG243: std_logic_vector(7 downto 0):= "00000000";	-- Trigger position, decimation
signal REG244: std_logic_vector(7 downto 0):= "00000000";	-- Trace 3 signal selection
signal REG245: std_logic_vector(7 downto 0):= "00000000";	-- Trigger position, decimation
signal REG246: std_logic_vector(7 downto 0):= "00000000";	-- Trace 4 signal selection
signal REG247: std_logic_vector(7 downto 0):= "00000000";	-- Trigger position, decimation
signal REG248: std_logic_vector(7 downto 0):= "10001101";	-- Trigger edge, trigger signal
signal REG249: std_logic_vector(7 downto 0):= "10111111";	-- Trigger threshold
signal SREG250: std_logic_vector(7 downto 0):= "00000000";
signal SREG251: std_logic_vector(7 downto 0):= "00000000";


--------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
begin
--// CLOCKS, RESET ---------------------
INTERNAL_FREQ_REF_001: if(SIMULATION = '1') generate
    process
    begin
        CLKREF_TCXOg <= '0';
        wait for 26.04 ns;
        CLKREF_TCXOg <= '1';
        wait for 26.04 ns;
    end process;
end generate;

INTERNAL_FREQ_REF_002: if(SIMULATION = '0') generate
    BUFG_001: BUFG port map(I => CLKREF_TCXO, O=> CLKREF_TCXOg);
end generate;

-- generate 10 MHz from 19.2 MHz VCTCXO
CLKGEN7C: CLKGEN7_MMCM_ADJ 
GENERIC MAP(
	CLKFBOUT_MULT_F => 50.000,
	  CLKOUT0_DIVIDE_F => 96.000,
	  CLKIN1_PERIOD => 52.083
 ) 
 PORT MAP(
	  CLK_IN1 => CLKREF_TCXOg,	-- 19.2 MHz TCXO clock 
	  CLK_OUT1 => CLK10,	-- 10 MHz not global
	  PHASE_SHIFT_VAL => x"00",	-- n/a here
	  PHASE_SHIFT_TRIGGER_TOGGLE => '0',
	  INPUT_CLK_STOPPED => CLKGEN7C_INPUT_CLK_STOPPED,
	  LOCKED => CLKGEN7C_LOCKED,
	  TP => open
 );

BUFG_003: BUFG port map (I => CLK10, O => CLK10g);

-- report presence/absence of VCTCXO clock
SREG(8)(0) <= not CLKGEN7C_INPUT_CLK_STOPPED;
-- report presence/absence of CLK_P processing clock
SREG(8)(1) <= CLKGEN7D_LOCKED;

-- generate 125 MHz processing clock from 10 MHz reference
CLKGEN7D: CLKGEN7_MMCM_ADJ 
GENERIC MAP(
	CLKFBOUT_MULT_F => 62.500,
	CLKOUT0_DIVIDE_F => 5.000,
	CLKIN1_PERIOD => 100.000
 ) 
PORT MAP(
	CLK_IN1 => CLK10g,	-- 10 MHz 
	CLK_OUT1 => CLK125_0,	-- 125 MHz not global
	PHASE_SHIFT_VAL => x"00",	-- n/a here
	PHASE_SHIFT_TRIGGER_TOGGLE => '0',
	INPUT_CLK_STOPPED => CLKGEN7D_INPUT_CLK_STOPPED,
	LOCKED => CLKGEN7D_LOCKED,
	TP => open
);

BUFG_002: BUFG port map(I => CLK125_0, O => CLK_P);

-- generate multiple offsets for the 125 MHz clock 
-- Includes several delayed versions for LAN PHY and DAC 
CLK25_RST <= not RESET_COUNTER(17);
  plle2_002 : PLLE2_ADV
generic map
 (BANDWIDTH            => "LOW",

  
  COMPENSATION         => "ZHOLD",
  DIVCLK_DIVIDE        => 1,
  CLKFBOUT_MULT        => 8,
  CLKFBOUT_PHASE       => 0.000,
  CLKOUT0_DIVIDE       => 8,	-- for LAN PHY 
  CLKOUT0_PHASE        => 22.5,	-- must be in the form 45deg*integer*125MHz/1GHz. 90deg = 2ns delay @125 MHz
  CLKOUT0_DUTY_CYCLE   => 0.500,
  CLKOUT1_DIVIDE       => 8,	-- for DAC clock (unused here)
  CLKOUT1_PHASE        => 45.0,	
  CLKOUT1_DUTY_CYCLE   => 0.500,
  CLKOUT2_DIVIDE       => 40,	-- for LAN PHY 25 MHz clock
  CLKOUT2_PHASE        => 0.0,	
  CLKOUT2_DUTY_CYCLE   => 0.500,
  CLKIN1_PERIOD        => 8.0)
port map
  -- Output clocks
 (
  CLKFBOUT            => CLK_P_FB,
  CLKOUT0             => CLK125_1,
  CLKOUT1             => CLK125_2,
  CLKOUT2             => CLK25,
  CLKOUT3             => open,
  CLKOUT4             => open,
  CLKOUT5             => open,
  -- Input clock control
  CLKFBIN             => CLK_P_FB,
  CLKIN1              => CLK_P,
  CLKIN2              => '0',
  -- Tied to always select the primary input clock
  CLKINSEL            => '1',
  -- Ports for dynamic reconfiguration
  DADDR               => (others => '0'),
  DCLK                => '0',
  DEN                 => '0',
  DI                  => (others => '0'),
  DO                  => open,
  DRDY                => open,
  DWE                 => '0',
  -- Other control and status signals
  LOCKED              => open,
  PWRDWN              => '0',
  RST                 => CLK25_RST
);
-- doubt: is the CLK125_1 signal propagation time nearly constant, or will it need to be compensated for every 
-- P&R? If so, maybe we should use a BUFG or BUFR to have more consistent timing control?





SREG(9)(1 downto 0) <= CLKGEN7D_LOCKED & CLKGEN7C_LOCKED;

 -- Generate miscellaneous global clocks and resets from the 
 -- reference 19.2 MHz clock (VCTCXO)
 RESET_STATE_MACHINE_001: process(CLKREF_TCXOg)
 begin
	  if rising_edge(CLKREF_TCXOG) then
			-- PLL need time to lock. The reset of the application is still in reset
			if(RESET_COUNTER(17) = '0') and (SIMULATION = '0') then
				 -- wait a bit before asserting the PLL lock
				 RESET_COUNTER <= RESET_COUNTER + 1;
			elsif(RESET_COUNTER(5) = '0') and (SIMULATION = '1') then  
				 -- make it short during simulations
				 -- wait a bit before asserting the PLL lock
				 RESET_COUNTER <= RESET_COUNTER + 1;
--			elsif(CLKGEN7C_LOCKED = '1') and (CLKGEN7D_LOCKED = '1') then
--				 -- assert the PLL lock
--				 RESET_STATE <= 1;
			else
				 -- above statement does not work. Unclear????
				 RESET_STATE <= 1;
			end if;
	  end if;
 end process;

 RESET_STATE_MACHINE_002: process(CLKREF_TCXOg)
 begin
	  if rising_edge(CLKREF_TCXOG) then
			if(RESET_STATE = 1) then
				 ASYNC_RESET <= '0';
			else
				 ASYNC_RESET <= '1';
			end if;
	  end if;
 end process;

-- generate a reset synchronous with CLK_P at the end of the ASYNC_RESET
SYNC_RESET_CLK_P_GEN: process(ASYNC_RESET, CLK_P)
begin
	if rising_edge(CLK_P) then
		ASYNC_RESET_D <= ASYNC_RESET;
		ASYNC_RESET_D2 <= ASYNC_RESET_D;
		
		if(ASYNC_RESET_D = '0') and (ASYNC_RESET_D2 = '1')  then
			SYNC_RESET_CLK_P <= '1';
		else
			SYNC_RESET_CLK_P <= '0';
		end if;
		
		-- '0' from power-up/async_reset until FPGA is ready
		if(SYNC_RESET_CLK_P = '1') then
			READY_FLAG_CLK_P <= '1';
		end if;
	end if;
end process;
READY_FLAG_CLK_Pn <= not READY_FLAG_CLK_P;

	-- external input clock
BUFG_006: BUFG  port map (I=> UC_WEB_IN, O=> UC_WEBG);	
	-- ARM WE#
BUFG_007: BUFG  port map (I=> UC_REB_IN, O=> UC_REBG);	
	-- ARM RE#


--//-- LEFT CONNECTOR INPUTS ----------------------------------
-- immediately reclock inputs
--BUFG_008: BUFG port map (I => LEFT_CONNECTOR_A(1), O => CLK_IN_LCg);
BUFR_001 : BUFR
generic map (
   BUFR_DIVIDE => "BYPASS",   -- Values: "BYPASS, 1, 2, 3, 4, 5, 6, 7, 8" 
   SIM_DEVICE => "7SERIES"  -- Must be set to "7SERIES" 
)
port map (
   O => CLK_IN_LCg,     -- 1-bit output: Clock output port
   CE => '1',   -- 1-bit input: Active high, clock enable (Divided modes only)
   CLR => '0', -- 1-bit input: Active high, asynchronous clear (Divided modes only)
   I => LEFT_CONNECTOR_A(1)      -- 1-bit input: Clock buffer input driven by an IBUF, MMCM or local interconnect
);

LC_RECLOCK_001: process(CLK_IN_LCg)
begin
	if rising_edge(CLK_IN_LCg) then
		LEFT_CONNECTOR_A_D(17 downto 2) <= LEFT_CONNECTOR_A(17 downto 2);
		LEFT_CONNECTOR_B_D(1) <= LEFT_CONNECTOR_B1(1);
		LEFT_CONNECTOR_B_D(11) <= LEFT_CONNECTOR_B2(11);
		LEFT_CONNECTOR_B_D(16) <= LEFT_CONNECTOR_B2(16);
	end if;
end process;

-- cross clock domain to CLK_P
CCD1_DATA_IN(3 downto 0) <= LEFT_CONNECTOR_A_D(5 downto 2);   -- 4-bit soft-quantized Coded  or 1-bit Uncoded
CROSS_CLK_DOMAINS_NODATALOSS_001: CROSS_CLK_DOMAINS_NODATALOSS PORT MAP(
	CLK_A => CLK_IN_LCg,
	CLK_B => CLK_P,
	ASYNC_RESET => ASYNC_RESET,
	DATA_IN => CCD1_DATA_IN,
	SAMPLE_CLK_IN => LEFT_CONNECTOR_B_D(1),
	SOF_IN => '0',
	EOF_IN => '0',
	SAMPLE_CLK_IN_REQ => LEFT_CONNECTOR_A(7),	-- CTS
	DATA_OUT => CCD1_DATA_OUT,
	SAMPLE_CLK_OUT => CCD1_SAMPLE_CLK_OUT,
	SOF_OUT => open,
	EOF_OUT => open,
	SAMPLE_CLK_OUT_REQ => CCD1_SAMPLE_CLK_OUT_REQ
);

CCD1_SAMPLE_CLK_OUT_REQ <= CCD1_SAMPLE_CLK_OUT_REQA or CCD1_SAMPLE_CLK_OUT_REQB;
	-- two possible input cases: to encoder or to decoder

--//-- LEFT CONNECTOR OUTPUTS ----------------------------------
ODDR_001 : ODDR
generic map(
	DDR_CLK_EDGE => "OPPOSITE_EDGE", -- "OPPOSITE_EDGE" or "SAME_EDGE" 
	INIT => '0',   -- Initial value for Q port ('1' or '0')
	SRTYPE => "SYNC") -- Reset Type ("ASYNC" or "SYNC")
port map (
	Q => LEFT_CONNECTOR_A(11),   -- 1-bit DDR output
	C => CLK_P,    -- 1-bit clock input
	CE => '1',  -- 1-bit clock enable input
	D1 => '1',  -- 1-bit data input (positive edge)
	D2 => '0',  -- 1-bit data input (negative edge)
	R => '0',    -- 1-bit reset input
	S => '0'     -- 1-bit set input
);

LC_OUT_001: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if (SYNC_RESET_CLK_P = '1') then
			LEFT_CONNECTOR_B2(11) <= '0';
			LEFT_CONNECTOR_A(12) <= '0';
			LEFT_CONNECTOR_B2(16) <= '0';
		elsif(unsigned(CREG(0)(5 downto 4)) = 0) then
			-- encoder output to left connector J4
			LEFT_CONNECTOR_B2(11) <= TX_SAMPLE1b1_CLK;
			LEFT_CONNECTOR_A(12) <= TX_DATA1b1;
			LEFT_CONNECTOR_B2(16) <= TX_SOF1b1;
		elsif(unsigned(CREG(5)(5 downto 4)) = 0) then
			-- decoder output to left connector J4
			LEFT_CONNECTOR_B2(11) <= RX_SAMPLE1b2_CLK;
			LEFT_CONNECTOR_A(12) <= RX_DATA1b2;
			LEFT_CONNECTOR_B2(16) <= RX_SOF1b2;
		else
			LEFT_CONNECTOR_B2(11) <= '0';
			LEFT_CONNECTOR_B2(16) <= '0';
		end if;
	end if;
end process;
LEFT_CONNECTOR_A(5 downto 1) <= (others => 'Z');
LEFT_CONNECTOR_A(17) <= 'Z';
LEFT_CONNECTOR_B1(1) <= 'Z';

--//-- RIGHT CONNECTOR INPUTS ----------------------------------
-- immediately reclock inputs
BUFR_002 : BUFR
generic map (
   BUFR_DIVIDE => "BYPASS",   -- Values: "BYPASS, 1, 2, 3, 4, 5, 6, 7, 8" 
   SIM_DEVICE => "7SERIES"  -- Must be set to "7SERIES" 
)
port map (
   O => CLK_IN_RCg,     -- 1-bit output: Clock output port
   CE => '1',   -- 1-bit input: Active high, clock enable (Divided modes only)
   CLR => '0', -- 1-bit input: Active high, asynchronous clear (Divided modes only)
   I => RIGHT_CONNECTOR_A(11)      -- 1-bit input: Clock buffer input driven by an IBUF, MMCM or local interconnect
);

RC_RECLOCK_001: process(CLK_IN_RCg)
begin
	if rising_edge(CLK_IN_RCg) then
		RIGHT_CONNECTOR_A_D(15 downto 12) <= RIGHT_CONNECTOR_A(15 downto 12);
		RIGHT_CONNECTOR_B_D(11) <= RIGHT_CONNECTOR_B2(11);
	end if;
end process;

-- cross clock domain to CLK_P
CCD2_DATA_IN(3 downto 0) <= RIGHT_CONNECTOR_A_D(15 downto 12);   -- 4-bit soft-quantized Coded  or 1-bit Uncoded
CROSS_CLK_DOMAINS_NODATALOSS_002: CROSS_CLK_DOMAINS_NODATALOSS PORT MAP(
	CLK_A => CLK_IN_RCg,
	CLK_B => CLK_P,
	ASYNC_RESET => ASYNC_RESET,
	DATA_IN => CCD2_DATA_IN,
	SAMPLE_CLK_IN => RIGHT_CONNECTOR_B_D(11),
	SOF_IN => '0',
	EOF_IN => '0',
	SAMPLE_CLK_IN_REQ => RIGHT_CONNECTOR_A(17),	-- CTS
	DATA_OUT => CCD2_DATA_OUT,
	SAMPLE_CLK_OUT => CCD2_SAMPLE_CLK_OUT,
	SOF_OUT => open,
	EOF_OUT => open,
	SAMPLE_CLK_OUT_REQ => CCD2_SAMPLE_CLK_OUT_REQ
);

CCD2_SAMPLE_CLK_OUT_REQ <= CCD2_SAMPLE_CLK_OUT_REQA or CCD2_SAMPLE_CLK_OUT_REQB;
	-- two possible input cases: to encoder or to decoder


--//-- RIGHT CONNECTOR OUTPUTS ----------------------------------
ODDR_002 : ODDR
generic map(
	DDR_CLK_EDGE => "OPPOSITE_EDGE", -- "OPPOSITE_EDGE" or "SAME_EDGE" 
	INIT => '0',   -- Initial value for Q port ('1' or '0')
	SRTYPE => "SYNC") -- Reset Type ("ASYNC" or "SYNC")
port map (
	Q => RIGHT_CONNECTOR_A(1),   -- 1-bit DDR output
	C => CLK_P,    -- 1-bit clock input
	CE => '1',  -- 1-bit clock enable input
	D1 => '1',  -- 1-bit data input (positive edge)
	D2 => '0',  -- 1-bit data input (negative edge)
	R => '0',    -- 1-bit reset input
	S => '0'     -- 1-bit set input
);

RC_OUT_001: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if (SYNC_RESET_CLK_P = '1') then
			RIGHT_CONNECTOR_B1(1) <= '0';
			RIGHT_CONNECTOR_A(2) <= '0';
			RIGHT_CONNECTOR_B2(6) <= '0';
		elsif(unsigned(CREG(0)(5 downto 4)) = 1) then
			-- encoder output to right connector J8
			RIGHT_CONNECTOR_B1(1) <= TX_SAMPLE1b1_CLK;
			RIGHT_CONNECTOR_A(2) <= TX_DATA1b1;
			RIGHT_CONNECTOR_B2(6) <= TX_SOF1b1;
		elsif(unsigned(CREG(5)(5 downto 4)) = 1) then
			-- decoder output to right connector J8
			RIGHT_CONNECTOR_B1(1) <= RX_SAMPLE1b2_CLK;
			RIGHT_CONNECTOR_A(2) <= RX_DATA1b2;
			RIGHT_CONNECTOR_B2(6) <= RX_SOF1b2;
		else
			RIGHT_CONNECTOR_B1(1) <= '0';
			RIGHT_CONNECTOR_B2(6) <= '0';
		end if;
	end if;
end process;
RIGHT_CONNECTOR_A(7) <= 'Z';
RIGHT_CONNECTOR_A(15 downto 11) <= (others => 'Z');
RIGHT_CONNECTOR_B2(11) <= 'Z';

--//-- GbE LAN ----------------------------------
-- Interface with on-board GbE PHY: Micrel KSZ9031
-- Support 10/100/1000 Ethernet LAN.
-- Note: COM-1800 hardware rev 0 and 1 are limited to 100 Mbps unless the 25 MHz MEMS oscillator is replaced with
-- a low-jitter crystal-based oscillator (done in hw rev2)
CLK_SKEW21 <= x"0310"; 	 --(INTERNAL_PHY_CLKS_DELAYS => '0')
CLK_SKEW22 <= x"0000";    -- future	

-- new: MAC address automatically generated from unique DNA_ID
LAN1_MAC_ADDR <= x"02" & DNA_ID_DATA(31 downto 0) & REG236(7 downto 1) & "0";    -- possible race condition: ARM vs DNA_ID?
LAN_001: COM5401 
GENERIC MAP(
	MII_SEL => '0',   	   -- select which MII interface: 0 = RGMII, 1 = GMII/MII
	PHY_ADDR => "00111",   -- PHY_AD0/1 pulled-up, PHY_AD2 pulled-up in .xdc file.
	CLK_FREQUENCY => CLK_FREQUENCY,
	PLATFORM => 7,	       -- 7 series Xilinx FPGA
	TARGET_PHY => 3,       -- target PHY: KSZ9031
	NO_1000 => '0',	-- advertize full 10/100/1000 Mbps
	INTERNAL_PHY_TX_CLKS_DELAYS => '0',
	INTERNAL_PHY_RX_CLKS_DELAYS => '0',
	SIMULATION => SIMULATION
)
PORT MAP(
	CLK => CLK_P,
	SYNC_RESET => READY_FLAG_CLK_Pn,	-- new 12/9/15 more reliable start
	CLK125_0 => CLK_P,
	CLK125_1 => CLK125_1,
	CLK25 => CLK25,
	MAC_TX_CONFIG => X"0003",	-- MAC must must provide pad + crc32
	MAC_RX_CONFIG => x"000F",	-- promiscuous mode, strip crc32, accept broadcast/multicast
	MAC_ADDR => LAN1_MAC_ADDR,
	PHY_CONFIG_CHANGE => LAN_ADDR_CHANGE_PULSE,		-- *080416
	PHY_RESET => '0',
	SPEED => "11",	-- supersedes defaults within if PHY_CONFIG_CHANGE = '1'
	DUPLEX => '1',	-- supersedes defaults within if PHY_CONFIG_CHANGE = '1'
	TEST_MODE => "00",	-- supersedes defaults within if PHY_CONFIG_CHANGE = '1'
	POWER_DOWN => '0', -- supersedes defaults within if PHY_CONFIG_CHANGE = '1'
	CLK_SKEW1 => CLK_SKEW21, -- supersedes defaults within if PHY_CONFIG_CHANGE = '1'
	CLK_SKEW2 => CLK_SKEW22, -- supersedes defaults within if PHY_CONFIG_CHANGE = '1'
	MAC_TX_DATA => LAN1_MAC_TX_DATA,
	MAC_TX_DATA_VALID => LAN1_MAC_TX_DATA_VALID,
	MAC_TX_EOF => LAN1_MAC_TX_EOF,
	MAC_TX_CTS => LAN1_MAC_TX_CTS,
	MAC_RX_DATA => LAN1_MAC_RX_DATA,	
	MAC_RX_DATA_VALID => LAN1_MAC_RX_DATA_VALID,
	MAC_RX_SOF => LAN1_MAC_RX_SOF,
	MAC_RX_EOF => LAN1_MAC_RX_EOF,
	MAC_RX_CTS => '1',  -- follow-on processing is expected to always accept data even at max speed.
	-- RGMII interface ----------------
	TXC => LAN_TXC,	
	TXD => LAN_TXD,
	TX_CTL => LAN_TX_CTL,
	RXC => LAN_RXC,
	RXD => LAN_RXD,
	RX_CTL => LAN_RX_CTL,
	RESET_N => LAN_RESET_N,
	MCLK => LAN_MCLK,
	MDIO => LAN_MDIO,	
	-- end of RGMII interface --------
	MII_TX_CLK => '0',	-- MII interface is unused -----
	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 => LAN1_LINK_STATUS,
	SPEED_STATUS => LAN1_SPEED_STATUS,
	DUPLEX_STATUS => LAN1_DUPLEX_STATUS,
	PHY_ID => LAN1_PHY_ID,
	N_RX_FRAMES => LAN1_N_RX_FRAMES,
	N_RX_BAD_CRCS => LAN1_N_RX_BAD_CRCS,
	N_RX_FRAMES_TOO_SHORT => LAN1_N_RX_FRAMES_TOO_SHORT,
	N_RX_FRAMES_TOO_LONG => LAN1_N_RX_FRAMES_TOO_LONG,
	N_RX_WRONG_ADDR => LAN1_N_RX_WRONG_ADDR,
	N_RX_LENGTH_ERRORS => LAN1_N_RX_LENGTH_ERRORS,
	CS_CLKG => open,
	CS1 => open,
	CS1_CLK => open,
	CS2 => open,
	CS2_CLK => open,
	CT1 => open,
	CT1_CLK => open,
	TP => LAN1_TP
);

-- report LAN PHY ID (should be x22)
SREG(7) <= LAN1_PHY_ID(7 downto 0);

-- monitoring
MONITORING_001: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(LATCH_MONITORING_PULSE = '1') then
			-- latch in multi-byte status registers upon reading status register SREG7
			-- report bad LAN CRCs
			SREG(9) <= LAN1_N_RX_BAD_CRCS(7 downto 0);
			SREG(10) <= LAN1_N_RX_BAD_CRCS(15 downto 8);
			-- report MAC address
			SREG(11) <= LAN1_MAC_ADDR(47 downto 40);
			SREG(12) <= LAN1_MAC_ADDR(39 downto 32);
			SREG(13) <= LAN1_MAC_ADDR(31 downto 24);
			SREG(14) <= LAN1_MAC_ADDR(23 downto 16);
			SREG(15) <= LAN1_MAC_ADDR(15 downto 8);
			SREG(16) <= LAN1_MAC_ADDR(7 downto 0);
		end if;
	end if;
end process;

---- fake input (to prevent optimization out). We need the pu/pd in .xdc
--SREG36(6) <= LAN_CLK125;

--//-- IP STACK, TCP SERVER -----------------------------------
-- reclock with CLK_P for easier P&R
-- 2 TCP connections: port 1028 for M&C, port 1024 for payload data
-- 1 UDP rx: port 1029 for M&C
RECLOCK_IP1: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(CONFIG_CHANGE_PULSE_CLK_P = '1') then
			IP1_ADDRv4(31 downto 0) <= CREG(14) & CREG(15) & CREG(16) & CREG(17);	-- local IP address
			SUBNET_MASK(31 downto 0) <= CREG(18) & CREG(19) & CREG(20) & CREG(21);	-- local IP address
			GATEWAY_IP_ADDR(31 downto 0) <= CREG(22) & CREG(23) & CREG(24) & CREG(25);	-- local IP address
		end if;
	end if;
end process;

IPSTACK_001: COM5402 
GENERIC MAP(
		NUDPTX => 0,
		NUDPRX => 1,
		NTCPSTREAMS => NTCPSTREAMS1,  
		CLK_FREQUENCY => CLK_FREQUENCY,	-- CLK_P 125 MHz, as time reference
		TX_IDLE_TIMEOUT => 50,	-- 50*4us = 200us 
		SIMULATION => SIMULATION
)
PORT MAP(
	CLK => CLK_P,
	SYNC_RESET => READY_FLAG_CLK_Pn,	
	MAC_ADDR => LAN1_MAC_ADDR,
	IPv4_ADDR => IP1_ADDRv4,
	IPv6_ADDR => x"00000000000000000000000000000000",
	MULTICAST_IP_ADDR => x"00000000",	-- n/a
	SUBNET_MASK => SUBNET_MASK,
	GATEWAY_IP_ADDR => GATEWAY_IP_ADDR,
	CONNECTION_RESET => "00",
	-- MAC interface
	MAC_TX_DATA => LAN1_MAC_TX_DATA,
	MAC_TX_DATA_VALID => LAN1_MAC_TX_DATA_VALID,
	MAC_TX_SOF => open,
	MAC_TX_EOF => LAN1_MAC_TX_EOF,
	MAC_TX_CTS => LAN1_MAC_TX_CTS,
	MAC_RX_DATA => LAN1_MAC_RX_DATA,
	MAC_RX_DATA_VALID => LAN1_MAC_RX_DATA_VALID,
	MAC_RX_SOF => LAN1_MAC_RX_SOF,
	MAC_RX_EOF => LAN1_MAC_RX_EOF,
	-- UDP rx
	UDP_RX_DATA => LAN1_UDP_RX_DATA, 
	UDP_RX_DATA_VALID => LAN1_UDP_RX_DATA_VALID, 
	UDP_RX_SOF => LAN1_UDP_RX_SOF, 
	UDP_RX_EOF => LAN1_UDP_RX_EOF, 
	UDP_RX_DEST_PORT_NO_IN => x"0405",	-- port 1029: M&C backdoor (reset, etc)
	CHECK_UDP_RX_DEST_PORT_NO => '1',
	UDP_RX_DEST_PORT_NO_OUT => open,
	-- 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 port 1028: M&C
	-- TCP port 1024: payload data
	TCP_RX_DATA => LAN1_TCP_RX_DATA,	
	TCP_RX_DATA_VALID => LAN1_TCP_RX_DATA_VALID,
	TCP_RX_RTS => open,
	TCP_RX_CTS => LAN1_TCP_RX_CTS,	
	-- TCP tx streams
	TCP_TX_DATA => LAN1_TCP_TX_DATA,
	TCP_TX_DATA_VALID => LAN1_TCP_TX_DATA_VALID,
	TCP_TX_CTS => LAN1_TCP_TX_CTS,	-- not connected
	-- Monitoring
	TCP_CONNECTED_FLAG => LAN1_TCP_CONNECTED_FLAG,
--	CS1 => S1_1,
--	CS1_CLK => S1_1_CLK,
--	CS2 => S2_1,
--	CS2_CLK => S2_1_CLK,
	TP => IPSTACK1_TP	
);

-- main taks is to reject bad UDP frames
PACKETS_2_STREAM_002: PACKETS_2_STREAM 
GENERIC MAP(
		NBUFS => 1    
)
PORT MAP(
    CLK => CLK_P,
    ASYNC_RESET => ASYNC_RESET,
    PACKET_DATA_IN => LAN1_UDP_RX_DATA,
    PACKET_DATA_VALID_IN => LAN1_UDP_RX_DATA_VALID,
    PACKET_EOF_IN => LAN1_UDP_RX_EOF,
    PACKET_CTS_OUT => open, -- no flow control here
    STREAM_DATA_OUT => LAN1_UDP_RX_DATA2,
    STREAM_DATA_VALID_OUT => LAN1_UDP_RX_DATA2_VALID,
    STREAM_SOF_OUT => open, 
    STREAM_EOF_OUT => open,
    STREAM_CTS_IN => LAN1_TCP_RX_CTS(0),
    BAD_PACKET => open,
    TP => open
);

-- one elastic buffer for each tcp rx stream
-- M&C, TCP port 1028 (port is defined within COM5402 component) OR UDP port 1029 
LAN1_RX_DATA0 <= LAN1_UDP_RX_DATA2 when (LAN1_UDP_RX_DATA2_VALID = '1') else LAN1_TCP_RX_DATA(0);
LAN1_RX_SAMPLE0_CLK <= LAN1_UDP_RX_DATA2_VALID or LAN1_TCP_RX_DATA_VALID(0);

ELASTIC_BUFFER_NRAMB2_001: ELASTIC_BUFFER_NRAMB2 
generic map(
	DATA_WIDTH => 8,
	ADDR_WIDTH => 11,	-- 16Kb buffer 
	READ_AHEAD_1ADDRESS => '1'	-- no read latency, tricky timing ok because ARM is slower.
)
PORT MAP(
	CLK => CLK_P,
	SYNC_RESET => READY_FLAG_CLK_Pn,
	DATA_IN => LAN1_RX_DATA0,
	SAMPLE_CLK_IN => LAN1_RX_SAMPLE0_CLK,
	SAMPLE_CLK_IN_REQ => LAN1_TCP_RX_CTS(0),
	DATA_OUT => RX_LAN,	
	SAMPLE_CLK_OUT => open,
	SAMPLE_CLK_OUT_E => EB1_SAMPLE_CLK_OUT_E,	-- unused
	SAMPLE_CLK_OUT_REQ => RX_LAN_SAMPLE_CLK_REQ,
	BUFFER_EMPTY => RX_LAN_BUFFER_EMPTY,
	USED => open
);

-- serialize 8-bit parallel input from TCP server @ port 1024
P8_TO_S1_CONVERSION_001: P8_TO_S1_CONVERSION PORT MAP(
	CLK => CLK_P,
	SYNC_RESET =>  READY_FLAG_CLK_Pn,
	DATA8_IN => LAN1_TCP_RX_DATA(1),
	SAMPLE8_CLK_IN => LAN1_TCP_RX_DATA_VALID(1),
	SAMPLE8_CLK_IN_REQ => LAN1_TCP_RX_CTS(1),
	DATA1_OUT => TCP_RX_DATA1b1,
	SAMPLE1_CLK_OUT => TCP_RX_SAMPLE1b1_CLK,
	SAMPLE1_CLK_OUT_REQ => TCP_RX_SAMPLE1b1_CLK_REQ,
	BUF_EMPTY => open
);


--//-- PRBS-11 TEST SEQUENCE ----------------------------------
LFSR11C_001: LFSR11C PORT MAP(
	CLK => CLK_P,
	SYNC_RESET => READY_FLAG_CLK_Pn,
	BIT_CLK_REQ => PRBS11_SAMPLE_CLK_REQ,
	SEED => "00000000000",
	LFSR_BIT => PRBS11_BIT,
	BIT_CLK_OUT => PRBS11_SAMPLE_CLK,
	SOF_OUT => PRBS11_SOF,
	LFSR_REG_OUT => open
);

--//-- 0-255 COUNTING TEST SEQUENCE ----------------------------------
TEST_COUNT_SEQ8b_GEN_001: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(READY_FLAG_CLK_P = '0') then
			TEST_COUNT_SEQ8b <= (others => '0');
			TEST_COUNT_SEQ8b_VALID <= '0';
		elsif(TEST_COUNT_SEQ8b_CTS = '1') then
			TEST_COUNT_SEQ8b <= TEST_COUNT_SEQ8b + 1;
			TEST_COUNT_SEQ8b_VALID <= '1';
		else
			TEST_COUNT_SEQ8b_VALID <= '0';
		end if;
	end if;
end process;
 
P8_TO_S1_CONVERSION_002: P8_TO_S1_CONVERSION PORT MAP(
	CLK => CLK_P,
	SYNC_RESET => READY_FLAG_CLK_Pn,
	DATA8_IN => std_logic_vector(TEST_COUNT_SEQ8b),
	SAMPLE8_CLK_IN => TEST_COUNT_SEQ8b_VALID,
	SAMPLE8_CLK_IN_REQ => TEST_COUNT_SEQ8b_CTS,
	DATA1_OUT => TEST_COUNT_SEQ1b,
	SAMPLE1_CLK_OUT => TEST_COUNT_SEQ1b_VALID,
	SAMPLE1_CLK_OUT_REQ => TEST_COUNT_SEQ1b_CTS,
	BUF_EMPTY => open
);
 
--// TC ENCODER SOURCE SELECTION -------------------------
CCD1_SAMPLE_CLK_OUT_REQA <= ENC_SAMPLE_CLK_IN_REQB when (unsigned(CREG(0)(2 downto 0)) = 1) else '0'; -- clock synchronous J4 left connector
CCD2_SAMPLE_CLK_OUT_REQA <= ENC_SAMPLE_CLK_IN_REQB when (unsigned(CREG(0)(2 downto 0)) = 2) else '0'; -- clock synchronous J8 right connector
TCP_RX_SAMPLE1b1_CLK_REQ <= ENC_SAMPLE_CLK_IN_REQB when (unsigned(CREG(0)(2 downto 0)) = 3) else '0';	-- TCP-IP server port 1024
PRBS11_SAMPLE_CLK_REQ <= ENC_SAMPLE_CLK_IN_REQB when (unsigned(CREG(0)(2 downto 0)) = 4) else '0';	-- internal PRBS-11 test sequence
TEST_COUNT_SEQ1b_CTS <= ENC_SAMPLE_CLK_IN_REQB when (unsigned(CREG(0)(2 downto 0)) = 5) else '0';	-- internal test counting sequence

ENCODER_ENABLED_001: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(READY_FLAG_CLK_P = '0') or (unsigned(CREG(0)(2 downto 0)) = 0) then
			-- reset or encoder bypassed
			ENCODER_ENABLED <= '0';
		else
			ENCODER_ENABLED <= '1';
		end if;
	end if;
end process;

ENC_INPUT_SEL: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(READY_FLAG_CLK_P = '0') then
			ENC_DATA_IN <= '0';
			ENC_SAMPLE_CLK_IN <= '0';
		else
			case CREG(0)(2 downto 0)  is
				when "001" => 	-- clock synchronous J4 left connector
					ENC_DATA_IN <= CCD1_DATA_OUT(0);	-- DATA_U_IN
					ENC_SAMPLE_CLK_IN <= CCD1_SAMPLE_CLK_OUT;
				when "010" => 	-- clock synchronous J8 right connector
					ENC_DATA_IN <= CCD2_DATA_OUT(0);	-- DATA_U_IN
					ENC_SAMPLE_CLK_IN <= CCD2_SAMPLE_CLK_OUT;
				when "011" => 	-- TCP-IP server port 1024
					ENC_DATA_IN <= TCP_RX_DATA1b1;
					ENC_SAMPLE_CLK_IN <= TCP_RX_SAMPLE1b1_CLK;
				when "100" => 	-- internal PRBS-11 test sequence
					ENC_DATA_IN <= PRBS11_BIT;
					ENC_SAMPLE_CLK_IN <= PRBS11_SAMPLE_CLK;
				when "101" => 	-- internal 0-255 count test sequence
					ENC_DATA_IN <= TEST_COUNT_SEQ1b;
					ENC_SAMPLE_CLK_IN <= TEST_COUNT_SEQ1b_VALID;
				when others => 	
					ENC_DATA_IN <= '0';
					ENC_SAMPLE_CLK_IN <= '0';
			end case;
		end if;
	end if;
end process;

-- flow control when encoder is enabled/bypassed
ENC_SAMPLE_CLK_IN_REQB <= ENC_SAMPLE_CLK_IN_REQ when (ENCODER_ENABLED = '1') else TX_SAMPLE1b1_CLK_REQ;


--// TURBO CODE ENCODER -----------------------------------------------------------
-- For most applications, there is only one configuration parameter: 
-- 1. Rate R1/R2

-- encoder configuration
TC_ENC_CONFIG_001: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		TC_ENC_SYNC_RESET <= READY_FLAG_CLK_Pn or CONFIG_CHANGE_PULSE_CLK_P;
		
		TC_ENC_BURST_PAYLOAD_SIZE <= CREG(1);
			-- Although the code is capable of going to 8000 bit payload,
			-- we limit size to <256 bytes to keep decoder size reasonably small
			-- Additional constraints in selecting the configuration: payload size must not be a multiple of 15 bytes.
			-- Payload size must be an integer multiple of the puncturing period.
		case CREG(2)(3 downto 0) is
			when "0000" => TC_ENC_R1 <= "001"; TC_ENC_R2 <= "0011";	-- rate 1/3
			when "0001" => TC_ENC_R1 <= "001"; TC_ENC_R2 <= "0010";	-- rate 1/2
			when "0010" => TC_ENC_R1 <= "010"; TC_ENC_R2 <= "0011";	-- rate 2/3
			when "0011" => TC_ENC_R1 <= "011"; TC_ENC_R2 <= "0100";	-- rate 3/4
			when "0100" => TC_ENC_R1 <= "100"; TC_ENC_R2 <= "0101";	-- rate 4/5
			when "0101" => TC_ENC_R1 <= "101"; TC_ENC_R2 <= "0110";	-- rate 5/6
			when "0110" => TC_ENC_R1 <= "110"; TC_ENC_R2 <= "0111";	-- rate 6/7
			when others => TC_ENC_R1 <= "111"; TC_ENC_R2 <= "1000";	-- rate 7/8
		end case;
		TC_E_BLOCK_SIZE <= CREG(4)(6 downto 0) & CREG(3);
			-- encoded block size in bits. Includes optional CRC16 but does not include unique word
		TC_ENC_CRC16_EN <= CREG(2)(7);
			-- optional insertion of 16-bit CRC
	end if;
end process;
TC_ENC_BURST_PAYLOAD_SIZEx <= "00" & TC_ENC_BURST_PAYLOAD_SIZE;

TC_ENC_CONFIG_002: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(unsigned(CREG(2)(3 downto 0)) = 0) then
			-- Rate 1/3. Only case when W parity bit is enabled
			TC_ENC_W_PUNCTURING_PATTERN <= '1';
		else
			TC_ENC_W_PUNCTURING_PATTERN <= '0';
		end if;
		
		case CREG(2)(3 downto 0) is
			when "0000" => -- rate 1/3
				TC_ENC_Y_PUNCTURING_PERIOD <= "00001";	-- 1
				TC_ENC_Y_PUNCTURING_PATTERN <= "0000000000000000000000000001";  -- flipped punct. pattern.
			when "0001" => -- rate 1/2
				TC_ENC_Y_PUNCTURING_PERIOD <= "00001";	-- 1
				TC_ENC_Y_PUNCTURING_PATTERN <= "0000000000000000000000000001";  -- flipped punct. pattern.
			when "0010" => -- rate 2/3
				TC_ENC_Y_PUNCTURING_PERIOD <= "00010";	-- 2
				TC_ENC_Y_PUNCTURING_PATTERN <= "0000000000000000000000000001";  -- flipped punct. pattern.
			when "0011" => -- rate 3/4
				TC_ENC_Y_PUNCTURING_PERIOD <= "00110";	-- 6
				TC_ENC_Y_PUNCTURING_PATTERN <= "0000000000000000000000000101";  -- flipped punct. pattern.
			when "0100" => -- rate 4/5
				TC_ENC_Y_PUNCTURING_PERIOD <= "00100";	-- 4
				TC_ENC_Y_PUNCTURING_PATTERN <= "0000000000000000000000000001";  -- flipped punct. pattern.
			when "0101" => -- rate 5/6
				TC_ENC_Y_PUNCTURING_PERIOD <= "10100";	-- 20
				TC_ENC_Y_PUNCTURING_PATTERN <= "0000000000000001000100010001";  -- flipped punct. pattern.
			when "0110" => -- rate 6/7
				TC_ENC_Y_PUNCTURING_PERIOD <= "01100";	-- 12
				TC_ENC_Y_PUNCTURING_PATTERN <= "0000000000000000000000010001";  -- flipped punct. pattern.
			when others => -- rate 7/8
				TC_ENC_Y_PUNCTURING_PERIOD <= "11100";	-- 28
				TC_ENC_Y_PUNCTURING_PATTERN <= "0000000100000001000000010001";  -- flipped punct. pattern.
		end case;
	end if;
end process;

TC_ENC_N(9 downto 2) <= unsigned(TC_ENC_BURST_PAYLOAD_SIZE);
TC_ENC_N(1 downto 0) <= "00";	-- number of N couples (K/2)
TC_ENC_P <= "0100101";
TC_ENC_Q0 <= "0000";
TC_ENC_Q1 <= "0010";
TC_ENC_Q2 <= "0000";
TC_ENC_Q3 <= "010";

-- safe coding. Add a small elastic buffer to ensure proper gap between successive frames
-- when the source is slow in responding to the clear-to-send flow control signal
ELASTIC_BUFFER16b_001: ELASTIC_BUFFER16b PORT MAP(
	CLK => CLK_P,
	SYNC_RESET => READY_FLAG_CLK_Pn,
	DATA_IN => ENC_DATA_IN,
	SAMPLE_CLK_IN => ENC_SAMPLE_CLK_IN,
	SAMPLE_CLK_IN_REQ => ENC_SAMPLE_CLK_IN_REQ,
	DATA_OUT => ENC_DATA_IN2,
	SAMPLE_CLK_OUT => ENC_SAMPLE_CLK_IN2,
	SAMPLE_CLK_OUT_REQ => ENC_SAMPLE_CLK_IN2_REQ
);
ENC_SAMPLE_CLK_IN2_REQ <= TC_U_CTS when (TC_U_EOF = '0') and (TC_U_EOF_E = '0') else '0';

-- 1-bit serial to 2-bit parallel conversion
TC_U_EOF_E <= '1' when (ENC_SAMPLE_CLK_IN2 = '1') and (TC_ENC_CNTR(TC_ENC_CNTR'left downto 1) = TC_ENC_N-1) and (TC_ENC_CNTR(0) = '1') else '0';
CNTR_GEN: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(READY_FLAG_CLK_P = '0') then
			TC_ENC_CNTR <= (others => '0');
			TC_U_DATA_VALID <= '0';
			TC_U_SOF <= '0';
			TC_U_EOF <= '0';
		elsif(ENC_SAMPLE_CLK_IN2 = '1') then
			TC_ENC_CNTR <= TC_ENC_CNTR + 1;
			TC_U_DATA(0) <= TC_U_DATA(1);		-- A
			TC_U_DATA(1) <= ENC_DATA_IN2;		-- B
				-- ENC_DATA_IN2 sequence is A0, B0, A1, B1, etc
			
			if(TC_ENC_CNTR(TC_ENC_CNTR'left downto 1) < TC_ENC_N) and (TC_ENC_CNTR(0) = '1') then
				TC_U_DATA_VALID <= '1';
			else
				TC_U_DATA_VALID <= '0';
			end if;
			if(TC_ENC_CNTR(TC_ENC_CNTR'left downto 1) = 0) and (TC_ENC_CNTR(0) = '1') then
				TC_U_SOF <= '1';
			else
				TC_U_SOF <= '0';
			end if;
			if(TC_ENC_CNTR(TC_ENC_CNTR'left downto 1) = TC_ENC_N-1) and (TC_ENC_CNTR(0) = '1') then
				TC_U_EOF <= '1';
				TC_ENC_CNTR <= (others => '0');
			else
				TC_U_EOF <= '0';
			end if;
		else
			TC_U_DATA_VALID <= '0';
			TC_U_SOF <= '0';
			TC_U_EOF <= '0';
		end if;	
	end if;
end process;

TC_ENCODER_DVB_RCS2_001: TC_ENCODER_DVB_RCS2 
GENERIC MAP	(
	SIMULATION => SIMULATION
)
PORT MAP(
	CLK => CLK_P,
	SYNC_RESET => TC_ENC_SYNC_RESET,
	DATA_IN => TC_U_DATA,
	DATA_IN_VALID => TC_U_DATA_VALID,
	SOF_IN => TC_U_SOF,
	CTS_OUT => TC_U_CTS,
	BURST_PAYLOAD_SIZE => TC_ENC_BURST_PAYLOAD_SIZEx,
	R1 => TC_ENC_R1,
	R2 => TC_ENC_R2,
	P => TC_ENC_P,
	Q0 => TC_ENC_Q0,
	Q1 => TC_ENC_Q1,
	Q2 => TC_ENC_Q2,
	Q3 => TC_ENC_Q3,
	Y_PUNCTURING_PERIOD => TC_ENC_Y_PUNCTURING_PERIOD,
	Y_PUNCTURING_PATTERN => TC_ENC_Y_PUNCTURING_PATTERN,
	W_PUNCTURING_PATTERN => TC_ENC_W_PUNCTURING_PATTERN,
	CRC16_EN => TC_ENC_CRC16_EN,
	DATA_OUT => TC_E_DATA,
	DATA_OUT_VALID => TC_E_DATA_VALID, 
	SOF_OUT => TC_E_SOF, 
	EOF_OUT => TC_E_EOF, 
	CTS_IN => TC_E_CTS,
	N_PARITY_BITS => TC_ENC_N_PARITY_BITS,
	N_PARITY_BITS_RDY => TC_ENC_N_PARITY_BITS_RDY,
	TP => TC_TP
);

--//-- INSERT SYNC WORD ------------------------------
TC_E_CTS <= '1' when (UW_GEN_STATE = 2) and (TX_SAMPLE1b1_CLK_REQ = '1') and (TC_E_CTS_D = '0') and (TC_E_EOF = '0') else '0';
	-- encoder output flow control. Insert a 1 CLK gap between two output symbols so that we can serialize the 2 bits.

-- TC encoder output state machine
-- Objective: regulate output flow control and insert unique word every 1,2,4,8 frames, depending on the frame size
UW_GEN_001: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		TC_E_CTS_D <= TC_E_CTS;
		TC_E_DATA_VALID_D <= TC_E_DATA_VALID;
		TC_E_DATA_D1 <= TC_E_DATA(1);	-- B bit
		UW_GEN_STATE_D <= UW_GEN_STATE;
		
		if(READY_FLAG_CLK_P = '0') then
			UW_GEN_STATE <= 0;
			UW_GEN_CNTR <= (others => '0');
			TC_ENC_FRAME_CNTR <= (others => '0');
		elsif(UW_GEN_STATE = 0) and (TX_SAMPLE1b1_CLK_REQ = '1') and (TC_ENC_FRAME_CNTR = 0) then
			-- start inserting the unique word
			UW_GEN_STATE <= 1;
			UW_GEN_CNTR <= to_unsigned(31,UW_GEN_CNTR'length);
		elsif(UW_GEN_STATE = 1) and (TX_SAMPLE1b1_CLK_REQ = '1') and (UW_GEN_CNTR = 0) then	-- *101916
			-- insert encoded frame
			UW_GEN_STATE <= 2;
		elsif(UW_GEN_STATE = 2) and (TC_E_EOF = '1') then
			-- end of encoded frame. Insert a UW next? depends on frame size
			if(TC_ENC_FRAME_CNTR = TC_ENC_FRAME_CNTR_MAX) then
				UW_GEN_STATE <= 0;
				TC_ENC_FRAME_CNTR <= (others => '0');
			else
				TC_ENC_FRAME_CNTR <= TC_ENC_FRAME_CNTR + 1;
			end if;
		elsif(UW_GEN_CNTR /= 0) and (TX_SAMPLE1b1_CLK_REQ = '1') then
			UW_GEN_CNTR <= UW_GEN_CNTR - 1;
		end if;
	end if;
end process;
		
-- Special cases if short frame: unique word is transmitted only once every 1,2,4,8 frames.
UW_GEN_002: process(TC_E_BLOCK_SIZE)
begin
	if(unsigned(TC_E_BLOCK_SIZE) < 256) then	-- < 256 bit long encoded block size
		TC_ENC_FRAME_CNTR_MAX <= "111";
	elsif(unsigned(TC_E_BLOCK_SIZE) < 512) then	-- < 512 bit long encoded block size
		TC_ENC_FRAME_CNTR_MAX <= "011";
	elsif(unsigned(TC_E_BLOCK_SIZE) < 1024) then	-- < 1024 bit long encoded block size
		TC_ENC_FRAME_CNTR_MAX <= "001";
	else	-- >= 1024 bit long payload size
		TC_ENC_FRAME_CNTR_MAX <= "000";
	end if;
end process;
		
-- unique word is fixed: 0x5A 0F BE 66, MSB transmitted first
UW_GEN_003: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(READY_FLAG_CLK_P = '0') then
			UW_REG <= x"5a0fbe66";
		elsif(UW_GEN_STATE = 1) and (TX_SAMPLE1b1_CLK_REQ = '1') then
			-- circular shift left
			UW_REG(31 downto 1) <= UW_REG(30 downto 0);
			UW_REG(0) <= UW_REG(31);
		end if;
	end if;
end process;
UW_BIT <= UW_REG(31);


-- Also serialize encoded data and unique word. Bit order is A0, B0, A1, B1, etc
-- bypass TC encoder? 
TX_DATA1b1 <= 	ENC_DATA_IN when (ENCODER_ENABLED = '0') else	-- bypass case
					UW_BIT when (UW_GEN_STATE = 1) else 
					TC_E_DATA(0) when (UW_GEN_STATE = 2) and (TC_E_DATA_VALID = '1') else
					TC_E_DATA_D1 when (UW_GEN_STATE_D = 2) and (TC_E_DATA_VALID_D = '1') else 
					'0';
TX_SAMPLE1b1_CLK <= 	ENC_SAMPLE_CLK_IN when (ENCODER_ENABLED = '0') else	-- bypass case
							TX_SAMPLE1b1_CLK_REQ when (UW_GEN_STATE = 1) else
							'1' when (UW_GEN_STATE = 2) and (TC_E_DATA_VALID = '1') else 
							'1' when (UW_GEN_STATE_D = 2) and (TC_E_DATA_VALID_D = '1') else 
							'0';

TX_SOF1b1 <= TC_E_SOF;

TX_SAMPLE1b1_CLK_REQ <= 
								TX_SAMPLE1b1_CLK_REQA and TX_SAMPLE1b1_CLK_REQB when (unsigned(CREG(5)(2 downto 0)) = 3) else -- encoded output to decoder in loopback mode;	
								LEFT_CONNECTOR_A(17) and TX_SAMPLE1b1_CLK_REQB when (unsigned(CREG(0)(5 downto 4)) = 0) else -- encoded output to J4 left connector
								RIGHT_CONNECTOR_A(7) and TX_SAMPLE1b1_CLK_REQB when (unsigned(CREG(0)(5 downto 4)) = 1) else -- encoded output to J8 right connector
								'0';	

--// LIMIT ENCODER THROUGHPUT  -------------------------
NCO_001: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		NCO1_MSB_D <= NCO1_ACC(NCO1_ACC'left);
		NCO1_VAL <= "0" & CREG(13) & CREG(12) & CREG(11)(7 downto 1);
			-- divide by two as the encoder generates 2 parallel encoded bits for each request
		
		if(READY_FLAG_CLK_P = '0') or (CREG(0)(7) = '0')then
			-- not squelching encoder output throughput
			NCO1_ACC <= (others => '0');
		else
			NCO1_ACC <= NCO1_ACC + unsigned(NCO1_VAL);
		end if;
		
		if(READY_FLAG_CLK_P = '0') or (CREG(0)(7) = '0')then
			-- not squelching encoder output throughput
			TX_SAMPLE1b1_CLK_REQB <= '1';
		elsif(NCO1_MSB_D = '0') and (NCO1_ACC(NCO1_ACC'left)= '1') then
			TX_SAMPLE1b1_CLK_REQB <= '1';
		else
			TX_SAMPLE1b1_CLK_REQB <= '0';
		end if;
	end if;
end process;


--// INTERNAL LOOPBACK  -------------------------
-- extend to 4 soft-quantized bits. TODO: add Gaussian noise
DATA11 <= (others => TX_DATA1b1);	-- unsigned, just like the input at the connector
SAMPLE11_CLK <= TX_SAMPLE1b1_CLK;
SOF11 <= TX_SOF1b1;


--// TC DECODER SOURCE SELECTION -------------------------
CCD1_SAMPLE_CLK_OUT_REQB <= DEC_SAMPLE_CLK_IN_REQB when (unsigned(CREG(5)(2 downto 0)) = 1) else '0'; -- clock synchronous J4 left connector
CCD2_SAMPLE_CLK_OUT_REQB <= DEC_SAMPLE_CLK_IN_REQB when (unsigned(CREG(5)(2 downto 0)) = 2) else '0'; -- clock synchronous J8 right connector
TX_SAMPLE1b1_CLK_REQA <= DEC_SAMPLE_CLK_IN_REQB when (unsigned(CREG(5)(2 downto 0)) = 3) else '0'; -- internal loopback

DECODER_ENABLED_001: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(READY_FLAG_CLK_P = '0') or (unsigned(CREG(5)(2 downto 0)) = 0) then
			-- reset or decoder bypassed
			DECODER_ENABLED <= '0';
		else
			DECODER_ENABLED <= '1';
		end if;
	end if;
end process;

DEC_INPUT_SEL: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(READY_FLAG_CLK_P = '0') then
			DEC_DATA_IN <= (others => '0');
			DEC_SAMPLE_CLK_IN <= '0';
			DEC_SOF_IN <= '0';
		else
			case CREG(5)(2 downto 0)  is
				when "001" => 	-- clock synchronous J4 left connector
					DEC_DATA_IN(3) <= CCD1_DATA_OUT(0);	-- MSb pin A2
					DEC_DATA_IN(2) <= CCD1_DATA_OUT(1);	
					DEC_DATA_IN(1) <= CCD1_DATA_OUT(2);	
					DEC_DATA_IN(0) <= CCD1_DATA_OUT(3);	-- LSb pin A5
					DEC_SAMPLE_CLK_IN <= CCD1_SAMPLE_CLK_OUT;
					DEC_SOF_IN <= '0';	-- TODO connect to optional connector pin
				when "010" => 	-- clock synchronous J8 right connector
					DEC_DATA_IN(3) <= CCD2_DATA_OUT(0);	-- MSb pin A12
					DEC_DATA_IN(2) <= CCD2_DATA_OUT(1);	
					DEC_DATA_IN(1) <= CCD2_DATA_OUT(2);	
					DEC_DATA_IN(0) <= CCD2_DATA_OUT(3);	-- LSb pin A15
					DEC_SAMPLE_CLK_IN <= CCD2_SAMPLE_CLK_OUT;
					DEC_SOF_IN <= '0';	-- TODO connect to optional connector pin
				when "011" => 	-- internal loopback
					DEC_DATA_IN <= DATA11;
					DEC_SAMPLE_CLK_IN <= SAMPLE11_CLK;
					DEC_SOF_IN <= SOF11;
				when others => 	
					DEC_DATA_IN <= (others => '0');
					DEC_SAMPLE_CLK_IN <= '0';
					DEC_SOF_IN <= '0';	
			end case;
		end if;
	end if;
end process;

--// TURBO CODE DECODER -----------------------------------------------------------
-- decoder configuration
TC_DEC_CONFIG_001: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		TC_DEC_BURST_PAYLOAD_SIZE <= resize(unsigned(CREG(6)), NADDRBITS);
			-- preferred sizes 14,63,250 BYTES
			-- Limited to < 256 bytes to keep the decoder size small
		TC_DEC_CRC16_EN <= CREG(7)(7);
			-- detect CRC16 appended after payload field
		TC_C_BLOCK_SIZE(7 downto 0) <= CREG(8);
		TC_C_BLOCK_SIZE(12 downto 8) <= CREG(9)(4 downto 0);
			-- coded block size in bits. Does not include unique word
		TC_DEC_N_ITER(3 downto 1) <= CREG(10)(3 downto 1);
		TC_DEC_N_ITER(0) <= '1';
			-- number of decoding iterations. MUST be odd.
	end if;
end process;

TC_DEC_CONFIG_002: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(unsigned(CREG(7)(3 downto 0)) = 0) then
			-- Rate 1/3. Only case when W parity bit is enabled
			TC_DEC_W_PUNCTURING_PATTERN <= '1';
		else
			TC_DEC_W_PUNCTURING_PATTERN <= '0';
		end if;
		
		case CREG(7)(3 downto 0) is
			when "0000" => -- rate 1/3
				TC_DEC_Y_PUNCTURING_PERIOD <= "00001";	-- 1
				TC_DEC_Y_PUNCTURING_PATTERN <= "0000000000000000000000000001";  -- flipped punct. pattern.
			when "0001" => -- rate 1/2
				TC_DEC_Y_PUNCTURING_PERIOD <= "00001";	-- 1
				TC_DEC_Y_PUNCTURING_PATTERN <= "0000000000000000000000000001";  -- flipped punct. pattern.
			when "0010" => -- rate 2/3
				TC_DEC_Y_PUNCTURING_PERIOD <= "00010";	-- 2
				TC_DEC_Y_PUNCTURING_PATTERN <= "0000000000000000000000000001";  -- flipped punct. pattern.
			when "0011" => -- rate 3/4
				TC_DEC_Y_PUNCTURING_PERIOD <= "00110";	-- 6
				TC_DEC_Y_PUNCTURING_PATTERN <= "0000000000000000000000000101";  -- flipped punct. pattern.
			when "0100" => -- rate 4/5
				TC_DEC_Y_PUNCTURING_PERIOD <= "00100";	-- 4
				TC_DEC_Y_PUNCTURING_PATTERN <= "0000000000000000000000000001";  -- flipped punct. pattern.
			when "0101" => -- rate 5/6
				TC_DEC_Y_PUNCTURING_PERIOD <= "10100";	-- 20
				TC_DEC_Y_PUNCTURING_PATTERN <= "0000000000000001000100010001";  -- flipped punct. pattern.
			when "0110" => -- rate 6/7
				TC_DEC_Y_PUNCTURING_PERIOD <= "01100";	-- 12
				TC_DEC_Y_PUNCTURING_PATTERN <= "0000000000000000000000010001";  -- flipped punct. pattern.
			when others => -- rate 7/8
				TC_DEC_Y_PUNCTURING_PERIOD <= "11100";	-- 28
				TC_DEC_Y_PUNCTURING_PATTERN <= "0000000100000001000000010001";  -- flipped punct. pattern.
		end case;
	end if;
end process;

TC_DEC_P <= "0100101";
TC_DEC_Q0 <= "0000";
TC_DEC_Q1 <= "0010";
TC_DEC_Q2 <= "0000";
TC_DEC_Q3 <= "010";

-- unique word is transmitted only once every 1, 2, 4 or 8 frames.
-- Tell SOF_SYNC only about the number of bits between UWs
UW1_PERIOD_GEN_001: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(CONFIG_CHANGE_PULSE_CLK_P = '1') then
			if(unsigned(TC_C_BLOCK_SIZE(12 downto 10)) /= 0) then
				-- code block size >= 1024 bits. UW once every block.
				UW1_PERIOD <= unsigned(TC_C_BLOCK_SIZE);
			elsif (TC_C_BLOCK_SIZE(9) = '1') then
				-- code block size < 1024 bits. UW once every two blocks.
				UW1_PERIOD(12 downto 1) <= unsigned(TC_C_BLOCK_SIZE(11 downto 0));
				UW1_PERIOD(0) <= '0';
			elsif (TC_C_BLOCK_SIZE(8) = '1') then
				-- code block size < 512 bits. UW once every four blocks.
				UW1_PERIOD(12 downto 2) <= unsigned(TC_C_BLOCK_SIZE(10 downto 0));
				UW1_PERIOD(1 downto 0) <= "00";
			else
				-- code block size < 256 bits. UW once every eight blocks.
				UW1_PERIOD(12 downto 3) <= unsigned(TC_C_BLOCK_SIZE(9 downto 0));
				UW1_PERIOD(2 downto 0) <= "000";
			end if;
		elsif(CONFIG_CHANGE_PULSE_CLK_P_D = '1') then
			UW1_PERIOD <= UW1_PERIOD + 32;	-- add overhead for 32 bit unique word
		end if;
	end if;
end process;

-- detects and remove periodic sync word (UW). Corrects phase ambiguity. Outlines data field.
TC_DEC_SYNC_RESET <= READY_FLAG_CLK_Pn or CONFIG_CHANGE_PULSE_CLK_P_D2;
SOF_SYNC_001: SOF_SYNC port map(
	ASYNC_RESET => TC_DEC_SYNC_RESET,
	CLK => CLK_P,
	DATA_IN => DEC_DATA_IN,
	BIT_CLK_IN => DEC_SAMPLE_CLK_IN,
	FRAME_LENGTH => std_logic_vector(UW1_PERIOD),	
	DATA_OUT => TDEC_DATA12,
	BIT_CLK_OUT => TDEC_SAMPLE12_CLK,
	SOF => TDEC_SOF12,
	SOF_LOCK_DETECT => TDEC_SOF_LOCK_DETECT12,
	PHASE => TDEC_PHASE12,
	DATA_ENABLE => TDEC_DATA_ENABLE12,
	BER => TDEC_BER12,
	TP_MRC_SOF => TP_MRC_SOF12

);

MONITORING_002: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(LATCH_MONITORING_PULSE = '1') then
			-- latch in multi-byte status registers upon reading status register SREG7
			-- report number errors in 1024 bits of sync words
			SREG(17) <= TDEC_BER12(7 downto 0);
			SREG(18) <= TDEC_BER12(15 downto 8);
		end if;
	end if;
end process;

--// store demodulated bits (soft) in dual port memory. 
-- reconstruct implied SOFs and EOFs
-- 1-bit serial to 2-sample parallel conversion
-- Also change format because decoder expects signed format: 
-- best '0' = most negative = 1000 and best '1' = most positive = 0111
TC_C_BIT_CNTR_INC <= TC_C_BIT_CNTR + 1;
TC_DEC_SOF_GEN: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(TC_DEC_SYNC_RESET = '1') then
			TC_C_BIT_CNTR <= (others => '0');
			TC_C_DATA <= (others => '0');
			TC_C_DATA_VALID <= '0';
			TC_C_SOF <= '0';
			TC_C_EOF <= '0';
		elsif(TDEC_SOF12 = '1') and (TDEC_DATA_ENABLE12 = '1') then
			TC_C_BIT_CNTR <= to_unsigned(1,TC_C_BIT_CNTR'length);
			TC_C_DATA_VALID <= '0';
			TC_C_DATA(3) <= not TDEC_DATA12(3);									-- shift in A then B
			TC_C_DATA(2 downto 0) <= TDEC_DATA12(2 downto 0);				
		elsif(TDEC_SAMPLE12_CLK = '1') and (TDEC_DATA_ENABLE12 = '1') then
			-- shift left to do serial to 2-sample parallel conversion
			TC_C_DATA(7 downto 4) <= TC_C_DATA(3 downto 0);	-- A 
			TC_C_DATA(3) <= not TDEC_DATA12(3);									-- shift in A then B
			TC_C_DATA(2 downto 0) <= TDEC_DATA12(2 downto 0);				
			
			if(TC_C_BIT_CNTR(0) = '1') then
				TC_C_DATA_VALID <= '1';
			else
				TC_C_DATA_VALID <= '0';
			end if;
			
			if(TC_C_BIT_CNTR_INC = unsigned(TC_C_BLOCK_SIZE) ) then
				TC_C_BIT_CNTR <= (others => '0');
				TC_C_EOF <= '1';
			else
				TC_C_BIT_CNTR <= TC_C_BIT_CNTR_INC;
				TC_C_EOF <= '0';
			end if;
			
			if(TC_C_BIT_CNTR = 1) then
				TC_C_SOF <= '1';
			else
				TC_C_SOF <= '0';
			end if;
			
			
		else
			TC_C_SOF <= '0';
			TC_C_EOF <= '0';
			TC_C_DATA_VALID <= '0';
		end if;
	end if;
end process;

-- write to elastic buffer
TC_DEC_BUF_001: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(TC_DEC_SYNC_RESET = '1') then
			TC_C_WPTR <= (others => '0');
		elsif(TC_C_DATA_VALID = '1') then
			TC_C_WPTR <= TC_C_WPTR + 1;
		end if;
	end if;
end process;


-- Dual port RAM 4-bit soft quantized sample. Large enough for 1+ full size frame = 6.1 Ksamples
TC_DEC_BUF_002: BRAM_DP2 
GENERIC MAP(
    DATA_WIDTHA => 8,        
    ADDR_WIDTHA => 12,
    DATA_WIDTHB => 8,         
    ADDR_WIDTHB => 12
)
PORT MAP(
	CSA => '1',
	CLKA => CLK_P,
	WEA => TC_C_DATA_VALID,
	ADDRA => std_logic_vector(TC_C_WPTR),
	DIA => TC_C_DATA,
	OEA => '0',
    DOA => open,
	CSB => '1',
	CLKB => CLK_P,
	WEB => '0',
	ADDRB => std_logic_vector(TC_C_RPTR),
	DIB => x"00",
	OEB => '1',
	DOB => TC_C_DATA2
);

-- smaller dual-port RAM to store SOF/EOF information
TC_C_SOFEOF(1) <= TC_C_SOF;
TC_C_SOFEOF(0) <= TC_C_EOF;
TC_DEC_BUF_003: BRAM_DP2 
GENERIC MAP(
    DATA_WIDTHA => 2,        
    ADDR_WIDTHA => 12,
    DATA_WIDTHB => 2,         
    ADDR_WIDTHB => 12
)
PORT MAP(
	CSA => '1',
	CLKA => CLK_P,
	WEA => TC_C_DATA_VALID,
	ADDRA => std_logic_vector(TC_C_WPTR),
	DIA => TC_C_SOFEOF,
	OEA => '0',
   DOA => open,
	CSB => '1',
	CLKB => CLK_P,
	WEB => '0',
	ADDRB => std_logic_vector(TC_C_RPTR),
	DIB => "00",
	OEB => '1',
	DOB => TC_C_SOFEOF2
);

TC_DEC_BUF_SIZE <= TC_C_WPTR + not(TC_C_RPTR);
TC_DEC_BUF_EMPTY <= '1' when (TC_DEC_BUF_SIZE = 0) else '0';

-- decoder input flow control. As for more coded input data when input buffer is < 87% full
DEC_SAMPLE_CLK_IN_REQ <= '1' when (TC_DEC_BUF_SIZE(TC_DEC_BUF_SIZE'left downto TC_DEC_BUF_SIZE'left-2) /= "111") else '0';

-- read elastic buffer
TC_DEC_BUF_004: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		-- a bit tricky... one has to prevent the next SOF from occurring just after the EOF
		if(TC_DEC_SYNC_RESET = '1') then
			TC_C_DATA2_VALID_E <= '0';
			TC_C_DATA2_VALID <= '0';
			TC_C_RPTR <= (others => '1');
		elsif(TC_C_EOF2 = '1') and (TC_C_DATA2_VALID_E = '1') then
			-- because of the 2clk latency in reading the memory, we read too far (1 clk past the eof). Rewind to eof position.
			TC_C_DATA2_VALID_E <= '0';
			TC_C_DATA2_VALID <= '0';
			TC_C_RPTR <= TC_C_RPTR - 1;
		elsif(TC_C_CTS = '1') and (TC_DEC_BUF_EMPTY = '0') then
			TC_C_DATA2_VALID_E <= '1';
			TC_C_RPTR <= TC_C_RPTR + 1;
			TC_C_DATA2_VALID <= TC_C_DATA2_VALID_E;
		else
			TC_C_DATA2_VALID_E <= '0';
			TC_C_DATA2_VALID <= TC_C_DATA2_VALID_E;
		end if;
	end if;
end process;

TC_C_SOF2 <= TC_C_SOFEOF2(1) and TC_C_DATA2_VALID;
TC_C_EOF2 <= TC_C_SOFEOF2(0) and TC_C_DATA2_VALID;

-- to minimize TC decoder size, limit the maximum payload size to < 2048 bits (<256 bytes)
TC_DECODER_DVB_RCS2_001: TC_DECODER_DVB_RCS2 
GENERIC MAP	(
	NQBITS => 4, 	-- number of soft-quantized bits at the decoder input
	NADDRBITS => NADDRBITS,	-- determines the maximum payload size (254?, 1000?)
	SIMULATION => SIMULATION
)
PORT MAP(
	CLK => CLK_P,
	SYNC_RESET => TC_DEC_SYNC_RESET,
	DATA_A_IN => TC_C_DATA2(7 downto 4),
	DATA_B_IN => TC_C_DATA2(3 downto 0),
	DATA_IN_VALID => TC_C_DATA2_VALID,
	SOF_IN => TC_C_SOF2,
	EOF_IN => TC_C_EOF2,
	CTS_OUT => TC_C_CTS,	
	BURST_PAYLOAD_SIZE => std_logic_vector(TC_DEC_BURST_PAYLOAD_SIZE),
	P => TC_DEC_P,
	Q0 => TC_DEC_Q0,
	Q1 => TC_DEC_Q1,
	Q2 => TC_DEC_Q2,
	Q3 => TC_DEC_Q3,
	Y_PUNCTURING_PERIOD => TC_DEC_Y_PUNCTURING_PERIOD,
	Y_PUNCTURING_PATTERN => TC_DEC_Y_PUNCTURING_PATTERN,
	W_PUNCTURING_PATTERN => TC_DEC_W_PUNCTURING_PATTERN,
	N_ITER => TC_DEC_N_ITER,
	CRC16_EN => TC_DEC_CRC16_EN,
	DATA_OUT => TC_D_DATA,
	DATA_OUT_VALID => TC_D_DATA_VALID, 
	SOF_OUT => TC_D_SOF, 
	CTS_IN => TC_D_CTS,
	CRC_VALID => TC_D_CRC_VALID,
	BAD_CRC => TC_D_BAD_CRC,
	FRAME_CNTR => TC_D_FRAME_CNTR,
	FRAME_ERROR_CNTR => TC_D_FRAME_ERROR_CNTR
);

MONITORING_003: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(LATCH_MONITORING_PULSE = '1') then
			-- latch in multi-byte status registers upon reading status register SREG7
			-- report number bit errors
			SREG(24) <= TC_D_FRAME_CNTR(7 downto 0);
			SREG(25) <= TC_D_FRAME_CNTR(15 downto 8);
			SREG(26) <= TC_D_FRAME_CNTR(23 downto 16);
			SREG(27) <= TC_D_FRAME_CNTR(31 downto 24);
			SREG(28) <= TC_D_FRAME_ERROR_CNTR(7 downto 0);
			SREG(29) <= TC_D_FRAME_ERROR_CNTR(15 downto 8);
			SREG(30) <= TC_D_FRAME_ERROR_CNTR(23 downto 16);
			SREG(31) <= TC_D_FRAME_ERROR_CNTR(31 downto 24);
		end if;
	end if;
end process;

-- serialize the decoded output
TC_DECODER_DVB_RCS2_002: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		TC_D_DATA_VALID_D <= TC_D_DATA_VALID;
		
		if(READY_FLAG_CLK_P = '0') then
			TC_D_CTS <= '0';
		elsif(RX_SAMPLE1b2_CLK_REQ = '1') and (TC_D_CTS = '0') then
			-- slow down TC decoder output to allow serialization
			TC_D_CTS <= '1';	
		else
			TC_D_CTS <= '0';	
		end if;
	end if;
end process;


RX_DATA1b2 <= 	DEC_DATA_IN(3) when (DECODER_ENABLED = '0') else 	-- bypass TC decoder 
					TC_D_DATA(0) when (TC_D_DATA_VALID = '1') else	-- TC decoded A bit first
					TC_D_DATA(1) when (TC_D_DATA_VALID_D = '1') else	-- TC decoded B bit
					'0';
RX_SAMPLE1b2_CLK <= 	DEC_SAMPLE_CLK_IN when (DECODER_ENABLED = '0') else 
					TC_D_DATA_VALID or TC_D_DATA_VALID_D;

RX_SOF1b2 <= 	DEC_SOF_IN when (DECODER_ENABLED = '0') else 
					TC_D_SOF;

RX_SAMPLE1b2_CLK_REQ <= LEFT_CONNECTOR_A(17) when (unsigned(CREG(5)(5 downto 4)) = 0) else -- decoded output to J4 left connector
								RIGHT_CONNECTOR_A(7) when (unsigned(CREG(5)(5 downto 4)) = 1) else -- decoded output to J8 right connector
								LAN1_TCP_TX_CTS(1) when (unsigned(CREG(5)(5 downto 4)) = 2) else -- decoded output to TCP server
								'1';	-- no restrictions when going to the BERT	
-- decoder input flow control
DEC_SAMPLE_CLK_IN_REQB <= 	RX_SAMPLE1b2_CLK_REQ when (DECODER_ENABLED = '0') else -- bypass TC decoder 
									DEC_SAMPLE_CLK_IN_REQ;

									

--//-- DECODER OUTPUT SERIAL TO 8-BIT PARALLEL CONVERSION --------------
-- Convert to 8-bit parallel for TCP server

S1_TO_P8_CONVERSION_001: S1_TO_P8_CONVERSION PORT MAP(
	CLK => CLK_P,
	SYNC_RESET => READY_FLAG_CLK_Pn,
	DATA1_IN => RX_DATA1b2,
	SAMPLE1_CLK_IN => RX_SAMPLE1b2_CLK,
	SOF1_IN => RX_SOF1b2,
	EOF1_IN => '0',
	DATA8_OUT => RX_DATA8b1,
	SAMPLE8_CLK_OUT => RX_SAMPLE8b1_CLK,
	SOF8_OUT => open,
	EOF8_OUT => open
);

-- to the TCP Server
LAN1_TCP_TX_DATA(1) <= RX_DATA8b1;
LAN1_TCP_TX_DATA_VALID(1) <= RX_SAMPLE8b1_CLK when (unsigned(CREG(5)(5 downto 4)) = 2) else '0';-- decoded output to TCP server

--//-- BER MEASUREMENT  ---------------------------------------------------------
-- BER measurement 1-bit serial input selection

-- Measure BER when a PRSB-11 test sequence is transmitted
BER_CONTROL(2 downto 0) <= "011" when (SIMULATION = '0') else "000"; 
	-- BER measured over a window of 8 Mbits, except during simulation when the window is shortened to 8000 bits.
				-- 000 = 1,000 bytes
				-- 001 = 10,000 bytes
				-- 010 = 100,000 bytes
				-- 011 = 1,000,000 bytes
				-- 100 = 10,000,000 bytes
				-- 101 = 100,000,000 bytes
				-- 110 = 1,000,000,000 bytes
BER_CONTROL(7 downto 3) <= (others => '0'); -- unused

BER2_001: BER2 PORT MAP(
	CLK => CLK_P,
	SYNC_RESET => READY_FLAG_CLK_Pn,
	DATA_IN => RX_DATA8b1,
	SAMPLE_CLK_IN => RX_SAMPLE8b1_CLK,
	CONTROL => BER_CONTROL,
	MF_DETECT => BER_MF_DETECT,	-- useful test point
	MF_DETECT_CONFIRMED => BER_MF_DETECT_CONFIRMED,
	SYNC_LOCK => BER_SYNC,	-- useful test point
	BYTE_ERROR => BER_BYTE_ERROR,		-- useful test point
	DATA_REPLICA => open,
	SAMPLE_CLK_OUT => open,
	BER => BER_ERROR_COUNT,
	BER_SAMPLE_CLK => open,
	TP => BER_TEST_POINT
);

MONITORING_004: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		if(LATCH_MONITORING_PULSE = '1') then
			-- latch in multi-byte status registers upon reading status register SREG7
			-- report number bit errors
			SREG(20)(7) <= BER_SYNC;	-- BERT synchronized
			SREG(21) <= BER_ERROR_COUNT(7 downto 0);
			SREG(22) <= BER_ERROR_COUNT(15 downto 8);
			SREG(23) <= BER_ERROR_COUNT(23 downto 16);
		end if;
	end if;
end process;

--//-- TEST POINTS  ---------------------------------------------------------
TP_001: process(CLK_P)
begin
	if rising_edge(CLK_P) then
	
	
		RIGHT_CONNECTOR_A(29) <= TP_MRC_SOF12(0);	-- sync word detection in the SOF_SYNC matched filter
		RIGHT_CONNECTOR_A(30) <= TDEC_DATA_ENABLE12;	-- rx coded data frame
		RIGHT_CONNECTOR_A(31) <= TDEC_DATA12(3);	-- rx coded data bits
		RIGHT_CONNECTOR_A(32) <= TDEC_SOF_LOCK_DETECT12;	-- '1' when periodic sync word is found periodically at the right position
		RIGHT_CONNECTOR_A(33) <= BER_MF_DETECT;	-- BERT detection of start of PRBS11 test sequence
		RIGHT_CONNECTOR_A(34) <= BER_SYNC;	-- BERT synchronized
		RIGHT_CONNECTOR_A(35) <= BER_BYTE_ERROR;	-- BERT byte error
		RIGHT_CONNECTOR_A(36) <= TC_C_CTS;	-- tc decoder input flow control
		RIGHT_CONNECTOR_A(37) <= TC_U_CTS;	-- tc encoder input flow control 
		--RIGHT_CONNECTOR_A(38) <= ;
		
		LEFT_CONNECTOR_A(29) <= TC_D_FRAME_CNTR(0);
		LEFT_CONNECTOR_A(30) <= TC_D_CRC_VALID;
		LEFT_CONNECTOR_A(31) <= TC_D_BAD_CRC;
	end if;
end process;
					
-- DNA Port ------------------------------------
-- Read FPGA unique DNA ID
DNA_ID_001: DNA_ID 
	GENERIC MAP(
		CLK_FREQUENCY => 125	-- CLK_P in MHz, as time reference
	)
	PORT MAP(
		CLK => CLK_P,
		SYNC_RESET => SYNC_RESET_CLK_P,
		ID_OUT => DNA_ID_DATA,
		ID_VALID_OUT => open,
		ID_SAMPLE_CLK_OUT => DNA_ID_SAMPLE_CLK 
);

-- M&C LAN interface --------------------------
-- REG255 reserved for reading serial port inputs 
-- These signals are pulled high (to mimic stop bit).
REG255 <= "1111" & RX_LAN_BUFFER_EMPTY & "111";
	-- M&C port through LAN 
	-- indicates AVAILABILITY of 8-bit byte from LAN. Not actual data.
	-- When low, uC must read byte from LAN

-- Reclock TX_LAN_TOGGLE
RECLOCK_TX_LAN_TOGGLE: process(CLK_P,TX_LAN_TOGGLE)
begin
	if rising_edge(CLK_P) then
		TX_LAN_TOGGLE_D <= TX_LAN_TOGGLE;
		TX_LAN_TOGGLE_D2 <= TX_LAN_TOGGLE_D;
		if(TX_LAN_TOGGLE_D /= TX_LAN_TOGGLE_D2) then
			LAN1_TCP_TX_DATA_VALID(0) <= '1';
		else
			LAN1_TCP_TX_DATA_VALID(0) <= '0';
		end if;
	end if;
end process;

-- Immediately upon completing reading a M&C byte from the USB or LAN, ask for the 
-- next one. 
-- RACE CONDITION??????? ARM IS FAST!!!!
RECLOCK_RDN_D: process(CLK_P, SREG254_READ_TOGGLE)
begin
	if rising_edge(CLK_P) then
		SREG254_READ_TOGGLE_D <= SREG254_READ_TOGGLE;
		SREG254_READ_TOGGLE_D2 <= SREG254_READ_TOGGLE_D;

		RX_LAN_BUFFER_EMPTY_D <= RX_LAN_BUFFER_EMPTY;
		RX_LAN_BUFFER_EMPTY_D2 <= RX_LAN_BUFFER_EMPTY_D;


		if (SREG254_READ_TOGGLE_D2 /= SREG254_READ_TOGGLE_D) then
			-- end of M&C byte read from ARM uC.
			if(RX_LAN_BUFFER_EMPTY_D2 = '0') then
				-- last M&C byte read was over LAN. Increment LAN elastic buffer read pointer
				RX_LAN_SAMPLE_CLK_REQ <= '1';
					-- identifies LAN as the media through which	this module exchanges 
					-- M&C information. Response will be directed the same way.
			end if;
		else
			RX_LAN_SAMPLE_CLK_REQ <= '0';
		end if;
	end if;
end process;

--// ARM CO-PROCESSOR INTERFACE ---------------------------------------------------
-- Primarily used for monitoring and control.
-- 8-bit shared address/data bus. clock synchronous.
-- PART OF THE FRAMEWORK. DO NOT CHANGE unless you want to add more control registers 
--(see UC_WRITE_001) or status registers (see UC_READ_001).
-- 
-- Address latch
UC_ADDR_001: process(UC_CSIB_IN, UC_WEBG, UC_ALE_IN, UC_AD)
begin
	if rising_edge(UC_WEBG) then
		if (UC_CSIB_IN = '0') and (UC_ALE_IN = '1') then
			UC_ADDRESS <= unsigned(UC_AD);
	  	end if;
  	end if;
end process;

-- Read status registers 
-- This template defines 10 status registers. 
-- User can define additional control registers using the same pattern. 
UC_READ_001: process(UC_ADDRESS, REG255, RX_LAN, SREG251, SREG250, SREG)
begin
	case(UC_ADDRESS) is
		-- ComBlock-reserved addresses ----
		when "11111111" => UC_AD_local <= REG255;		-- reg 255. Async serial from 3 connectors
		when "11111110" => UC_AD_local <= RX_LAN;		-- reg 254 = 8-bit data from LAN M&C channel
		when "11111101" => UC_AD_local <= REVISION;	-- reg 253 = fpga revision
		when "11111100" => UC_AD_local <= OPTION;		-- reg 252 = fpga option
		when "11111011" => UC_AD_local <= SREG251;		-- reg 251 = comscope  status
		when "11111010" => UC_AD_local <= SREG250;		-- reg 250 = comscope data byte

		-- User-defined status registers -------
		-- Note: SREG0-6 are inserted by the ARM co-processor, not the FPGA.
		when "00000111" => UC_AD_local <= SREG(7);
		when "00001000" => UC_AD_local <= SREG(8);
		when "00001001" => UC_AD_local <= SREG(9);
		when "00001010" => UC_AD_local <= SREG(10);
		when "00001011" => UC_AD_local <= SREG(11);
		when "00001100" => UC_AD_local <= SREG(12);
		when "00001101" => UC_AD_local <= SREG(13);
		when "00001110" => UC_AD_local <= SREG(14);
		when "00001111" => UC_AD_local <= SREG(15);
		when "00010000" => UC_AD_local <= SREG(16);
		when "00010001" => UC_AD_local <= SREG(17);
		when "00010010" => UC_AD_local <= SREG(18);
		when "00010011" => UC_AD_local <= SREG(19);
		when "00010100" => UC_AD_local <= SREG(20);
		when "00010101" => UC_AD_local <= SREG(21);
		when "00010110" => UC_AD_local <= SREG(22);
		when "00010111" => UC_AD_local <= SREG(23);
		when "00011000" => UC_AD_local <= SREG(24);
		when "00011001" => UC_AD_local <= SREG(25);
		when "00011010" => UC_AD_local <= SREG(26);
		when "00011011" => UC_AD_local <= SREG(27);
		when "00011100" => UC_AD_local <= SREG(28);
		when "00011101" => UC_AD_local <= SREG(29);
		when "00011110" => UC_AD_local <= SREG(30);
		when "00011111" => UC_AD_local <= SREG(31);
--		when "00100000" => UC_AD_local <= SREG(32);
--		when "00100001" => UC_AD_local <= SREG(33);
--		when "00100010" => UC_AD_local <= SREG(34);
--		when "00100011" => UC_AD_local <= SREG(35);
--		when "00100100" => UC_AD_local <= SREG(36);
--		when "00100101" => UC_AD_local <= SREG(37);
--		when "00100110" => UC_AD_local <= SREG(38);
--		when "00100111" => UC_AD_local <= SREG(39);
--		when "00101000" => UC_AD_local <= SREG(40);
--		when "00101001" => UC_AD_local <= SREG(41);
--		when "00101010" => UC_AD_local <= SREG(42);
--		when "00101011" => UC_AD_local <= SREG(43);
--		when "00101100" => UC_AD_local <= SREG(44);
--		when "00101101" => UC_AD_local <= SREG(45);
--		when "00101110" => UC_AD_local <= SREG(46);
--		when "00101111" => UC_AD_local <= SREG(47);
--		when "00110000" => UC_AD_local <= SREG(48);
--		when "00110001" => UC_AD_local <= SREG(49);
--		when "00110010" => UC_AD_local <= SREG(50);
--		when "00110011" => UC_AD_local <= SREG(51);
--		when "00110100" => UC_AD_local <= SREG(52);
--		when "00110101" => UC_AD_local <= SREG(53);
--		when "00110110" => UC_AD_local <= SREG(54);
--		when "00110111" => UC_AD_local <= SREG(55);
--		when "00111000" => UC_AD_local <= SREG(56);
--		when "00111001" => UC_AD_local <= SREG(57);
--		when "00111010" => UC_AD_local <= SREG(58);
--		when "00111011" => UC_AD_local <= SREG(59);
--		when "00111100" => UC_AD_local <= SREG(60);
		when others => UC_AD_local <= x"00";

	end case;
end process;
UC_AD <= UC_AD_local when (UC_CSIB_IN = '0') and (UC_REB_IN = '0') else (others => 'Z');
	-- when to drive the data bus between ARM and FPGA

-- toggle a few flags upon reading specific status registers
UC_READ_002: process(ASYNC_RESET, UC_REBG, UC_CSIB_IN, UC_ADDRESS, 
						SREG254_READ_TOGGLE)
begin
	if(ASYNC_RESET = '1') then
		SREG254_READ_TOGGLE <= '0';
	elsif rising_edge(UC_REBG) then
		if (UC_CSIB_IN = '0')  then
			if (UC_ADDRESS = 7) then
				SREG7_READ_TOGGLE <= not SREG7_READ_TOGGLE;
			end if;
			if (UC_ADDRESS = 254) then
				SREG254_READ_TOGGLE <= not SREG254_READ_TOGGLE;
			end if;
		end if;
	end if;
end process;

-- reclock with CLK_P
RECLOCK_SREG9_TOGGLE: process(CLK_P,SREG7_READ_TOGGLE)
begin
	if rising_edge(CLK_P) then
		SREG7_READ_TOGGLE_D <= SREG7_READ_TOGGLE;
		SREG7_READ_TOGGLE_D2 <= SREG7_READ_TOGGLE_D;
		if(SREG7_READ_TOGGLE_D /= SREG7_READ_TOGGLE_D2) then
			LATCH_MONITORING_PULSE <= '1';
		else
			LATCH_MONITORING_PULSE <= '0';
		end if;
	end if;
end process;

-- write to FPGA control registers
UC_WRITE_001ax: if (SIMULATION = '0') generate
	UC_WRITE_001a: process(UC_WEBG)
	begin
		if rising_edge(UC_WEBG) then
			if (UC_CSIB_IN = '0') and (UC_ALE_IN = '0') and (UC_REB_IN = '1')  then
				-- registers 0 to NCREG_IMIN-1 reserved for ARM processor 
				for I in NCREG_IMIN to NCREG_IMAX loop
					if(UC_ADDRESS = I) then
						CREG(I) <= UC_AD;
					end if;
				end loop;
				
				if (UC_ADDRESS = NCREG_IMAX) then
					CONFIG_CHANGE_TOGGLE <= not CONFIG_CHANGE_TOGGLE;	
					-- Configuration change toggles upon writing the last control register
					-- This happens invisibly to the user (only the ARM uC writes to the last control register
					-- which is invible to the user and to the ComBlock Control Center).
					UC_CONFIGURATION_DONE <= '1';
				end if;

				-- special case: MAC address LSB, at an address not erased when importing new settings
				if (UC_ADDRESS = 236) then
					REG236 <= UC_AD;	
					LAN_ADDR_CHANGE_TOGGLE <= not LAN_ADDR_CHANGE_TOGGLE;
				end if;

				-- Reserved:
				-- REG254 reserved for output serial
				-- REG255 write reserved for output serial (8-bit parallel format)
				if (UC_ADDRESS = 255) then
					-- REG255 write reserved for output serial (8-bit parallel format)
					-- route response to host query over LAN/TCP-IP
					LAN1_TCP_TX_DATA(0) <= UC_AD;
					TX_LAN_TOGGLE <= not TX_LAN_TOGGLE;
				end if;
				
			end if;
		end if;
	end process;
end generate;

-- initialize control registers for simulation
UC_WRITE_001y: if (SIMULATION = '1') generate
	-- initialize the control registers during simulation
	
	-- no CRC case
	CREG(0) <= x"14";		-- encoder input selection, encoder output selection, limit encoder output data rate
    CREG(1) <= x"B1";     -- turbo code encoder payload size in Bytes
    CREG(2) <= x"03";     -- turbo code encoder rate, crc insertion 
    CREG(3) <= x"60";     -- turbo code encoded block size in bits, including optional CRC16 (LSB)
    CREG(4) <= x"07";     -- turbo code encoded block size in bits, including optional CRC16 (MSB)
    CREG(5) <= x"13";     -- decoder input selection, decoder output selection, internal loopback
    CREG(6) <= x"B1";     -- turbo code decoder payload size in Bytes 
    CREG(7) <= x"03";     -- turbo code decoder rate, crc check
    CREG(8) <= x"60";     -- turbo code coded block size in bits, including optional CRC16 (LSB)
    CREG(9) <= x"07";     -- turbo code coded block size in bits, including optional CRC16 (MSB)
    CREG(10) <= x"0F";     -- turbo code number of decoding iterations
    CREG(11) <= x"48";     -- encoder maximum output rate (LSB)
    CREG(12) <= x"62";     -- encoder maximum output rate 
    CREG(13) <= x"10";     -- encoder maximum output rate (MSB)
    CREG(14) <= x"AC";     -- IPv4 address (MSB)
    CREG(15) <= x"10";     -- IPv4 address 
    CREG(16) <= x"01";     -- IPv4 address 
    CREG(17) <= x"80";     -- IPv4 address 
    CREG(18) <= x"FF";     -- Subnet mask (MSB)
    CREG(19) <= x"FF";     -- Subnet mask 
    CREG(20) <= x"FF";     -- Subnet mask 
    CREG(21) <= x"00";     -- Subnet mask (LSB)
    CREG(22) <= x"AC";     -- Gateway IP address (MSB)
    CREG(23) <= x"10";     -- Gateway IP address 
    CREG(24) <= x"01";     -- Gateway IP address 
    CREG(25) <= x"03";     -- Gateway IP address (LSB)
	
	-- with CRC
--	CREG(0) <= x"14";		-- encoder input selection, encoder output selection, limit encoder output data rate
--	CREG(1) <= x"AF";	 -- turbo code encoder payload size in Bytes
--	CREG(2) <= x"83";	 -- turbo code encoder rate, crc insertion 
--	CREG(3) <= x"4B";	 -- turbo code encoded block size in bits, including optional CRC16 (LSB)
--	CREG(4) <= x"07";	 -- turbo code encoded block size in bits, including optional CRC16 (MSB)
--	CREG(5) <= x"13";	 -- decoder input selection, decoder output selection, internal loopback
--	CREG(6) <= x"AF";	 -- turbo code decoder payload size in Bytes 
--	CREG(7) <= x"83";	 -- turbo code decoder rate, crc check
--	CREG(8) <= x"4B";	 -- turbo code coded block size in bits, including optional CRC16 (LSB)
--	CREG(9) <= x"07";	 -- turbo code coded block size in bits, including optional CRC16 (MSB)
--	CREG(10) <= x"07";	 -- turbo code number of decoding iterations
--	CREG(11) <= x"48";	 -- encoder maximum output rate (LSB)
--	CREG(12) <= x"62";	 -- encoder maximum output rate 
--	CREG(13) <= x"10";	 -- encoder maximum output rate (MSB)
--	CREG(14) <= x"AC";	 -- IPv4 address (MSB)
--	CREG(15) <= x"10";	 -- IPv4 address 
--	CREG(16) <= x"01";	 -- IPv4 address 
--	CREG(17) <= x"80";	 -- IPv4 address 
--	CREG(18) <= x"FF";	 -- Subnet mask (MSB)
--	CREG(19) <= x"FF";	 -- Subnet mask 
--	CREG(20) <= x"FF";	 -- Subnet mask 
--	CREG(21) <= x"00";	 -- Subnet mask (LSB)
--	CREG(22) <= x"AC";	 -- Gateway IP address (MSB)
--	CREG(23) <= x"10";	 -- Gateway IP address 
--	CREG(24) <= x"01";	 -- Gateway IP address 
--	CREG(25) <= x"03";	 -- Gateway IP address (LSB)
	
	
	-- fake a configuration change during simulation
	process
	begin
		CONFIG_CHANGE_TOGGLE <= '0';
		wait for 10 us;
		CONFIG_CHANGE_TOGGLE <= '1';
		wait;
	end process;
end generate;

-- Reclock CONFIG_CHANGE_TOGGLE to be synchronous with processing clock CLK_P
RECLOCK_CLK_P_001: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		CONFIG_CHANGE_TOGGLE_D <= CONFIG_CHANGE_TOGGLE;
		CONFIG_CHANGE_TOGGLE_D2 <= CONFIG_CHANGE_TOGGLE_D;
		CONFIG_CHANGE_PULSE_CLK_P_D <= CONFIG_CHANGE_PULSE_CLK_P;
		CONFIG_CHANGE_PULSE_CLK_P_D2 <= CONFIG_CHANGE_PULSE_CLK_P_D;
		
		if(CONFIG_CHANGE_TOGGLE_D /= CONFIG_CHANGE_TOGGLE_D2) then
			CONFIG_CHANGE_PULSE_CLK_P <= '1';
		else
			CONFIG_CHANGE_PULSE_CLK_P <= '0';
		end if;
	end if;
end process;

LAN_ADDR_CHANGE_PULSE_GEN: process(CLK_P)
begin
	if rising_edge(CLK_P) then
		LAN_ADDR_CHANGE_TOGGLE_D <= LAN_ADDR_CHANGE_TOGGLE;
		LAN_ADDR_CHANGE_TOGGLE_D2 <= LAN_ADDR_CHANGE_TOGGLE_D;
		if(LAN_ADDR_CHANGE_TOGGLE_D /= LAN_ADDR_CHANGE_TOGGLE_D2) then
			LAN_ADDR_CHANGE_PULSE <= '1';
		else
			LAN_ADDR_CHANGE_PULSE <= '0';
		end if;
	end if;
end process;

end Behavioral;

