----------------------------------------------
-- MSS copyright 1999-2001
-- Filename: MATCHED_FILTER32.VHD
-- Authors: 
--		Alain Zarembowitch / MSS
--		Nayef Ahmar / MSS
-- Inheritance: Sirius MATCHED_FILTER48, REV 0.003 2-15-01
-- Edit date: 12/7/01
-- Revision: 0.001
----------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;    
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity 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 MATCHED_FILTER32;
  
architecture BEHAVIOR of MATCHED_FILTER32 is
-----------------------------------------------------------------
-- COMPONENTS
-----------------------------------------------------------------
component PC_16 is
	port (
		A: in std_logic_vector(15 downto 0);	-- input A
		O: out std_logic_vector(4 downto 0)	-- added value
	);
end component;

-----------------------------------------------------------------
-- SIGNALS
-----------------------------------------------------------------
signal zero: std_logic;
signal one: std_logic;     
signal REG32: std_logic_vector(31 downto 0);   
	-- 31 data bits storage
signal MATCH_A: std_logic_vector(15 downto 0);
	-- 16 xnor products before computing partial sum A
signal MATCH_B: std_logic_vector(15 downto 0);
	-- 16 xnor products before computing partial sum B   
signal MATCH_C: std_logic_vector(31 downto 0);
signal PARTIAL_CORRELATION_A: std_logic_vector(4 downto 0);
signal PARTIAL_CORRELATION_A_D: std_logic_vector(4 downto 0);
signal PARTIAL_CORRELATION_A_D_E: std_logic_vector(5 downto 0);
	-- partial correlation A, range 0 - 24  
signal PARTIAL_CORRELATION_B: std_logic_vector(4 downto 0);
signal PARTIAL_CORRELATION_B_D: std_logic_vector(4 downto 0);
signal PARTIAL_CORRELATION_B_D_E: std_logic_vector(5 downto 0);
	-- partial correlation B, range 0 - 24
signal PARTIAL_CORRELATION_C: std_logic_vector(4 downto 0);
signal PARTIAL_CORRELATION_C_D: std_logic_vector(4 downto 0);
signal PARTIAL_CORRELATION_C_D_E: std_logic_vector(5 downto 0);

signal PARTIAL_CORRELATION_D: std_logic_vector(4 downto 0);
signal PARTIAL_CORRELATION_D_D: std_logic_vector(4 downto 0);
signal PARTIAL_CORRELATION_D_D_E: std_logic_vector(5 downto 0);
	
signal SUM_APLUSB: std_logic_vector(5 downto 0);
signal SUM_CPLUSD: std_logic_vector(5 downto 0);
 



signal SUM_AMINUSB: std_logic_vector(5 downto 0);
signal SUM_AMINUSB_ABS: std_logic_vector(5 downto 0);

signal BIT_CLK_IN_D: std_logic;     
signal BIT_CLK_IN_D2: std_logic;     
signal DETECT: std_logic;  
signal PHASE: std_logic_vector(1 downto 0);
-----------------------------------------------------------------
-- IMPLEMENTATION
-----------------------------------------------------------------
begin 
zero <= '0';
one <= '1';   

-- Input data is shifted into 32 bit shift register
-- Shift register   
SHIFT_IN: process (CLK, ASYNC_RESET)
begin
	if (ASYNC_RESET = '1') then
		REG32 <= (others => '0');
		BIT_CLK_IN_D <= '0';
	elsif (rising_edge(CLK)) then 
		BIT_CLK_IN_D <= BIT_CLK_IN;
		if(BIT_CLK_IN = '1') then 
			REG32(30 downto 0) <= REG32(31 downto 1);
			REG32(31) <= DATA_IN;
		end if;
	end if;
end process;      
    

-- compute partial match products A 
MATCH_A(0) <= REG32(0);
MATCH_A(1) <= REG32(2);
MATCH_A(2) <= not REG32(4);
MATCH_A(3) <= not REG32(6);
MATCH_A(4) <= REG32(9);
MATCH_A(5) <= REG32(11);
MATCH_A(6) <= not REG32(13);
MATCH_A(7) <= not REG32(15);
MATCH_A(8) <= not REG32(16);
MATCH_A(9) <= not REG32(19);
MATCH_A(10) <= not REG32(21);
MATCH_A(11) <= not REG32(22);
MATCH_A(12) <=  REG32(24);
MATCH_A(13) <= not REG32(26);
MATCH_A(14) <=  REG32(28);
MATCH_A(15) <= not REG32(30);

