LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;

ENTITY ADC_AD9220_all IS
	PORT (
			n_reset		: IN STD_LOGIC ;
			n_write		: IN STD_LOGIC ;
			n_read		: IN STD_LOGIC ;
			Hold		: IN STD_LOGIC ;
			clock_machine	: IN STD_LOGIC ;
			subadd		: IN STD_LOGIC_VECTOR (6 DOWNTO 0);
			user_data	: INOUT STD_LOGIC_VECTOR (7 DOWNTO 0);
			adc			: IN STD_LOGIC_VECTOR (12 DOWNTO 1);
			OTR			: IN STD_LOGIC ;
			nb_channels	: IN STD_LOGIC_VECTOR (1 DOWNTO 0);
			nb_acq		: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
			ck_usb		: IN STD_LOGIC ;
			clk_adc		: OUT STD_LOGIC;
			srin_read	: OUT STD_LOGIC;
			ck_read		: OUT STD_LOGIC;
			resetb_read	: OUT STD_LOGIC;
			sel_read	: OUT STD_LOGIC;
			RazChn		: OUT STD_LOGIC;
			SPY1		: OUT STD_LOGIC;
			SPY2		: OUT STD_LOGIC;
			SPY3		: OUT STD_LOGIC;
			SPY4		: OUT STD_LOGIC;
			SPY5		: OUT STD_LOGIC;
			SPY6		: OUT STD_LOGIC
		);
END ADC_AD9220_all;

ARCHITECTURE SYN OF ADC_AD9220_all IS
	SIGNAL sel_word		: Std_Logic_vector (7 downto 0);
	SIGNAL nb_ch		: Std_Logic_vector (9 downto 0);
	SIGNAL StateMachine	: Std_Logic_Vector (3 DOWNTO 0);
	SIGNAL StartCycle	: Std_Logic;
	SIGNAL StartCycleMem: Std_Logic;
	SIGNAL EnableStartCycle: Std_Logic;
	SIGNAL end_cycle	: Std_Logic;
	SIGNAL En_wr_FIFO	: Std_Logic;
	SIGNAL EN_COUNT, EN_COUNT_EVT		: Std_Logic;
	SIGNAL RESET_COUNT, RESET_COUNT_EVT	: Std_Logic;
	SIGNAL clr_fifo		: Std_Logic;
	SIGNAL RazChn_0		: Std_Logic;
	SIGNAL Count, Count_Evt	: Std_Logic_Vector (9 DOWNTO 0);
	SIGNAL read_word_20, read_word_21, read_word_22, read_word_24, word_20	: STD_LOGIC_VECTOR (7 DOWNTO 0);
	signal FIFO_ReadOut_20	: std_logic_vector (7 downto 0);
	signal FIFO_ReadOut_21	: std_logic_vector (7 downto 0);
	signal rdusedw_20, rdusedw_21 	: std_logic_vector (9 downto 0);
	signal rdempty_20, rdfull_20	: std_logic;
	signal rdempty_21, rdfull_21	: std_logic;
	signal tampon, rdreq20, rdreq21	: std_logic;
	signal one, two, three	: std_logic;
	signal A, B			: std_logic;

component reg_8bits
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
		enable		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
	);
end component;

COMPONENT Read_Word
	PORT
	(
	reset		: IN	STD_LOGIC;
	n_read		: IN	STD_LOGIC;	
	selection	: IN	STD_LOGIC;	-- selection lecture 
	word_x		: IN	STD_LOGIC_VECTOR(7 DOWNTO 0); -- registre à lire
	User_Data	: INOUT	STD_LOGIC_VECTOR(7 DOWNTO 0) -- bus USB
	);
END	COMPONENT;


component counter_10b
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		cnt_en		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (9 DOWNTO 0)
	);
end component;

component fifo_adc
	PORT
	(
		aclr		: IN STD_LOGIC  := '0';
		data		: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
		rdclk		: IN STD_LOGIC ;
		rdreq		: IN STD_LOGIC ;
		wrclk		: IN STD_LOGIC ;
		wrreq		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
		rdempty		: OUT STD_LOGIC ;
		rdfull		: OUT STD_LOGIC ;
		rdusedw		: OUT STD_LOGIC_VECTOR (9 DOWNTO 0)
	);
end component;

BEGIN
fifo_adc_inst_20 : fifo_adc PORT MAP (
		aclr	 => NOT (n_reset) OR clr_fifo,
		data	 => read_word_20,
		rdclk	 => NOT (ck_usb),
		rdreq	 => rdreq20,
		wrclk	 => clock_machine,
		wrreq	 => En_wr_FIFO,
		q		 =>	FIFO_ReadOut_20,
		rdempty	 => rdempty_20,
		rdfull	 => rdfull_20,
		rdusedw	 => rdusedw_20
	);

