----------------------------------------------
-- MSS copyright 1999-2002
-- Filename: SOF_SYNC.VHD
-- Authors: 
--		Alain Zarembowitch / MSS
--		Nayef Ahmar / MSS
-- Inheritance: Sirius MRC_SOF.VHD rev0.004
-- Edit date: 2-6-02
-- Revision: 0.002
--
--	Rev 0.002 AZ 2-6-02
-- Programmable period
----------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;    
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity SOF_SYNC is
    port (
		CLK: in std_logic;	
			-- reference clock, typically 30 MHz, for all synchronous design
    	ASYNC_RESET: in  std_logic;
			-- asynchronous reset active high for initialization to well known state prior to power up
      DATA_IN: in std_logic_vector(3 downto 0);     
			-- demodulated data bits from QPSK demodulator
			-- Read DATA_IN at rising edge of CLK when BIT_CLK = '1'
		BIT_CLK_IN: in std_logic;
			-- defines the bit period. pulse is 1 CLK period long.
		FRAME_LENGTH: in std_logic_vector(12 downto 0);
			-- unique word period.


		BIT_CLK_OUT: out std_logic;
			-- 1 CLK period long	
		SOF: out std_logic;
			-- recovered start of frame. width = 1 bit long
			-- Read when BIT_CLK_OUT = '1'
		   -- coincides with bit 48 (counts start at 0) of a 2048 bit frame. 
     	SOF_LOCK_DETECT: out std_logic;
			-- indicates solid tracking of the training sequence if CONSTANTLY at 1
			-- indicates that the circuit is trying to acquire the training sequence
			-- if this flag toggles. 
			-- synchronous with the rising edge of the clock CLK
			-- Read when BIT_CLK_OUT = '1'
		PHASE: out std_logic_vector(1 downto 0);
			--phase after error correction 
			-- Read when BIT_CLK_OUT = '1'
		DATA_ENABLE: out std_logic;
			-- indicates the start of data receive
			-- should occur coincidental with bit 48(count starts at 0) 
			-- of a 2048-bit frame.  
			-- Read when BIT_CLK_OUT = '1'
		DATA_OUT: out std_logic_vector(3 downto 0);
			-- output data after correction of I&Q phase ambiguity
			-- Read when BIT_CLK_OUT = '1'
		BER: out std_logic_vector(16 downto 0);
			-- bit error rate: number of detected bit errors over 1024 bits of sync words 
		TP_MRC_SOF: out std_logic_vector(3 downto 0)
			-- test points
			-- bit 0 detect
			-- bit 1 phase detect 0
			-- bit 2 phase detect 1
			-- bit 3 SOF_LOCAL
	  
		);
 end SOF_SYNC;
  
architecture BEHAVIOR of SOF_SYNC is
-----------------------------------------------------------------
-- COMPONENTS
-----------------------------------------------------------------
-- matched filter
component MATCHED_FILTER32 is
    port (
		CLK: in std_logic;	
			-- reference clock, synchronous design
    	ASYNC_RESET: in  std_logic;
			-- asynchronous reset active high for initialization to well known state prior to power up
      DATA_IN: in std_logic;     
			-- demodulated data bits from QPSK demodulator (MSB, soft quantized bits not needed here)
			-- Read DATA_IN at rising edge of CLK when BIT_CLK_IN = '1'
		BIT_CLK_IN: in std_logic;
			-- defines the bit period. pulse is 1 CLK period long.
		DETECT_OUT: out std_logic;
			-- output of the matched filter  
			-- The DETECT pulse will nominally occur while I = bit 31 (start counting at zero)
			-- DETECT and phase are available 3 CLK after start of input bit 31      
		PHASE_OUT: out std_logic_vector(1 downto 0);
			-- two bits that will help us resolve the QPSK phase ambiguity
			-- This signal is valid only when the DETECT is HIGH
		UW_SYMBOL_ALIGNMENT: out std_logic
			-- '1' if unique word is aligned with symbol at the modulor,
			-- '0' otherwise
	);
 end component;      


