-------------------------------------------------------------
-- MSS copyright 2012
-- Filename:  tb_viterbi_decoder.VHD
-- Authors: 
--		Alain Zarembowitch / MSS
-- Version: Rev 2
-- Last modified: 12/8/12

-- Inheritance: 	N/A
--
-- description:  encoded input file -> decoder 
-- Channel impairements (AWGN, etc) are generated by generated by Matlab .m program
-- The decoded BER will be measured if the original bit stream is a PRBS-11 test sequence.
--
-- Rev 2 11/30/12 AZ
-- Passed parameters through generic for more configuration flexibility instead of common com1509pkg
-- 
-- Rev 3 12/8/12 AZ
-- Added decoded stream BER measurement.
--------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
 
ENTITY tb_viterbi_decoder IS
END tb_viterbi_decoder;
 
ARCHITECTURE behavior OF tb_viterbi_decoder IS 
 
 
--------------------------------------------------------
--      COMPONENTS
----------------------------------------------------------
   COMPONENT VITERBI_DECODER
	GENERIC(
		K_MAX: integer;	
		N_PARITY_BITS_MAX: integer;
		NDEC: integer;  
		HARD_SOFTN_DECISION: std_logic;
		TB_DEPTH: integer;	
		SIMULATION: std_logic
	);
   PORT(
		CLK : IN  std_logic;
		SYNC_RESET : IN  std_logic;
		DATAIN: in std_logic_vector(31 downto 0);
		DATAIN_VALID : IN  std_logic;
		DATAIN_READY : OUT  std_logic;
		SKIP1BIT_PULSE: in std_logic;
		G: in std_logic_vector(62 downto 0);  
		N_PARITY_BITS: in integer range 2 to 7;
		K: in integer range 3 to 9;
		R1: in integer range 1 to 7;
		R2: in integer range 2 to 8;
		STANDARD: in integer range 0 to 1;
		DIFF_ENC_ON: in std_logic;
		DATAOUT1b: out std_logic;
		DATAOUT1b_VALID: out std_logic;
		DATAOUT8b: out std_logic_vector(7 downto 0);
		DATAOUT8b_VALID: out std_logic;
		BER: out std_logic_vector(23 downto 0);
		BER_VALID : OUT  std_logic;
		BIT_ERROR: out std_logic;
		OUT_OF_SYNC : OUT  std_logic;
		LOCK_STATUS: out std_logic
        );
    END COMPONENT;

	COMPONENT INFILE2SIM
	 GENERIC (
		N_COLS: integer;	
		FILENAME: string
	 );
	PORT(
		CLK : IN std_logic;
		SAMPLE_CLK_IN : IN std_logic;          
		DATA1 : OUT std_logic_vector(11 downto 0);
		DATA2 : OUT std_logic_vector(11 downto 0);
		DATA3 : OUT std_logic_vector(11 downto 0)
		);
	END COMPONENT;

	COMPONENT BER2
	PORT(
		CLK : IN std_logic;
		SYNC_RESET : IN std_logic;
		DATA_IN : IN std_logic_vector(7 downto 0);
		SAMPLE_CLK_IN : IN std_logic;
		CONTROL : IN std_logic_vector(7 downto 0);          
		MF_DETECT : OUT std_logic;
		MF_DETECT_CONFIRMED : OUT std_logic;
		SYNC_LOCK : OUT std_logic;
		BYTE_ERROR : OUT std_logic;
		DATA_REPLICA : OUT std_logic_vector(7 downto 0);
		SAMPLE_CLK_OUT : OUT std_logic;
		BER : OUT std_logic_vector(31 downto 0);
		BER_SAMPLE_CLK : OUT std_logic;
		TP : OUT std_logic_vector(10 downto 1)
		);
	END COMPONENT;

	component SIM2OUTFILE is
		 Generic (
			FILENAME: string
		 );
		 Port ( 
			--// CLK, RESET
			CLK: in std_logic;
				-- Reference clock
			DATA1: in std_logic_vector(11 downto 0);
			DATA2: in std_logic_vector(11 downto 0);
			DATA3: in std_logic_vector(11 downto 0);
			SAMPLE_CLK_IN: in std_logic
				-- DATA_IN is read at the rising edge of CLK when SAMPLE_CLK_IN = '1'

	);
	END COMPONENT;