fifo_adc_inst_21 : fifo_adc PORT MAP (
		aclr	 => NOT (n_reset) OR clr_fifo,
		data	 => read_word_21,
		rdclk	 => NOT (ck_usb),
		rdreq	 => rdreq21,
		wrclk	 => clock_machine,
		wrreq	 => En_wr_FIFO,
		q		 =>	FIFO_ReadOut_21,
		rdempty	 => rdempty_21,
		rdusedw	 => rdusedw_21
	);

counter_10b_inst : counter_10b PORT MAP (
		aclr	 => RESET_COUNT,
		clock	 => NOT(clock_machine),
		cnt_en	 => EN_COUNT,
		q	 => Count
	);

counter_10b_evt : counter_10b PORT MAP (
		aclr	 => RESET_COUNT_EVT,
		clock	 => NOT(clock_machine),
		cnt_en	 => EN_COUNT_EVT,
		q	 => Count_Evt
	);

---- USB Read instantiation       // Machine de lecture du Word 20 (ecriture sur bus USB)
--Read_Word20 : Read_Word PORT MAP (
--		reset		=> n_reset,
--		n_read		=> n_read,
--		selection	=> sel_word(0), 
--		word_x		=> FIFO_ReadOut_20,	-- registre à lire
--		User_Data	=> user_data -- bus USB
--	);
--
----								// Machine de lecture du Word 21 (ecriture sur bus USB)
--Read_Word21 : Read_Word PORT MAP (
--		reset		=> n_reset,
--		n_read		=> n_read,
--		selection	=> sel_word(1), 
--		word_x		=> FIFO_ReadOut_21,	-- registre à lire
--		User_Data	=> user_data -- bus USB
--	);

Read_Word22 : Read_Word PORT MAP (
		reset		=> n_reset,
		n_read		=> n_read,
		selection	=> sel_word(2), 
		word_x		=> read_word_22,	-- registre à lire
		User_Data	=> user_data -- bus USB
	);

Read_Word24 : Read_Word PORT MAP (
		reset		=> n_reset,
		n_read		=> n_read,
		selection	=> sel_word(3), 
		word_x		=> read_word_24,	-- registre à lire
		User_Data	=> user_data -- bus USB
	);

reg_8bits_inst : reg_8bits PORT MAP ( --// Machine d'ecriture du Word 20
		aclr	 => NOT (n_reset),
		clock	 => n_write,
		data	 => user_data,
		enable	 => sel_word(0),
		q	 => word_20
	);

