--=================================================================================================
-- File Name                           : adc_scaling_tb.vhd

-- Description                         : This module implements the test environment for
--                                       adc_scaling block

-- Targeted device                     : Microsemi-SoC
-- Author                              : India Solutions Team
--
-- SVN Revision Information            :
-- SVN $Revision                       :
-- SVN $Date                           :
--
-- COPYRIGHT 2016 BY MICROSEMI
-- THE INFORMATION CONTAINED IN THIS DOCUMENT IS SUBJECT TO LICENSING RESTRICTIONS FROM MICROSEMI
-- CORP. IF YOU ARE NOT IN POSSESSION OF WRITTEN AUTHORIZATION FROM MICROSEMI FOR USE OF THIS
-- FILE, THEN THE FILE SHOULD BE IMMEDIATELY DESTROYED AND NO BACK-UP OF THE FILE SHOULD BE MADE.
--
--=================================================================================================

--=================================================================================================
-- Libraries
--=================================================================================================
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE STD.TEXTIO.ALL;
USE IEEE.STD_LOGIC_TEXTIO.ALL;
USE IEEE.STD_LOGIC_SIGNED.ALL;
USE IEEE.NUMERIC_STD.ALL;
USE IEEE.MATH_REAL.ALL;   -- FOR UNIFORM, TRUNC FUNCTIONS
LIBRARY MODELSIM_LIB;
USE MODELSIM_LIB.UTIL.ALL;
USE work.sim_pkg.all;
use work.coreparameters.all;

--=================================================================================================
-- adc_scaling_tb entity declaration
--=================================================================================================
ENTITY adc_scaling_tb IS

END adc_scaling_tb;

--=================================================================================================
-- adc_scaling_tb architecture body
--=================================================================================================
ARCHITECTURE behavioral OF adc_scaling_tb IS
COMPONENT ADC_SCALING IS
GENERIC(
    g_DEBUG                            : INTEGER := 0;
    g_SIGNED                           : INTEGER := 0;
	g_ADC_RESULTS_WIDTH                : INTEGER := 12;
    g_NO_MCYCLE_PATH                   : INTEGER RANGE 0 TO 4 := 2
);
PORT (
    reset_i                            : IN  STD_LOGIC;
    sys_clk_i                          : IN  STD_LOGIC;
	adc_results_rdy_i                  : IN  STD_LOGIC;
    adc_scale_val_i                    : IN  STD_LOGIC_VECTOR(17  DOWNTO 0);
    adc_result_ch0_i                   : IN  STD_LOGIC_VECTOR(g_ADC_RESULTS_WIDTH-1  DOWNTO 0);
    adc_result_ch1_i	               : IN  STD_LOGIC_VECTOR(g_ADC_RESULTS_WIDTH-1  DOWNTO 0);
    fault_threshold_i                  : IN  STD_LOGIC_VECTOR(17   DOWNTO 0);
    done_o                             : OUT STD_LOGIC;
	calib_done_o                       : OUT STD_LOGIC;
	over_current_fault_o               : OUT STD_LOGIC;
    ia_adc_o                    	   : OUT STD_LOGIC_VECTOR(17 DOWNTO 0);
    ib_adc_o                    	   : OUT STD_LOGIC_VECTOR(17 DOWNTO 0)
);
END COMPONENT;

--=================================================================================================
-- Signal declarations
--=================================================================================================
CONSTANT SYSCLK_PERIOD                 : TIME := 100 ns;
TYPE     adc_op_state is               (IDLE,CALIBRATION,IA_IB_GEN,IND_TEST,OUTPUT_COMPARE,DUMMY);

