-------------------------------------------------------------
-- MSS copyright 2012-2014
-- Filename:  tb_encoder_decoder_back2back.VHD
-- Authors: 
--		Alain Zarembowitch / MSS
-- Version: Rev 3
-- Last modified: 10/6/14

-- Inheritance: 	N/A
--
-- description:  prbs11 test sequence -> encoder-> decoder 
-- No bit errors. Ideal conditions.

-- Rev 2 11/30/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;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
 
ENTITY tb_encoder_decoder_back2back IS
END entity;
 
ARCHITECTURE behavior OF tb_encoder_decoder_back2back IS 
 
 
--------------------------------------------------------
--      COMPONENTS
----------------------------------------------------------
	COMPONENT LFSR11
	PORT(
		ASYNC_RESET : IN std_logic;
		CLK : IN std_logic;
		BIT_CLK_REQ : IN std_logic;
		SYNC_RESET : IN std_logic;
		LFSR_BIT : OUT std_logic;
		BIT_CLK_OUT : OUT std_logic;
		SOF_OUT : OUT std_logic
		);
	END COMPONENT;

	COMPONENT ENCODER_ROOT
	PORT(
		CLK : IN std_logic;
		ASYNC_RESET : IN std_logic;
		DATA_IN : IN std_logic;
		SAMPLE_CLK_IN : IN std_logic;
		SOF_RESET : IN std_logic;
		SAMPLE_CLK_OUT_REQ : IN std_logic;
		CONTROL : IN std_logic_vector(15 downto 0);          
		SAMPLE_CLK_IN_REQ : OUT std_logic;
		DATA_OUT : OUT std_logic_vector(3 downto 0);
		SAMPLE_CLK_OUT : OUT std_logic;
		TP : OUT std_logic_vector(4 downto 0)
		);
	END COMPONENT;

   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 K_MAX;
			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;
			HIGH_SNR: 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;
         IN_SYNC : OUT  std_logic;
         OUT_OF_SYNC : OUT  std_logic;
			LOCK_STATUS: out std_logic
        );
    END COMPONENT;

--------------------------------------------------------
--     SIGNALS
--------------------------------------------------------
	constant K_MAX: integer := 7;	
		-- maximum constraint length. Select 3,5,7, or 9
	constant N_PARITY_BITS_MAX: integer := 2;
		-- 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.
	signal STANDARD: integer := 1;
		-- There are some minor variations among standards, such as different puncturing scheme.
		-- 0 = Intelsat 
		-- 1 = CCSDS
		-- others = yet TBD
	constant TB_DEPTH: integer := 6*K_MAX;	
		-- traceback depth. MUST BE LESS THAN 120


signal CLK : std_logic := '0';
signal SYNC_RESET : std_logic := '0';

