library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

--  Uncomment the following lines to use the declarations that are
--  provided for instantiating Xilinx primitive components.
--library UNISIM;
--use UNISIM.VComponents.all;

-- ************************************************************************
-- ALL Signals are active LOW unless specified
-- ************************************************************************
-- 
-- ************************************************************************
-- REV 1.1 / February 25 2004 
-- Addition of the FIFO3 enable to start the
-- transfer into FIFO3
-- ************************************************************************

-- ************************************************************************
-- REV 1.2 / November 22 2004 
-- a> Split of the counters N1 and 4095-N1
-- b> Reset	dataready used to reset 2nd cnt and its ovf
-- ************************************************************************

-- ************************************************************************
-- REV 1.3 / June 2006
-- Major revision !
-- (a)consolidation of fifo1,2,3 codes into a single fsm
-- (b)Change in the data transfer to fifo3:
-- (b-1)	In acq with trigger, the transfer takes place after
-- 		the record has been stored in fifo2.  The acquisition
--			is halted (no write in fifo2) until transfer completed.
--	(b-2)	In acq w/o trigger, the fifo are transparent and the data ready
--			is generated once the record length is fifo3 is 4086 (4096-10).
-- ************************************************************************

-- ************************************************************************
-- REV 1.4 / July 2006
-- In order to cope with the different clock frequencies between the syst
-- and the channel, the reset dataready is made synchronous.
-- ************************************************************************

-- ************************************************************************
-- REV 1.5 / July 2006
-- Modification of the reset of the transfer counter
-- ************************************************************************


-- ##################################################################### --
-- TRIGGER MODE																			 --
-- trigmode 																				 --
-- 	0: Acquisition WITH trigger													 --
-- 	1: Acquisition WITHOUT trigger												 --
-- ##################################################################### --

-- ##################################################################### --
-- DECIMATION RATIO																		 --
-- The decimation is performed by controlling the write and read enable. --
-- The clock signals are NOT gated.													 --
--	decim_ratio:																			 --
--		00 <=>  No decimation															 --
--		01 <=>  1:2          															 --
--		10 <=>  1:4																			 --
--		11 <=>  1:8																			 --
--	Once the decim flag (trigger received) is active then the decimation	 --
-- stops																						 --
-- ##################################################################### --