SIGNAL   state                         : adc_op_state;
SIGNAL sys_clk_tb                      : STD_LOGIC:= '0';
SIGNAL reset_tb                        : STD_LOGIC:= '0';
SIGNAL reset_test                      : STD_LOGIC;
SIGNAL s_reset_tb_pul                  : STD_LOGIC;
SIGNAL s_reset_tb_dly                  : STD_LOGIC;
SIGNAL s_start_tb                      : STD_LOGIC;
SIGNAL s_start_tb_dly                  : STD_LOGIC;
SIGNAL s_calib_done_tb                 : STD_LOGIC;
SIGNAL s_adc_scale_done_tb             : STD_LOGIC;
SIGNAL s_adc_scale_done_tb_dly         : STD_LOGIC;
SIGNAL s_calib_done_tb_dly             : STD_LOGIC;
SIGNAL s_calib_done_tb_pul             : STD_LOGIC;
SIGNAL s_over_current_fault_tb         : STD_LOGIC;
SIGNAL s_flag_tb                       : STD_LOGIC;
SIGNAL s_done_tb                       : STD_LOGIC;
SIGNAL s_calib_done_count_tb           : STD_LOGIC_VECTOR(15 DOWNTO 0);
SIGNAL s_adc_scale_val_tb              : STD_LOGIC_VECTOR(17 DOWNTO 0);
SIGNAL s_adc_result_ch0_tb             : STD_LOGIC_VECTOR(19 DOWNTO 0);
SIGNAL s_adc_result_ch1_tb             : STD_LOGIC_VECTOR(19 DOWNTO 0);
SIGNAL s_adc_result_ch0_tb_ext         : STD_LOGIC_VECTOR(31 DOWNTO 0);
SIGNAL s_adc_result_ch1_tb_ext         : STD_LOGIC_VECTOR(31 DOWNTO 0);
SIGNAL s_ch0_offset_tb                 : STD_LOGIC_VECTOR(31 DOWNTO 0);
SIGNAL s_ch1_offset_tb                 : STD_LOGIC_VECTOR(31 DOWNTO 0);
SIGNAL s_start_count_tb                : STD_LOGIC_VECTOR(11 DOWNTO 0);
SIGNAL s_ia_adc_tb                     : STD_LOGIC_VECTOR(17 DOWNTO 0);
SIGNAL s_ib_adc_tb                     : STD_LOGIC_VECTOR(17 DOWNTO 0);
SIGNAL counter                         : STD_LOGIC_VECTOR(11 DOWNTO 0);
SIGNAL s_ia_tb                         : STD_LOGIC_VECTOR(35 DOWNTO 0);
SIGNAL s_ib_tb                         : STD_LOGIC_VECTOR(35 DOWNTO 0);
SIGNAL s_fault_threshold_tb            : STD_LOGIC_VECTOR(17 DOWNTO 0);
--========================================================
-- File read operations
--========================================================
--NA--
--========================================================
-- File write operations
--========================================================
--NA--
--========================================================
-- Procedure Declarations
--========================================================
PROCEDURE adc_scaling_tb
	(
	SIGNAL reset_tb     		: IN STD_LOGIC;
	SIGNAL sys_clk_tb   		: IN STD_LOGIC;
	SIGNAL start        		: IN STD_LOGIC;
	SIGNAL ch0_results_i        : IN STD_LOGIC_VECTOR(g_ADC_RESULTS_WIDTH-1 DOWNTO 0);
	SIGNAL ch1_results_i   		: IN STD_LOGIC_VECTOR(g_ADC_RESULTS_WIDTH-1 DOWNTO 0);
	SIGNAL ch0_offset_i   		: IN STD_LOGIC_VECTOR(31 DOWNTO 0);
	SIGNAL ch1_offset_i   		: IN STD_LOGIC_VECTOR(31 DOWNTO 0);
	SIGNAL scale_value_i   		: IN STD_LOGIC_VECTOR(17 DOWNTO 0);
	SIGNAL done_tb              : INOUT STD_LOGIC;
	SIGNAL ia_tb                : INOUT STD_LOGIC_VECTOR(35 DOWNTO 0);
	SIGNAL ib_tb         	    : INOUT STD_LOGIC_VECTOR(35 DOWNTO 0)
	) IS
BEGIN
    IF reset_tb = '0' THEN
        ia_tb 	        <= (OTHERS =>'0');
        ib_tb 			<= (OTHERS =>'0');
		done_tb 		<= '0';
    ELSIF RISING_EDGE (sys_clk_tb) THEN
		IF(start = '1') THEN
            ia_tb <= (ch0_results_i - (ch0_offset_i(30 DOWNTO 13)))* scale_value_i;
            ib_tb <= (ch1_results_i - (ch1_offset_i(30 DOWNTO 13)))* scale_value_i;
        END IF;
    END IF;
END adc_scaling_tb;
BEGIN

--========================================================
-- signal spy operations
--========================================================
--NA--

