----------------------------------------------
-- MSS copyright 2012-2017
-- Filename: VA_TBU.VHD
-- Author: Alain Zarembowitch / MSS
-- Inheritance: N/A
-- Edit date: 5/25/17
-- Revision: 0
--
-- VHDL code for Viterbi algorithm, hard-decision traceback unit
-- Traceback length = 5*L = 15
----------------------------------------------      
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;
use IEEE.MATH_REAL.ALL;
use work.CPM_MF_PKG.all;	-- defines types for this interface

entity VA_TBU is
 	generic (
		-- NOTE: most customization parameters defined in CPM_MF_PKG (SEE cpm_mf.vhd)
		SIMULATION: std_logic := '0'
	);
   port (
		--// CLOCKS, RESET
		CLK: in std_logic;
			-- reference clock for synchronous design
		SYNC_RESET: in std_logic;
			-- global reset, active high.


		--// INPUTS
		SAMPLE_CLK_IN: in std_logic;
			-- read input sample at rising_edge of CLK and SAMPLE_CLK_IN  = '1'.
			-- One CLK wide pulse.
		WINNER: IN std_logic_vector(N_TRELLIS_STATES_MAX - 1 downto 0);	
			-- selected best prior state for each current state
		BEST_END_STATE: in std_logic_vector((LOG2_N_TRELLIS_STATES_MAX-1) downto 0);
			-- end state with the best metric 

		--// OUTPUTS
		TB_OUT: out TB_TYPE;
			-- hard decision traceback information. Needed by reliability traceback unit when SOVA is enabled.
		SAMPLE_CLK_OUT: out std_logic;
			-- Read at rising edge of CLK and SAMPLE_CLK_OUT = '1'.
		DATA_OUT: out std_logic
			-- demodulated bit.
    );
end entity;

architecture behavioral of VA_TBU is
-----------------------------------------------------------------
-- COMPONENTS
-----------------------------------------------------------------
-----------------------------------------------------------------
-- SIGNALS
-----------------------------------------------------------------
-- suffix _D denotes a one-CLK delayed version of the net with the same name
signal TB: TB_TYPE := (others => (others => '0'));
signal BEST_END_STATE_D: unsigned((LOG2_N_TRELLIS_STATES_MAX-1) downto 0) := (others => '0');
signal SAMPLE_CLK_IN_D: std_logic := '0';
-----------------------------------------------------------------
-- IMPLEMENTATION
-----------------------------------------------------------------
begin   

-- traceback ending with 00 as most recent state
-- end state 00, from start state A=01(0) or start state B=11(1)
TB_GEN_00: process(CLK)
begin
	if rising_edge(CLK) then
		if (SAMPLE_CLK_IN = '1') then
			TB(0)(TB_LENGTH -1) <= WINNER(0);
			if(WINNER(0) = '0') then
				-- ACS selected path A as best origin
				for I in 1 to (TB_LENGTH-1) loop
					TB(0)(I-1) <= TB(1)(I);	-- shift left
				end loop;
			else
				-- ACS selected path B as best origin
				for I in 1 to (TB_LENGTH-1) loop
					TB(0)(I-1) <= TB(3)(I);
				end loop;
			end if;
		end if;
	end if;
end process;

-- traceback ending with 01 as most recent state
-- end state 01, from start state A=10(0) or start state B=00(1)
TB_GEN_01: process(CLK)
begin
	if rising_edge(CLK) then
		if (SAMPLE_CLK_IN = '1') then
			TB(1)(TB_LENGTH -1) <= WINNER(1);
			if(WINNER(1) = '0') then
				-- ACS selected path A as best origin
				for I in 1 to (TB_LENGTH-1) loop
					TB(1)(I-1) <= TB(2)(I);	-- shift left
				end loop;
			else
				-- ACS selected path B as best origin
				for I in 1 to (TB_LENGTH-1) loop
					TB(1)(I-1) <= TB(0)(I);
				end loop;
			end if;
		end if;
	end if;
end process;

-- traceback ending with 10 as most recent state
-- end state 10, from start state A=11(0) or start state B=01(1)
TB_GEN_10: process(CLK)
begin
	if rising_edge(CLK) then
		if (SAMPLE_CLK_IN = '1') then
			TB(2)(TB_LENGTH -1) <= WINNER(2);
			if(WINNER(2) = '0') then
				-- ACS selected path A as best origin
				for I in 1 to (TB_LENGTH-1) loop
					TB(2)(I-1) <= TB(3)(I);	-- shift left
				end loop;
			else
				-- ACS selected path B as best origin
				for I in 1 to (TB_LENGTH-1) loop
					TB(2)(I-1) <= TB(1)(I);
				end loop;
			
			end if;
		end if;
	end if;
end process;

-- traceback ending with 11 as most recent state
-- end state 11, from start state A=00(0) or start state B=10(1)
TB_GEN_11: process(CLK)
begin
	if rising_edge(CLK) then
		if (SAMPLE_CLK_IN = '1') then
			TB(3)(TB_LENGTH -1) <= WINNER(3);
			if(WINNER(3) = '0') then
				-- ACS selected path A as best origin
				for I in 1 to (TB_LENGTH-1) loop
					TB(3)(I-1) <= TB(0)(I);	-- shift left
				end loop;
			else
				-- ACS selected path B as best origin
				for I in 1 to (TB_LENGTH-1) loop
					TB(3)(I-1) <= TB(2)(I);
				end loop;
			
			end if;
		end if;
	end if;
end process;

-- demodulated bit is at the start of the best path
-- trace back the treillis from the best end state to the origin state.
DEMOD_001: process(CLK)
begin
	if rising_edge(CLK) then
		-- wait one CLK so that we reshuffle the traceback
		SAMPLE_CLK_IN_D <= SAMPLE_CLK_IN;
		if (SAMPLE_CLK_IN = '1') then
			BEST_END_STATE_D <= unsigned(BEST_END_STATE);
		end if;
		
		SAMPLE_CLK_OUT <= SAMPLE_CLK_IN_D;
		if(SAMPLE_CLK_IN_D = '1') then
			DATA_OUT <= TB(to_integer(BEST_END_STATE_D))(0);
		end if;
	end if;
end process;

TB_OUT <= TB;
	-- hard decision traceback information. Needed by reliability traceback unit when SOVA is enabled.


end behavioral;					
