--=================================================================================================
-- File Name                           : encoder_interface_tb.vhd

-- Description                         : This module implements the test environment for
--                                       encoder interface 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 IEEE.STD_LOGIC_unsigned.ALL      ;

--=================================================================================================
-- encoder_interface_tb entity declaration
--=================================================================================================

ENTITY encoder_interface_tb IS
    
END encoder_interface_tb;

--=================================================================================================
-- encoder_interface_tb architecture body
--=================================================================================================
ARCHITECTURE encoder_interface_tb OF encoder_interface_tb IS

COMPONENT encoder_interface IS
--GENERIC (
--    g_STD_IO_WIDTH                        : INTEGER := 18
--);
PORT (
    reset_i                                  : IN  STD_LOGIC;
    sys_clk_i                                : IN  STD_LOGIC;
    fil_trig_i  							 : IN  STD_LOGIC; 
    direction_config_i                       : IN STD_LOGIC ;
    clear_buffer_i                           : IN STD_LOGIC;
    sensor_reset_i                           : IN STD_LOGIC;
    QA_i                                     : IN  STD_LOGIC;
    QB_i                                     : IN  STD_LOGIC;
    speed_factor_i                           : IN STD_LOGIC_VECTOR(17 DOWNTO 0);
    angle_factor_i                           : IN STD_LOGIC_VECTOR(17 DOWNTO 0);
    angle_count_max_i                        : IN STD_LOGIC_VECTOR(17 DOWNTO 0); 
    speed_window_i                           : IN STD_LOGIC_VECTOR(17 DOWNTO 0); 
    filter_factor_i                          : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
    dir_o                                    : OUT STD_LOGIC;
    speed_done_o                             : OUT STD_LOGIC;
    speed_filter_done_o                      : OUT STD_LOGIC;
    omega_out_o                              : OUT STD_LOGIC_VECTOR(17 DOWNTO 0);
    angle_out_o                              : OUT STD_LOGIC_VECTOR(17 DOWNTO 0);
    line_count_o                             : OUT STD_LOGIC_VECTOR(17 downto 0)
);
END COMPONENT;
--=================================================================================================
-- Signal declarations
--=================================================================================================

CONSTANT SYSCLK_PERIOD_100  : TIME := 5 ns;
SIGNAL SYSCLK               : STD_LOGIC := '0';
SIGNAL SYSCLK_2_5_MHZ       : STD_LOGIC := '0';
SIGNAL RESET_n_I_tb         : STD_LOGIC := '0';
SIGNAL QA_tb                : STD_LOGIC := '0';
SIGNAL QB_tb                : STD_LOGIC := '0';
SIGNAL s_fil_timer_flag     : STD_LOGIC;
SIGNAL s_enc_timer_flag     : STD_LOGIC;
SIGNAL s_sensor_reset       : STD_LOGIC := '1';
SIGNAL s_motor_stopped      : STD_LOGIC := '1';
SIGNAL s_enc_sig_gen_cnt    : STD_LOGIC_VECTOR(2 DOWNTO 0);
SIGNAL s_fil_timer          : STD_LOGIC_VECTOR(15 DOWNTO 0);
SIGNAL s_enc_timer          : STD_LOGIC_VECTOR(15 DOWNTO 0);
SIGNAL s_enc_timer_match    : STD_LOGIC_VECTOR(15 DOWNTO 0);
SIGNAL s_speed_factor       : STD_LOGIC_VECTOR(17 DOWNTO 0);
SIGNAL s_angle_factor       : STD_LOGIC_VECTOR(17 DOWNTO 0);
SIGNAL s_angle_cnt_max      : STD_LOGIC_VECTOR(17 DOWNTO 0);
SIGNAL s_speed_window       : STD_LOGIC_VECTOR(17 DOWNTO 0);
SIGNAL s_omega_out          : STD_LOGIC_VECTOR(17 DOWNTO 0);
SIGNAL s_angle_out          : STD_LOGIC_VECTOR(17 DOWNTO 0);
SIGNAL s_filter_factor      : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL run_enc              : STD_LOGIC;
SIGNAL direction_config_tb  : STD_LOGIC;

