-------------------------------------------------------------
-- MSS copyright 2014-2025
-- Filename:  COM1826_RX.VHD
-- Authors: 
--		Alain Zarembowitch / MSS
-- Version: Rev 14c
-- Last modified: 6/15/25

-- Inheritance: COM1826.VHD 4/12/15
--
-- description:  TDRSS DAS receiver, including demodulator, FEC decoder, NRZ conversion
--
-- Declaration template --------------------------
--COMPONENT COM1826_RX
--GENERIC (
--    SIMULATION: std_logic
--);
--PORT(
--    CLK : IN std_logic;
--    SYNC_RESET : IN std_logic;
--    ADC_DATA_I_IN : IN std_logic_vector(13 downto 0);
--    ADC_DATA_Q_IN : IN std_logic_vector(13 downto 0);
--    ADC_SAMPLE_CLK_IN : IN std_logic;
--    AGC_RESPONSE : IN std_logic_vector(4 downto 0);
--    RECEIVER_CENTER_FREQ : IN std_logic_vector(31 downto 0);
--    NOMINAL_CHIP_RATE : IN std_logic_vector(31 downto 0);
--    CIC_R: in std_logic_vector(15 downto 0);    
--    NOMINAL_SYMBOL_RATE1: in std_logic_vector(31 downto 0);
--    NOMINAL_SYMBOL_RATE2: in std_logic_vector(31 downto 0);
--    SPREADING_FACTOR1 : IN std_logic_vector(12 downto 0);
--    SPREADING_FACTOR2 : IN std_logic_vector(12 downto 0);
--    LFSRA_INIT: in std_logic_vector(10 downto 0);
--    LFSRC_INIT: in std_logic_vector(10 downto 0);
--    CODE_MODE: in std_logic;
--    FREQ_SCAN_N_COARSE_STEPS : IN std_logic_vector(7 downto 0);
--    DEMOD_CONTROL : IN std_logic_vector(15 downto 0);
--    RESET_DEMOD_IN_FALSE_LOCK : IN std_logic;          
--    AGC_DAC : OUT std_logic_vector(11 downto 0);
--    AGC_DAC_SAMPLE_CLK : OUT std_logic;
--    DATA_I_OUT: out std_logic_vector(7 downto 0);
--    DATA_Q_OUT: out std_logic_vector(7 downto 0);
--    SAMPLE_I_CLK_OUT: out std_logic;
--    SAMPLE_Q_CLK_OUT: out std_logic;
--    SYNC_PULSE : OUT std_logic;
--    CARRIER_LOCK_OUT : OUT std_logic;
--    CODE_LOCK_OUT : OUT std_logic;
--    SIGNAL_PRESENT_OUT: OUT std_logic;
--    CARRIER_FREQUENCY_ERROR1 : OUT std_logic_vector(31 downto 0);
--    CARRIER_FREQUENCY_ERROR2 : OUT std_logic_vector(31 downto 0);
--    POWER_S_AVERAGE_OUT : OUT std_logic_vector(17 downto 0);
--    POWER_N_AVERAGE_OUT : OUT std_logic_vector(17 downto 0);
--    SNR1_LOCKED_OUT : OUT std_logic_vector(17 downto 0);
--    SNR2_LOCKED_OUT : OUT std_logic_vector(17 downto 0);
--    DESPREAD1_I_OUT : OUT std_logic_vector(13 downto 0);
--    DESPREAD1_Q_OUT : OUT std_logic_vector(13 downto 0);
--    DESPREAD1_SAMPLE_CLK : OUT std_logic;
--    BER_SYNC : OUT std_logic;
--    BER_ERROR_COUNT : OUT std_logic_vector(31 downto 0);
--    BYTE_ERROR : OUT std_logic;
--    CS0 : OUT std_logic_vector(7 downto 0);
--    CS0_CLK : 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;
--    CS3 : OUT std_logic_vector(7 downto 0);
--    CS3_CLK : OUT std_logic;
--    CS4 : OUT std_logic_vector(7 downto 0);
--    CS4_CLK : OUT std_logic;
--    CS5 : OUT std_logic_vector(7 downto 0);
--    CS5_CLK : OUT std_logic;
--    CS6 : OUT std_logic_vector(7 downto 0);
--    CS6_CLK : OUT std_logic;
--    CS7 : OUT std_logic_vector(7 downto 0);
--    CS7_CLK : OUT std_logic;
--    CS8 : OUT std_logic_vector(7 downto 0);
--    CS8_CLK : OUT std_logic;
--    CS9 : OUT std_logic_vector(7 downto 0);
--    CS9_CLK : OUT std_logic;
--    CS10 : OUT std_logic_vector(7 downto 0);
--    CS10_CLK : OUT std_logic;
--    CS11 : OUT std_logic_vector(7 downto 0);
--    CS11_CLK : OUT std_logic;
--    T1 : OUT std_logic;
--    T1_CLK : OUT std_logic;
--    T2 : OUT std_logic;
--    T2_CLK : OUT std_logic;
--    TP : OUT std_logic_vector(20 downto 1)
--    );
--END COMPONENT;

-- Instantiation template ------------------------
--COM1826_RX_001: COM1826_RX 
--generic map(
--	SIMULATION => SIMULATION
--	) 
--PORT MAP(
--	CLK => CLK_P,
--	SYNC_RESET => RECEIVER_RESET,  -- reset is MANDATORY to load the code generator initial condition
--	ADC_DATA_I_IN => RX_DATA2_I,
--	ADC_DATA_Q_IN => RX_DATA2_Q,
--	ADC_SAMPLE_CLK_IN => RX_SAMPLE2_CLK,
--	AGC_DAC => AGC_DAC,
--	AGC_DAC_SAMPLE_CLK => AGC_DAC_SAMPLE_CLK,
--	AGC_RESPONSE => RECEIVER_AGC_RESPONSE,
--	RECEIVER_CENTER_FREQ => std_logic_vector(RECEIVER_CENTER_FREQ_DYNAMIC),	
--	NOMINAL_CHIP_RATE => std_logic_vector(NOMINAL_CHIP_RATE_DYNAMIC),	
--	CIC_R => CIC_R,
--	NOMINAL_SYMBOL_RATE1 => NOMINAL_SYMBOL_RATE1,
--	NOMINAL_SYMBOL_RATE2 => NOMINAL_SYMBOL_RATE2,
--	SPREADING_FACTOR1 => SPREADING_FACTOR1, 
--	SPREADING_FACTOR2 => SPREADING_FACTOR2,
--	LFSRA_INIT => DEMOD_LFSRA_INIT, 
--	LFSRC_INIT => DEMOD_LFSRC_INIT, 
--	CODE_MODE => DEMOD_CODE_MODE,
--	FREQ_SCAN_N_COARSE_STEPS => FREQ_SCAN_N_COARSE_STEPS,
--	DEMOD_CONTROL => DEMOD_CONTROL,			
--	RESET_DEMOD_IN_FALSE_LOCK => '0',
--	DATA_I_OUT => DATA_I_OUT,
--	DATA_Q_OUT => DATA_Q_OUT,
--	SAMPLE_I_CLK_OUT => SAMPLE_I_CLK_OUT,
--	SAMPLE_Q_CLK_OUT => SAMPLE_Q_CLK_OUT,
--	SYNC_PULSE => open,
--	CARRIER_LOCK_OUT => CARRIER_LOCK_OUT,
--	CODE_LOCK_OUT => CODE_LOCK_OUT,
--	SIGNAL_PRESENT_OUT => SIGNAL_PRESENT_OUT,
--	CARRIER_FREQUENCY_ERROR1 => CARRIER_FREQUENCY_ERROR1,
--	CARRIER_FREQUENCY_ERROR2 => CARRIER_FREQUENCY_ERROR2,
--	POWER_S_AVERAGE_OUT => POWER_S_AVERAGE_OUT,
--	POWER_N_AVERAGE_OUT => POWER_N_AVERAGE_OUT,
--	SNR1_LOCKED_OUT => SNR1_LOCKED_OUT,
--	SNR2_LOCKED_OUT => SNR2_LOCKED_OUT,
--	DESPREAD1_I_OUT => open,
--	DESPREAD1_Q_OUT => open,
--	DESPREAD1_SAMPLE_CLK => open,
--	BER_SYNC => open,
--	BER_ERROR_COUNT => open,
--	BYTE_ERROR => open,
--	CS0 => open,
--	CS0_CLK => open,	
--	CS1 => open,	--  spread I-channel after frequency scanning, resampling and channel LPF filter
--	CS1_CLK => open,
--	CS2 => S1_3,	--  despread I-channel after coherent I&D, 2 samples/symbol
--	CS2_CLK => S1_3_CLK,
--	CS3 => open,	-- despread Q-channel after coherent I&D
--	CS3_CLK => open,
--	CS4 =>  S2_3,		-- demodulated I, 1 sample/symbol
--	CS4_CLK => S2_3_CLK,
--	CS5 => S1_2,	-- demodulated Q
--	CS5_CLK => S1_2_CLK,
--	CS6 => open,	--  agc18 scaling gain
--	CS6_CLK => open,
--	CS7 => S2_2,	-- code replica, 2 samples/chip
--	CS7_CLK => S2_2_CLK,
--	CS8 =>  S3_1,		-- accumulated code tracking phase correction (8 MSbs)
--	CS8_CLK => S3_1_CLK,
--	CS9 => S3_2,	-- accumulated carrier phase correction(8 MSBs)
--	CS9_CLK => S3_2_CLK,
--	CS10 =>  S3_3,		-- accumulated symbol timing phase correction (8 MSbs)
--	CS10_CLK => S3_3_CLK,
--	CS11 =>  S1_4,		-- 2(S+N)/N, valid only if code lock. Linear, not in dBs.
--	CS11_CLK => S1_4_CLK,
--	T1 => 	T1,			-- start of code replica
--	T1_CLK => T1_CLK,
--	T2 => T2,			-- code lock (1-bit). assessed once per code-sweep period
--	T2_CLK => T2_CLK,
--	TP => DEMOD_TP
--);
---------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.numeric_std.all;

