-------------------------------------------------------------------------------
-- Title      : Toplevel module of Tacho measurement unit
-------------------------------------------------------------------------------
-- File       : top_level_tach_measure.vhd
-- Author     : Pavan Marisetti
-- Company    : Microsemi Corporation
-- Device     : SmartFusion
-- Standard   : VHDL
-------------------------------------------------------------------------------
-- Description: This code implementes enable signals to tacho mesuremnt and 
--              pulse stretching.
-------------------------------------------------------------------------------
-- Copyright (c) 2011   Microsemi Corporation
--                      All rights reserved.
-------------------------------------------------------------------------------
-- Revisions  : V1.0
-------------------------------------------------------------------------------


library ieee;
library std;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;

entity top_level_tach_measure is
	generic ( APB_DWIDTH : INTEGER := 32 );
	port (	PRESETN              : IN STD_LOGIC;
		    PCLK                 : IN STD_LOGIC;
		    PSEL                 : IN STD_LOGIC;
		    PENABLE              : IN STD_LOGIC;
		    PWRITE               : IN STD_LOGIC;
		    PADDR                : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
		    PWDATA               : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
		    PRDATA               : OUT STD_LOGIC_VECTOR(APB_DWIDTH - 1 DOWNTO 0);
		    TACHIN               : IN STD_LOGIC;
		    TACHINT              : OUT STD_LOGIC;
            PULSE_STRETC_EN      : OUT std_logic;
            TACH_SEL_LINE        : OUT std_logic_vector(1 downto 0)
        );
end top_level_tach_measure;

architecture top_level_tach_measure of top_level_tach_measure is
    type   tach_tdm_fsm is (idle, enable);
  	signal tach_tdm_fsm_state : tach_tdm_fsm ;

	signal proc_enable		 : std_logic;
    signal pulse_stretch_en  : std_logic;
	signal TACHREAD_DIR	 : std_logic_vector(23 downto 0);
	signal counter_done	 : std_logic;
	signal read_done	 : std_logic;
    signal tach_count_en : std_logic;
    signal tach_inp_sel      : std_logic_vector(1 downto 0);
    signal interrupt_to_proc :std_logic;
    signal pulse_stretch   : std_logic;
	component tach_measure is 
		port (	clock        : in  std_logic; -- clock
			    reset        : in  std_logic; -- active low reset
			    enable       : in  std_logic; -- Tacho reading enable signal
			    TACHIN       : in  std_logic; -- TACH input 
                read_done    : in  std_logic; -- read done
			    counter_done : out std_logic; -- tacho count done signal
			    TACHREAD_DIR : out std_logic_vector(23 downto 0)
              ); 
	end component;


	begin
	tach_measure_inst : tach_measure port map (
						clock => PCLK,
						reset => PRESETN,
						enable => tach_count_en,
						TACHIN => TACHIN,
                        read_done => read_done,
						counter_done => counter_done,
						TACHREAD_DIR => TACHREAD_DIR						
					    );

	-- Generation of pulse stretch enable, Tacho selection, and tacho count enable signals

    enable_p :  process (PCLK, PRESETN)
		begin
			if (not(PRESETN) = '1')  then
				proc_enable <= '0';	
                pulse_stretch_en <= '0';
                tach_inp_sel <= "00";		
			elsif (PCLK = '1' and PCLK'event) then
				if ((PSEL = '1') AND (PWRITE = '1') AND (PENABLE = '1') AND (PADDR(7 DOWNTO 0) = "11110000")) THEN
					proc_enable <= PWDATA(0);	
                    tach_inp_sel <= PWDATA(2 downto 1);
                    pulse_stretch_en <= PWDATA(3);	
				end if;
			end if;
		end process;

    -- tach values read operation from MSS
	TACHREAD_REG_p: process (PCLK, PRESETN)
		begin
		if (not(PRESETN) = '1')  then
			read_done <= '0';
			PRDATA <= (others => '0');
		elsif (PCLK = '1' and PCLK'event) then
			if ((PSEL = '1') AND (PWRITE = '0') AND (PENABLE = '1') AND (PADDR(7 DOWNTO 0) = "11110100")) then
				PRDATA <=  "000000"& tach_inp_sel & TACHREAD_DIR;
				read_done <= '1';
			else
				read_done <= '0';
			end if;
		end if;
	end process;

    -- FSM to enable/disable Tacho measurement
	dig_sch_trig_process: process (PCLK, PRESETN)
		begin
			if (PRESETN = '0')  then
				tach_tdm_fsm_state <= idle;
                pulse_stretch <= '0';
                tach_count_en <= '0';
                interrupt_to_proc <= '0';	
            elsif (PCLK = '1' and PCLK'event) then   
   			  case tach_tdm_fsm_state is					
				when idle =>

                  if(proc_enable = '1') then
                    pulse_stretch <= '1';
                    tach_count_en <= '1';
                    tach_tdm_fsm_state <= enable;
			      else
                    tach_tdm_fsm_state  <= idle;
                    pulse_stretch <= '0';
                    tach_count_en <= '0';
				  end if;
                  interrupt_to_proc <= '0';

                when enable =>
                  if(read_done = '1') then
                     tach_tdm_fsm_state  <= idle;
                  elsif(counter_done = '1') then
                     interrupt_to_proc <= '1';
                     pulse_stretch <= '0';
                     tach_count_en <= '0';
                     tach_tdm_fsm_state  <= enable;
                  else
                     interrupt_to_proc <= '0';
                     tach_tdm_fsm_state  <= enable;
                  end if;                
                end case;
			end if;
      end process;

					
			
		TACHINT <= interrupt_to_proc;	
		PULSE_STRETC_EN <= 	pulse_stretch when pulse_stretch_en = '1' else
                            '0';	
		TACH_SEL_LINE <= tach_inp_sel;
end top_level_tach_measure;