component SOF_TRACK is
    port (
		CLK: in std_logic;	
			-- reference clock for synchronous design
  		ASYNC_RESET: in  std_logic;
			-- asynchronous reset active high for initialization to well known state prior to power up
      DETECT: in std_logic;     
			-- flag indicating training sequence detection by the 32-bit matched
			-- filter. Synchronous with rising edge of the clock CLK.  
			-- Generated immediately after receiving the last bit of the UW (bit 31).
			-- Read when BIT_CLK = '1'.
      PHASE_IN: in std_logic_vector(1 downto 0);
			--input phase, somewhat unreliable as it is not protected against bit errors.
			-- Read when BIT_CLK = '1' and DETECT = '1'
		BIT_CLK: in std_logic;
			-- defines the bit period. pulse is 1 CLK period long.
			-- First CLK of each new data bit.
		FRAME_LENGTH: in std_logic_vector(12 downto 0);
			-- unique word period.


		SOF: out std_logic;
			-- recovered start of frame. width = 1 bit long
			-- Read when BIT_CLK_D = '1'
		   -- coincides with bit 32 (counts start at 0) of a TBD bit frame. 
     	SOF_LOCK_DETECT: out std_logic;
			-- indicates solid tracking of the training sequence if CONSTANTLY at 1
			-- indicates that the circuit is trying to acquire the training sequence
			-- if this flag toggles. 
			-- synchronous with the rising edge of the clock CLK
		PHASE: out std_logic_vector(1 downto 0);
			--phase after error correction 
			-- Read when BIT_CLK_D = '1'
		DATA_ENABLE: out std_logic;
			-- indicates the start of data receive
			-- should occur coincidental with bit 32(count starts at 0) 
			-- of a 4096+32-bit frame.  
			-- Read when BIT_CLK_D = '1'
		TP: out std_logic_vector(0 downto 0)
	);
end component;

component PHASE_AMBIGUITY_REMOVAL is
    port (
 		CLK: in std_logic;	
			-- reference clock, typically 30 MHz, for all synchronous design
    	ASYNC_RESET: in  std_logic;
			-- asynchronous reset active high for initialization to well known state prior to power up
      DATA_IN: in std_logic_vector(3 downto 0);     
			-- demodulated data bits from QPSK demodulator, soft quantized with 4 bits
			-- representation is 0 - F, 0 is most negative, F is most positive, 
			-- no zero representation, 7 is the least negative, 8 is the least positive.
			-- Read DATA_IN at rising edge of CLK when BIT_CLK = '1'
		BIT_CLK_IN: in std_logic;
			-- defines the bit period. pulse is 1 CLK period long.
		SOF: in std_logic;
			-- start of frame. synchronous with rising edge of CLK.
			-- typically high during bit 48 of a 2048 bit frame (we start counting at zero).
		PHASE: in std_logic_vector(1 downto 0);
			-- two bits that will help us resolve the QPSK phase ambiguity
			-- This signal is valid only when the DETECT is HIGH

		DATA_OUT: out std_logic_vector(3 downto 0)
			-- output data after correction of I&Q phase ambiguity
			-- Latency: 1 bit + 1 CLK
	);
end component;

component BER_MEASUREMENT2 is
    port (
    	ASYNC_RESET: in  std_logic;
			-- asynchronous reset active high for initialization to well known state prior to power up
 		CLK: in std_logic;	
			-- reference clock, synchronous design
      SOF: in std_logic;
		BIT_CLK: in std_logic;
      DATA: in std_logic;
		FRAME_LENGTH: in std_logic_vector(12 downto 0);
			-- unique word period.

		BER: out std_logic_vector(16 downto 0)
			-- bit error rate, measured over 1024 bits .

	);
end component;


-----------------------------------------------------------------
-- SIGNALS
-----------------------------------------------------------------
-- Suffix _D denotes one CLK delayed version of the net with the same name.
signal zero: std_logic;
signal one: std_logic;    
signal BIT_CLK0: std_logic;
signal DATA0: std_logic_vector(3 downto 0);
signal DETECT: std_logic;
signal PHASE_DETECT: std_logic_vector(1 downto 0);
signal DATA_IN_D: std_logic_vector(3 downto 0);
signal DATA_IN_D2: std_logic_vector(3 downto 0);
signal DATA_IN_D3: std_logic_vector(3 downto 0);
signal DATA_IN_D4: std_logic_vector(3 downto 0);
signal DATA_OUT_LOCAL: std_logic_vector(3 downto 0);
signal BIT_CLK_IN_D: std_logic;
signal BIT_CLK_IN_D2: std_logic;
signal BIT_CLK_IN_D3: std_logic;
signal BIT_CLK_IN_D4: std_logic;
signal BIT_CLK_IN_D5: std_logic;
signal SOF_LOCAL: std_logic;
signal PHASE_LOCAL: std_logic_vector(1 downto 0);
signal DATA_ENABLE_LOCAL: std_logic;
signal SOF_LOCK_DETECT_LOCAL: std_logic;

