----------------------------------------------------------------------------------
-- Company: APC
-- Engineer: CC
-- 
-- Create Date:    11:49:52 28/02/2017
-- Design Name: 
-- Module Name:    data_out_fsm - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: gather data to be sent: TDC, SPI
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Revision 0.02 - new data format add busy trigger
-- Revision 0.03 - sync data tdcns with fsm, sync event counters and busy counters
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;



-- Data format 96 bits bits ---- SPI 16bits

--	95        80       		 	72            64  			 62          60    	59     58	      	 32  	  		4		  3         0     
--	-------------------------------------------------------------------------------------------------------------------------------
--	|   SPI    | event counter	| busy counter | PPS counter | seconds   | busy | time  |clock counter | 8ns tag | spare | 1ns tag |
--	|  16bits  |  8bits lsb  	|  8bits lsb   |   2bits 	  | 2bits lsb |   	| valid |	26bits 	  | 28 bits |	'0'  |  3bits	|
--	-------------------------------------------------------------------------------------------------------------------------------



entity data_out_fsm is

	generic(
		 g_spi_timeout_val : natural := 50 	--	~800ns @ 62.5MHz enough ?? 
		 );

    Port ( clk_i 					: in  STD_LOGIC;
			  clk_125m_pllref_i	: in  STD_LOGIC;
           rst_i 					: in  STD_LOGIC;
			  event_flag_i			: in  STD_LOGIC;
			  busy_flag_i			: in  STD_LOGIC;
			  event_cnt_i			: in  STD_LOGIC_VECTOR(7 downto 0);		--event counter 8bits lsb
			  busy_cnt_i			: in  STD_LOGIC_VECTOR(7 downto 0);		--busy trigger counter 8bits lsb
			  pps_cnt_i				: in  STD_LOGIC_VECTOR(1 downto 0);		--PPS counter 2bits lsb
			  clk_cnt_i				: in  STD_LOGIC_VECTOR(25 downto 0);	--clock counter 26bits
			  tx_tag_tai_i			: in  STD_LOGIC_VECTOR(1 downto 0);		--seconds 2bits lsb
			  tx_tag_cycles_i 	: in  STD_LOGIC_VECTOR(27 downto 0);	---8ns tag 28bits
			  tdc_data_evt_i		: in  STD_LOGIC_VECTOR(2 downto 0);		-- 1ns timestamp 3bits event trigger
			  tdc_data_bsy_i		: in  STD_LOGIC_VECTOR(2 downto 0);		-- 1ns timestamp 3bits busy trigger
			  data_rx_spi_i		: in  STD_LOGIC_VECTOR(15 downto 0);	-- Rx SPI data 16bits
			  tdc_evt_rdy_i		: in  STD_LOGIC;
			  tdc_bsy_rdy_i		: in  STD_LOGIC;
			  tm_time_valid_i		: in  STD_LOGIC;
			  tx_tag_valid_i		: in  STD_LOGIC;	
           data_r_spi_i 		: in  STD_LOGIC;
			  tx_data_o				: out STD_LOGIC_VECTOR(95 downto 0);
			  ack_event_flag_o	: out STD_LOGIC;
			  ack_busy_flag_o		: out STD_LOGIC;
           tx_ready_o 			: out STD_LOGIC;
			  tdc_en_o 				: out STD_LOGIC:= '1'
			  --TRIG0 : out std_logic_vector(31 downto 0)
			 );
end data_out_fsm;

architecture Behavioral of data_out_fsm is


	component time_out_gen is
	generic(
		 g_timeout_val : natural := 65500 --	~1ms @ 62.5MHz
		 );
    Port (
		clk_i				: in std_logic;
		rst_i				: in std_logic;
		timeout_en_i 	: in std_logic;
		timeout_hit_o	: out std_logic
	 );
	end component;

	type STATE_TYPE is (IDLE, DATA_TDC, SPI);
	
	signal current_state		: STATE_TYPE;
	signal tx_data_ready, tdc_data_r1	: std_logic;
	signal tdc_data_buf : std_logic_vector(5 downto 0);
	---timeout signals ---
  signal timeout_hit  : std_logic := '0';
  signal timeout_en   : std_logic := '0';
	
begin

--	tdc_data_buf(2 downto 0)  <= tdc_data_i; 

---- time out generator for SPI data ---	
	U_hold_off_gen : time_out_gen 
	generic map (g_timeout_val => g_spi_timeout_val)		
    Port map (
		clk_i				=> clk_i,
     	rst_i 		 	=> rst_i,
		timeout_en_i 	=> timeout_en,
		timeout_hit_o	=> timeout_hit
	 );
		
	tx_ready_o <= tx_data_ready;
	--tx_data_o(3)  <= '0';	--	spare bit
		
	process (clk_i)
	begin
	if rising_edge(clk_i)then
		if (rst_i = '1') then
			tx_data_ready	<= '0';
			timeout_en 		<= '0';	
			tx_data_o		<= (others => '0');
			current_state	<= IDLE;	

		else
			case current_state is
			
				when IDLE => 
					tx_data_ready	<= '0';
					tdc_en_o 		<= '0';			-- '0' doesn't disable fine TDC
					timeout_en 		<= '0';
					if (event_flag_i = '1') then	--event counter data ready
						tx_data_o(79 downto 72)  	<= event_cnt_i;			--event counter 8bits lsb
						tx_data_o(63 downto 62) 	<= pps_cnt_i;				--PPS counter	2bits lsb
						tx_data_o(59)   			 	<= '0';						--busy trigger flag, '0' if event trigger