--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------

--// FEC DECODER CONFIGURATION ---------------------------------------
	constant K_MAX: integer := 9;	
		-- maximum constraint length. Select 3,5,7, or 9
	constant N_PARITY_BITS_MAX: integer := 3;
		-- maximum number of parity bits. For example 3 for rate 1/3, or 2 for rate 2/3. 
		-- valid range 2 - 7
		-- size vectors/arrays accordingly.
		-- If this decoder is only used with 2-bit parity, smaller implementations may be achieved by setting N_PARITY_BITS_MAX=2
	constant NDEC: integer := 1;  
		-- number of parallel FEC decoders
		-- Valid range: 1,2,4,8
	constant	HARD_SOFTN_DECISION: std_logic := '0';
		-- '1' for hard-decision (1-bit) decoding. Hamming distance (number of differing bits) is generated for each hypothesis being tested.
		-- '0' for 4-bit soft-decision decoding. Local (approximation of Euclidian) distance is generated.
		-- When configured for hard decision decoding, the input bit should be placed at DATAIN(3), while DATAIN(2 downto 0) is ignored.
	constant STANDARD: integer := 0;
		-- There are some minor variations among standards, such as different puncturing scheme.
		-- 0 = Intelsat 
		-- 1 = CCSDS
		-- 2 = DVB rate 1/2
		-- others = yet TBD
	--constant TB_DEPTH: integer := 6*K_MAX;	-- for min latency when no puncturing
	constant TB_DEPTH: integer := 96;	-- use when puncturing
		-- traceback depth. MUST BE LESS THAN 120
	signal N_PARITY_BITS: integer range 2 to 7 := 2;
	signal K: integer range 3 to 9 := 7;
	signal R1: integer range 1 to 7 := 1;
	signal R2: integer range 2 to 8 := 2;
--//-----------------------------------------------------------------------------
   signal CLK : std_logic := '0';
   signal SYNC_RESET : std_logic := '0';
   signal SAMPLE_CLK_IN : std_logic := '0';
   signal SAMPLE_CLK_IN_D : std_logic := '0';
	signal STIMULUS: std_logic_vector(11 downto 0):= (others => '0');
	signal BIT_CNTR: std_logic_vector(2 downto 0) := "001";	-- create offset here to test self synchronization
	signal DATAIN: std_logic_vector(31 downto 0):= (others => '0');
   signal DATAIN_VALID : std_logic := '0';
   signal DATAIN_READY : std_logic := '1';
   signal DATAOUT1b : std_logic := '0';
   signal DATAOUT1b_VALID : std_logic := '0';
   signal DATAOUT8b : std_logic_vector(7 downto 0) := (others => '0');
   signal DATAOUT8b_VALID : std_logic := '0';
   signal BER : std_logic_vector(23 downto 0);
   signal BER_VALID : std_logic;
   signal OUT_OF_SYNC : std_logic;
	signal READ_CNTR: std_logic_vector(1 downto 0) := (others => '0');
	signal G: std_logic_vector(62 downto 0) := (others => '0');
	signal LOCK_STATUS: std_logic := '0';
	signal BIT_ERROR: std_logic := '0';

	--//-- BER MEASUREMENT  ---------------------------------------------------------
	signal BER_CONTROL: std_logic_vector(7 downto 0) := (others => '0');
	signal BER_MF_DETECT: std_logic := '0';
	signal BER_MF_DETECT_CONFIRMED: std_logic := '0';
	signal BER_SYNC: std_logic := '0';
	signal BER_BYTE_ERROR: std_logic := '0';
	signal BER_ERROR_COUNT: std_logic_vector(31 downto 0) := (others => '0');
	signal BER_TEST_POINT: std_logic_vector(10 downto 1) := (others => '0');

   -- Clock period definitions
   constant CLK_period : time := 10 ns;
 