-- compute partial match products B
MATCH_B(0) <= not REG32(1);
MATCH_B(1) <= not REG32(3);
MATCH_B(2) <= REG32(5);
MATCH_B(3) <= REG32(7);
MATCH_B(4) <= REG32(8);
MATCH_B(5) <= REG32(10);
MATCH_B(6) <= not REG32(12);
MATCH_B(7) <= not REG32(14);
MATCH_B(8) <= REG32(17);
MATCH_B(9) <= not REG32(18);
MATCH_B(10) <= not REG32(20);
MATCH_B(11) <= REG32(23);
MATCH_B(12) <= not REG32(25);
MATCH_B(13) <= REG32(27);
MATCH_B(14) <= not REG32(29);
MATCH_B(15) <= REG32(31);

-- compute matched filter C (assumes that the 1st bit of the 32-bit unique word is transmitted
-- on one symbol while the 2nd bit is transmitted on the next symbol).
MATCH_C(0) <= not REG32(0);
MATCH_C(1) <= REG32(1);
MATCH_C(2) <= REG32(2);
MATCH_C(3) <= not REG32(3);
MATCH_C(4) <= REG32(4);
MATCH_C(5) <= not REG32(5);
MATCH_C(6) <= not REG32(6);
MATCH_C(7) <= REG32(7);
MATCH_C(8) <= not REG32(8);
MATCH_C(9) <= REG32(9);
MATCH_C(10) <= not REG32(10);
MATCH_C(11) <= not REG32(11);
MATCH_C(12) <= not REG32(12);
MATCH_C(13) <= not REG32(13);
MATCH_C(14) <= REG32(14);
MATCH_C(15) <= not REG32(15);
MATCH_C(16) <= REG32(16);
MATCH_C(17) <= not REG32(17);
MATCH_C(18) <= not REG32(18);
MATCH_C(19) <= not REG32(19);
MATCH_C(20) <= REG32(20);
MATCH_C(21) <= not REG32(21);
MATCH_C(22) <= REG32(22);
MATCH_C(23) <= REG32(23);
MATCH_C(24) <= not REG32(24);
MATCH_C(25) <= not REG32(25);
MATCH_C(26) <= REG32(26);
MATCH_C(27) <= REG32(27);
MATCH_C(28) <= not REG32(28);
MATCH_C(29) <= not REG32(29);
MATCH_C(30) <= REG32(30);
MATCH_C(31) <= REG32(31);

-- compute partial sums
PC_16A: PC_16 port map(A => MATCH_A, O => PARTIAL_CORRELATION_A);
PC_16B: PC_16 port map(A => MATCH_B, O => PARTIAL_CORRELATION_B);
PC_16C: PC_16 port map(A => MATCH_C(15 downto 0), O => PARTIAL_CORRELATION_C);
PC_16D: PC_16 port map(A => MATCH_C(31 downto 16), O => PARTIAL_CORRELATION_D);



-- Pipeline 
RECLOCK_001: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		PARTIAL_CORRELATION_A_D <= (others => '0');
		PARTIAL_CORRELATION_B_D <= (others => '0');
		PARTIAL_CORRELATION_C_D <= (others => '0');
		PARTIAL_CORRELATION_D_D <= (others => '0');
		BIT_CLK_IN_D2 <= '0';
	elsif rising_edge(CLK) then
		BIT_CLK_IN_D2 <= BIT_CLK_IN_D;

		if(BIT_CLK_IN_D = '1') then 
			PARTIAL_CORRELATION_A_D <= PARTIAL_CORRELATION_A;
			PARTIAL_CORRELATION_B_D <= PARTIAL_CORRELATION_B;
			PARTIAL_CORRELATION_C_D <= PARTIAL_CORRELATION_C;
			PARTIAL_CORRELATION_D_D <= PARTIAL_CORRELATION_D;
	  	end if;

	end if;
end process;