--						tx_data_o(58)   			 	<= tm_time_valid_i;		--flag for SPLL locked & local time synchronyzed to Master
						tx_data_o(57 downto 32)  	<= clk_cnt_i;				--clock counter 26bits
--						tx_data_o(2 downto 0)      <= tdc_data_buf(5 downto 3);  --TDC 1ns precision
						--timeout_en 						<= '1';						--start hold off counter to wait for SPI data	
						ack_event_flag_o 				<= '1';
						current_state					<= DATA_TDC;				
					elsif (busy_flag_i = '1') then		--busy counter data ready							
						tx_data_o(71 downto 64)  	<= busy_cnt_i;				--busy trigger counter 8bits lsb
						tx_data_o(63 downto 62) 	<= pps_cnt_i;				--PPS counter	2bits lsb
						tx_data_o(59)   			 	<= busy_flag_i;			--busy trigger flag 
--						tx_data_o(58)   			 	<= tm_time_valid_i;		--flag for SPLL locked & local time synchronyzed to Master			
						tx_data_o(57 downto 32)  	<= clk_cnt_i;				--clock counter 26bits
--						tx_data_o(2 downto 0)      <= tdc_data_buf(5 downto 3);  --TDC 1ns precision
						--timeout_en 						<= '1';						--start hold off counter to wait for SPI data
						ack_busy_flag_o 				<= '1';
						current_state					<= DATA_TDC;	
					else 	
--						timeout_en 		 			<= '0';
						ack_busy_flag_o 			<= '0';
						ack_event_flag_o 			<= '0';
						
					end if;
				
				when DATA_TDC => 
					ack_busy_flag_o 	<= '0';
					ack_event_flag_o 	<= '0';
					tx_data_ready		<= '0';
					tdc_en_o 			<= '0';
					if (tx_tag_valid_i = '1') then		--coarse TDC data ready			
						tx_data_o(61 downto 60)  	<= tx_tag_tai_i;			--seconds 2bitslsb 
						tx_data_o(58)   			 	<= tm_time_valid_i;		--flag for SPLL locked & local time synchronyzed to Master			
						tx_data_o(31 downto 4)   	<= tx_tag_cycles_i; 		--8ns tag 28bits
						tx_data_o(2 downto 0)      <= tdc_data_buf(5 downto 3);  --TDC 1ns precision
						timeout_en 						<= '1';						--start time out counter to wait for SPI data
						ack_busy_flag_o 				<= '1';
						current_state					<= SPI;	
					else 	
						timeout_en 		 <= '0';
					end if;

				when SPI =>	
					--ack_busy_flag_o <= '0';
					if (data_r_spi_i = '1') or (timeout_hit = '1') then		
						tdc_en_o 						<= '1';					--enable tdc when data are written in FIFO
						tx_data_o(95 downto 80) 	<= data_rx_spi_i;  	--SPI data
						tx_data_ready					<= '1';
						timeout_en 						<= '0';				--stop & reset time out counter
						current_state					<= IDLE;				
					else
						tdc_en_o 		<= '0';
						timeout_en 		<= '1';
						tx_data_ready	<= '0';
					end if;
				
				when others => 
					current_state	<=	IDLE;			
			end case;
			end if; 
	end if;
	end process;
	
	
	----Process hold TDC data
	tdc_buf_proc: process(clk_125m_pllref_i)
		BEGIN	  
			if rising_edge(clk_125m_pllref_i) then
				if (tdc_evt_rdy_i = '1') then
					tdc_data_buf(2 downto 0)  <= tdc_data_evt_i;  	--TDC 1ns event trigger
				elsif (tdc_bsy_rdy_i = '1') then
					tdc_data_buf(2 downto 0)  <= tdc_data_bsy_i;		--TDC 1ns busy trigger
				end if;
			end if;
  end process;
  
   --- sync different clock domains			--use async FIFO or in SPI state of FSM  ???
	sync_tdc_proc: process(clk_i)
		BEGIN	
			if rising_edge(clk_i) then 
					tdc_data_buf(5 downto 3)  <= tdc_data_buf(2 downto 0);  	---TDC 1ns precision	
					--tx_data_o(2 downto 0)     <= tdc_data_buf(5 downto 3);  	---TDC 1ns precision				
			end if;
  end process;
		
end Behavioral;