--------------------------------------------------------------------------
-- Name       : RESET_GEN_PROC
-- Description: PROCESS generates the reset signal
--------------------------------------------------------------------------
RESET_GEN_PROC:
    PROCESS
        VARIABLE vhdl_initial : BOOLEAN := TRUE;
    BEGIN
        IF ( vhdl_initial ) THEN
            reset_tb <= '0';
            WAIT FOR ( SYSCLK_PERIOD * 10 );
            reset_tb <= '1';
            WAIT;
        END IF;
    END PROCESS;

--------------------------------------------------------------------------
-- Name       : CLOCK_GEN
-- Description: Logic generates 100 Mhz clock
--------------------------------------------------------------------------
sys_clk_tb <= NOT sys_clk_tb AFTER (SYSCLK_PERIOD / 2.0 );


--------------------------------------------------------------------------
-- Name       : START_COUNT_GEN_PROC
-- Description: Counter to generate initial start signal
--------------------------------------------------------------------------
START_COUNT_GEN_PROC:
    PROCESS(reset_tb,sys_clk_tb)
    BEGIN
        IF reset_tb = '0' THEN
            s_start_count_tb            <= (OTHERS => '0');
            s_flag_tb                   <= '0';
        ELSIF RISING_EDGE(sys_clk_tb) THEN
            IF(s_calib_done_tb = '0') THEN
                IF(s_start_count_tb = x"3")THEN
                    s_start_count_tb <= (OTHERS => '0');
                ELSE
                    s_start_count_tb        <= s_start_count_tb + '1';
                END IF;
            END IF;
        END IF;
    END PROCESS;
--------------------------------------------------------------------------
-- Name       : START_GEN_PROC
-- Description: PROCESS generates the start signal
--------------------------------------------------------------------------
START_GEN_PROC:
    PROCESS(reset_tb,sys_clk_tb)
    BEGIN
        IF reset_tb = '0' THEN
            s_start_tb                  <= '0';
            s_start_tb_dly                  <= '0';
        ELSIF RISING_EDGE(sys_clk_tb) THEN
            IF(s_calib_done_tb = '0') THEN
                IF(s_start_count_tb = x"3")THEN
                    s_start_tb              <= '1';
                ELSE
                    s_start_tb              <= '0';
                END IF;
            ELSE
                IF(state = IND_TEST) THEN
                    s_start_tb <= '1';
                ELSIF(state = OUTPUT_COMPARE) THEN
                    s_start_tb <= '0';
                ELSE
                    s_start_tb <= '0';
                END IF;

            END IF;
        s_start_tb_dly <= s_start_tb;
        END IF;
    END PROCESS;

--------------------------------------------------------------------------
-- Name       : RESET_PUL_GEN_PROC
-- Description: Process to generate a reset pulse
--------------------------------------------------------------------------
RESET_PUL_GEN_PROC:
    PROCESS(reset_tb,sys_clk_tb)
    BEGIN
        IF(reset_tb = '0') THEN
            s_reset_tb_dly <= '0';
        ELSIF(RISING_EDGE (sys_clk_tb))THEN
            s_reset_tb_dly <= reset_tb;
        END IF;
    END PROCESS;
    s_reset_tb_pul <= reset_tb AND (not(s_reset_tb_dly ));
--------------------------------------------------------------------------
-- Name       : CALIB_DONE_PUL_GEN_PROC
-- Description: Process to generate calib_done pulse
--------------------------------------------------------------------------

CALIB_DONE_PUL_GEN_PROC:
    PROCESS(reset_tb,sys_clk_tb)
    BEGIN
        IF(reset_tb = '0') THEN
            s_calib_done_tb_dly <= '0';
        ELSIF(RISING_EDGE (sys_clk_tb))THEN
            s_calib_done_tb_dly <= s_calib_done_tb;
        END IF;
    END PROCESS;
    s_calib_done_tb_pul <= s_calib_done_tb AND (not(s_calib_done_tb_dly ));
