----------------------------------------------
-- MSS copyright 1999-2013
--	File: SOF_TRACK
-- Authors: 
--		Alain Zarembowitch / MSS
--		Nayef Ahmar / MSS
-- Inheritance: n/a
-- Edit date: 4/30/13
-- Revision: 8
--
-- VHDL code for Training sequence tracking/acquisition circuit
--SOF goes high at the first 48th bit 
--Enable Data goes high at the first 48th bit 
--and stays high without resetting for the first encounter of DETECT
--When first encounter a DETECT high, reset counter  ,send a SOF HIGH,
-- and increment state counter
--A glitch of reset occurs at the second DETECT, meaningless as long as harmless

-- Rev 0.002 AZ
-- Made SOF_LOCAL twice as long, to account for the fact that the DETECT pulse can
-- be at 2048 or 2049 bit 
--
-- Rev 0.003 AZ
-- Simplified. removed BIT_COUNT_PLUS variable.
-- Removed reference to work.math library. no inc_slv used here.
-- Removed SC_ENABLE (bad code)
--
-- Rev 0.004 az
-- Editorial + made DATA_ENABLE and PHASE synchronous(fuzzy code before)
--
-- Rev 0.005 az
-- switched from active low to active high asynchronous reset
-- 
-- Rev 0.006 AZ
-- Vigyan adaptation. Frame length is 4096 + 32 bits.
--
-- Rev 0.007 AZ
-- ComBlock adaptation. Frame length is programmable.
--
-- Rev 8 4/30/13 AZ
-- Increase size of confidence counter COUNT to lower the operational Eb/No threshold
----------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity 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 SOF_TRACK;
  
architecture BEHAVIOR of SOF_TRACK is
-----------------------------------------------------------------
-- COMPONENTS
-----------------------------------------------------------------
-----------------------------------------------------------------
-- SIGNALS
-----------------------------------------------------------------
constant COUNT_NBITS: integer := 4;	-- number of bits in the confidence counter
signal BIT_CLK_D: std_logic;
signal BIT_COUNT: std_logic_vector(12 downto 0);
	-- bit counter 0 - 4095+32, modulo 4096+32
signal COUNT: std_logic_vector((COUNT_NBITS-1) downto 0) := (others => '0');
  	-- 0 to 3
signal SOF_LOCK_DETECT_LOCAL: std_logic;
	-- active low for counter= 00

-----------------------------------------------------------------
-- IMPLEMENTATION
-----------------------------------------------------------------
begin 
 
COUNTER: process(CLK, ASYNC_RESET)
begin       
	if (ASYNC_RESET = '1') then
		BIT_COUNT <= (others => '0');        	
	elsif rising_edge(CLK) then  
	  if(BIT_CLK = '1') then
		if (DETECT = '1') and (SOF_LOCK_DETECT_LOCAL = '0') then
			-- reset at the first UW detect when not in lock
			-- next bit is bit 32
			BIT_COUNT <= "0000000100000"; 	-- 32
		elsif(BIT_COUNT = FRAME_LENGTH - 1) then
 	   	-- modulo FRAME_LENGTH
			BIT_COUNT <= (others => '0');        	
		else
			-- increment
			BIT_COUNT <= BIT_COUNT + 1;
		end if;
	  end if;
	end if;
end process; 

count2_up_down: process (CLK, ASYNC_RESET)
-- confidence counter
begin
	if (ASYNC_RESET = '1') then
		COUNT <= (others => '0'); 
	elsif rising_edge(CLK) then 
   	-- special case: first UW detected
		if((BIT_CLK = '1') and (DETECT = '1') and (COUNT = 0)) then
			-- declare lock upon receiving the first UW when being out of lock.
			-- Reason: we don't want to waste a good frame
	 		COUNT <= COUNT + 1;
		elsif (BIT_CLK = '1') and (BIT_COUNT = 31) then
			-- we expect a new UW detection here.
			if(DETECT = '1') then
				-- if the locally generated SOF matches the SOF detected by the matched filter,
				-- everything is OK, increment the counter. Otherwise, decrement counter.
				-- COUNT is a measure of confidence as to the SOF detection.
				if(COUNT(COUNT'left) = '0') then
					COUNT <= COUNT + 1;
				end if;
		 	else
				if(COUNT /= 0) then
					COUNT <= COUNT - 1;
				end if;
		 	end if;
		end if;              
	end if;
end process; 

SOF_LOCK_DETECT_LOCAL <= '1' when (COUNT /= 0) else '0';
SOF_LOCK_DETECT <= SOF_LOCK_DETECT_LOCAL;

-- Confirm phase ambiguity (same criteria as for confirming SOF lock above)
PHASE_CONFIRM_001: process (CLK, ASYNC_RESET)
begin
	if (ASYNC_RESET = '1') then
		PHASE <= "00"; 
	elsif rising_edge(CLK) then 
		if((BIT_CLK = '1') and (DETECT = '1') and (COUNT = 0)) then
	   	-- special case: first UW detected
	 		PHASE <= PHASE_IN;
		elsif (BIT_COUNT = 31) and (BIT_CLK = '1') and (DETECT = '1') then
			-- periodic SOF
	 		PHASE <= PHASE_IN;
		end if;              
	end if;
end process; 


SOF <= '1' when ((BIT_COUNT = 32) and (BIT_CLK_D = '1')) else '0';


-- Delay BIT_CLK
RECLOCK_002: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		BIT_CLK_D <= '0';
	elsif rising_edge(CLK) then
		BIT_CLK_D <= BIT_CLK;
	end if;
end process;

DATA_ENABLE <= '1' when (BIT_COUNT > 31) else '0';

-- test point
TP(0) <= SOF_LOCK_DETECT_LOCAL;

   
end  BEHAVIOR; 
