----------------------------------------------
-- MSS copyright 2014-2016
-- Filename: CODEGEN3.vhd
-- Author: Alain Zarembowitch / MSS
-- Edit date: 4/19/16
-- Revision: 2
-- Inheritance: CODEGEN.VHD 4/30/12, CODEGEN2.VHD 8/30/12
-- 
-- Description: 
--		Generation of pseudo random (PN) sequences for direct sequence spread-spectrum
-- 	CODE_MODE = '0': TDRSS codes, command forward link. 1023 chip Gold codes. 
-- 	Generates one code.
-- 	CODE_MODE = '1': TDRSS codes, Mode 2 return link. 2047 chip Gold codes. 
-- 	Generates two codes for I and Q channels.
-- Reference:
-- Space network interoperable pn code libraries, Appendix A
--
-- Usage: mandatory reset (SYNC_RESET = '1') during mode change.
--
-- Rev 2 4/19/16 AZ
-- Added support for 1023 chip length Gold codes (forward command link) 
---------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity CODEGEN3 is
  port (
	CLK: in  std_logic;   
		-- clock synchronous
	BIT_CLK_REQ: in std_logic;
		-- request for output code bit, 
		-- read output bit at rising_edge of CLK and BIT_CLK_REQ_D = '1'
	SYNC_RESET: in std_logic;
		-- synchronous reset for linear feedback shift register.
		-- 1 CLK wide pulse aligned with BIT_CLK_REQ.  

	--// code selection
	-- LFSR initialization. see definition in Space network interoperable pn code libraries, Appendix A
	-- LFSRC_INIT unused in forward command link mode
	LFSRA_INIT: in std_logic_vector(10 downto 0);
	LFSRC_INIT: in std_logic_vector(10 downto 0);
	CODE_MODE: in std_logic;
		-- 0 = forward command link Gold codes
		-- 1 = return mode 2 link Gold codes


	BIT_CLK_OUT: out std_logic;
		-- Latency between input clock and output clock is 1CLK.
  	CODE_START: out std_logic;
		-- 1 CLK wide pulse, aligned with BIT_CLK_OUT.
		-- Indicates that CODE_BIT is the first bit of the periodic code sequence.
	CODE_I_BIT: out std_logic;
	CODE_Q_BIT: out std_logic;
		-- code sequence output. Read at rising edge of CLK when BIT_CLK_OUT = '1'
		-- Q-code is null in forward command link mode
		
	--// monitoring
	BIT_COUNT_OUT: out std_logic_vector(10 downto 0) 
		-- 
    );
end entity;

architecture behavior of CODEGEN3 is

-----------------------------------------------------------------
-- SIGNALS
-----------------------------------------------------------------
signal BIT_COUNT: unsigned(10 downto 0) := (others => '0');
signal LFSRA_REG     : std_logic_vector(10 downto 0) := (others => '0');
signal LFSRA_TAPS     : std_logic_vector(10 downto 0) := (others => '0');
signal FEEDBACKA		: std_logic:= '0';
signal LFSRB_REG     : std_logic_vector(10 downto 0) := (others => '0');
signal LFSRB_TAPS     : std_logic_vector(10 downto 0) := (others => '0');
signal FEEDBACKB		: std_logic:= '0';
signal LFSRC_REG     : std_logic_vector(10 downto 0) := (others => '0');
signal LFSRC_TAPS     : std_logic_vector(10 downto 0) := (others => '0');
signal FEEDBACKC		: std_logic:= '0';
signal G1:  std_logic_vector(10 downto 0) := "10000000010";--    01000000001";
signal G2:  std_logic_vector(10 downto 0) := "10010010010";--      01001001001";
signal LFSRA_INIT_FLIPPED: std_logic_vector(10 downto 0);
signal LFSRC_INIT_FLIPPED: std_logic_vector(10 downto 0);

-----------------------------------------------------------------
-- IMPLEMENTATION
-----------------------------------------------------------------
begin

--// Count the number of bits in the sequence. Raise a flag for the first one
BIT_COUNT_GEN: process(CLK)
begin
  	if rising_edge(CLK) then
		BIT_COUNT_OUT <= std_logic_vector(BIT_COUNT);	-- for monitoring purposes
		BIT_CLK_OUT <= BIT_CLK_REQ;	-- 1 CLK latency between module input and output

		if(SYNC_RESET = '1') then
			-- initialize to 1
			BIT_COUNT <= (0 => '1', others => '0');
			CODE_START <= '1';
		elsif(BIT_CLK_REQ = '1') then
			if((CODE_MODE = '0') and (BIT_COUNT = 1023)) or ((CODE_MODE = '1') and (BIT_COUNT = 2047)) then
				-- reset count
				BIT_COUNT <= (0 => '1', others => '0');
				CODE_START <= '1';
		  	else
				BIT_COUNT <= BIT_COUNT + 1;
				CODE_START <= '0';
				
			end if;
		else
			CODE_START <= '0';
	  	end if;
	end if;