signal SOF_FLAG: std_logic;
signal DATA_ENABLE_FLAG: std_logic;
signal SOF_LOCK_DETECT_FLAG: std_logic;
signal PHASE_FLAG: std_logic_vector(1 downto 0);

signal SOF_FLAG_D: std_logic;
signal DATA_ENABLE_FLAG_D: std_logic;
signal SOF_LOCK_DETECT_FLAG_D: std_logic;
signal PHASE_FLAG_D: std_logic_vector(1 downto 0);

signal SOF_D5: std_logic;       
signal UW_SYMBOL_ALIGNMENT: std_logic;
signal SOF_1BIT_DELAY: std_logic;
signal PHASE_1BIT_DELAY: std_logic_vector(1 downto 0);
signal DATA_ENABLE_1BIT_DELAY: std_logic;    
signal SOF2: std_logic;
signal PHASE2: std_logic_vector(1 downto 0);
signal DATA_ENABLE2: std_logic;    

signal SOF_TRACK_TP: std_logic_vector(0 downto 0);
-----------------------------------------------------------------
-- IMPLEMENTATION
-----------------------------------------------------------------
begin 
zero <= '0';
one <= '1';    

-- Reclock input
RECLOCK_INPUT: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		BIT_CLK0 <= '0';
		DATA0 <= (others => '0');
	elsif rising_edge(CLK) then
		BIT_CLK0 <= BIT_CLK_IN;       
		if(BIT_CLK_IN = '1') then
			DATA0 <= DATA_IN;
		end if;
	end if;
end process;

-- instantiate the 32-bit matched filter 
-- uses most significant bit of DATA0
-- Latency is 3 CLKs.     
-- DETECT pulse is one bit wide.
MF001: MATCHED_FILTER32 port map(
	CLK => CLK, 
	ASYNC_RESET => ASYNC_RESET, 
	DATA_IN => DATA0(3), 
	BIT_CLK_IN => BIT_CLK0, 
	DETECT_OUT => DETECT, 
	PHASE_OUT => PHASE_DETECT,
	UW_SYMBOL_ALIGNMENT => UW_SYMBOL_ALIGNMENT
	);

-- delay clock
RECLOCK_000: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		BIT_CLK_IN_D <= '0';
		BIT_CLK_IN_D2 <= '0';
		BIT_CLK_IN_D3 <= '0';
	elsif rising_edge(CLK) then
		BIT_CLK_IN_D <= BIT_CLK0;
		BIT_CLK_IN_D2 <= BIT_CLK_IN_D;
		BIT_CLK_IN_D3 <= BIT_CLK_IN_D2;
	end if;
end process;

-- confirm and track SOF and PHASE ambiguity
-- Inputs DETECT, PHASE_DETECT are aligned with BIT_CLK_IN_D3
-- Latency: 1 CLK
-- SOF_LOCAL ready at BIT_CLK_IN_D4
SOF_TRACK_001: SOF_TRACK port map(
	CLK => CLK, 
	ASYNC_RESET => ASYNC_RESET, 
	DETECT => DETECT,
	PHASE_IN => PHASE_DETECT, 
	BIT_CLK => BIT_CLK_IN_D3, 
	FRAME_LENGTH => FRAME_LENGTH,
	SOF => SOF_LOCAL, 
	SOF_LOCK_DETECT => SOF_LOCK_DETECT_LOCAL,
	PHASE => PHASE_LOCAL, 
	DATA_ENABLE => DATA_ENABLE_LOCAL,
	TP => SOF_TRACK_TP
	);


RECLOCK_001: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		BIT_CLK_IN_D4 <= '0';
	elsif rising_edge(CLK) then
		BIT_CLK_IN_D4 <= BIT_CLK_IN_D3;
	end if;
end process;


-- delay data by 4 CLKs
RECLOCK_002: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		DATA_IN_D <= (others => '0');
		DATA_IN_D2 <= (others => '0');
		DATA_IN_D3 <= (others => '0');
		DATA_IN_D4 <= (others => '0');
	elsif rising_edge(CLK) then
		DATA_IN_D <= DATA0;
		DATA_IN_D2 <= DATA_IN_D;
		DATA_IN_D3 <= DATA_IN_D2;
		DATA_IN_D4 <= DATA_IN_D3;
	end if;
end process;    