-- ##################################################################### --
-- Pretrigger Data Record Length														 --
-- ptrig_data																				 --
-- 	00:	 512																			 --
--		01:	1024																			 --
--		10:	2048																			 --
--		11:	2560																			 --
-- ##################################################################### --

			  
entity fsm1 is
    Port ( reset 			: in std_logic;			 					-- reset
           clk 			: in std_logic;								-- clk (sampling)
           acqen 			: in std_logic;								-- acquisition enable (command)
			  trigmode		: in std_logic;								-- = 0 , acq w/ trig ##  = 1 w/o trig
           trigger		: in std_logic;			 					-- trigger signal (synch'd)
			  decim_ratio	: in std_logic_vector(1 downto 0);		-- decimation ratio
			  ptrig_data	: in std_logic_vector(1 downto 0);		-- pre-trigger data record length 
           rstdataready	: in std_logic;

			  rst1 			: out std_logic;								-- fifo#1 Reset
           wen1 			: out std_logic;								-- fifo#1 Write Enable
           ren1 			: out std_logic;								-- fifo#1 Read Enable          
			  rst2 			: out std_logic;								-- fifo#2 Reset
 			  wen2 			: out std_logic;								-- fifo#2 Write Enable
           ren2 			: out std_logic;								-- fifo#2 Read Enable
			  rst3 			: out std_logic;								-- fifo#3 Reset
 			  wen3 			: out std_logic;								-- fifo#3 Write Enable
			  trigger_en	: out std_logic;								-- Trigger Enable
			  decim_flag	: out std_logic;								-- Decimation Flag
			  dataready		: out std_logic);								
end fsm1;


architecture Behavioral of fsm1 is

-- Components

	COMPONENT ren_wen
	PORT(
		reset 		: IN std_logic;
		clk 			: IN std_logic;
		decim_ratio : IN std_logic_vector(1 downto 0);
		decim_en 	: IN std_logic;
		decim_flag	: IN std_logic;
		enable_r 	: IN std_logic;
		enable_w 	: IN std_logic;          
		wen2 			: OUT std_logic;
		ren2 			: OUT std_logic
		);
	END COMPONENT;

	

-- Signals
-------------------------------------------------------
	type state_TYPE is (s0, s1, s2, s3, s4, s5, s6, s7);
	attribute ENUM_ENCODING: STRING;
	attribute ENUM_ENCODING of state_TYPE: type is "000 001 010 011 100 101 110 111";

	signal state, next_state : state_TYPE;

	signal rst_fifo_cnt 		: std_logic;	-- rst fifos and cnt
	
	signal enable_w2 			: std_logic;	-- enable w from FSM to ren_wen
	signal enable_r2 			: std_logic;	-- enable r from FSM to ren_wen

	signal decim_en			: std_logic;	-- decim enable to ren_wen
	signal decim_flag_sig	: std_logic;	-- decimation flag sig

	signal wen2_sig 			: std_logic;
	signal ren2_sig 			: std_logic;

	signal cnt_delay_en		: std_logic;  	-- cnt enable delay (delay between read and write for fifo#1)
	signal cnt_record_en		: std_logic;	-- cnt enable data record (pre- and post-trigger data counter)
	signal cnt_transfer_en	: std_logic;	-- cnt enable transfer from fifo#2 to fifo#3

	signal cnt_delay			: integer range 31 downto 0;  	-- counter
	signal cnt_record			: integer range 4095 downto 0;  	-- counter
	signal cnt_transfer		: integer range 4095 downto 0;  	-- counter

	signal cnt_delay_ovf		: std_logic;						  	-- =0 when count = fs (32)
	signal cnt_record_ptrg	: std_logic;						  	-- =0 when count = pretrigger data amount	(ptrig_par)
	signal cnt_record_ovf	: std_logic;						  	-- =0 when count = fs (4k)
	signal cnt_transfer_ovf : std_logic;						  	-- =0 when count = fs (4k)

	signal ptrg_val_sig		: integer range 4095 downto 0;	-- pre trigger data amount setting for counter/comparator to generate cnt_record_ptrg
	signal dataready_sig		: std_logic;
-------------------------------------------------------
-- architecture description
-------------------------------------------------------
begin

	----------------------------------------------------
 	-- component's call
	----------------------------------------------------

	Inst_ren_wen: ren_wen PORT MAP(
		reset 		=> reset,
		clk 			=> clk,
		decim_ratio	=> decim_ratio,
		decim_en 	=> decim_en,
		decim_flag 	=> decim_flag_sig,
		enable_r 	=> enable_r2,
		enable_w 	=> enable_w2,
		wen2 			=> wen2_sig,
		ren2 			=> ren2_sig
	);

	--------------------------------------------------------------------------------------		
 	-- assignments
	--------------------------------------------------------------------------------------		
	rst1 			<= rst_fifo_cnt;
	rst2 			<= rst_fifo_cnt;
	rst3 			<= rst_fifo_cnt;
	wen2 			<= wen2_sig;
	ren2			<= ren2_sig;
	decim_flag	<= decim_flag_sig;
	dataready	<= dataready_sig;

	--------------------------------------------------------------------------------------		
	-- processes
	--------------------------------------------------------------------------------------		

	--------------------------------------------------------------------------------------		
	-- FSM sequence / definition	
	--------------------------------------------------------------------------------------		
	process (reset, clk)
	begin
		if reset = '0' then
			state <= s0;
		elsif (clk'event and clk= '1') then
				state <= next_state;
			else
				state <= state;
		end if;
	end process;
	--------------------------------------------------------------------------------------		

	
	--------------------------------------------------------------------------------------		
	-- FSM Description
	--------------------------------------------------------------------------------------		
	process (state, acqen, trigmode, cnt_delay_ovf, cnt_record_ptrg, trigger, cnt_record_ovf, 
				cnt_transfer_ovf, dataready_sig, rstdataready)
	begin
		case state is
			--------------------------------------------------------------------------------------		
			-- Initial State --
			--------------------------------------------------------------------------------------		

			when s0 =>	 

				rst_fifo_cnt		<= '0';
				decim_en				<= '1';
				decim_flag_sig		<= '0';
				wen1					<= '1';
				ren1					<= '1';
				enable_w2			<= '1';
				enable_r2			<= '1';
				wen3					<= '1';
				cnt_delay_en		<= '1';
				cnt_record_en		<= '1';
				cnt_transfer_en	<= '1';
				trigger_en			<= '1';

				if acqen = '0'  then
					if trigmode = '0' then 	  -- acq	w/ trigger
  						next_state <= s1;

					else
  						next_state <= s6;		  -- acq w/o trigger
					end if;
				else
					next_state <= s0;
				end if;
			
			--------------------------------------------------------------------------------------		
			-- acquisition	w/ trigger
			-- Acq starts / Wait for FIFO1 delay	
			--------------------------------------------------------------------------------------		

			when s1 =>	

				rst_fifo_cnt		<= '1'; --*
				decim_en				<= '0'; --*
				decim_flag_sig		<= '0';
				wen1					<= '0'; --*
				ren1					<= '1';
				enable_w2			<= '1';
				enable_r2			<= '1';
				wen3					<= '1';
				cnt_delay_en		<= '0'; --* start counter for delay
				cnt_record_en		<= '1';
				cnt_transfer_en	<= '1';
				trigger_en			<= '1';
 
				if acqen = '0'  then

 					if cnt_delay_ovf = '0' then
						next_state <= s2;
 					else
						next_state <= s1;
					end if;
				else
						next_state <= s0;
 				end if;
 
			--------------------------------------------------------------------------------------		
			-- acquisition	w/ trigger
			-- Record the pretrigger data samples
			--------------------------------------------------------------------------------------		

			when s2 =>	

				rst_fifo_cnt		<= '1';
				decim_en				<= '0'; 
				decim_flag_sig		<= '0';
				wen1					<= '0';
				ren1					<= '0'; --*	 fifo1 is now only a pipeline delay
				enable_w2			<= '0'; --* enable write operation for fifo2
				enable_r2			<= '1';
				wen3					<= '1';
				cnt_delay_en		<= '1'; --* stop counter for delay
				cnt_record_en		<= '0'; --* start the record counter
				cnt_transfer_en	<= '1';
				trigger_en			<= '1';

				if acqen = '0'  then
 					if cnt_record_ptrg = '0' then  -- Pre-trigger data amount in fifo2
						next_state <= s3;
 					else
						next_state <= s2;
 					end if;
 				else
					next_state <= s0;
				end if;

			--------------------------------------------------------------------------------------		
			-- acquisition	w/ trigger
			-- Arm trigger and refresh data record in fifo2 (halt record counter)
			-- If a request (dataready = 1) is already pending the trigger is not armed
			--------------------------------------------------------------------------------------		

			when s3 =>	

				rst_fifo_cnt		<= '1';
				decim_en				<= '0'; 
				decim_flag_sig		<= '0';
				wen1					<= '0';
				ren1					<= '0'; 
				enable_w2			<= '0'; 
				enable_r2			<= '0'; --*
				wen3					<= '1';
				cnt_delay_en		<= '1'; 
				cnt_record_en		<= '1'; --* stop the record counter
				cnt_transfer_en	<= '1';
				trigger_en			<= '0';

				if acqen = '0'  then
					if ( dataready_sig = '0' and trigger = '1' ) then
						next_state <= s4;
					else
						next_state <= s3;
					end if;
				else
					next_state <= s0;
				end if;

			--------------------------------------------------------------------------------------		
 			-- acquisition	w/ trigger
			--Trigger received / Record post trigger samples
			--------------------------------------------------------------------------------------		

			when s4 =>

				rst_fifo_cnt		<= '1';
				decim_en				<= '0'; 
				decim_flag_sig		<= '1'; --*
				wen1					<= '0';
				ren1					<= '0'; 
				enable_w2			<= '0'; 
				enable_r2			<= '1'; --*	stop reading and accumualte the rest of the samples
				wen3					<= '1';
				cnt_delay_en		<= '1'; 
				cnt_record_en		<= '0'; --* restart the record counter
				cnt_transfer_en	<= '1';
				trigger_en			<= '1';

				if acqen = '0'  then
					if cnt_record_ovf = '0' then	-- all the samples are recorded
						next_state <= s5;
					else
						next_state <= s4;
					end if;
				else
					next_state <= s0;
				end if;

			--------------------------------------------------------------------------------------		
 			-- acquisition	w/ trigger
			--transfer into FIFO3
			--------------------------------------------------------------------------------------		
			
			when s5 =>	

				rst_fifo_cnt		<= '1';
				decim_en				<= '0'; 
				decim_flag_sig		<= '1'; 
				wen1					<= '1';
				ren1					<= '1'; 
				enable_w2			<= '1'; --* stop writing
				enable_r2			<= '0'; --*	start reading into ffio3
				wen3					<= '0'; --* write data from fifo2 into fifo3
				cnt_delay_en		<= '1'; 
				cnt_record_en		<= '1'; --* stops the record counter
				cnt_transfer_en	<= '0';
				trigger_en			<= '1';

				if acqen = '0'  then
					if cnt_transfer_ovf = '0' then
						next_state <= s7;
					else
						next_state <= s5;
					end if;
				else
					next_state <= s0;
				end if;

			--------------------------------------------------------------------------------------
 			-- acquisition	w/o trigger
			-- FIFO 1 and FIFO 2 are transparent, data is written into FIFO3
			--------------------------------------------------------------------------------------
			when s6 =>

				rst_fifo_cnt		<= '1';
				decim_en				<= '1'; 
				decim_flag_sig		<= '1'; 
				wen1					<= '0'; --* enable write / read from fifo 1 to 2 to 3
				ren1					<= '0'; --*
				enable_w2			<= '0'; --* 
				enable_r2			<= '0'; --*	
				wen3					<= '0'; --* 
				cnt_delay_en		<= '1'; 
				cnt_record_en		<= '1'; 
				cnt_transfer_en	<= '0'; --*	enable counter
				trigger_en			<= '1';

				if acqen = '0'  then
					if cnt_transfer_ovf = '0' then
						next_state <= s7;
					else
						next_state <= s6;
					end if;
				else
					next_state <= s0;
				end if;

			--------------------------------------------------------------------------------------		
			-- acquisition	with and without trigger - Disable all transfers until the 	rsdry is received
			--------------------------------------------------------------------------------------		
			when s7 =>		

				rst_fifo_cnt		<= '1';
				decim_en				<= '1'; 
				decim_flag_sig		<= '1'; 
				wen1					<= '1'; --* 
				ren1					<= '1'; --*
				enable_w2			<= '1'; --* 
				enable_r2			<= '1'; --*	
				wen3					<= '1'; --* 
				cnt_delay_en		<= '1'; 
				cnt_record_en		<= '1'; 
				cnt_transfer_en	<= '1'; --*	disable counter
				trigger_en			<= '1';

				if acqen = '0' then	 -- 
					if rstdataready = '0' then

						if trigmode = '0' then 	  -- acq	w/ trigger
	  						next_state <= s2;
						else
	  						next_state <= s6;		  -- acq w/o trigger
						end if;

					else
						next_state <= s7;
					end if;

				else
					next_state <= s0;
				end if;

			-------------------------
			when others =>

				rst_fifo_cnt		<= '0';
				decim_en				<= '1';
				decim_flag_sig		<= '1';
				wen1					<= '1';
				ren1					<= '1';
				enable_w2			<= '1';
				enable_r2			<= '1';
				wen3					<= '1';
				cnt_delay_en		<= '1';
				cnt_record_en		<= '1';
				cnt_transfer_en	<= '1';
				trigger_en			<= '1';
		
				next_state <= s0;

		end case;
    end process;
	----------------------------------------------------

	--------------------------------------------------------------------------------------		
	-- Pretrigger data amount - Value Selection
	--------------------------------------------------------------------------------------		
	process (ptrig_data)
	begin
		case ptrig_data is 
			-- remove the ";--" from the following n1_val assignments
			-- to get the proper values: 511, 1023, 2047, 2559

			when "00" =>					
				ptrg_val_sig <= 511;			-- Value - 1
	
			when "01" =>
				ptrg_val_sig <= 1023;

			when "10" =>
				ptrg_val_sig <= 2047;

			when others =>
				ptrg_val_sig <= 2559;

		end case;

	end process;
	--------------------------------------------------------------------------------------		

	--------------------------------------------------------------------------------------		
	-- process counter - DELAY	between WEN and REN for FIFO#1 for Decimation ratio
	--------------------------------------------------------------------------------------		
	process(rst_fifo_cnt, clk, cnt_delay_en, cnt_delay, cnt_delay_ovf)
	begin
		if rst_fifo_cnt = '0' then 
					cnt_delay		<= 0;
					cnt_delay_ovf	<= '1';

		elsif ( clk'event and clk = '1' ) then

			if cnt_delay_en = '0' then
	
				if cnt_delay < 31 then
					cnt_delay_ovf	<= '1';
					cnt_delay		<= cnt_delay + 1;
				else
					cnt_delay_ovf 	<= '0';
					cnt_delay		<= cnt_delay;
				end if;
	
			else
					cnt_delay_ovf	<= cnt_delay_ovf;
					cnt_delay		<= cnt_delay;
			end if;	 

		end if;

	end process;
	--------------------------------------------------------------------------------------		
	-- process counter  - RECORD
	-- Counter Value is Record-2 counts
	-- Header size = 10
	-- Record = 4096
	-- FS	= 4096-10-2= 4084
	--------------------------------------------------------------------------------------		
	process(rst_fifo_cnt, clk, cnt_record_en, cnt_record, cnt_record_ovf, wen2_sig, cnt_transfer_ovf)
	begin
		if ( rst_fifo_cnt = '0' or cnt_transfer_ovf = '0' )then 

					cnt_record		<= 0;
					cnt_record_ovf	<= '1';

		elsif ( clk'event and clk = '1' ) then

			if ( cnt_record_en = '0' and wen2_sig = '0' ) then

				if	cnt_record < 4084 then
					cnt_record		<= cnt_record + 1;
					cnt_record_ovf	<= '1';
				else
					cnt_record		<= cnt_record;
					cnt_record_ovf	<= '0';
				end if;

			else
					cnt_record		<= cnt_record;
					cnt_record_ovf	<= cnt_record_ovf;
			end if;

		end if;

	end process;

	--------------------------------------------------------------------------------------		
	-- Process pre trigger data counter
	--	Generates an overflow signal when counter value reached ptrg_data
	--------------------------------------------------------------------------------------		
	process(rst_fifo_cnt, cnt_transfer_ovf, clk, cnt_record, ptrg_val_sig)
	begin
		if ( rst_fifo_cnt = '0' or cnt_transfer_ovf = '0' )then 

			cnt_record_ptrg	<= '1';

		elsif ( clk'event and clk = '1' ) then

			if cnt_record < ptrg_val_sig then
					cnt_record_ptrg	<= '1';
			else
					cnt_record_ptrg	<= '0';
			end if;
		
		end if;

	end process;	
	
	--------------------------------------------------------------------------------------		

	--------------------------------------------------------------------------------------		
	-- process counter  - TRANSFER  
	--------------------------------------------------------------------------------------		
	process(rst_fifo_cnt, rstdataready, clk, cnt_transfer_en, cnt_transfer, cnt_transfer_ovf)
	begin
		if ( rst_fifo_cnt = '0' or rstdataready = '0' ) then 		 -- modification 7/20
					cnt_transfer		<= 0;
					cnt_transfer_ovf	<= '1';

		elsif ( clk'event and clk = '1' ) then

			if cnt_transfer_en = '0' then

				if cnt_transfer < 4084 then
					cnt_transfer		<= cnt_transfer + 1;
					cnt_transfer_ovf	<= '1';
				else
					cnt_transfer		<= cnt_transfer;
					cnt_transfer_ovf	<= '0';
				end if;					

			else
				cnt_transfer		<= cnt_transfer;
				cnt_transfer_ovf	<= cnt_transfer_ovf;
			end if;

		end if;
	end process;
	--------------------------------------------------------------------------------------		
	-- process counter  - DATAREADY
	--------------------------------------------------------------------------------------		
	process(rst_fifo_cnt, clk, dataready_sig, cnt_transfer_ovf,rstdataready)
	begin
		if ( clk'event and clk = '1' ) then
		
			if ( rst_fifo_cnt = '0' or rstdataready = '0') then 
	
				dataready_sig		<= '0';

			elsif  cnt_transfer_ovf = '0' then

				dataready_sig	<= '1';
			else
				dataready_sig	<= dataready_sig;

			end if;					

		else
				dataready_sig	<= dataready_sig;
		end if;
	end process;
	--------------------------------------------------------------------------------------		


end Behavioral;
