-------------------------------------------------------------
-- MSS copyright 2015-2016
-- Filename:  BM_GEN.VHD
-- Authors: 
--		Alain Zarembowitch / MSS
-- Version: Rev 1
-- Last modified: 10/25/16

-- Inheritance: 	N/A
--
-- description:  Generate the 16 branch metrics value, based on the received samples ABYW and the
-- associated erasure information (when puncturing is enabled). Latency: 1 CLK
-------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity BM_GEN is
	generic (
		NQBITS: integer range 3 to 8 := 4;
			-- number of soft-quantized bits at the decoder input
		NLLRBITS: integer := 11;
			-- LLR precision
		NFEWERBITS: integer
			-- reduce BM range (tradeoff-speed vs performance)
			-- 0 for maximum performance
			-- 1 or 2 for increased clock speed
	);
    Port ( 
		--GLOBAL CLOCKS
		CLK: in std_logic;
		SYNC_RESET: in std_logic;
		
		-- Inputs
		-- received samples ABYW at time k
		A : IN std_logic_vector((NQBITS-1) downto 0);          
		B : IN std_logic_vector((NQBITS-1) downto 0);          
		Y : IN std_logic_vector((NQBITS-1) downto 0);          
		W : IN std_logic_vector((NQBITS-1) downto 0);   
			-- signed format
		ERASURE_Y: in std_logic;
		ERASURE_W: in std_logic;
		-- a priori LLRba for AB hypothesis
		LLR00 : in std_logic_vector(NLLRBITS-1 downto 0);  
		LLR01 : in std_logic_vector(NLLRBITS-1 downto 0);  
		LLR10 : in std_logic_vector(NLLRBITS-1 downto 0);  
		LLR11 : in std_logic_vector(NLLRBITS-1 downto 0);  
		IN_VALID: in std_logic;
			-- '1' when the above inputs are valid

		-- branch metrics at time k
		-- The index I in BM(I) represents ABYW, where A is the LSb and W the MSb.
		-- (keeping it the same order as in /Matlab/turbo.m)
		BM0 : out std_logic_vector(NLLRBITS-1 downto 0);          
		BM1 : out std_logic_vector(NLLRBITS-1 downto 0);           
		BM2 : out std_logic_vector(NLLRBITS-1 downto 0);      
		BM3 : out std_logic_vector(NLLRBITS-1 downto 0);           
		BM4 : out std_logic_vector(NLLRBITS-1 downto 0);           
		BM5 : out std_logic_vector(NLLRBITS-1 downto 0);         
		BM6 : out std_logic_vector(NLLRBITS-1 downto 0);          
		BM7 : out std_logic_vector(NLLRBITS-1 downto 0);          
		BM8 : out std_logic_vector(NLLRBITS-1 downto 0);          
		BM9 : out std_logic_vector(NLLRBITS-1 downto 0);          
		BM10 : out std_logic_vector(NLLRBITS-1 downto 0);          
		BM11 : out std_logic_vector(NLLRBITS-1 downto 0);          
		BM12 : out std_logic_vector(NLLRBITS-1 downto 0);          
		BM13 : out std_logic_vector(NLLRBITS-1 downto 0);          
		BM14 : out std_logic_vector(NLLRBITS-1 downto 0);          
		BM15 : out std_logic_vector(NLLRBITS-1 downto 0);
		OUT_VALID: out std_logic
  );
end entity;

architecture Behavioral of BM_GEN is
--------------------------------------------------------
--      COMPONENTS
--------------------------------------------------------
--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------
-- Suffix _D indicates a one CLK delayed version of the net with the same name
-- Suffix _X 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 YE: signed((NQBITS-1) downto 0) := (others => '0');  
signal WE: signed((NQBITS-1) downto 0) := (others => '0');  

signal AB00: signed(NQBITS downto 0) := (others => '0');  
signal AB01: signed(NQBITS downto 0) := (others => '0');  
signal AB10: signed(NQBITS downto 0) := (others => '0');  
signal AB11: signed(NQBITS downto 0) := (others => '0');  

signal YW00: signed(NQBITS downto 0) := (others => '0');  
signal YW01: signed(NQBITS downto 0) := (others => '0');  
signal YW10: signed(NQBITS downto 0) := (others => '0');  
signal YW11: signed(NQBITS downto 0) := (others => '0');  

signal BM_0: signed((NQBITS+1) downto 0) := (others => '0');  
signal BM_1: signed((NQBITS+1) downto 0) := (others => '0');  
signal BM_2: signed((NQBITS+1) downto 0) := (others => '0');  
signal BM_3: signed((NQBITS+1) downto 0) := (others => '0');  
signal BM_4: signed((NQBITS+1) downto 0) := (others => '0');  
signal BM_5: signed((NQBITS+1) downto 0) := (others => '0');  
signal BM_6: signed((NQBITS+1) downto 0) := (others => '0');  
signal BM_7: signed((NQBITS+1) downto 0) := (others => '0');  
signal BM_8: signed((NQBITS+1) downto 0) := (others => '0');  
signal BM_9: signed((NQBITS+1) downto 0) := (others => '0');  
signal BM_10: signed((NQBITS+1) downto 0) := (others => '0');  
signal BM_11: signed((NQBITS+1) downto 0) := (others => '0');  
signal BM_12: signed((NQBITS+1) downto 0) := (others => '0');  
signal BM_13: signed((NQBITS+1) downto 0) := (others => '0');  
signal BM_14: signed((NQBITS+1) downto 0) := (others => '0');  
signal BM_15: signed((NQBITS+1) downto 0) := (others => '0');  
--------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
begin