-- Delay all synchronization signals by one data bit
RECLOCK_003: process(ASYNC_RESET, CLK)
begin       
	if(ASYNC_RESET = '1') then
		SOF_1BIT_DELAY <= '0';
		PHASE_1BIT_DELAY <= "00";     
		DATA_ENABLE_1BIT_DELAY <= '0';
	elsif rising_edge(CLK) then   
		if(BIT_CLK_IN_D4 = '1') then
			SOF_1BIT_DELAY <= SOF_LOCAL;
			PHASE_1BIT_DELAY <= PHASE_LOCAL;     
			DATA_ENABLE_1BIT_DELAY <= DATA_ENABLE_LOCAL;
		end if;
	end if;
end process;  

--// Delay one extra bit when the unique word is not aligned with the data symbols at modulation                
SOF2 <= SOF_LOCAL when(UW_SYMBOL_ALIGNMENT = '1') else (SOF_1BIT_DELAY and BIT_CLK_IN_D4);
PHASE2 <= PHASE_LOCAL when(UW_SYMBOL_ALIGNMENT = '1') else PHASE_1BIT_DELAY;
DATA_ENABLE2 <= DATA_ENABLE_LOCAL when(UW_SYMBOL_ALIGNMENT = '1') else DATA_ENABLE_1BIT_DELAY;
            
-- Latency is 1 bit and 1 CLK   
-- All inputs aligned with BIT_CLK_IN_D4
PHASE_AMBIGUITY_REMOVAL_001: PHASE_AMBIGUITY_REMOVAL port map(
		CLK => CLK, 
		ASYNC_RESET => ASYNC_RESET,
		DATA_IN => DATA_IN_D4, 
		BIT_CLK_IN => BIT_CLK_IN_D4, 
		SOF => SOF2,  	
		PHASE => PHASE2,
		DATA_OUT => DATA_OUT_LOCAL);
DATA_OUT <= DATA_OUT_LOCAL;

--// BELOW... implement the 1bit and 1clk delay for the bit clock, sof and data enable signals.
-- delay bit clock
RECLOCK_004: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		BIT_CLK_IN_D5 <= '0';
	elsif rising_edge(CLK) then
		BIT_CLK_IN_D5 <= BIT_CLK_IN_D4;
	end if;
end process;
BIT_CLK_OUT <= BIT_CLK_IN_D5;


-- realign SOF
RECLOCK_005: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		SOF_FLAG <= '0';
		DATA_ENABLE_FLAG <= '0';
		SOF_LOCK_DETECT_FLAG <= '0';
		PHASE_FLAG <= "00";    

		SOF_FLAG_D <= '0';
		DATA_ENABLE_FLAG_D <= '0';
		SOF_LOCK_DETECT_FLAG_D <= '0';
		PHASE_FLAG_D <= "00";    

		SOF_D5 <= '0';
		DATA_ENABLE <= '0';
		SOF_LOCK_DETECT <= '0';
		PHASE <= "00";    
	elsif rising_edge(CLK) then
		if(BIT_CLK_IN_D4 = '1') then
			SOF_FLAG <= SOF_LOCAL;
			DATA_ENABLE_FLAG <= DATA_ENABLE_LOCAL;
			SOF_LOCK_DETECT_FLAG <= SOF_LOCK_DETECT_LOCAL;
			PHASE_FLAG <= PHASE_LOCAL;

			SOF_FLAG_D <= SOF_FLAG;
			DATA_ENABLE_FLAG_D <= DATA_ENABLE_FLAG;
			SOF_LOCK_DETECT_FLAG_D <= SOF_LOCK_DETECT_FLAG;
			PHASE_FLAG_D <= PHASE_FLAG;

			SOF_D5 <= SOF_FLAG_D; 
			DATA_ENABLE <= DATA_ENABLE_FLAG_D;
			SOF_LOCK_DETECT <= SOF_LOCK_DETECT_FLAG_D;
			PHASE <= PHASE_FLAG_D;
			
		else                
			SOF_D5 <= '0';
		end if;
		
		
		
	end if;
end process;    
SOF <= SOF_D5;

-- bit error rate measurement
BER_001: BER_MEASUREMENT2 port map(
	ASYNC_RESET => ASYNC_RESET,
	CLK => CLK,
	SOF => SOF_D5,
	BIT_CLK => BIT_CLK_IN_D5,
	DATA => DATA_OUT_LOCAL(3),
	FRAME_LENGTH => FRAME_LENGTH,
	BER => BER
	);





-- test points
TP_MRC_SOF(0) <= DETECT;
TP_MRC_SOF(1) <= PHASE_DETECT(0);
TP_MRC_SOF(2) <= PHASE_DETECT(1);
TP_MRC_SOF(3) <= SOF_LOCAL;




end  BEHAVIOR;
