-------------------------------------------------------------
-- MSS copyright 1999-2001
--	Filename:  TCM_23.VHD
-- Author: Alain Zarembowitch / MSS
--	Version: 0.001
--	Date last modified: 12-30-01
-- Inheritance: 	none
--
-- description:  
-- COM-1010
-- Treillis coded modulation. Rate 2/3
-- Includes phase ambiguity resolution encoder (PARE). See Intelsat IESS-310 p 53, figure 11b.
---------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity TCM_23 is
    port ( 
		--GLOBAL CLOCKS, RESET
	   CLK : in std_logic;	-- master clock for this FPGA, synchronous 
		ASYNC_RESET: in std_logic;	-- asynchronous reset

		--// Input samples
		DATA_IN: in std_logic;
			-- input bit. Read at rising edge of CLK when SAMPLE_CLK_IN = '1';
		SAMPLE_CLK_IN: in std_logic;
			-- one CLK-wide pulse
	  	SOF_RESET: in std_logic;
			-- 1 CLK-wide pulse indicating that the encoder shall be reset. 
			-- Aligned with SAMPLE_CLK_IN.
			-- Used in the block mode. 


		--// Output samples
		DATA_OUT: out std_logic_vector(2 downto 0);
			-- output sample. Read at rising edge of CLK when SAMPLE_CLK_OUT = '1';
			-- 3-bit parallel output
		SAMPLE_CLK_OUT: out std_logic
			-- one CLK-wide pulse. same rate as SAMPLE_CLK_IN
			-- Latency is 1 CLK.
		
			);
end entity;

architecture behavioral of TCM_23 is
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------
component ENCODER_K7R2 is
    port ( 
		--GLOBAL CLOCKS, RESET
	   CLK : in std_logic;	-- master clock for this FPGA, synchronous 
		ASYNC_RESET: in std_logic;	-- asynchronous reset

		--// Input samples
		DATA_IN: in std_logic;
			-- input bit. Read at rising edge of CLK when SAMPLE_CLK_IN = '1';
		SAMPLE_CLK_IN: in std_logic;
			-- one CLK-wide pulse
	  	SOF_RESET: in std_logic;
			-- 1 CLK-wide pulse indicating that the encoder shall be reset. 
			-- Aligned with SAMPLE_CLK_IN.
			-- Used in the block mode. 

		--// Output samples
		DATA_OUT: out std_logic_vector(1 downto 0);
			-- output sample. Read at rising edge of CLK when SAMPLE_CLK_IN = '1';
			-- 2-bit parallel output
		SAMPLE_CLK_OUT: out std_logic
			-- one CLK-wide pulse. same rate as SAMPLE_CLK_IN
			-- Latency is 1 CLK.
		
			);
end component;
--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------
-- Suffix _D indicates a one CLK delayed version of the net with the same name
-- Suffix _E 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
signal TOGGLE: std_logic;	
signal SAMPLE_CLK_CONV: std_logic;	
signal SAMPLE_CLK_CONV_D: std_logic;	
signal SAMPLE_CLK_PARE: std_logic;	
signal DATA_IN_CONV: std_logic;
signal DATA_IN_CONV_D: std_logic;
signal DATA_CONV: std_logic_vector(1 downto 0);
signal DATA_PARE_D: std_logic;
signal DATA_PARE: std_logic;
signal DATA_U: std_logic;
signal DATA_U_D: std_logic;
signal DATA_V: std_logic;
signal DATA_V_D: std_logic;
signal DATA_PARE_OUT: std_logic;
--------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------

begin

-- separate PARE path and rate 1/2 encoder path
-- every other bit.
S2P: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		TOGGLE <= '0';
	elsif rising_edge(CLK) then
		if(SAMPLE_CLK_IN = '1')  then
			TOGGLE <= not TOGGLE;
	  	end if;
	end if;
end process;


SAMPLE_CLK_CONV <= SAMPLE_CLK_IN and TOGGLE;
SAMPLE_CLK_PARE <= SAMPLE_CLK_IN and (not TOGGLE);

-- Differential encoder prior to the rate 1/2 convolutional encoder
DIFF_CONV: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		DATA_IN_CONV_D <= '0';
	elsif rising_edge(CLK) then
		if(SAMPLE_CLK_CONV = '1') then
			DATA_IN_CONV_D <= DATA_IN_CONV;
	  	end if;
	end if;
end process;
DATA_IN_CONV <= DATA_IN_CONV_D xor DATA_IN;


-- Latency is 1 CLK.
ENCODER_K7R2_GEN: ENCODER_K7R2 port map(
	ASYNC_RESET => ASYNC_RESET,
	CLK => CLK,
	DATA_IN => DATA_IN_CONV,
	SOF_RESET => SOF_RESET,
	SAMPLE_CLK_IN => SAMPLE_CLK_CONV,
	DATA_OUT => DATA_CONV
	);

-- Reclock PARE input data to align with SAMPLE_CLK_CONV.
-- DATA_PARE_D is aligned timewise with DATA_CONV.
RECLOCK_001: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		DATA_PARE <= '0';
		DATA_PARE_D <= '0';
		SAMPLE_CLK_CONV_D <= '0';
	elsif rising_edge(CLK) then
		SAMPLE_CLK_CONV_D <= SAMPLE_CLK_CONV;
		if(SAMPLE_CLK_PARE = '1')  then
			DATA_PARE <= DATA_IN;
	  	end if;
		if(SAMPLE_CLK_CONV = '1')  then
			DATA_PARE_D <= DATA_PARE;
	  	end if;
	end if;
end process;

-- Two differential encoders U and V
DIFF_U: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		DATA_U_D <= '0';
	elsif rising_edge(CLK) then
		if(SAMPLE_CLK_CONV_D = '1') and (DATA_CONV(0) = '0') then
			-- Select = 0 path U
			DATA_U_D <= DATA_U ;
	  	end if;
	end if;
end process;
DATA_U <= DATA_U_D xor DATA_PARE_D;

DIFF_V: process(ASYNC_RESET, CLK)
begin
	if(ASYNC_RESET = '1') then
		DATA_V_D <= '0';
	elsif rising_edge(CLK) then
		if(SAMPLE_CLK_CONV_D = '1') and (DATA_CONV(0) = '1') then
			-- Select = 1 path V
			DATA_V_D <= DATA_V ;
	  	end if;
	end if;
end process;
DATA_V <= DATA_V_D xor DATA_PARE_D;

-- select differential decoder output.
DIFF_SEL: process(DATA_CONV, DATA_U, DATA_V)
begin
	if(DATA_CONV(0) = '0') then
		DATA_PARE_OUT <= DATA_U;
	else
		DATA_PARE_OUT <= DATA_V;
	end if;
end process;

--// output
DATA_OUT(0) <= DATA_PARE_OUT;
DATA_OUT(1) <= DATA_CONV(0);
DATA_OUT(2) <= DATA_CONV(1);
SAMPLE_CLK_OUT <= SAMPLE_CLK_CONV_D;

end behavioral;