--------------------------------------------------------
--      IMPLEMENTATION
--------------------------------------------------------
BEGIN

   -- Clock process definitions
   CLK_process :process
   begin
		CLK <= '0';
		wait for CLK_period/2;
		CLK <= '1';
		wait for CLK_period/2;
   end process;

   -- Stimulus process
   stim_proc: process
   begin		
		SYNC_RESET <= '1';
      -- hold reset state for 100 ns.
      wait for 100 ns;	
		SYNC_RESET <= '0';

      wait for CLK_period*10;
      wait;
   end process;

	-- read stimulus file as fast as possible
	SAMPLE_CLK_IN <= (not SYNC_RESET) and DATAIN_READY;
--	-- read at slower pace
--	READ_SLOW: process(CLK)
--	begin
--		if rising_edge(CLK) then
--			if(SYNC_RESET = '1') then
--				SAMPLE_CLK_IN <= '0';
--			else
--				READ_CNTR <= READ_CNTR + 1;
--				if(READ_CNTR = 0) and (DATAIN_READY = '1') then 
--					SAMPLE_CLK_IN <= '1';
--				else
--					SAMPLE_CLK_IN <= '0';
--				end if;
--			end if;
--		end if;
--	end process;

	-- read stimulus file 
 	-- Baseband input stream 4-bit soft quantized samples. Range 0 - 15
	-- 1 CLK latency between SAMPLE_CLK_IN and output
	Inst_INFILE2SIM: INFILE2SIM 
	generic map(
		N_COLS => 1,
		FILENAME => "fecdecin.txt"	
--		FILENAME => ".\sim\fecdecin.txt"	
	)
	PORT MAP(
		CLK => CLK,
		SAMPLE_CLK_IN => SAMPLE_CLK_IN,
		DATA1 => STIMULUS,
		DATA2 => open,
		DATA3 => open
	);

	-- collect 8 bits (x1 or x4 when soft-decision) before sending to Viterbi_decoder
	-- MSb is first (DATAIN(31 downto 28) is the first received soft-decision sample)
	BIT_CNTR_GEN: process(CLK)
	variable index: integer;
	begin
		index := 7 - conv_integer(BIT_CNTR);	
		if rising_edge(CLK) then
			SAMPLE_CLK_IN_D <= SAMPLE_CLK_IN;
			
			if(SAMPLE_CLK_IN_D = '1') then
				BIT_CNTR <= BIT_CNTR + 1;
				DATAIN((4*index+3) downto (4*index)) <= STIMULUS(3 downto 0);	
				if(BIT_CNTR = 7) then
					DATAIN_VALID <= '1';
				else
					DATAIN_VALID <= '0';
				end if;
			else
				DATAIN_VALID <= '0';
			end if;
		end if;
	end process;



	-- Instantiate the Unit Under Test (UUT)
G_GEN: process
begin
	-- generator polynomials
	if (STANDARD = 0) and (K = 7) then
		-- Intelsat
		N_PARITY_BITS <= 2;
		G(8 downto 0) <= O"133";
		G(17 downto 9) <= O"171";
	elsif(STANDARD = 1) and (K = 7) then
		-- CCSDS
		N_PARITY_BITS <= 2;
		G(8 downto 0) <= O"171";
		G(17 downto 9) <= O"133";
	elsif (K = 9) and (R1 = 1) and (R2 = 3) then
		-- K=9, rate 1/3
		N_PARITY_BITS <= 3;
		G(8 downto 0) <= O"557";
		G(17 downto 9) <= O"663";
		G(26 downto 18) <= O"711";
	else
	--elsif (K = 9) then
		-- K=9, rates 1/2, 2/3
		N_PARITY_BITS <= 2;
		G(8 downto 0) <= O"753";
		G(17 downto 9) <= O"561";
	end if;
	wait;