end process;

-- Gx selection
GX_SEL: process(CLK)
begin
  	if rising_edge(CLK) then
		if(CODE_MODE = '0') then
			-- forward command link (1023-chip Gold code: bit 10 unused)
			G1 <= "01110100110";
			G2 <= "01000000100";
		else
		--elsif(CODE_MODE = '1') then
			-- return mode 2 link (2047-chip Gold code)
			G1 <= "10000000010";
			G2 <= "10010010010";
		end if;
	end if;
end process;


--// flip LFSR initialization vectors (we insert feedback at tap 0 whereas
-- specs inserts feedback at tap 10)
FLIP_001: process(CLK)
begin
  	if rising_edge(CLK) then
		if(CODE_MODE = '0') then
			-- forward command link
			for I in 0 to 9 loop
				LFSRA_INIT_FLIPPED(I) <= LFSRA_INIT(9-I);
			end loop;
			--LFSRA_INIT_FLIPPED(10) <= '0';	-- unused
		--elsif(CODE_MODE = '1') then
		else
			for I in 0 to 10 loop
				LFSRA_INIT_FLIPPED(I) <= LFSRA_INIT(10-I);
				LFSRC_INIT_FLIPPED(I) <= LFSRC_INIT(10-I);
			end loop;
		end if;
	end if;
end process;

--// linear feedback shift register A
LFSRA_GEN: process(CLK, FEEDBACKA)
begin
	if rising_edge(CLK) then

		if(SYNC_RESET = '1') then
			-- force start of code. 
			LFSRA_REG <= LFSRA_INIT_FLIPPED;
		elsif(BIT_CLK_REQ = '1') then
			LFSRA_REG(10 downto 1) <= LFSRA_REG(9 downto 0);
			LFSRA_REG(0) <= FEEDBACKA;
	  	end if;
	end if;
end process;

-- Mask all unused taps
LFSRA_TAPS <= (LFSRA_REG and G1);

LFSRA_GEN_002: process(LFSRA_TAPS)
variable V: std_logic;
begin
	V := '0';
  for I in 0 to 10 loop
     V := V xor LFSRA_TAPS(I);
  end loop;
  FEEDBACKA <= V;
end process;

--// linear feedback shift register B
LFSRB_GEN: process(CLK, FEEDBACKB)
begin
	if rising_edge(CLK) then

		if(SYNC_RESET = '1') then
			-- force start of code. 
			if(CODE_MODE = '0') then
				-- forward command link
				LFSRB_REG <= "00001001001";
			--elsif(CODE_MODE = '1') then
			else
				-- return mode 2 link
				LFSRB_REG <= (10 => '1', others => '0');
			end if;
		elsif(BIT_CLK_REQ = '1') then
			LFSRB_REG(10 downto 1) <= LFSRB_REG(9 downto 0);
			LFSRB_REG(0) <= FEEDBACKB;
	  	end if;
	end if;
end process;

-- Mask all unused taps
LFSRB_TAPS <= (LFSRB_REG and G2);

LFSRB_GEN_002: process(LFSRB_TAPS)
variable V: std_logic;
begin
	V := '0';
  for I in 0 to 10 loop
     V := V xor LFSRB_TAPS(I);
  end loop;
  FEEDBACKB <= V;
end process;

--// linear feedback shift register C
LFSRC_GEN: process(CLK, FEEDBACKC)
begin
	if rising_edge(CLK) then

		if(SYNC_RESET = '1') then
			-- force start of code. 
			LFSRC_REG <= LFSRC_INIT_FLIPPED;
		elsif(BIT_CLK_REQ = '1') and (CODE_MODE = '1') then
			LFSRC_REG(10 downto 1) <= LFSRC_REG(9 downto 0);
			LFSRC_REG(0) <= FEEDBACKC;
	  	end if;
	end if;
end process;

-- Mask all unused taps
LFSRC_TAPS <= (LFSRC_REG and G1);

LFSRC_GEN_002: process(LFSRC_TAPS)
variable V: std_logic;
begin
	V := '0';
  for I in 0 to 10 loop
     V := V xor LFSRC_TAPS(I);
  end loop;
  FEEDBACKC <= V;
end process;

-- Gold code
CODE_I_BIT <= LFSRA_REG(10) xor LFSRB_REG(10) when (CODE_MODE = '1') else LFSRA_REG(9) xor LFSRB_REG(9); 
CODE_Q_BIT <= LFSRC_REG(10) xor LFSRB_REG(10) when (CODE_MODE = '1') else '0'; 



end behavior;