--------------------------------------------------------------------------
-- Name       : RESET_TEST_PROC
-- Description: PROCESS to check the state of all outputs at reset
--------------------------------------------------------------------------
RESET_TEST_PROC:
    PROCESS(s_reset_tb_pul,
            s_adc_scale_done_tb,
            s_calib_done_tb,
            s_over_current_fault_tb,
            s_ia_adc_tb,
            s_ib_adc_tb)
    BEGIN
        IF (s_reset_tb_pul = '1') THEN
            IF((s_adc_scale_done_tb = '0') AND (s_calib_done_tb = '0') AND (s_over_current_fault_tb = '0') AND
                (s_ia_adc_tb = "00" & x"0000") AND (s_ib_adc_tb = "00" & x"0000") )THEN
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                print(">>>>>>>>                   ADC_SCALING IP INTEGRATED SIMULATION                     <<<<<<<");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                print(">>>>>>>>     THIS TESTBENCH COMPARES THE FUNCTIONALITY W.R.T THE TESTBENCH MODEL    <<<<<<<");
                print(">>>>>>>>     WITH IN THE TOLERANCE RANGE [-1,0,+1]                                  <<<<<<<");
                print(">>>>>>>>                                                                            <<<<<<<");
                print(">>>>>>>>     ALL  PARAMETERS/GENERICS ARE FIXED TO THE FOLLOWING:                   <<<<<<<");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                print(">>>>>>>>     g_DEBUG                    =  0                                        <<<<<<<");
                print(">>>>>>>>     g_ADC_RESULTS_WIDTH        = 12                                        <<<<<<<");
                print(">>>>>>>>     g_STD_IO_WIDTH             = 18                                        <<<<<<<");
                print(">>>>>>>>     g_APB3_IF_DATA_WIDTH       = 32                                        <<<<<<<");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                print("                                                        ");
                print("                                                        ");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                print(">>>>        ADC_SCALING_RESET_TEST : PASSED         <<<<");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                print(">>>>     done_o                = 0                  <<<<");
                print(">>>>     calib_done_o          = 0                  <<<<");
                print(">>>>     over_current_fault_o  = 0                  <<<<");
                print(">>>>     ia_adc_o              = 0                  <<<<");
                print(">>>>     ib_adc_o              = 0                  <<<<");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            ELSE
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                print(">>>>>>>>                   ADC_SCALING IP INTEGRATED SIMULATION                     <<<<<<<");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                print(">>>>>>>>     THIS TESTBENCH COMPARES THE FUNCTIONALITY W.R.T THE TESTBENCH MODEL    <<<<<<<");
                print(">>>>>>>>     WITH IN THE TOLERANCE RANGE [-1,0,+1]                                  <<<<<<<");
                print(">>>>>>>>                                                                            <<<<<<<");
                print(">>>>>>>>     ALL  PARAMETERS/GENERICS ARE FIXED TO THE FOLLOWING:                   <<<<<<<");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                print(">>>>>>>>     g_DEBUG                    =  0                                        <<<<<<<");
                print(">>>>>>>>     g_ADC_RESULTS_WIDTH        = 12                                        <<<<<<<");
                print(">>>>>>>>     g_STD_IO_WIDTH             = 18                                        <<<<<<<");
                print(">>>>>>>>     g_APB3_IF_DATA_WIDTH       = 32                                        <<<<<<<");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                print("                                                        ");
                print("                                                        ");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                print(">>>>        ADC_SCALING_RESET_TEST : FAILED         <<<<");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                print(">>>>     done_o               /= 0                  <<<<");
                print(">>>>     calib_done_o         /= 0                  <<<<");
                print(">>>>     over_current_fault_o /= 0                  <<<<");
                print(">>>>     ia_adc_o             /= 0                  <<<<");
                print(">>>>     ib_adc_o             /= 0                  <<<<");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            END IF;
        END IF;
    END PROCESS;

--------------------------------------------------------------------------
-- Name       : CALIB_DONE_CHECK_PROC
-- Description: PROCESS to check the status of calib_done signal
--------------------------------------------------------------------------
CALIB_DONE_CHECK_PROC:
    PROCESS(reset_tb, sys_clk_tb)
    BEGIN
        IF(s_calib_done_tb_pul = '1') THEN
            IF((s_calib_done_count_tb = x"2000")) THEN
                print("                                                                       ");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                print(">>>>                                                               <<<<");
                print(">>>>     TESTCASE         : CALIBRATION_TEST                       <<<<");
                print(">>>>                                                               <<<<");
                print(">>>>     STATUS           : PASSED                                 <<<<");
                print(">>>>     DESCRIPTION      : CALIBRATION SEQUENCE PERFORMED         <<<<");
                print(">>>>                                                               <<<<");
                print(">>>>     FEATURES COVERED : CALIBRATION                            <<<<");
                print(">>>>                                                               <<<<");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");

            ELSE
                print("                                                                       ");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                print(">>>>                                                               <<<<");
                print(">>>>     TESTCASE         : CALIBRATION_TEST                       <<<<");
                print(">>>>                                                               <<<<");
                print(">>>>     STATUS           : FAILED                                 <<<<");
                print(">>>>     DESCRIPTION      : CALIBRATION SEQUENCE NOT PERFORMED     <<<<");
                print(">>>>                                                               <<<<");
                print(">>>>     FEATURES COVERED : CALIBRATION                            <<<<");
                print(">>>>                                                               <<<<");
                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            END IF;
        END IF;

    END PROCESS;