mem_ENstartcycle: PROCESS(n_reset, end_cycle, StartCycle)
BEGIN
	IF (end_cycle = '1' OR n_reset = '0') THEN
		EnableStartCycle <= '0';
	ELSIF (StartCycle'EVENT  AND StartCycle = '1') THEN
			EnableStartCycle <= '1';
	END IF;
END PROCESS mem_ENstartcycle;

mem_startcycle: PROCESS(n_reset, end_cycle, Hold)
BEGIN
	IF (end_cycle = '1' OR n_reset = '0' OR EnableStartCycle = '0' OR RazChn_0 = '1') THEN
		StartCycleMem <= '0';
	ELSIF (Hold'EVENT  AND Hold = '1') THEN
			StartCycleMem <= '1';
	END IF;
END PROCESS mem_startcycle;
		
ADC_readout: PROCESS (n_reset, clock_machine)
BEGIN
	IF n_reset = '0' THEN 
		StateMachine <= "0000";
	ELSIF (clock_machine'event AND clock_machine = '1') THEN
			CASE StateMachine is
				WHEN "0000"	=> 	IF EnableStartCycle = '0' THEN
										StateMachine 	<= "0000";
									ELSE
										StateMachine	<= "0001";
									END IF;
				WHEN "0001"	=> 	IF StartCycleMem = '0' THEN
										StateMachine 	<= "0001";
									ELSE
										StateMachine	<= "0011";
									END IF;
				WHEN "0011"	=>	StateMachine	<= "0010";
				WHEN "0010"	=>	StateMachine	<= "0110";
				WHEN "0110"	=>	StateMachine	<= "0100";
				WHEN "0100"	=>	StateMachine	<= "0101";
				WHEN "0101"	=>	StateMachine	<= "0111";
				WHEN "0111"	=>	IF (Count = nb_ch + 4)	THEN
									StateMachine	<= "1111";
								ELSE
									StateMachine	<= "0110";
								END IF;
				WHEN "1111"	=>	StateMachine	<= "1110";
				WHEN "1110"	=>	StateMachine	<= "1010";
				WHEN "1010"	=>	IF (Count_Evt = nb_acq)	THEN
									StateMachine	<= "1000";
								ELSE
									StateMachine	<= "1011";
								END IF;
				WHEN "1000"	=>	StateMachine	<= "0000";
				WHEN "1011"	=>	StateMachine	<= "0011";
				WHEN OTHERS	=>	StateMachine	<= "0000";
			END CASE;
	END IF;
END PROCESS ADC_readout;	

with StateMachine select
one <=	'1' when "0110", '1' when "1111", '1' when "0010", 
		'0' when  others;

with StateMachine select
two <=	'1' when "0101",
		'0' when  others;

with StateMachine select
three <=	'1' when "0111",
			'0' when  others;

with StateMachine select
RESET_COUNT <=	'1' when "0010",'1' when "0011",
				'0' when  others;
				
with StateMachine select
RESET_COUNT_EVT <=	'1' when "0000",
				'0' when  others;
				
with StateMachine select
EN_COUNT_EVT <=	'1' when "1110",
				'0' when  others;
				
with StateMachine select
srin_read <='1' when "0010",'1' when "0011",
			'0' when  others;

with StateMachine select
resetb_read <=	'0' when "0001", '0' when "1011",
				'1' when  others;

with StateMachine select
end_cycle <=	'1' when "1000",
				'0' when  others;

with StateMachine select
clr_fifo <=	'1' when "0001",
				'0' when  others;

with StateMachine select
RazChn_0 <=	'1' when "1010",
				'0' when  others;

A <= '1' when Count < nb_ch else '0';
B <= '1' when Count > 3  else '0';

ck_read		<=	one AND A;
clk_adc		<=	three;
EN_COUNT	<=	two;
En_wr_FIFO	<=	one AND B;

-- FIFO Reading Enable Signal

process (ck_usb, n_reset) 
begin
	if (n_reset = '0') then
		tampon <= '0';
	elsif (ck_usb'event AND ck_usb = '1') then
		tampon <= NOT (n_read);
	end if;
end process;

rdreq20 <= sel_word(0) AND NOT(tampon) AND NOT(n_read);	-- Réduction du pulse de read à 1 période
rdreq21 <= sel_word(1) AND NOT(tampon) AND NOT(n_read);	-- Réduction du pulse de read à 1 période

user_data <= "ZZZZZZZZ" when n_reset = '0' else
	FIFO_ReadOut_21 when (sel_word(1) = '1' AND n_read = '0') else 
	FIFO_ReadOut_20 when (sel_word(0) = '1' AND n_read = '0') else "ZZZZZZZZ" ;

make_sel_word : PROCESS(subadd)
BEGIN
	CASE subadd IS
	WHEN "0010100"	=>	sel_word <= "00000001";	-- add(word_20) = 0
	WHEN "0010101"	=>	sel_word <= "00000010";	-- add(word_21) = 1
	WHEN "0010110"	=>	sel_word <= "00000100";	-- add(word_22) = 2
	WHEN "0011000"	=>	sel_word <= "00001000";	-- add(word_24) = 3
	WHEN OTHERS	=>	sel_word <= "00000000";
END CASE;
END PROCESS make_sel_word;

make_nb_channels : PROCESS(nb_channels)
BEGIN
	CASE nb_channels IS
	WHEN "00"	=>	nb_ch <= "0000100100";	-- 36 channels (SPIROC)
	WHEN "01"	=>	nb_ch <= "0001000000";	-- 64 channels (HARDROC/SKIROC)
	WHEN "10"	=>	nb_ch <= "0010000100";	-- 128 channels
	WHEN "11"	=>	nb_ch <= "0100000000";	-- 256 channels
	WHEN OTHERS	=>	nb_ch <= "0001000000";
END CASE;
END PROCESS make_nb_channels;

StartCycle	<=	word_20(7);  -- Enable Start Cycle signal (all channel readout)
read_word_20 <=	'0' & '0' & '0' & OTR & adc(12 downto 9);
read_word_21 <=	adc(8 downto 1);
read_word_22 <=	rdempty_20 & rdempty_21 & rdfull_20 & rdfull_21 & '0' & '0' & rdusedw_20(9 downto 8);
read_word_24 <=	rdusedw_20(7 downto 0);
sel_read	<=	StartCycleMem;
RazChn <= RazChn_0;

SPY1 <= rdreq20 ;
SPY2 <= En_wr_FIFO ;
SPY3 <= rdempty_20 ;
SPY4 <= two ;
SPY5 <= clr_fifo ;
SPY6 <= rdfull_20 ;

END SYN;