-- resize to prevent overflow
YE <= signed(Y) when (ERASURE_Y = '0') else (others => '0');
WE <= signed(W) when (ERASURE_W = '0') else (others => '0');

AB00 <= -resize(signed(A),NQBITS+1) - resize(signed(B),NQBITS+1);
AB01 <= -resize(signed(A),NQBITS+1) + resize(signed(B),NQBITS+1);
AB10 <= resize(signed(A),NQBITS+1) - resize(signed(B),NQBITS+1);
AB11 <= resize(signed(A),NQBITS+1) + resize(signed(B),NQBITS+1);

YW00 <= -resize(signed(YE),NQBITS+1) - resize(signed(WE),NQBITS+1);
YW01 <= -resize(signed(YE),NQBITS+1) + resize(signed(WE),NQBITS+1);
YW10 <= resize(signed(YE),NQBITS+1) - resize(signed(WE),NQBITS+1);
YW11 <= resize(signed(YE),NQBITS+1) + resize(signed(WE),NQBITS+1);

BM_0 <= resize(AB00,NQBITS+2) + resize(YW00,NQBITS+2); 
BM_1 <= resize(AB10,NQBITS+2) + resize(YW00,NQBITS+2);
BM_2 <= resize(AB01,NQBITS+2) + resize(YW00,NQBITS+2);
BM_3 <= resize(AB11,NQBITS+2) + resize(YW00,NQBITS+2);
BM_4 <= resize(AB00,NQBITS+2) + resize(YW10,NQBITS+2);
BM_5 <= resize(AB10,NQBITS+2) + resize(YW10,NQBITS+2);
BM_6 <= resize(AB01,NQBITS+2) + resize(YW10,NQBITS+2);
BM_7 <= resize(AB11,NQBITS+2) + resize(YW10,NQBITS+2);
BM_8 <= resize(AB00,NQBITS+2) + resize(YW01,NQBITS+2);
BM_9 <= resize(AB10,NQBITS+2) + resize(YW01,NQBITS+2);
BM_10 <= resize(AB01,NQBITS+2) + resize(YW01,NQBITS+2);
BM_11 <= resize(AB11,NQBITS+2) + resize(YW01,NQBITS+2);
BM_12 <= resize(AB00,NQBITS+2) + resize(YW11,NQBITS+2);
BM_13 <= resize(AB10,NQBITS+2) + resize(YW11,NQBITS+2);
BM_14 <= resize(AB01,NQBITS+2) + resize(YW11,NQBITS+2);
BM_15 <= resize(AB11,NQBITS+2) + resize(YW11,NQBITS+2);

BM_GEN_001: process(CLK)
begin
	if rising_edge(CLK) then
		OUT_VALID <= IN_VALID;
		
		if(SYNC_RESET = '1') then 
			BM0 <= (others => '0');
			BM1 <= (others => '0');
			BM2 <= (others => '0');
			BM3 <= (others => '0');
			BM4 <= (others => '0');
			BM5 <= (others => '0');
			BM6 <= (others => '0');
			BM7 <= (others => '0');
			BM8 <= (others => '0');
			BM9 <= (others => '0');
			BM10 <= (others => '0');
			BM11 <= (others => '0');
			BM12 <= (others => '0');
			BM13 <= (others => '0');
			BM14 <= (others => '0');
			BM15 <= (others => '0');
		elsif(IN_VALID = '1') then
         -- add a priori LLR from previous SISO   
			-- simplification: in Matlab turbo.m, the apriori LLR added to the branch metrics is 2*La(k,1+bitand(i-1,3))
			-- However La is also scaled by 0.5 after each iteration (optimum):         Lscaled = 0.5*L;
			-- Consequently, we skip the 2* and 0.5* steps to simplify.
			-- Clarification: LLR indices are LLRba (A is the LSb)
			
			-- scale down BM_X (and consequently NLLRBITS) to tradeoff speed/performance
			BM0 <= std_logic_vector(resize(BM_0(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR00));	 
			BM1 <= std_logic_vector(resize(BM_1(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR01));
			BM2 <= std_logic_vector(resize(BM_2(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR10));
			BM3 <= std_logic_vector(resize(BM_3(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR11));
			BM4 <= std_logic_vector(resize(BM_4(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR00));
			BM5 <= std_logic_vector(resize(BM_5(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR01));
			BM6 <= std_logic_vector(resize(BM_6(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR10));
			BM7 <= std_logic_vector(resize(BM_7(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR11));
			BM8 <= std_logic_vector(resize(BM_8(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR00));
			BM9 <= std_logic_vector(resize(BM_9(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR01));
			BM10 <= std_logic_vector(resize(BM_10(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR10));
			BM11 <= std_logic_vector(resize(BM_11(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR11));
			BM12 <= std_logic_vector(resize(BM_12(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR00));
			BM13 <= std_logic_vector(resize(BM_13(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR01));
			BM14 <= std_logic_vector(resize(BM_14(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR10));
			BM15 <= std_logic_vector(resize(BM_15(NQBITS+1 downto NFEWERBITS), NLLRBITS) +  signed(LLR11));
		end if;
	end if;
end process;
	

end Behavioral;