PARTIAL_CORRELATION_A_D_E(4 downto 0) <= PARTIAL_CORRELATION_A_D;
PARTIAL_CORRELATION_A_D_E(5) <= '0';
PARTIAL_CORRELATION_B_D_E(4 downto 0) <= PARTIAL_CORRELATION_B_D;
PARTIAL_CORRELATION_B_D_E(5) <= '0';
PARTIAL_CORRELATION_C_D_E(4 downto 0) <= PARTIAL_CORRELATION_C_D;
PARTIAL_CORRELATION_C_D_E(5) <= '0';
PARTIAL_CORRELATION_D_D_E(4 downto 0) <= PARTIAL_CORRELATION_D_D;
PARTIAL_CORRELATION_D_D_E(5) <= '0';

-- compute sum of partial correlations A + B
-- output is in the range 0 - 32
SUM_APLUSB <= PARTIAL_CORRELATION_A_D_E + PARTIAL_CORRELATION_B_D_E;

-- Partial correlation A + 2's complement of partial correlation B
-- Result is 2's complement number. Range is -16 to +16 signed.
SUM_AMINUSB <= PARTIAL_CORRELATION_A_D_E + not(PARTIAL_CORRELATION_B_D_E) + 1;

-- Correlation for the case when the unique word is not aligned with the modulator symbol period.
SUM_CPLUSD <= PARTIAL_CORRELATION_C_D_E + PARTIAL_CORRELATION_D_D_E;

-- Take absolute value
ABS_001: process(SUM_AMINUSB)
begin
	if(SUM_AMINUSB(5) = '0') then
		-- positive
		SUM_AMINUSB_ABS <= SUM_AMINUSB;
 	else
		-- negative
		SUM_AMINUSB_ABS <= not SUM_AMINUSB + 1;
	end if;
end process;

--threshold is 29/32
-- Detect a Peak and resolve QPSK ambiguity.
-- The DETECT pulse will occur while I = bit 31 (start counting at zero)
-- Size for up to 10% BER (3 errors in 32 bits).
PEAK_DETECT: process (CLK, ASYNC_RESET)
begin
	if (ASYNC_RESET = '1') then
		DETECT <= '0';
		PHASE <= "00";       
		UW_SYMBOL_ALIGNMENT <= '0';
	elsif (rising_edge(CLK)) then   
	  if (BIT_CLK_IN_D2 = '1') then
		-- delay detect pulse so that its start coincides with the last bit of the 
		-- training sequence
		if (SUM_APLUSB > 28) then
			DETECT <= '1';
			PHASE(1 downto 0) <= "10";
			UW_SYMBOL_ALIGNMENT <= '1';
          --Phase 2
		elsif (SUM_AMINUSB(5) = '1') and (SUM_AMINUSB_ABS > 12) then
			-- range -13 to -16 inclusive
			DETECT <= '1';
			PHASE(1 downto 0) <= "01";   
			UW_SYMBOL_ALIGNMENT <= '1';
            --Phase II
		elsif (SUM_APLUSB < 4) then
			-- range 0 - 3 inclusive
			DETECT <= '1';
			PHASE(1 downto 0) <= "00";
			UW_SYMBOL_ALIGNMENT <= '1';
            --Phase 1
		elsif (SUM_CPLUSD > 27) then
			-- lower threshold a bit because the data symbols immediately preceeding the uw
			-- and immediately following the unique word affect the correlation value.
			-- range 28-32 inclusive   
			DETECT <= '1';
			PHASE(1 downto 0) <= "01";   
			UW_SYMBOL_ALIGNMENT <= '0';
            --Phase 1
		elsif (SUM_CPLUSD < 5) then
			-- lower threshold a bit because the data symbols immediately preceeding the uw
			-- and immediately following the unique word affect the correlation value.
			-- range 0-4 inclusive
			-- Make sure that the DETECT pulse is aligned with the I/Q symbol pair. thus the one bit offset.
			DETECT <= '1';
			PHASE(1 downto 0) <= "11";   
			UW_SYMBOL_ALIGNMENT <= '0';
		elsif (SUM_AMINUSB(5) = '0') and (SUM_AMINUSB_ABS > 12) then
			-- range +13 to +16 inclusive
			DETECT <= '1';
			PHASE(1 downto 0) <= "11";
			UW_SYMBOL_ALIGNMENT <= '1';
            --Phase IV
		else 
			DETECT <= '0';   
		end if;   
	  else
		DETECT <= '0';   
	  end if;
	end if;

end process;         

DETECT_OUT <= DETECT;	
PHASE_OUT <= PHASE;


end  BEHAVIOR;