--//-- CONVOLUTIONAL ENCODING ----------------------------------
signal ENC_CONTROL: std_logic_vector(15 downto 0) := (others => '0');
signal ENC_DATA_IN: std_logic := '0';
signal ENC_SAMPLE_CLK_IN: std_logic := '0';
signal ENC_SAMPLE_CLK_IN_REQ: std_logic := '0';
signal ENC_SAMPLE_CLK_IN_REQB: std_logic := '0';
signal ENC_SAMPLE_CLK_EN: std_logic := '0';
signal ENC_DATA_OUT: std_logic_vector(3 downto 0) := (others => '0');
signal ENC_DATA_OUT_X: std_logic_vector(7 downto 0) := (others => '0');
signal ENC_SAMPLE_CLK_OUT: std_logic := '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) := (others => '0');
signal BER_VALID : std_logic;
signal IN_SYNC : 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 N_PARITY_BITS: integer range 2 to 7 := 2;
signal K: integer range 3 to K_MAX := 7;
signal R1: integer range 1 to 7 := 1;
signal R2: integer range 2 to 8 := 2;
signal LOCK_STATUS: std_logic := '0';
signal BIT_ERROR: std_logic := '0';
signal RX_DATA : std_logic_vector(3 downto 0) := (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;

--//-- PRBS-11 TEST SEQUENCE ----------------------------------
Inst_LFSR11: LFSR11 PORT MAP(
	ASYNC_RESET => '0',
	CLK => CLK,
	BIT_CLK_REQ => ENC_SAMPLE_CLK_IN_REQB,
	SYNC_RESET => SYNC_RESET,
	LFSR_BIT => ENC_DATA_IN,
	BIT_CLK_OUT => ENC_SAMPLE_CLK_IN,
	SOF_OUT => open
);

	-- flow control. Slow down encoder speed
	FLOW_CONTROL_001: process
	begin
		ENC_SAMPLE_CLK_EN <= '1';
		wait for 12ns;
		ENC_SAMPLE_CLK_EN <= '0';
		wait for 1000ns;
	end process;	

--	ENC_SAMPLE_CLK_IN_REQB <= ENC_SAMPLE_CLK_IN_REQ and ENC_SAMPLE_CLK_EN;
	ENC_SAMPLE_CLK_IN_REQB <= ENC_SAMPLE_CLK_IN_REQ;

--//-- CONVOLUTIONAL ENCODING ----------------------------------
-- Current implementation is serial. However, plan for 8-bit interface component at higher speeds.
-- For the moment, the ENCODER_ROOT is surrounded by parallel to serial and serial to parallel conversions.

ENC_CONTROL(0) <= '0';	-- N/A
ENC_CONTROL(4 downto 1) <= "0001";	-- K=7,R=1/2, Intelsat
--ENC_CONTROL(4 downto 1) <= "1011";	-- K=7,R=1/2, CCSDS
--ENC_CONTROL(4 downto 1) <= "0101";	-- K=7,R=7/8, Intelsat
ENC_CONTROL(5) <= '0';	-- no differential encoding
ENC_CONTROL(6) <= '0';	-- continuous mode only
ENC_CONTROL(7) <= '0';	-- N/A
ENC_CONTROL(9 downto 8) <= "00";	-- 1-bit wide output
ENC_CONTROL(11 downto 10) <= "00";	-- N/A
ENC_CONTROL(12) <= '0';	-- flow control set by modulator symbol rate
ENC_CONTROL(15 downto 13) <= "000";	-- N/A


ENCODER_ROOT_001: ENCODER_ROOT PORT MAP(
	CLK => CLK,
	ASYNC_RESET => SYNC_RESET,
	DATA_IN => ENC_DATA_IN,	
	SAMPLE_CLK_IN => ENC_SAMPLE_CLK_IN,	
	SAMPLE_CLK_IN_REQ => ENC_SAMPLE_CLK_IN_REQ, 
	SOF_RESET => '0',
	DATA_OUT => ENC_DATA_OUT,
	SAMPLE_CLK_OUT => ENC_SAMPLE_CLK_OUT,
	SAMPLE_CLK_OUT_REQ => '1',
	CONTROL => ENC_CONTROL,
	TP => 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)
	RX_DATA <= (others => ENC_DATA_OUT(0));		-- hard quantization
	--RX_DATA <= (3 => ENC_DATA_OUT(0), 2 => ENC_DATA_OUT(0), 1 => not ENC_DATA_OUT(0), 0 => not ENC_DATA_OUT(0));	-- symmetrical, not full scale
	--RX_DATA <= (3 => not ENC_DATA_OUT(0), 2 => not ENC_DATA_OUT(0), 1 => ENC_DATA_OUT(0), 0 => ENC_DATA_OUT(0));	-- inverted, symmetrical, not full scale
	--RX_DATA <= (3 => ENC_DATA_OUT(0), 2 => ENC_DATA_OUT(0), 1 => '0', 0 => '0');	-- symmetrical, not full scale
	
	
	BIT_CNTR_GEN: process(CLK)
	variable index: integer;
	begin
		index := 7 - conv_integer(BIT_CNTR);	
		if rising_edge(CLK) then
			
			if(ENC_SAMPLE_CLK_OUT = '1') then
				BIT_CNTR <= BIT_CNTR + 1;
				DATAIN((4*index+3) downto (4*index)) <= RX_DATA;		
				
				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)
	-- generator polynomials
	-- Intelsat (check consistency with the STANDARD constant)
	G(8 downto 0) <= O"133";
	G(17 downto 9) <= O"171";
	STANDARD <= 0;	
	-- CCSDS
--	G(8 downto 0) <= O"171";
--	G(17 downto 9) <= O"133";
--	STANDARD <= 1;	
	N_PARITY_BITS <= 2;
	R1 <= 1;	-- rate 1/2
	R2 <= 2;
--	R1 <= 7;	-- rate 7/8
--	R2 <= 8;
 
	-- 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,
          DATAIN_READY => DATAIN_READY,
			 SKIP1BIT_PULSE => '0',
			 G => G,
			 N_PARITY_BITS => N_PARITY_BITS,
			 K => K,
			 R1 => R1,
			 R2 => R2,
			 STANDARD => STANDARD,
			 DIFF_ENC_ON => '0',
			 HIGH_SNR => '1',
          DATAOUT1b => DATAOUT1b,
          DATAOUT1b_VALID => DATAOUT1b_VALID,
          DATAOUT8b => DATAOUT8b,
          DATAOUT8b_VALID => DATAOUT8b_VALID,
          BER => BER,
          BER_VALID => BER_VALID,
			 BIT_ERROR => BIT_ERROR,
			 IN_SYNC => IN_SYNC,
          OUT_OF_SYNC => OUT_OF_SYNC,
			 LOCK_STATUS => LOCK_STATUS
        );

END;