end process;

 
	-- Instantiate the Unit Under Test (UUT)
   uut: VITERBI_DECODER 
	GENERIC MAP(
		K_MAX => K_MAX,
		N_PARITY_BITS_MAX => N_PARITY_BITS_MAX,
		NDEC => NDEC,
		HARD_SOFTN_DECISION => HARD_SOFTN_DECISION,
		TB_DEPTH => TB_DEPTH,
		SIMULATION => '0'
	)
	PORT MAP (
          CLK => CLK,
          SYNC_RESET => SYNC_RESET,
          DATAIN => DATAIN,
          DATAIN_VALID => DATAIN_VALID,
			 SKIP1BIT_PULSE => '0',
			 G => G,
			 N_PARITY_BITS => N_PARITY_BITS,
			 K => K,
			 R1 => R1,
			 R2 => R2,
			 STANDARD => STANDARD,
			 DIFF_ENC_ON => '0',
          DATAIN_READY => DATAIN_READY,
          DATAOUT1b => DATAOUT1b,
          DATAOUT1b_VALID => DATAOUT1b_VALID,
          DATAOUT8b => DATAOUT8b,
          DATAOUT8b_VALID => DATAOUT8b_VALID,
          BER => BER,	-- this is the ENCODED STREAM BER (approximation). The actual DECODED STREAM BER is measured below by the BER2 component
          BER_VALID => BER_VALID,
			 BIT_ERROR => BIT_ERROR,
          OUT_OF_SYNC => OUT_OF_SYNC,
			 LOCK_STATUS => LOCK_STATUS
        );


-- BER measurement (when a PRBS11 test sequence is encoded in fecdecin.txt)
-- Use viterbi_dec_input_genprbs11.m to generate an encoded PRBS-11 test sequence as input stimulus for this testbench.
BER_CONTROL(2 downto 0) <= "000";
				-- 000 = 1,000 bytes
				-- 001 = 10,000 bytes
				-- 010 = 100,000 bytes
				-- 011 = 1,000,000 bytes
				-- 100 = 10,000,000 bytes
				-- 101 = 100,000,000 bytes
				-- 110 = 1,000,000,000 bytes
BER_CONTROL(7 downto 3) <= (others => '0'); -- unused

BER2_001: BER2 PORT MAP(
	CLK => CLK,
	SYNC_RESET => SYNC_RESET,
	DATA_IN => DATAOUT8b,
	SAMPLE_CLK_IN => DATAOUT8b_VALID,
	CONTROL => BER_CONTROL,
	MF_DETECT => BER_MF_DETECT,	-- useful test point
	MF_DETECT_CONFIRMED => BER_MF_DETECT_CONFIRMED,
	SYNC_LOCK => BER_SYNC,	-- useful test point
	BYTE_ERROR => BER_BYTE_ERROR,		-- useful test point
	DATA_REPLICA => open,
	SAMPLE_CLK_OUT => open,
	BER => BER_ERROR_COUNT,
	BER_SAMPLE_CLK => open,
	TP => BER_TEST_POINT
);




 
--// simulation. send to a tab-delimited text file for subsequent (Matlab) plot.
--	Inst_SIM2OUTFILE0: SIM2OUTFILE 
--	generic map(
--		FILENAME => "fecdecout.txt"
--	)
--	PORT MAP(
--		CLK => CLK,
--		DATA1 => x"0" & DATAOUT8b,
--		DATA2 => x"000",
--		DATA3 =>  x"000",
--		SAMPLE_CLK_IN => DATAOUT8b_VALID
--	);





END;