-------------------------------------------------------------------------------
-- Name       : SIGN_EXTENSION_TO_32_BIT
-- Description: Sign extension to 32 bit
-------------------------------------------------------------------------------   
s_adc_result_ch0_tb_ext <= ((32-1 DOWNTO g_ADC_RESULTS_WIDTH =>s_adc_result_ch0_tb(g_ADC_RESULTS_WIDTH-1))
                        &s_adc_result_ch0_tb(g_ADC_RESULTS_WIDTH-1 DOWNTO 0)) WHEN g_SIGNED = 1 ELSE
                            ((32-1 DOWNTO g_ADC_RESULTS_WIDTH =>'0')
                        &s_adc_result_ch0_tb(g_ADC_RESULTS_WIDTH-1 DOWNTO 0));

s_adc_result_ch1_tb_ext <=((32-1 DOWNTO g_ADC_RESULTS_WIDTH =>s_adc_result_ch1_tb(g_ADC_RESULTS_WIDTH-1)) 
                        &s_adc_result_ch1_tb(g_ADC_RESULTS_WIDTH-1 DOWNTO 0)) WHEN g_SIGNED = 1 ELSE
                            ((32-1 DOWNTO g_ADC_RESULTS_WIDTH =>'0')
                        &s_adc_result_ch1_tb(g_ADC_RESULTS_WIDTH-1 DOWNTO 0));
------------------------------------------------------------------------------
-- Name       : ADC_SCALING_OFFSET_PROC
-- Description: PROCESS to generate the offset value for ia and ib computation
------------------------------------------------------------------------------
ADC_SCALING_OFFSET_PROC:
    PROCESS(reset_tb,sys_clk_tb)
    BEGIN
        IF(reset_tb = '0') THEN
            s_ch0_offset_tb <= (OTHERS => '0');
            s_ch1_offset_tb <= (OTHERS => '0');
            s_calib_done_count_tb <= (OTHERS => '0');
        ELSIF(RISING_EDGE (sys_clk_tb)) THEN
            IF(s_start_tb_dly = '1') THEN
                IF(s_calib_done_count_tb < x"2000")  THEN
                    s_ch0_offset_tb <= s_adc_result_ch0_tb_ext + s_ch0_offset_tb;
                    s_ch1_offset_tb <= s_adc_result_ch1_tb_ext + s_ch1_offset_tb;
                    s_calib_done_count_tb <= s_calib_done_count_tb + '1';

                END IF;
            END IF;
        END IF;

    END PROCESS;

--------------------------------------------------------------------------
-- Name       : ADC_SCALING_INPUT_DRIVER_CH0_PROC
-- Description: PROCESS to provide random input channel information for channel 0
--------------------------------------------------------------------------
ADC_SCALING_INPUT_DRIVER_CH0_PROC:
    PROCESS(reset_tb,sys_clk_tb)
    VARIABLE seed1, seed2: integer :=7;
    VARIABLE rand: real;
    VARIABLE int_rand: integer;
    BEGIN
        IF(reset_tb = '0') THEN
            s_adc_result_ch0_tb   <= (OTHERS => '0');
        ELSIF  RISING_EDGE(sys_clk_tb) THEN
            IF(state = CALIBRATION)  THEN
                IF(s_start_tb = '1') THEN
                    UNIFORM(seed1,seed2, rand);
                    int_rand := INTEGER(rand*4095.0);
                    s_adc_result_ch0_tb <= std_logic_vector(to_unsigned(int_rand, 20));
                END IF;
            ELSIF(state = IND_TEST) THEN
                    UNIFORM(seed1,seed2, rand);
                    int_rand := INTEGER(rand*4095.0);
                    s_adc_result_ch0_tb <= std_logic_vector(to_unsigned(int_rand, 20));
            END IF;
        END IF;
    END PROCESS;
