----------------------------------------------
-- MSS copyright 2012
-- Filename: VA_BMU2.VHD
-- Author: Alain Zarembowitch / MSS
-- Inheritance: N/A
-- Edit date: 11/29/12
-- Revision: 2
-- See also: VA_BMU.vhd
--
-- VHDL code for Viterbi algorithm, branch metric unit (BMU)
-- 2**N_PARITY_BITS states. Typical application: Viterbi decoder
-- Computes the local distance (a simplified Euclidian distance) between received soft-quantized bits
-- and the HYPOTHESIS being tested. In the case of hard-decoding case, the simpler Hamming distance
-- is computed.
-- Received bits marked with the ERASURES(i) flag are ignored in the distance computation.
--
-- Rev2 11/29/12 AZ
-- Passed parameters through generic for more configuration flexibility instead of common com1509pkg
----------------------------------------------      
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity VA_BMU2 is
 	generic (
		N_PARITY_BITS_MAX: integer := 3;
		NBITS_BM: integer := 6;
		HARD_SOFTN_DECISION: std_logic := '0'
	);
   port (
		-- GLOBAL CLOCKS, RESET
		CLK: in std_logic;	-- synchronous clock
		SYNC_RESET: in std_logic;		-- synchronous reset. active high.

		HYPOTHESIS: in std_logic_vector((N_PARITY_BITS_MAX - 1) downto 0);
			-- coding group of N_PARITY_BITS being tested against the received coding group
			-- This vector is sized for the code with the most parity bits, but only the N_PARITY_BITS least significant bits are used within.

		--// INPUTS
		-- Coding group
		DATAIN: in std_logic_vector((N_PARITY_BITS_MAX*4 - 1) downto 0);  	
			-- group of received (soft-quantized) bits associated with generator polynominal G0,G1,G2, etc 
			-- This array is sized for the code with the most parity bits, but only the N_PARITY_BITS least significant bits are used within.
			-- In the case of hard-decision decoding, the received encoded bit is placed at index 3, other soft-decision bits (2:0) being zero.
		ERASURES: in std_logic_vector((N_PARITY_BITS_MAX - 1) downto 0);	
			-- erasures on bit 0,1 or 2 ('1' indicates a puncture)	
			-- tells the BMU to ignore a specific bit or bits during distance computation.
		INPUT_VALID: in std_logic;
			-- 1-CLK wide pulse for each input coding group 
			-- above inputs are read at the rising edge of CLK when INPUT_VALID = '1'

		--// OUTPUTS
		-- Latency: 2 CLKs after INPUT_VALID
		DISTANCE_OUT : out std_logic_vector((NBITS_BM-1) downto 0);
			-- overall distance between received coding group and HYPOTHESIS being tested.
			-- always positive. 0 when ideal match.
			-- Effective width: 2 bits for hard decision decoding, 5 bits for soft-decision (N_PARITY_BITS = 2),
			-- 6 bits for soft-decision (N_PARITY_BITS = 3) 
		OUTPUT_VALID: out std_logic
			-- read output at the rising edge of CLK when OUTPUT_VALID = '1'
    );
end entity;

architecture behavioral of VA_BMU2 is
-----------------------------------------------------------------
-- COMPONENTS
-----------------------------------------------------------------
-----------------------------------------------------------------
-- SIGNALS
-----------------------------------------------------------------
-- suffix _D denotes a one-CLK delayed version of the net with the same name
type SLV4xNPARtype is array (integer range 0 to (N_PARITY_BITS_MAX-1)) of std_logic_vector(3 downto 0);
signal DISTANCE: SLV4xNPARtype := (others => (others => '0'));
signal INPUT_VALID_D: std_logic := '0';
-----------------------------------------------------------------
-- IMPLEMENTATION
-----------------------------------------------------------------
begin   

-- compute individual distances for each received bit in a coding group
DISTANCE_001: for I in 0 to N_PARITY_BITS_MAX-1 generate
	DISTANCE_00x: process(CLK)
	begin
		if rising_edge(CLK) then
			if(SYNC_RESET = '1') then
				DISTANCE(I) <= (others => '0');
			elsif(INPUT_VALID = '1') then
				if(ERASURES(I) = '0') then
					-- received bit (no erasure)
					if(HARD_SOFTN_DECISION = '0') then
						-- soft-decision decoding. Use all 4 soft-quantized bits
						if(HYPOTHESIS(I) = '0') then
							DISTANCE(I) <= DATAIN((I*4+3) downto (I*4));
						else
							DISTANCE(I) <= "1111" - DATAIN((I*4+3) downto (I*4));
						end if;
					else
						-- hard-decision. Use information bit (bit 3)
						DISTANCE(I)(0) <= DATAIN(I*4 +3) xor HYPOTHESIS(I);
					end if;
				else
					-- erasure. Ignore this bit while computing the overall distance
					DISTANCE(I) <= (others => '0');
				end if;
			end if;
		end if;
	end process;
end generate;

-- compute overall distance (sum)
SUM_001: process(CLK, DISTANCE)
variable DISTANCE_SUM: std_logic_vector((NBITS_BM-1) downto 0);
begin
	DISTANCE_SUM := (others => '0');
	for I in 0 to (N_PARITY_BITS_MAX-1) loop
		DISTANCE_SUM := DISTANCE_SUM + ext(DISTANCE(I), NBITS_BM);
	end loop;

	if rising_edge(CLK) then
		INPUT_VALID_D <= INPUT_VALID;
		OUTPUT_VALID <= INPUT_VALID_D;
		
		if(SYNC_RESET = '1') then
			DISTANCE_OUT <= (others => '0');
		elsif(INPUT_VALID_D = '1') then
			DISTANCE_OUT <= DISTANCE_SUM;
		end if;
	end if;
end process;


end behavioral;					