--========================================================
-- File read operations
--========================================================
--NA--
--========================================================
-- File Write operations
--========================================================
--NA--
--========================================================
-- Procedure Declarations
--========================================================
--NA--

BEGIN
--========================================================
-- SIGNAL spy operations
--========================================================
--NA--
--------------------------------------------------------------------------
-- Name       : CLOCK_GEN
-- Description: Logic generates 100 MHz clock
--------------------------------------------------------------------------
SYSCLK <= NOT SYSCLK AFTER (SYSCLK_PERIOD_100 / 2.0 );
--------------------------------------------------------------------------
-- Name       : MAIN
-- Description: Process provides various test inputs
--------------------------------------------------------------------------
MAIN:
    PROCESS
        VARIABLE vhdl_initial : BOOLEAN := TRUE;

    BEGIN
        IF ( vhdl_initial ) THEN
            -- Assert Reset
            REPORT("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            REPORT(">>>>>>>>                   ENCODER INTERFACE SIMULATION                             <<<<<<<");
            REPORT("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
            RESET_n_I_tb <= '0';
            run_enc <= '0';
            s_motor_stopped <= '0';
            s_sensor_reset <= '0';
            s_speed_factor  <= "00"&x"8889";
            s_angle_factor  <= "00"&x"0BC0";
            s_angle_cnt_max <= "00"&x"02CF";
            s_speed_window  <= "00"&x"03E8";
            s_enc_timer_match <= x"3FFF";            
            direction_config_tb <= '1';
            s_filter_factor <= x"6";
            WAIT FOR ( SYSCLK_PERIOD_100 * 10 );
            RESET_n_I_tb <= '1';
            s_sensor_reset <= '0';
            WAIT FOR ( SYSCLK_PERIOD_100 * 10 );
            s_sensor_reset <= '1';
            WAIT FOR ( SYSCLK_PERIOD_100 * 10 );
            run_enc <= '1';                        
            s_sensor_reset <= '0';
            s_speed_factor  <= "00"&x"8889";
            s_angle_factor  <= "00"&x"0BC0";
            s_angle_cnt_max <= "00"&x"02CF";
            s_speed_window  <= "00"&x"03E8"; 
            direction_config_tb <= '1';
            s_enc_timer_match <= x"03FF";
            s_filter_factor <= x"6";
            s_speed_factor  <= "00"&x"8889";
            s_angle_factor  <= "01"&x"6C16";
            s_angle_cnt_max <= "00"&x"0B3C";
            s_speed_window  <= "00"&x"03E8"; 
            direction_config_tb <= '1';
            s_enc_timer_match <= x"3FFF";
            WAIT;
        END IF;
    END PROCESS;

--------------------------------------------------------------------------
-- Name       : ENC_SIG_GEN_PROC
-- Description: Process generates encoder states based on triggers from
--              encoder timer.
--------------------------------------------------------------------------
ENC_SIG_GEN_PROC:PROCESS(RESET_n_I_tb,SYSCLK)
BEGIN
	IF(RESET_n_I_tb = '0')THEN
		s_enc_sig_gen_cnt <= (OTHERS => '0');
	ELSIF RISING_EDGE(SYSCLK) THEN
		IF(s_enc_sig_gen_cnt = "100")THEN
			s_enc_sig_gen_cnt <= (OTHERS => '0');
		ELSIF(s_enc_timer_flag = '1')THEN
			s_enc_sig_gen_cnt <= s_enc_sig_gen_cnt + 1;
		END IF;
	END IF;
END PROCESS;

--------------------------------------------------------------------------
-- Name       : FIL_TIMER_PROC
-- Description: Process runs a timer to generate timing pulses to trigger 
--              filter.
--------------------------------------------------------------------------
FIL_TIMER_PROC:PROCESS(RESET_n_I_tb,SYSCLK)
BEGIN
	IF(RESET_n_I_tb = '0')THEN
		s_fil_timer <= (OTHERS => '0');
		s_fil_timer_flag <= '0';
	ELSIF RISING_EDGE(SYSCLK) THEN
			IF(s_fil_timer = "00"&x"04E2")THEN
				s_fil_timer <= (OTHERS => '0');
				s_fil_timer_flag <= '1';
			ELSE
				s_fil_timer <= s_fil_timer + 1;
				s_fil_timer_flag <= '0';
			END IF;
	END IF;
END PROCESS;

--------------------------------------------------------------------------
-- Name       : ENC_TIMER_PROC
-- Description: Process runs a timer to generate timing pulses for 
--              encoder signal generation.
--------------------------------------------------------------------------
ENC_TIMER_PROC:PROCESS(RESET_n_I_tb,SYSCLK)
BEGIN
	IF(RESET_n_I_tb = '0')THEN
		s_enc_timer <= (OTHERS => '0');
		s_enc_timer_flag <= '0';
	ELSIF RISING_EDGE(SYSCLK) THEN
		IF(run_enc = '1') THEN
			IF(s_enc_timer = s_enc_timer_match)THEN
				s_enc_timer <= (OTHERS => '0');
				s_enc_timer_flag <= '1';
			ELSE
				s_enc_timer <= s_enc_timer + 1;
				s_enc_timer_flag <= '0';
			END IF;
		END IF;
	END IF;
END PROCESS;

--------------------------------------------------------------------------
-- Name       : ENC_THETA_GEN_PROC
-- Description: Process generates encoder signals based on encoder states 
--              and direction.
--------------------------------------------------------------------------   
ENC_THETA_GEN_PROC:PROCESS(s_enc_sig_gen_cnt)
BEGIN
    IF(direction_config_tb = '1')THEN
        CASE s_enc_sig_gen_cnt IS
                WHEN "000"=>QA_tb <= '0';
                            QB_tb <= '0';
    
                WHEN "001"=>QA_tb <= '1';
                            QB_tb <= '0';
    
                WHEN "010"=>QA_tb <= '1';
                            QB_tb <= '1';
    
                WHEN "011"=>QA_tb <= '0';
                            QB_tb <= '1';
                            
                WHEN OTHERS=>QA_tb <= '0';
                             QB_tb <= '0'; 
            END CASE;
    ELSE
        CASE s_enc_sig_gen_cnt IS
                WHEN "011"=>QA_tb <= '0';
                            QB_tb <= '0';
    
                WHEN "010"=>QA_tb <= '1';
                            QB_tb <= '0';
    
                WHEN "001"=>QA_tb <= '1';
                            QB_tb <= '1';
    
                WHEN "000"=>QA_tb <= '0';
                            QB_tb <= '1';
                            
                WHEN OTHERS=>QA_tb <= '0';
                             QB_tb <= '0'; 
            END CASE;
    END IF;
END PROCESS;
--=================================================================================================
-- Component Instantiations
--=================================================================================================
-------------------------------------------------
-- ENCODER_UUT_INST
-------------------------------------------------
ENCODER_UUT_INST: encoder_interface
PORT MAP(
    
    reset_i                                  =>  RESET_n_I_tb,
    sys_clk_i                                =>  SYSCLK,
    fil_trig_i  							 =>  s_fil_timer_flag,
    direction_config_i                       =>  direction_config_tb,
    clear_buffer_i                    		 =>  s_motor_stopped,
    sensor_reset_i                       	 =>  s_sensor_reset,
    QA_i                                     =>  QA_tb,
    QB_i                                     =>  QB_tb,
	speed_factor_i                           =>  s_speed_factor, 
    angle_factor_i                           =>  s_angle_factor, 
    angle_count_max_i                        =>  s_angle_cnt_max,
    speed_window_i                           =>  s_speed_window,
	filter_factor_i							 =>  s_filter_factor,
    dir_o                                    =>  OPEN,
    speed_done_o                             =>  OPEN,
    speed_filter_done_o                      =>  OPEN,
    omega_out_o                              =>  s_omega_out,
    angle_out_o                              =>  s_angle_out,
    line_count_o                             =>  OPEN
);

END encoder_interface_tb;