--------------------------------------------------------------------------
-- Name       : ADC_SCALING_INPUT_DRIVER_CH1_PROC
-- Description: PROCESS to provide random input channel information for channel 1
--------------------------------------------------------------------------
ADC_SCALING_INPUT_DRIVER_CH1_PROC:
    PROCESS(reset_tb,sys_clk_tb)
    VARIABLE seed3, seed4: integer :=2;
    VARIABLE rand1: real;
    VARIABLE int_rand1: integer;
    BEGIN
        IF(reset_tb = '0') THEN
            s_adc_result_ch1_tb   <= (OTHERS => '0');
        ELSIF  RISING_EDGE(sys_clk_tb) THEN
            IF(state = CALIBRATION) THEN
                IF(s_start_tb = '1') THEN
                    UNIFORM(seed3,seed4, rand1);
                    int_rand1 := INTEGER(rand1*4095.0);
                    s_adc_result_ch1_tb <= std_logic_vector(to_unsigned(int_rand1, 20));
                END IF;
            ELSIF(state = IND_TEST) THEN
                    UNIFORM(seed3,seed4, rand1);
                    int_rand1 := INTEGER(rand1*4095.0);
                    s_adc_result_ch1_tb <= std_logic_vector(to_unsigned(int_rand1, 20));
            END IF;
        END IF;
    END PROCESS;

--------------------------------------------------------------------------
-- Name       : ADC_SCALING_TB_FSM_PROC
-- Description: FSM implementing the adc_scaling IP testbench controller operation
--------------------------------------------------------------------------
ADC_SCALING_TB_FSM_PROC:
    PROCESS(sys_clk_tb,reset_tb)
    BEGIN
        IF(reset_tb = '0') THEN
            state                       <= IDLE;
            reset_test <= '1';
            s_adc_scale_val_tb  <= (OTHERS => '0');
            s_fault_threshold_tb  <= (OTHERS => '0');

        ELSIF (RISING_EDGE(sys_clk_tb)) THEN
            CASE(state)IS
--------------------
-- IDLE state
--------------------
            WHEN IDLE =>

                IF(counter < x"014") THEN
                    state <= CALIBRATION;
                ELSE
                    state <= IDLE;
                END IF;

--------------------
-- CALIBRATION state
--------------------
            WHEN CALIBRATION =>
                s_fault_threshold_tb <= "01"&x"D8EF";
                IF(s_calib_done_tb = '1') THEN
                    state <= IND_TEST;
                    s_adc_scale_val_tb <= "00"&x"4000";
                ELSE
                    state <= CALIBRATION;
                END IF;

--------------------
-- IND_TEST state
--------------------
            WHEN IND_TEST =>

                IF(counter < x"014") THEN
                    state <= OUTPUT_COMPARE;
                ELSE
                    state <= IDLE;
                    print("");
                    print("");
                    print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                    print("<<<<      END OF ADC_SCALING IP SIMULATION                     >>>>");
                    print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                END IF;