entity COM1826_RX is
	generic (
		SIMULATION: std_logic := '0'
			-- 1 during simulation, 0 for release	
	);
    Port ( 
		--GLOBAL CLOCKS
		CLK: in std_logic;
			-- A/D converter clock. Global (no BUFG used within)
		SYNC_RESET: in std_logic;
			-- Component MUST be reset upon configuration or configuration change
		
		--// ADC interface
		ADC_DATA_I_IN: in std_logic_vector(13 downto 0);	-- ADC data, use MSbs, 2's complement
		ADC_DATA_Q_IN: in std_logic_vector(13 downto 0);	-- ADC data, use MSbs, 2's complement
		ADC_SAMPLE_CLK_IN: in std_logic;
			-- ADC samples, in-phase(I) and quadrature (Q)
			-- Use both I and Q in the case of near-zero center frequency input signal
			-- Use I only (force Q to zero) in the case of IF input signal, IF undesampling for example.
			-- Samples are read at the rising edge of the ADC sampling clock CLK
			-- In the case of lower precision ADCs, align the samples to the left (MSb) and fill the 
			-- the least significant bits with zeros.
			
			-- Trick: if the samples are in binary offset format, just invert the most significant bit.

		--// FRONT-END RECEIVER GAIN CONTROL
		-- When external AGC is enabled, this component can control an external attenuator or 
		-- variable gain amplifier.
		AGC_DAC: out std_logic_vector(11 downto 0);
			-- gain control. May need to be inverted depending on the analog front-end.
			-- Here, maximum AGC_DAC really means minimum gain.
		AGC_DAC_SAMPLE_CLK: out std_logic;
			-- read AGC_DAC at the rising edge of CLK when AGC_DAC_SAMPLE_CLK = 1.
		

		--// CONTROLS 
	   AGC_RESPONSE : IN std_logic_vector(4 downto 0) := "01001";          
			-- Adjust the AGC response time. approximately log2(NSymbols). 
		RECEIVER_CENTER_FREQ: in std_logic_vector(31 downto 0);	
			-- nominal (i.e. expected) center frequency. Expressed as fc/demodulator processing clock * 2^32
			-- This frequency is subtracted from the input signal center frequency. 
			-- Add -fclk/4 when used in conjunction with IF undersampling. 
		NOMINAL_CHIP_RATE: in std_logic_vector(31 downto 0);
			-- = fchip rate / fclk * 2^32
	   CIC_R: in std_logic_vector(15 downto 0);    
			-- CIC Decimation ratio. The output sampling rate is thus fclk/R
			-- 1 to bypass. 0 is illegal, otherwise, nominal range is 1 to 16384.
			-- Usage: be careful not to decimate too much as the CIC decimation filter is not very sharp and thus
			-- can distort the modulated signal. 
			-- Rule of thumb: the CIC filter output sampling rate should be >= 8 samples per symbol.
		NOMINAL_SYMBOL_RATE1: in std_logic_vector(31 downto 0);
		NOMINAL_SYMBOL_RATE2: in std_logic_vector(31 downto 0);
			-- = fsymbol rate / fclk * 2^32 = nominal chip rate / spreading factor
			-- 1 for I channel, 2 for Q channel
	 	SPREADING_FACTOR1: in std_logic_vector(12 downto 0);
	 	SPREADING_FACTOR2: in std_logic_vector(12 downto 0);
			-- spreading factor. Valid range 3 - 8191 = nominal chip rate / nominal symbol rate
			-- Not necessarily equal to the spreading code period.
			-- Channel1/I spreading factor is always less than channel2/Q.
			-- IMPORTANT!!!!
			-- KEY ASSUMPTION: the number of parallel circuits NACQ MUST be less (or equal) than the number of 
			-- CLKs in half a symbol period.
			-- IMPORTANT!!!!   Adjust the NACQ constant within accordingly.
		LFSRA_INIT: in std_logic_vector(10 downto 0);
		LFSRC_INIT: in std_logic_vector(10 downto 0);
			-- LFSR initialization. see definition in Space network interoperable pn code libraries, Appendix A
		CODE_MODE: in std_logic;
			-- 0 = forward command link Gold codes
			-- 1 = return mode 2 link Gold codes
		FREQ_SCAN_N_COARSE_STEPS: in std_logic_vector(7 downto 0);
			-- number of frequency acquisition steps in each direction
			-- total number of frequencies is thus 2*N_STEPS+1
			-- Coarse scan step size is (symbol rate/4)
	   DEMOD_CONTROL: in std_logic_vector(15 downto 0);
			-- bit 0: spectrum inversion off (0), on (1)
			-- bit 1: BPSK (0) vs SQPN(1)
			-- bit 2: SQPN dual source independent symbol rates on I/Q (0),or single source identical data on I/Q(1)
			-- bits 3-5: encoding
			--     0 = NRZ-L
			--     1 = NRZ-M
			-- 	 2 = NRZ-S
			-- 	 4 = Biphase-L
			-- bit 6: 1/2 symbol Q delay
			-- bit 7: alternating I/Q bits (yes = 1, no = 0)

			-- bit 9: Output format (0) 8 demodulated bits packed in a byte, hard-quantized (1) 4-bit soft-quantized, .
		RESET_DEMOD_IN_FALSE_LOCK: in std_logic;
			-- 1 CLK wide pulse to reset frequency scanning, carrier tracking and symbol timing loops, but not the AGC
			-- justification: a more reliable assessment of the demod lock status is generally available at 
			-- components further down the receiver (FEC decoder, HDLC deframing, etc).
			
		--// OUTPUT 
		DATA_I_OUT: out std_logic_vector(7 downto 0);
		DATA_Q_OUT: out std_logic_vector(7 downto 0);
			-- Demodulated data bits, MSb first
			-- Read at rising edge of CLK when SAMPLE_CLK_OUT = '1';
			-- Two output formats, as selected by DEMOD_CONTROL(9):
			--   4-bit soft-quantized, or 8 demodulated bits packed in a byte hard-quantization
		SAMPLE_I_CLK_OUT: out std_logic;
		SAMPLE_Q_CLK_OUT: out std_logic;
			-- one CLK-wide pulse
		SYNC_PULSE: out std_logic;
			-- 1 CLK wide pulse once per code period
			
		--// Monitoring Information
		CARRIER_LOCK_OUT: out std_logic;
		CODE_LOCK_OUT: out std_logic;
		SIGNAL_PRESENT_OUT: out std_logic;
		CARRIER_FREQUENCY_ERROR1: out std_logic_vector(31 downto 0);
            -- report the frequency error in two parts (different units, simpler to do the aggregation outside in a micro)
            -- Center frequency error1: offset with respect to the nominal carrier frequency. 
            -- 32-bit signed integer (2's complement) expressed as cfe1 * 2^32  / fclk. 
        CARRIER_FREQUENCY_ERROR2: out std_logic_vector(31 downto 0);
            -- Center frequency error2: offset with respect to the nominal carrier frequency. 
            -- 32-bit signed integer (2's complement) expressed as cfe2 * 2^32  / fchiprate. 
		POWER_S_AVERAGE_OUT: out std_logic_vector(17 downto 0);
		POWER_N_AVERAGE_OUT: out std_logic_vector(17 downto 0);
			-- averaged on-time signal and noise power. 
			-- Units are irrelevant because of the many AGCs. 
        SNR1_LOCKED_OUT: out std_logic_vector(17 downto 0) := (others => '0');
        SNR2_LOCKED_OUT: out std_logic_vector(17 downto 0) := (others => '0');
		DESPREAD1_I_OUT: out std_logic_vector(13 downto 0);
		DESPREAD1_Q_OUT: out std_logic_vector(13 downto 0);
		DESPREAD1_SAMPLE_CLK : OUT std_logic;
		BER_SYNC: out std_logic;
			-- BER measurement is synchronized with received PRBS11 test sequence
		BER_ERROR_COUNT: out std_logic_vector(31 downto 0);
			-- BER measurement over the specified window. Valid only when synchronized (BER_SYNC = '1')
			-- with the received PRBS11 test sequence
			-- bit errors expressed in number of BITS
			-- (whereas the window is expressed in bytes)
		BYTE_ERROR: out std_logic;
			-- one pulse for each byte error (helpful in visualizing the bit error distribution with an oscilloscope)
	
		-- COMSCOPE test points
		-- CS0: receiver output I-channel (after open-loop frequency translation to baseband, decimation, lpf, agc)
		-- CS1: spread I-channel after AFC, resampling and channel LPF filter
		-- CS2: despread I-channel after coherent I&D
		-- CS3: despread Q-channel after coherent I&D
		-- CS4: demodulated I
		-- CS5: demodulated Q
		-- CS6: agc18 scaling gain
		-- CS7: code replica
		-- CS8: accumulated code tracking phase correction (8 MSbs)
		-- CS9: carrier NCO phase (8 MSBs)
		-- CS10: accumulated symbol timing phase correction (8 MSbs)
		-- CS11: 2(S+N)/N, valid only if code lock. Linear, not in dBs.
		-- T1: start of code replica
		-- T2: code lock (1-bit). assessed once per code-sweep period
		CS0: out std_logic_vector(7 downto 0); 
		CS0_CLK: 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;
		CS3: out std_logic_vector(7 downto 0);	
		CS3_CLK: out std_logic;
		CS4: out std_logic_vector(7 downto 0); 
		CS4_CLK: out std_logic;
		CS5: out std_logic_vector(7 downto 0);
		CS5_CLK: out std_logic;
		CS6: out std_logic_vector(7 downto 0);
		CS6_CLK: out std_logic;
		CS7: out std_logic_vector(7 downto 0);
		CS7_CLK: out std_logic;
		CS8: out std_logic_vector(7 downto 0); 
		CS8_CLK: out std_logic;
		CS9: out std_logic_vector(7 downto 0); 
		CS9_CLK: out std_logic;
		CS10: out std_logic_vector(7 downto 0); 
		CS10_CLK: out std_logic;
		CS11: out std_logic_vector(7 downto 0); 
		CS11_CLK: out std_logic;
		T1: out std_logic;	
		T1_CLK: out std_logic;
		T2: out std_logic;	
		T2_CLK: out std_logic;

		TP : OUT std_logic_vector(20 downto 1)

			  );
end entity;

architecture Behavioral of COM1826_RX is
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------
	COMPONENT RECEIVER1
	PORT(
		CLK : IN std_logic;
		SYNC_RESET : IN std_logic;
		DATA_I_IN : IN std_logic_vector(13 downto 0);
		DATA_Q_IN : IN std_logic_vector(13 downto 0);
		SAMPLE_CLK_IN: IN std_logic;
		CENTER_FREQ : IN std_logic_vector(31 downto 0);
		AGC_RESPONSE : IN std_logic_vector(4 downto 0);
		AGC_INITIAL_GAIN: IN std_logic_vector(11 downto 0); 
	   CIC_R: in std_logic_vector(15 downto 0);    
		CONTROL : IN std_logic_vector(2 downto 0);          
		AGC_DAC : OUT std_logic_vector(11 downto 0);
		AGC_DAC_SAMPLE_CLK : OUT std_logic;
		DATA_I_OUT: out std_logic_vector(13 downto 0);
		DATA_Q_OUT: out std_logic_vector(13 downto 0);
		SAMPLE_CLK_OUT: out std_logic;
		SATURATION: out std_logic;
		TP : OUT std_logic_vector(10 downto 1);
		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;
		CS3 : OUT std_logic_vector(7 downto 0);
		CS3_CLK : OUT std_logic;
		CS4 : OUT std_logic_vector(7 downto 0);
		CS4_CLK : OUT std_logic
		);
	END COMPONENT;

	COMPONENT DSSS_DEMOD_TDRSS
	generic (
		SIMULATION: std_logic 
	);
	PORT(
		CLK : IN std_logic;
		SYNC_RESET : IN std_logic;
		SYMBOL_CLK: out std_logic;
		DATA_I_IN : IN std_logic_vector(13 downto 0);
		DATA_Q_IN : IN std_logic_vector(13 downto 0);
		SAMPLE_CLK_IN: in std_logic;
		NOMINAL_CHIP_RATE : IN std_logic_vector(31 downto 0);
		NOMINAL_SYMBOL_RATE1: in std_logic_vector(31 downto 0);
		NOMINAL_SYMBOL_RATE2: in std_logic_vector(31 downto 0);
		SPREADING_FACTOR1 : IN std_logic_vector(12 downto 0);
		SPREADING_FACTOR2 : IN std_logic_vector(12 downto 0);
		LFSRA_INIT: in std_logic_vector(10 downto 0);
		LFSRC_INIT: in std_logic_vector(10 downto 0);
		CODE_MODE: in std_logic;
		FREQ_SCAN_N_COARSE_STEPS: in std_logic_vector(7 downto 0);
		CONTROL : IN std_logic_vector(15 downto 0);
		RESET_DEMOD_IN_FALSE_LOCK: in std_logic;
		DATA_I_OUT: out std_logic_vector(3 downto 0);
		DATA_Q_OUT: out std_logic_vector(3 downto 0);
		SAMPLE_I_CLK_OUT: out std_logic;
		SAMPLE_Q_CLK_OUT: out std_logic;
		CODE_START_OUT: out std_logic;
		CARRIER_LOCK_OUT : OUT std_logic;
		CODE_LOCK_OUT : OUT std_logic;
		SIGNAL_PRESENT_OUT: out std_logic;
		CARRIER_FREQUENCY_ERROR1: out std_logic_vector(31 downto 0);
		CARRIER_FREQUENCY_ERROR2: out std_logic_vector(31 downto 0);
		POWER_S_AVERAGE_OUT: out std_logic_vector(17 downto 0);
		POWER_N_AVERAGE_OUT: out std_logic_vector(17 downto 0);
		SNR1_LOCKED_OUT: out std_logic_vector(17 downto 0);
		SNR2_LOCKED_OUT: out std_logic_vector(17 downto 0);
		DESPREAD1_I_OUT: out std_logic_vector(13 downto 0);
		DESPREAD1_Q_OUT: out std_logic_vector(13 downto 0);
		DESPREAD1_SAMPLE_CLK : 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;
		CS3: out std_logic_vector(7 downto 0);	
		CS3_CLK: out std_logic;
		CS4: out std_logic_vector(7 downto 0); 
		CS4_CLK: out std_logic;
		CS5: out std_logic_vector(7 downto 0);
		CS5_CLK: out std_logic;
		CS6: out std_logic_vector(7 downto 0);
		CS6_CLK: out std_logic;
		CS7: out std_logic_vector(7 downto 0);
		CS7_CLK: out std_logic;
		CS8: out std_logic_vector(7 downto 0); 
		CS8_CLK: out std_logic;
		CS9: out std_logic_vector(7 downto 0); 
		CS9_CLK: out std_logic;
		CS10 : OUT std_logic_vector(7 downto 0);
		CS10_CLK : OUT std_logic;
		CS11: out std_logic_vector(7 downto 0); 
		CS11_CLK: out std_logic;
		T1: out std_logic;	
		T1_CLK: out std_logic;
		T2: out std_logic;	
		T2_CLK: out std_logic;
		TP : OUT std_logic_vector(20 downto 1)
		);
	END COMPONENT;

	COMPONENT PX_TO_P8_CONVERSION
	PORT(
		CLK : IN std_logic;
		DATA_IN : IN std_logic_vector(7 downto 0);
		SAMPLE_CLK_IN : IN std_logic;
		WIDTH_IN : IN std_logic_vector(2 downto 0);          
		DATA_OUT : OUT std_logic_vector(7 downto 0);
		SAMPLE_CLK_OUT : OUT std_logic
		);
	END COMPONENT;

COMPONENT VITERBI_DECODER
GENERIC(
    K_MAX: integer;	
    N_PARITY_BITS_MAX: integer;
    NDEC: integer;  
    HARD_SOFTN_DECISION: std_logic;
    TB_DEPTH: integer;	
    SIMULATION: std_logic
);
PORT(
    CLK : IN  std_logic;
    SYNC_RESET : IN  std_logic;
    DATAIN: in std_logic_vector(31 downto 0);
    DATAIN_VALID : IN  std_logic;
    DATAIN_READY : OUT  std_logic;
    SKIP1BIT_PULSE: in std_logic;
    SYNC_CONTROL: in std_logic;
    G: in std_logic_vector(62 downto 0);  
    N_PARITY_BITS: in integer range 2 to 7;
    K: in integer range 3 to 9;
    R1: in integer range 1 to 7;
    R2: in integer range 2 to 8;
    STANDARD: in integer range 0 to 2;
    DIFF_ENC_ON: in std_logic;
    HIGH_SNR: in std_logic;
    FEC_G1_INVERSION: in std_logic;
    DATAOUT1b: out std_logic;
    DATAOUT1b_VALID: out std_logic;
    DATAOUT8b: out std_logic_vector(7 downto 0);
    DATAOUT8b_VALID: out std_logic;
    BER: out std_logic_vector(23 downto 0);
    BER_VALID : OUT  std_logic;
    BIT_ERROR: out std_logic;
    IN_SYNC: out std_logic;
    OUT_OF_SYNC : OUT  std_logic;
    LOCK_STATUS: out std_logic
    );
END COMPONENT;

COMPONENT NRZ1
PORT(
    CLK : IN std_logic;
    SYNC_RESET : IN std_logic;
    DATA_IN : IN std_logic;
    DATA_VALID_IN : IN std_logic;
    CONTROL : IN std_logic_vector(2 downto 0);          
    DATA_OUT : OUT std_logic;
    DATA_VALID_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 SIM2OUTFILE is
     Generic (
        FILENAME: string
     );
     Port ( 
        --// CLK, RESET
        CLK: in std_logic;
            -- Reference clock
        DATA1: in std_logic_vector(11 downto 0);
        DATA2: in std_logic_vector(11 downto 0);
        DATA3: in std_logic_vector(11 downto 0);
        SAMPLE_CLK_IN: in std_logic
            -- DATA_IN is read at the rising edge of CLK when SAMPLE_CLK_IN = '1'

);
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

--//-- RECLOCK INPUTS ---------------------
signal ADC_DATA_I_IN_D: std_logic_vector(13 downto 0) := (others => '0');
signal ADC_DATA_Q_IN_D: std_logic_vector(13 downto 0) := (others => '0');
signal ADC_SAMPLE_CLK_IN_D: std_logic := '0';

--//-- DIGITAL RECEIVER FRONT-END -------------------------
signal DATA1I: std_logic_vector(13 downto 0) := (others => '0');
signal DATA1Q: std_logic_vector(13 downto 0) := (others => '0');
signal SAMPLE1_CLK: std_logic := '0';
signal RECEIVER1_SATURATION: std_logic := '0';

--//-- DEMODULATOR --------------------------------------------
signal SYMBOL_CLK: std_logic := '0';	-- misnomer: chip clk
signal DATA_I_OUT_local: std_logic_vector(3 downto 0) := (others => '0');
signal DATA_Q_OUT_local: std_logic_vector(3 downto 0) := (others => '0');
signal SAMPLE_I_CLK_OUT_local: std_logic := '0';
signal SAMPLE_Q_CLK_OUT_local: std_logic := '0';
signal ANALOG_DEMOD_SYMBOL_CLK_OUT: std_logic := '0';
signal ANALOG_DEMOD_I_OUT: std_logic_vector(17 downto 0) := (others => '0');
signal ANALOG_DEMOD_Q_OUT: std_logic_vector(17 downto 0) := (others => '0');
signal DSSS_DEMOD_TP: std_logic_vector(20 downto 1) := (others => '0');
signal SNR1_LOCKED_OUT_local: std_logic_vector(17 downto 0) := (others => '0');
signal SNR2_LOCKED_OUT_local: std_logic_vector(17 downto 0) := (others => '0');

   --//-- VITERBI FEC DECODERS --------------------------------------------
signal FEC_DEC_G: std_logic_vector(62 downto 0) := (others => '0');
signal FEC_DEC_R1: integer range 1 to 7 := 1;
signal FEC_DEC_R2: integer range 2 to 8 := 2;
signal FEC_DEC_STANDARD: integer range 0 to 2 := 0;
signal FEC_DEC_DIFF_ENC_ON: std_logic := '0';
signal FEC_DEC_ENABLE: std_logic := '0';
signal FEC_G1_INVERSION: std_logic := '0';

signal FEC_DEC1_HIGH_SNR: std_logic := '0';
signal FEC_DEC1_DATAIN: std_logic_vector(31 downto 0) := (others => '0');
signal FEC_DEC1_DATAIN_VALID: std_logic := '0';
signal FEC_DEC1_DATAIN_CNTR: unsigned(2 downto 0) := (others => '0');
signal FEC_DEC1_BIT_VALID: std_logic := '0';
signal FEC_DEC1_BIT: std_logic := '0';
signal FEC_DEC8b1: std_logic_vector(7 downto 0) := (others => '0');
signal FEC_DEC8b1_VALID: std_logic := '0';
signal FEC_DEC1_LOCK_STATUS: std_logic := '0';
signal FEC_DEC1_BER_COUNT: std_logic_vector(23 downto 0) := (others => '0');
signal FEC_DEC1_BER_VALID: std_logic := '0';
signal FEC_DEC1_BIT_ERROR: std_logic := '0';
signal FEC_DEC1_IN_SYNC: std_logic := '0';
signal FEC_DEC1_OUT_OF_SYNC: std_logic := '0';
signal FEC_DEC1_LOCK_CONFIDENCE: unsigned(2 downto 0) := (others => '0');
signal FEC_DEC1_CONFIRMED_LOCK: std_logic := '0';

signal FEC_DEC2_HIGH_SNR: std_logic := '0';
signal FEC_DEC2_DATAIN: std_logic_vector(31 downto 0) := (others => '0');
signal FEC_DEC2_DATAIN_VALID: std_logic := '0';
signal FEC_DEC2_DATAIN_CNTR: unsigned(2 downto 0) := (others => '0');
signal FEC_DEC2_SKIP1BIT_PULSE: std_logic := '0';
signal FEC_DEC2_SYNC_CONTROL: std_logic := '0';
signal FEC_DEC2_BIT_VALID: std_logic := '0';
signal FEC_DEC2_BIT: std_logic := '0';
signal FEC_DEC2_LOCK_STATUS: std_logic := '0';
signal FEC_DEC2_BER_COUNT: std_logic_vector(23 downto 0) := (others => '0');
signal FEC_DEC2_BER_VALID: std_logic := '0';
signal FEC_DEC2_BIT_ERROR: std_logic := '0';
signal FEC_DEC2_IN_SYNC: std_logic := '0';
signal FEC_DEC2_OUT_OF_SYNC: std_logic := '0';
signal FEC_DEC2_LOCK_CONFIDENCE: unsigned(2 downto 0) := (others => '0');
signal FEC_DEC2_CONFIRMED_LOCK: std_logic := '0';

--//-- DATA FORMAT CONVERTER (RX) --------------------------------------
signal NRZ1_RX_CONTROL: std_logic_vector(2 downto 0) := (others => '0');
signal NRZ1_RX_DATA1_IN: std_logic := '0';
signal NRZ1_RX_DATA1_VALID_IN: std_logic := '0';
signal NRZ1_RX_DATA2_IN: std_logic := '0';
signal NRZ1_RX_DATA2_VALID_IN: std_logic := '0';
signal NRZ1_RX_DATA1_OUT: std_logic := '0';
signal NRZ1_RX_DATA1_VALID_OUT: std_logic := '0';
signal NRZ1_RX_DATA2_OUT: std_logic := '0';
signal NRZ1_RX_DATA2_VALID_OUT: std_logic := '0';

--//-- SERIAL TO 8-BIT PARALLEL  ---------------------------------------------------------
signal S2P1_CNTR: unsigned(2 downto 0) := (others => '0');
signal S2P2_CNTR: unsigned(2 downto 0) := (others => '0');
signal S2P1_DATA_IN: std_logic_vector(7 downto 0) := (others => '0');
signal S2P2_DATA_IN: std_logic_vector(7 downto 0) := (others => '0');
signal S2P1_DATA_VALID_IN: std_logic := '0';
signal S2P2_DATA_VALID_IN: std_logic := '0';

--//-- BER MEASUREMENT  ---------------------------------------------------------
signal BER2_DATA_IN: std_logic_vector(7 downto 0) := (others => '0');
signal BER2_SAMPLE_CLK_IN: 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_BYTE_ERROR: std_logic := '0';
signal BER_TEST_POINT: std_logic_vector(10 downto 1) := (others => '0');
--------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
begin

--// RECLOCK INPUTS ---------------------
-- Immediately reclock inputs for best timing.
RECLOCK_IN_001: process(CLK)
begin
	if rising_edge(CLK) then
		ADC_SAMPLE_CLK_IN_D <= ADC_SAMPLE_CLK_IN;
		ADC_DATA_I_IN_D(13 downto 0) <= ADC_DATA_I_IN(13 downto 0);
		ADC_DATA_Q_IN_D(13 downto 0) <= ADC_DATA_Q_IN(13 downto 0);
	end if;
end process;

--//-- DIGITAL RECEIVER FRONT-END -------------------------
-- Includes AGC, frequency translation to baseband, decimation and LPF.
RECEIVER1_001: RECEIVER1 PORT MAP(
	CLK => CLK,
	SYNC_RESET => SYNC_RESET,
	DATA_I_IN => ADC_DATA_I_IN_D,
	DATA_Q_IN => ADC_DATA_Q_IN_D,	-- when IF undersampling. Force Q to zero
	SAMPLE_CLK_IN => ADC_SAMPLE_CLK_IN_D,
	AGC_DAC => AGC_DAC,
	AGC_DAC_SAMPLE_CLK => AGC_DAC_SAMPLE_CLK,
	AGC_RESPONSE => AGC_RESPONSE,
	AGC_INITIAL_GAIN => x"800",	-- mid range
	CENTER_FREQ => RECEIVER_CENTER_FREQ,
	CIC_R => CIC_R,	
	CONTROL => "010",	-- enable both internal + external AGCs 
	   -- changed *0110822 because COM-3010 receiver does not have internal AGC
	DATA_I_OUT => DATA1I,
	DATA_Q_OUT => DATA1Q,
	SAMPLE_CLK_OUT => SAMPLE1_CLK,
	SATURATION => RECEIVER1_SATURATION,
	TP => open,
	CS1 => open,
	CS1_CLK => open,
	CS2 => open,
	CS2_CLK => open,
	CS3 => open,
	CS3_CLK => open,
	CS4 => open,
	CS4_CLK => open
);

--//-- DEMODULATOR --------------------------------------------
DSSS_DEMOD_TDRSS_001: DSSS_DEMOD_TDRSS 
generic map(
	SIMULATION => SIMULATION
)
PORT MAP(
	CLK => CLK,
	SYNC_RESET => SYNC_RESET, 
	SYMBOL_CLK => SYMBOL_CLK,	-- misnomer: chip clk
	DATA_I_IN => DATA1I,	--input sampling rate is CLK. 2's complement,
	DATA_Q_IN => DATA1Q,
	SAMPLE_CLK_IN => SAMPLE1_CLK,
	NOMINAL_CHIP_RATE => NOMINAL_CHIP_RATE,
	NOMINAL_SYMBOL_RATE1 => NOMINAL_SYMBOL_RATE1,
	NOMINAL_SYMBOL_RATE2 => NOMINAL_SYMBOL_RATE2,
	SPREADING_FACTOR1 => SPREADING_FACTOR1,
	SPREADING_FACTOR2 => SPREADING_FACTOR2,
	LFSRA_INIT => LFSRA_INIT,
	LFSRC_INIT => LFSRC_INIT,
	CODE_MODE => CODE_MODE,
	FREQ_SCAN_N_COARSE_STEPS => FREQ_SCAN_N_COARSE_STEPS,
	CONTROL => DEMOD_CONTROL,
	RESET_DEMOD_IN_FALSE_LOCK => RESET_DEMOD_IN_FALSE_LOCK,
	DATA_I_OUT => DATA_I_OUT_local,
	DATA_Q_OUT => DATA_Q_OUT_local,
	SAMPLE_I_CLK_OUT => SAMPLE_I_CLK_OUT_local,
	SAMPLE_Q_CLK_OUT => SAMPLE_Q_CLK_OUT_local,
	CODE_START_OUT => SYNC_PULSE,
	CARRIER_LOCK_OUT => CARRIER_LOCK_OUT,
	CODE_LOCK_OUT => CODE_LOCK_OUT,
	SIGNAL_PRESENT_OUT => SIGNAL_PRESENT_OUT,
	CARRIER_FREQUENCY_ERROR1 => CARRIER_FREQUENCY_ERROR1,
	CARRIER_FREQUENCY_ERROR2 => CARRIER_FREQUENCY_ERROR2,
	POWER_S_AVERAGE_OUT => POWER_S_AVERAGE_OUT,
	POWER_N_AVERAGE_OUT => POWER_N_AVERAGE_OUT,
	SNR1_LOCKED_OUT => SNR1_LOCKED_OUT_local,
	SNR2_LOCKED_OUT => SNR2_LOCKED_OUT_local,
	DESPREAD1_I_OUT => DESPREAD1_I_OUT,
	DESPREAD1_Q_OUT => DESPREAD1_Q_OUT,
	DESPREAD1_SAMPLE_CLK => DESPREAD1_SAMPLE_CLK,
	CS1 => CS1,	--  spread I-channel after frequency scanning, resampling and channel LPF filter
	CS1_CLK => CS1_CLK,
	CS2 => CS2,	--  despread I-channel after coherent I&D
	CS2_CLK => CS2_CLK,
	CS3 => CS3,	-- despread Q-channel after coherent I&D
	CS3_CLK => CS3_CLK,
	CS4 =>  CS4,		-- demodulated I
	CS4_CLK => CS4_CLK,
	CS5 => CS5,	-- demodulated Q
	CS5_CLK => CS5_CLK,
	CS6 => CS6,	--  agc18 scaling gain
	CS6_CLK => CS6_CLK,
	CS7 => CS7,	-- code replica
	CS7_CLK => CS7_CLK,
	CS8 =>  CS8,		-- accumulated code tracking phase correction (8 MSbs)
	CS8_CLK => CS8_CLK,
	CS9 => CS9,	-- accumulated carrier phase correction(8 MSBs)
	CS9_CLK => CS9_CLK,
	CS10 =>  CS10,		-- accumulated symbol timing phase correction (8 MSbs)
	CS10_CLK => CS10_CLK,
	CS11 =>  CS11,		-- 2(S+N)/N, valid only if code lock. Linear, not in dBs.
	CS11_CLK => CS11_CLK,
	T1 => T1,			-- start of code replica
	T1_CLK => T1_CLK,
	T2 => T2,			-- code lock (1-bit). assessed once per code-sweep period
	T2_CLK => T2_CLK,
	TP => DSSS_DEMOD_TP
);
SNR1_LOCKED_OUT <= SNR1_LOCKED_OUT_local;
SNR2_LOCKED_OUT <= SNR2_LOCKED_OUT_local;

--//-- VITERBI FEC DECODERS -------------------------------------------
FEC_DEC_ENABLE <= '1';
-- Rate R = R1/R2
FEC_DEC_R1 <= 1;
FEC_DEC_R2 <= 2;
FEC_DEC_STANDARD <= 1; -- CCSDS 
FEC_DEC_G(8 downto 0) <= O"171";
FEC_DEC_G(17 downto 9) <= O"133";
FEC_DEC_DIFF_ENC_ON <= '0';

-- FEC DECODER#1  I-CHANNEL -------------------
-- Adjust FEC threshold BER as a function of the measured SNR (measured in the demod).
-- This provides a better tradeoff between missed out of lock at high SNR and false out of lock at low SNR.
FEC_DECODER_001: process(CLK) 
begin
	if rising_edge(CLK) then
		if(unsigned(SNR1_LOCKED_OUT_local) < 40) then	-- heuristic threshold for low SNR  (10 dB)
			FEC_DEC1_HIGH_SNR <= '0';
		else
			FEC_DEC1_HIGH_SNR <= '1';
		end if;
	end if;
end process;

-- pack 8 soft-quantized samples into a 32-bit word
FEC_DECODER_002: process(CLK) 
begin
	if rising_edge(CLK) then
		if(SYNC_RESET ='1') or (FEC_DEC_ENABLE = '0') then
			FEC_DEC1_DATAIN <= (others => '0');
			FEC_DEC1_DATAIN_CNTR <= (others => '0');
			FEC_DEC1_DATAIN_VALID <= '0';
		elsif(SAMPLE_I_CLK_OUT_local = '1') then
			-- shift in next 4-bit soft-quantized sample
			FEC_DEC1_DATAIN(3 downto 0) <= DATA_I_OUT_local(3 downto 0);
			FEC_DEC1_DATAIN(31 downto 4) <= FEC_DEC1_DATAIN(27 downto 0);
			FEC_DEC1_DATAIN_CNTR <= FEC_DEC1_DATAIN_CNTR + 1;
			if(FEC_DEC1_DATAIN_CNTR = 7) then
				-- modulo-8 counter
				-- vector is packed. Pass to Viterbi decoder.
				FEC_DEC1_DATAIN_VALID <= '1';
			else
				FEC_DEC1_DATAIN_VALID <= '0';
			end if;
		else
			FEC_DEC1_DATAIN_VALID <= '0';
		end if;
	end if;
end process;

FEC_DECODER_003: VITERBI_DECODER 
	GENERIC MAP(
		K_MAX => 7,
		N_PARITY_BITS_MAX => 2,
		NDEC => 1,
		HARD_SOFTN_DECISION => '0',
		TB_DEPTH => 88,	-- TEST TEST TEST
		SIMULATION => '0'
	)
	PORT MAP (
	 CLK => CLK,
	 SYNC_RESET => SYNC_RESET,  -- reset is MANDATORY to initialize configuration within.
	 DATAIN => FEC_DEC1_DATAIN,
	 DATAIN_VALID => FEC_DEC1_DATAIN_VALID,
	 SKIP1BIT_PULSE => '0',
	 SYNC_CONTROL => '0',
	 G => FEC_DEC_G, 	-- encoder generator polynomials
	 N_PARITY_BITS => 2, -- fixed. 2 generator polynomials G0/G1
	 K => 7,	-- fixed constraint length K=7
	 R1 => FEC_DEC_R1,
	 R2 => FEC_DEC_R2,
	 STANDARD => FEC_DEC_STANDARD,	
	 DIFF_ENC_ON => FEC_DEC_DIFF_ENC_ON,
	 HIGH_SNR => FEC_DEC1_HIGH_SNR,
	 FEC_G1_INVERSION => FEC_G1_INVERSION,
	 DATAIN_READY => open,	-- no input flow control
	 DATAOUT1b => FEC_DEC1_BIT,
	 DATAOUT1b_VALID => FEC_DEC1_BIT_VALID,
	 DATAOUT8b => FEC_DEC8b1,	-- unused
	 DATAOUT8b_VALID => FEC_DEC8b1_VALID, -- unused
	 BER => FEC_DEC1_BER_COUNT,
	 BER_VALID => FEC_DEC1_BER_VALID,
	 BIT_ERROR => FEC_DEC1_BIT_ERROR,
	 IN_SYNC => FEC_DEC1_IN_SYNC,
	 OUT_OF_SYNC => FEC_DEC1_OUT_OF_SYNC,
	 LOCK_STATUS => open
  );

-- generate a FEC lock confidence level (more reliable at threshold SNR)
-- A kind of flywheel. We will not declare 'FEC out of lock' for just one bad report.
-- Very sensitive trigger: just one report is sufficient to declare FEC decoder lock, at least temporarily.
FEC_DEC1_LOCK_CONFIDENCE_GEN_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(SYNC_RESET = '1') then
			FEC_DEC1_LOCK_CONFIDENCE <= (others => '0');
		elsif(FEC_DEC1_IN_SYNC = '1') and ((not FEC_DEC1_LOCK_CONFIDENCE) /= 0) then
			FEC_DEC1_LOCK_CONFIDENCE <= FEC_DEC1_LOCK_CONFIDENCE + 1;
		elsif(FEC_DEC1_OUT_OF_SYNC = '1') and (FEC_DEC1_LOCK_CONFIDENCE /= 0) then
			FEC_DEC1_LOCK_CONFIDENCE <= FEC_DEC1_LOCK_CONFIDENCE - 1;
		end if;
	end if;
end process;
FEC_DEC1_LOCK_STATUS <= '0' when (FEC_DEC1_LOCK_CONFIDENCE = 0) else '1';	
	-- Very sensitive trigger: just one report is sufficient to declare FEC decoder lock, at least temporarily.
FEC_DEC1_CONFIRMED_LOCK <= '1' when ((not FEC_DEC1_LOCK_CONFIDENCE) = 0) else '0';
	-- highest degree of confidence that Viterbi decoder is in sync,

-- FEC DECODER#2  Q-CHANNEL -------------------
-- Adjust FEC threshold BER as a function of the measured SNR (measured in the demod).
-- This provides a better tradeoff between missed out of lock at high SNR and false out of lock at low SNR.
FEC_DECODER_011: process(CLK) 
begin
	if rising_edge(CLK) then
		if(unsigned(SNR2_LOCKED_OUT_local) < 40) then	-- heuristic threshold for low SNR  (10 dB)
			FEC_DEC2_HIGH_SNR <= '0';
		else
			FEC_DEC2_HIGH_SNR <= '1';
		end if;
	end if;
end process;

-- pack 8 soft-quantized samples into a 32-bit word
FEC_DECODER_012: process(CLK) 
begin
	if rising_edge(CLK) then
		if(SYNC_RESET ='1') or (FEC_DEC_ENABLE = '0') then
			FEC_DEC2_DATAIN <= (others => '0');
			FEC_DEC2_DATAIN_CNTR <= (others => '0');
			FEC_DEC2_DATAIN_VALID <= '0';
		elsif(SAMPLE_Q_CLK_OUT_local = '1') then
			-- shift in next 4-bit soft-quantized sample
			FEC_DEC2_DATAIN(3 downto 0) <= DATA_Q_OUT_local(3 downto 0);
			FEC_DEC2_DATAIN(31 downto 4) <= FEC_DEC2_DATAIN(27 downto 0);
			FEC_DEC2_DATAIN_CNTR <= FEC_DEC2_DATAIN_CNTR + 1;
			if(FEC_DEC2_DATAIN_CNTR = 7) then
				-- modulo-8 counter
				-- vector is packed. Pass to Viterbi decoder.
				FEC_DEC2_DATAIN_VALID <= '1';
			else
				FEC_DEC2_DATAIN_VALID <= '0';
			end if;
		else
			FEC_DEC2_DATAIN_VALID <= '0';
		end if;
	end if;
end process;

---- Synchronize both Viterbi decoders (dec1 is master, dec2 is slave) in the case of SQPN alternating i/q mode
--FEC_DEC2_SKIP1BIT_PULSE <= FEC_DEC1_OUT_OF_SYNC when (REG26(1) = '1') and (REG26(7) = '1') else '0';
--FEC_DEC2_SYNC_CONTROL <= '1' when (REG26(1) = '1') and (REG26(7) = '1') else '0';

FEC_DECODER_013: VITERBI_DECODER 
	GENERIC MAP(
		K_MAX => 7,
		N_PARITY_BITS_MAX => 2,
		NDEC => 1,
		HARD_SOFTN_DECISION => '0',
		TB_DEPTH => 88,	
		SIMULATION => '0'
	)
	PORT MAP (
	 CLK => CLK,
	 SYNC_RESET => SYNC_RESET,  -- reset is MANDATORY to initialize configuration within.
	 DATAIN => FEC_DEC2_DATAIN,
	 DATAIN_VALID => FEC_DEC2_DATAIN_VALID,
	 SKIP1BIT_PULSE => FEC_DEC2_SKIP1BIT_PULSE,
	 SYNC_CONTROL => FEC_DEC2_SYNC_CONTROL,
	 G => FEC_DEC_G, 	-- encoder generator polynomials
	 N_PARITY_BITS => 2, -- fixed. 2 generator polynomials G0/G1
	 K => 7,	-- fixed constraint length K=7
	 R1 => FEC_DEC_R1,
	 R2 => FEC_DEC_R2,
	 STANDARD => FEC_DEC_STANDARD,	
	 DIFF_ENC_ON => FEC_DEC_DIFF_ENC_ON,
	 HIGH_SNR => FEC_DEC2_HIGH_SNR,
	 FEC_G1_INVERSION => FEC_G1_INVERSION,
	 DATAIN_READY => open,	-- no input flow control
	 DATAOUT1b => FEC_DEC2_BIT,
	 DATAOUT1b_VALID => FEC_DEC2_BIT_VALID,
	 DATAOUT8b => open,
	 DATAOUT8b_VALID => open,
	 BER => FEC_DEC2_BER_COUNT,
	 BER_VALID => FEC_DEC2_BER_VALID,
	 BIT_ERROR => FEC_DEC2_BIT_ERROR,
	 IN_SYNC => FEC_DEC2_IN_SYNC,
	 OUT_OF_SYNC => FEC_DEC2_OUT_OF_SYNC,
	 LOCK_STATUS => open
  );

-- generate a FEC lock confidence level (more reliable at threshold SNR)
-- A kind of flywheel. We will not declare 'FEC out of lock' for just one bad report.
-- Very sensitive trigger: just one report is sufficient to declare FEC decoder lock, at least temporarily.
FEC_DEC2_LOCK_CONFIDENCE_GEN_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(SYNC_RESET = '1') then
			FEC_DEC2_LOCK_CONFIDENCE <= (others => '0');
		elsif(FEC_DEC2_IN_SYNC = '1') and ((not FEC_DEC2_LOCK_CONFIDENCE) /= 0) then
			FEC_DEC2_LOCK_CONFIDENCE <= FEC_DEC2_LOCK_CONFIDENCE + 1;
		elsif(FEC_DEC2_OUT_OF_SYNC = '1') and (FEC_DEC2_LOCK_CONFIDENCE /= 0) then
			FEC_DEC2_LOCK_CONFIDENCE <= FEC_DEC2_LOCK_CONFIDENCE - 1;
		end if;
	end if;
end process;
FEC_DEC2_LOCK_STATUS <= '0' when (FEC_DEC2_LOCK_CONFIDENCE = 0) else '1';	
	-- Very sensitive trigger: just one report is sufficient to declare FEC decoder lock, at least temporarily.
FEC_DEC2_CONFIRMED_LOCK <= '1' when ((not FEC_DEC2_LOCK_CONFIDENCE) = 0) else '0';
	-- highest degree of confidence that Viterbi decoder is in sync,

--//-- DATA FORMAT CONVERTER (RX) --------------------------------------
-- converts NRZ-L/M/S to NRZ-L
-- Two converters, for I and Q channels respectively
NRZ1_RX_CONTROL <= "000";	-- NRZ-L unchanged
--NRZ1_RX_CONTROL <= "011";	-- NRZ_M to NRZ-L
--NRZ1_RX_CONTROL <= "100";	-- NRZ_S to NRZ-L

	-- bypass FEC decoding?
	NRZ1_RX_INPUT_SEL: process(CLK)
	begin
		if rising_edge(CLK) then
			if(FEC_DEC_ENABLE = '0') then
				-- FEC decoders are bypassed
				NRZ1_RX_DATA1_IN <= DATA_I_OUT_local(3);
				NRZ1_RX_DATA1_VALID_IN <= SAMPLE_I_CLK_OUT_local;
				NRZ1_RX_DATA2_IN <= DATA_Q_OUT_local(3);
				NRZ1_RX_DATA2_VALID_IN <= SAMPLE_Q_CLK_OUT_local;
			else
				NRZ1_RX_DATA1_IN <= FEC_DEC1_BIT;
				NRZ1_RX_DATA1_VALID_IN <= FEC_DEC1_BIT_VALID;
				NRZ1_RX_DATA2_IN <= FEC_DEC2_BIT;
				NRZ1_RX_DATA2_VALID_IN <= FEC_DEC2_BIT_VALID;
			end if;
		end if;
	end process;

	NRZ1_RX_001: NRZ1 PORT MAP(
		CLK => CLK,
		SYNC_RESET => SYNC_RESET,
		DATA_IN => NRZ1_RX_DATA1_IN,
		DATA_VALID_IN => NRZ1_RX_DATA1_VALID_IN,
		CONTROL => NRZ1_RX_CONTROL,
		DATA_OUT => NRZ1_RX_DATA1_OUT,
		DATA_VALID_OUT => NRZ1_RX_DATA1_VALID_OUT
	);

	NRZ1_RX_002: NRZ1 PORT MAP(
		CLK => CLK,
		SYNC_RESET => SYNC_RESET,
		DATA_IN => NRZ1_RX_DATA2_IN,
		DATA_VALID_IN => NRZ1_RX_DATA2_VALID_IN,
		CONTROL => NRZ1_RX_CONTROL,
		DATA_OUT => NRZ1_RX_DATA2_OUT,
		DATA_VALID_OUT => NRZ1_RX_DATA2_VALID_OUT
	);

--//-- SERIAL TO 8-BIT PARALLEL  ---------------------------------------------------------
	S2P_001: process(CLK)
	begin
		if rising_edge(CLK) then
			if(SYNC_RESET = '1') then
				S2P1_CNTR <= "000";	-- modulo-8 bit counter
				S2P1_DATA_VALID_IN <= '0';
				S2P1_DATA_IN <= x"00";
			elsif(NRZ1_RX_DATA1_VALID_OUT = '1') then
				if(DEMOD_CONTROL(7) = '1') then
					-- special case. Alternating I/Q modes, shift-in both I and Q bits, I first
					S2P1_CNTR(2 downto 1) <= unsigned(S2P1_CNTR(2 downto 1)) + 1;
					S2P1_CNTR(0) <= '0';	-- force even counter alignment
					S2P1_DATA_IN <= S2P1_DATA_IN(5 downto 0) & NRZ1_RX_DATA1_OUT & NRZ1_RX_DATA2_OUT;	-- shift left (MSb first)
					if(S2P1_CNTR = 6) then
						S2P1_DATA_VALID_IN <= '1';
					else
						S2P1_DATA_VALID_IN <= '0';
					end if;
				else
					S2P1_CNTR <= S2P1_CNTR + 1;
					S2P1_DATA_IN <= S2P1_DATA_IN(6 downto 0) & NRZ1_RX_DATA1_OUT;	-- shift left (MSb first)
					if(S2P1_CNTR = 7) then
						S2P1_DATA_VALID_IN <= '1';
					else
						S2P1_DATA_VALID_IN <= '0';
					end if;
				end if;
			else
				S2P1_DATA_VALID_IN <= '0';
			end if;
		end if;
	end process;
	
	S2P_002: process(CLK)
	begin
		if rising_edge(CLK) then
			if(SYNC_RESET = '1') then
				S2P2_CNTR <= "000";	-- modulo-8 bit counter
				S2P2_DATA_VALID_IN <= '0';
				S2P2_DATA_IN <= x"00";
			elsif(NRZ1_RX_DATA2_VALID_OUT = '1') then
				S2P2_CNTR <= S2P2_CNTR + 1;
				S2P2_DATA_IN <= S2P2_DATA_IN(6 downto 0) & NRZ1_RX_DATA2_OUT;	-- shift left (MSb first)
				if(S2P2_CNTR = 7) then
					S2P2_DATA_VALID_IN <= '1';
				else
					S2P2_DATA_VALID_IN <= '0';
				end if;
			else
				S2P2_DATA_VALID_IN <= '0';
			end if;
		end if;
	end process;
	
--//-- BER MEASUREMENT  ---------------------------------------------------------
-- Measure BER when a PRSB-11 test sequence is transmitted
-- BER measurement 8-bit parallel serial input selection
BER2_001: process(CLK)
begin
	if rising_edge(CLK) then
        -- I-channel BER measurement
        BER2_DATA_IN <= S2P1_DATA_IN;
        BER2_SAMPLE_CLK_IN <= S2P1_DATA_VALID_IN;
--        -- Q-channel BER measurement
--        BER2_DATA_IN <= S2P2_DATA_IN;
--        BER2_SAMPLE_CLK_IN <= S2P2_DATA_VALID_IN;
	end if;
end process;

BER_CONTROL(2 downto 0) <= "001"; -- BER measured over 80,000-bit window.
BER_CONTROL(7 downto 3) <= (others => '0'); -- unused

BER2_002: BER2 PORT MAP(
	CLK => CLK,
	SYNC_RESET => SYNC_RESET,
	DATA_IN => BER2_DATA_IN,
	SAMPLE_CLK_IN => BER2_SAMPLE_CLK_IN,
	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
);























---- 1-bit serial to 8-bit parallel conversion
--RX_DATA1b1_X <= (0 => DATA_I_OUT_local(3), others => '0');
--RX_SAMPLE1b1_CLK <= SAMPLE_I_CLK_OUT_local;
--PX_TO_P8_CONVERSION_003: PX_TO_P8_CONVERSION 
--PORT MAP(
--	CLK => CLK,
--	DATA_IN => RX_DATA1b1_X,		-- 1-bit serial input
--	SAMPLE_CLK_IN => RX_SAMPLE1b1_CLK,
--	WIDTH_IN => "001",
--	DATA_OUT => RX_DATA8b1,		-- 8-bit parallel output
--	SAMPLE_CLK_OUT => RX_SAMPLE8b1_CLK
--);

--RX_DATA1b2_X <= (0 => DATA_Q_OUT_local(3), others => '0');
--RX_SAMPLE1b2_CLK <= SAMPLE_Q_CLK_OUT_local;
--PX_TO_P8_CONVERSION_004: PX_TO_P8_CONVERSION 
--PORT MAP(
--	CLK => CLK,
--	DATA_IN => RX_DATA1b2_X,		-- 1-bit serial input
--	SAMPLE_CLK_IN => RX_SAMPLE1b2_CLK,
--	WIDTH_IN => "001",
--	DATA_OUT => RX_DATA8b2,		-- 8-bit parallel output
--	SAMPLE_CLK_OUT => RX_SAMPLE8b2_CLK
--);

---- to output
---- select output format:
---- bit 9: Output format (0) 8 demodulated bits packed in a byte, hard-quantized (1) 4-bit soft-quantized, .
--OUTPUT_FORMAT_001: process(CLK)
--begin
--    if rising_edge(CLK) then
--        if(DEMOD_CONTROL(9) = '1') then
--            -- Output format (1) 4-bit soft-quantized
--            DATA_I_OUT <= "0000" & DATA_I_OUT_local;
--            DATA_Q_OUT <= "0000" & DATA_Q_OUT_local;
--            SAMPLE_I_CLK_OUT <= SAMPLE_I_CLK_OUT_local;
--            SAMPLE_Q_CLK_OUT <= SAMPLE_Q_CLK_OUT_local;
--        else
--            -- Output format (0) 8 demodulated bits packed in a byte, hard-quantized.
--            DATA_I_OUT <= RX_DATA8b1;
--            DATA_Q_OUT <= RX_DATA8b2;
--            SAMPLE_I_CLK_OUT <= RX_SAMPLE8b1_CLK;
--            SAMPLE_Q_CLK_OUT <= RX_SAMPLE8b2_CLK;
--        end if;
--    end if;
--end process;


--// SIM2OUTFILE --------------------------------------------
-- simulation. send to a tab-delimited text file for subsequent (Matlab) plot.
--
SIM2OUTFILE_X: if(SIMULATION = '1') generate
	SIM2OUTFILE_001: SIM2OUTFILE 
	generic map(
		FILENAME => "rx_top1.txt"
	)
	PORT MAP(
		CLK => CLK,
		DATA1 => DATA1I(13 downto 2),	-- receiver1 output I,
		DATA2 => DATA1Q(13 downto 2),	-- receiver1 output Q,
		DATA3 => x"000",
		SAMPLE_CLK_IN => SAMPLE1_CLK
	);

end generate;

--// MONITORING, TEST POINTS --------------------------------------------
CS0 <= DATA1I(13 downto 6);
CS0_CLK <= SAMPLE1_CLK;
TP(19 downto 1) <= DSSS_DEMOD_TP(19 downto 1);
TP(20) <= RECEIVER1_SATURATION;
end Behavioral;