--------------------
-- OUTPUT_COMPARE state
--------------------
            WHEN OUTPUT_COMPARE =>
                IF(s_adc_scale_done_tb = '1') THEN
                    state <= IND_TEST;
                        IF(s_ia_tb(25 DOWNTO 8) = s_ia_adc_tb ) AND (s_ib_tb(25 DOWNTO 8) = s_ib_adc_tb)THEN

                            print("                                                                 ");
                            print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                            print_text_val("|  TESTCASE   :  ",(to_integer(signed(counter))),"                                               |");
                            print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                            print("   INPUTS                                                      ");
                            print_text_val("       CH0_IN           =  ",(to_integer(signed(s_adc_result_ch0_tb))),"                        ");
                            print_text_val("       CH1_IN           =  ",(to_integer(signed(s_adc_result_ch1_tb))),"                   ");
                            print_text_val("       SCALE_VAL        =  ",(to_integer(signed(s_adc_scale_val_tb))),"                   ");
                            print("                                                                ");
                            print("   OUTPUTS                                                    ");
                            print_text_val("       IA_DUT_OUT       =  ",(to_integer(signed(s_ia_adc_tb))),"                       ");
                            print_text_val("       IB_DUT_OUT       =  ",(to_integer(signed(s_ib_adc_tb))),"                       ");
                            print_text_val("       IA_TB_OUT        =  ",(to_integer(signed(s_ia_tb(25 DOWNTO 8))))," ");
                            print_text_val("       IB_TB_OUT        =  ",(to_integer(signed(s_ib_tb(25 DOWNTO 8))))," ");
                            print("                                                           ");
                            print("     STATUS            :  PASSED                           ");
                            print("     DESCRIPTION       :  TB AND DUT OUTPUTS MATCH         ");
                            print("                                                           ");
                            print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                        ELSE

                            print("                                                                 ");
                            print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                            print_text_val("|  TESTCASE   :  ",(to_integer(signed(counter))),"                                               |");
                            print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                            print("     INPUTS                                            ");
                            print_text_val("       RL_IN            =  ",(to_integer(signed(s_adc_result_ch0_tb))),"                        ");
                            print_text_val("       SLEW_COUNT       =  ",(to_integer(signed(s_adc_result_ch1_tb))),"                   ");
                            print_text_val("       RATE_COUNT       =  ",(to_integer(signed(s_adc_scale_val_tb))),"                   ");
                            print("                                                                ");
                            print("   OUTPUTS                                                    ");
                            print_text_val("       IA_DUT_OUT       =  ",(to_integer(signed(s_ia_adc_tb))),"                       ");
                            print_text_val("       IB_DUT_OUT       =  ",(to_integer(signed(s_ib_adc_tb))),"                       ");
                            print_text_val("       IA_TB_OUT        =  ",(to_integer(signed(s_ia_tb(25 DOWNTO 8))))," ");
                            print_text_val("       IB_TB_OUT        =  ",(to_integer(signed(s_ib_tb(25 DOWNTO 8))))," ");
                            print("                                                           ");
                            print("     STATUS            :  FAILED                           ");
                            print("     DESCRIPTION       :  TB AND DUT OUTPUTS DO NOT MATCH  ");
                            print("                                                           ");
                            print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                        END IF;


                        IF(s_ia_tb(25 DOWNTO 8) = s_ia_adc_tb ) AND (s_ib_tb(25 DOWNTO 8) = s_ib_adc_tb) AND(s_ia_tb(25 DOWNTO 8) > s_fault_threshold_tb) AND (s_ia_adc_tb > s_fault_threshold_tb) THEN
                            IF(s_over_current_fault_tb = '1') THEN
                                print("                                                                 ");
                                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                                print("|TESTCASE : OVER_CURRENT_FAULT_TEST                               |");
                                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                                print("   INPUTS                                                      ");
                                print_text_val("       CH0_IN           =  ",(to_integer(signed(s_adc_result_ch0_tb))),"                        ");
                                print_text_val("       CH1_IN           =  ",(to_integer(signed(s_adc_result_ch1_tb))),"                   ");
                                print_text_val("       SCALE_VAL        =  ",(to_integer(signed(s_adc_scale_val_tb))),"                   ");
                                print("                                                                ");
                                print("   OUTPUTS                                                    ");
                                print_text_val("       FAULT_THRESOLD   =  ",(to_integer(signed(s_fault_threshold_tb))),"                       ");
                                print_text_val("       IA_DUT_OUT       =  ",(to_integer(signed(s_ia_adc_tb))),"                       ");
                                print_text_val("       IB_DUT_OUT       =  ",(to_integer(signed(s_ib_adc_tb))),"                       ");
                                print_text_val("       IA_TB_OUT        =  ",(to_integer(signed(s_ia_tb(25 DOWNTO 8))))," ");
                                print_text_val("       IB_TB_OUT        =  ",(to_integer(signed(s_ib_tb(25 DOWNTO 8))))," ");
                                print("                                                           ");
                                print("     STATUS            :  PASSED                           ");
                                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                            ELSE
                                print("                                                                 ");
                                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                                print("|TESTCASE : OVER_CURRENT_FAULT_TEST                               |");
                                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                                print("   INPUTS                                                      ");
                                print_text_val("       CH0_IN           =  ",(to_integer(signed(s_adc_result_ch0_tb))),"                        ");
                                print_text_val("       CH1_IN           =  ",(to_integer(signed(s_adc_result_ch1_tb))),"                   ");
                                print_text_val("       SCALE_VAL        =  ",(to_integer(signed(s_adc_scale_val_tb))),"                   ");
                                print("                                                                ");
                                print("   OUTPUTS                                                    ");
                                print_text_val("       FAULT_THRESOLD   =  ",(to_integer(signed(s_fault_threshold_tb))),"                       ");
                                print_text_val("       IA_DUT_OUT       =  ",(to_integer(signed(s_ia_adc_tb))),"                       ");
                                print_text_val("       IB_DUT_OUT       =  ",(to_integer(signed(s_ib_adc_tb))),"                       ");
                                print_text_val("       IA_TB_OUT        =  ",(to_integer(signed(s_ia_tb(25 DOWNTO 8))))," ");
                                print_text_val("       IB_TB_OUT        =  ",(to_integer(signed(s_ib_tb(25 DOWNTO 8))))," ");
                                print("                                                           ");
                                print("     STATUS            :  FAILED                           ");
                                print("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
                            END IF;
                        END IF;
                ELSE
                    state <= OUTPUT_COMPARE;
                END IF;
--------------------
-- OTHERS state
--------------------
            WHEN OTHERS =>
                state               <= IDLE;
            END CASE;
        END IF;
    END PROCESS;
--------------------------------------------------------------------------
-- Name       : DELAY_PROC
-- Description: Process to delay a signal
--------------------------------------------------------------------------
DELAY_PROC:PROCESS(sys_clk_tb,reset_tb)
BEGIN
    IF reset_tb = '0' THEN
        s_adc_scale_done_tb_dly   <= '0';
    ELSIF RISING_EDGE(sys_clk_tb) THEN
        s_adc_scale_done_tb_dly    <= s_adc_scale_done_tb;
    END IF;
END PROCESS;
--------------------------------------------------------------------------
-- Name       : COUNT_PROC
-- Description: counter to decide the number of iterations
--------------------------------------------------------------------------
COUNT_PROC:PROCESS(reset_tb,sys_clk_tb)
BEGIN
    IF(reset_tb = '0') THEN
        counter <= (OTHERS => '0');
    ELSIF RISING_EDGE (sys_clk_tb) THEN
        IF(state = IND_TEST) THEN
            IF(counter < x"014") THEN
                counter <= counter + '1';
            END IF;
        END IF;
    END IF;
END PROCESS;
--------------------------------------------------------------------------
-- Name       : PROCEDURE_CALL_PROC
-- Description: adc_scaling testbench model
--------------------------------------------------------------------------
PROCEDURE_CALL_PROC: PROCESS(reset_tb,sys_clk_tb)
BEGIN
    adc_scaling_tb(reset_tb,sys_clk_tb,s_start_tb_dly,s_adc_result_ch0_tb(g_ADC_RESULTS_WIDTH-1 DOWNTO 0),s_adc_result_ch1_tb(g_ADC_RESULTS_WIDTH-1 DOWNTO 0),s_ch0_offset_tb,s_ch1_offset_tb,s_adc_scale_val_tb,s_done_tb,s_ia_tb,s_ib_tb);
END PROCESS;

--=================================================================================================
-- Component Instantiations
--=================================================================================================
-------------------------------------------------
-- ADC_SCALING_UUT_INST
-------------------------------------------------
ADC_SCALING_UUT_INST: ADC_SCALING
GENERIC MAP(
    g_DEBUG                          =>  g_DEBUG,
    g_SIGNED                         =>  g_SIGNED,
	g_ADC_RESULTS_WIDTH              =>  g_ADC_RESULTS_WIDTH,
    g_NO_MCYCLE_PATH                 =>  g_NO_MCYCLE_PATH
)
PORT MAP(
    reset_i                          => reset_tb,
    sys_clk_i                        => sys_clk_tb,
	adc_results_rdy_i                => s_start_tb_dly,
    adc_scale_val_i                  => s_adc_scale_val_tb,
    adc_result_ch0_i                 => s_adc_result_ch0_tb(g_ADC_RESULTS_WIDTH-1 DOWNTO 0),
    adc_result_ch1_i	             => s_adc_result_ch1_tb(g_ADC_RESULTS_WIDTH-1 DOWNTO 0),
    fault_threshold_i                => s_fault_threshold_tb,
    done_o                           => s_adc_scale_done_tb,
	calib_done_o                     => s_calib_done_tb,
	over_current_fault_o             => s_over_current_fault_tb,
    ia_adc_o                    	 => s_ia_adc_tb,
    ib_adc_o                    	 => s_ib_adc_tb
);

END behavioral;


