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

ENTITY SlowControl_SK2_ERO IS
	PORT (
			ck_usb		: IN STD_LOGIC ;
			n_reset		: IN STD_LOGIC ;
			n_write		: IN STD_LOGIC ;
			n_read		: 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);
			word_0		: INOUT	STD_LOGIC_VECTOR (7 DOWNTO 0);
			word_1		: INOUT	STD_LOGIC_VECTOR (7 DOWNTO 0);
			word_2		: INOUT	STD_LOGIC_VECTOR (7 DOWNTO 0);
			word_3		: INOUT	STD_LOGIC_VECTOR (7 DOWNTO 0);
			write_word_4	: INOUT	STD_LOGIC_VECTOR (7 DOWNTO 0);
			word_5		: INOUT	STD_LOGIC_VECTOR (7 DOWNTO 0);
			word_6		: INOUT	STD_LOGIC_VECTOR (7 DOWNTO 0);
			word_7		: INOUT	STD_LOGIC_VECTOR (7 DOWNTO 0);
			sr_ck		: OUT STD_LOGIC;
			ck_read		: OUT STD_LOGIC;
			sr_in		: OUT STD_LOGIC;
			srin_read	: OUT STD_LOGIC;
			sr_out		: IN STD_LOGIC;	-- ASIC's daisy chain slow control output
			srout_read	: IN STD_LOGIC;	-- ASIC's daisy chain read register output
			SPY1		: OUT STD_LOGIC;
			SPY2		: OUT STD_LOGIC;
			SPY3		: OUT STD_LOGIC;
			SPY4		: OUT STD_LOGIC;
			End_ReadOut1	: IN STD_LOGIC;
			End_ReadOut2	: IN STD_LOGIC;
			ChipSatb		: IN STD_LOGIC;
			Resetb			: IN STD_LOGIC;
			StartAcq		: IN STD_LOGIC;
			StartRO			: IN STD_LOGIC
		);
END SlowControl_SK2_ERO;


ARCHITECTURE SYN OF SlowControl_SK2_ERO IS
	CONSTANT ShiftData : STD_LOGIC_VECTOR := "1000"; 		-- Nombre de bits à emettre sur le dernier mot du slow control/probe/read
	CONSTANT ShiftDebug : STD_LOGIC_VECTOR := "0001"; 		-- Nombre de bits à emettre sur le dernier mot en phase de debug

	SIGNAL sel_w_sr		: Std_Logic;	-- 
	SIGNAL sel_w_read	: Std_Logic;
	SIGNAL mem_w_sr		: Std_Logic;
	SIGNAL mem_w_read	: Std_Logic;
	SIGNAL sr_ck0		: STD_LOGIC;
	SIGNAL sr_in0		: STD_LOGIC;
	SIGNAL ck_read0		: STD_LOGIC;
	SIGNAL srin_read0 	: STD_LOGIC;
	SIGNAL checksum_sr, checksum_read	: STD_LOGIC;
	SIGNAL input_cor_sr, input_cor_read	: STD_LOGIC;
	SIGNAL sel_word		: Std_Logic_Vector (7 DOWNTO 0);
	SIGNAL clk_shift	: Std_Logic;	-- Serializer Clock
	SIGNAL rd_fifo		: Std_Logic;
	SIGNAL usedw_sig	: STD_LOGIC_VECTOR (7 DOWNTO 0);
	SIGNAL q_sig		: STD_LOGIC_VECTOR (7 DOWNTO 0);
	SIGNAL q_fifo		: STD_LOGIC_VECTOR (7 DOWNTO 0);
	SIGNAL wr_fifo		: Std_Logic;
	SIGNAL StateMachine	: Std_Logic_Vector(3 DOWNTO 0);
	SIGNAL Count		: Std_Logic_Vector(3 DOWNTO 0);
	SIGNAL EN_count, Clear_count	: Std_Logic;
	SIGNAL StartCycle	: Std_Logic;
	SIGNAL StartCycleMem: Std_Logic;
	SIGNAL end_cycle	: Std_Logic;
	SIGNAL out_shift	: Std_Logic;
	SIGNAL empty, Cout	: Std_Logic;
	SIGNAL full			: Std_Logic;
	SIGNAL read_word_0, read_word_1, read_word_2, read_word_3, read_word_5	: STD_LOGIC_VECTOR (7 DOWNTO 0);
	SIGNAL read_word_6, read_word_7: STD_LOGIC_VECTOR (7 DOWNTO 0);
	SIGNAL word_4		: STD_LOGIC_VECTOR (7 DOWNTO 0);
	SIGNAL ERO1, ERO2, Sat	: Std_Logic;
	SIGNAL Shift_order	: Std_Logic_Vector(3 DOWNTO 0);

COMPONENT latch_8
	port(
			aclr	: IN STD_LOGIC ;
			n_write	: IN STD_LOGIC ;
			data	: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
			sel_word: IN STD_LOGIC_VECTOR (7 DOWNTO 0);
			word0	: OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
			word1	: OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
			word2	: OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
			word3	: OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
			word4	: OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
			word5	: OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
			word6	: OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
			word7	: OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
		);
END COMPONENT;

COMPONENT fifo
	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 ;
		rdusedw		: OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
		wrfull		: OUT STD_LOGIC 
	);
END COMPONENT;

COMPONENT flipflop
	PORT
	(
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC 
	);
END COMPONENT;

COMPONENT flipflopaclr
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC 
	);
END COMPONENT;

COMPONENT flipflopaclr_en
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC ;
		enable		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC 
	);
END COMPONENT;

COMPONENT Read_Word
	PORT
	(
	reset		: IN	STD_LOGIC;
	n_read		: IN	STD_LOGIC;	-- horloge pour la sm et l'ADC
	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 count4bits 
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clk_en		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		cout		: OUT STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (3 DOWNTO 0)
	);
END COMPONENT;

BEGIN
-- 8x8 bits Latch Instantiation    // Machine d'ecriture du bus USB vers Word 0 à 7
Ins0_7_Latch8 : latch_8 PORT MAP (
		aclr		=> NOT (n_reset),
		n_write		=> n_write,
		data		=> user_data,
		sel_word	=> sel_word,
		word0		=> word_0,
		word1		=> word_1,
		word2		=> word_2,
		word3		=> word_3,
		word4		=> word_4,
		word5		=> word_5,
		word6		=> word_6,
		word7		=> word_7
	);

-- FIFO instantiation: 
fifo_inst : fifo PORT MAP (
		aclr	 => NOT (n_reset),
		data	 => user_data,
		rdclk	 => clock_machine,
		rdreq	 => rd_fifo,
		wrclk	 => ck_usb,
		wrreq	 => wr_fifo,
		q	 	 => q_sig,
		rdempty	 => empty,
		rdusedw	 => usedw_sig,
		wrfull	 => full
	);
	
-- Bascule D, pour réduire à 1 période le signal write et le synchroniser sur les fronts descendants.
-- (dans les anciennes versions d'interface Usb, le signal fait 2 périodes, ce qui pourrait entrainer 2 écritures)
flipflopaclr_instwr : flipflopaclr PORT MAP (
		aclr	 => NOT (n_reset),
		clock	 => NOT (ck_usb),
		data	 => Not (n_write) AND NOT (wr_fifo) AND (sel_w_sr OR sel_w_read),
		q	 => wr_fifo	
		);
	
-- USB Read instantiation        // Machine de lecture du Word 0 (ecriture sur bus USB)
Read_Word0 : Read_Word PORT MAP (
		reset		=> n_reset,
		n_read		=> n_read,
		selection	=> sel_word(0), 
		word_x		=> read_word_0,	-- registre à lire
		User_Data	=> user_data -- bus USB
	);

--								// Machine de lecture du Word 1 (ecriture sur bus USB)
Read_Word1 : Read_Word PORT MAP (
		reset		=> n_reset,
		n_read		=> n_read,
		selection	=> sel_word(1), 
		word_x		=> read_word_1,	-- registre à lire
		User_Data	=> user_data -- bus USB
	);

--								// Machine de lecture du Word 2 (ecriture sur bus USB)
Read_Word2 : Read_Word PORT MAP (
		reset		=> n_reset,
		n_read		=> n_read,
		selection	=> sel_word(2), 
		word_x		=> read_word_2,	-- registre à lire
		User_Data	=> user_data -- bus USB
	);

--								// Machine de lecture du Word 3 (ecriture sur bus USB)
Read_Word3 : Read_Word PORT MAP (
		reset		=> n_reset,
		n_read		=> n_read,
		selection	=> sel_word(3), 
		word_x		=> read_word_3,	-- registre à lire
		User_Data	=> user_data -- bus USB
	);

--								// Machine de lecture du Word 4 (ecriture sur bus USB)
Read_Word4 : Read_Word PORT MAP (
		reset		=> n_reset,
		n_read		=> n_read,
		selection	=> sel_word(4), 
		word_x		=> write_word_4,	-- registre à lire
		User_Data	=> user_data -- bus USB
	);

--								// Machine de lecture du Word 5 (ecriture sur bus USB)
Read_Word5 : Read_Word PORT MAP (
		reset		=> n_reset,
		n_read		=> n_read,
		selection	=> sel_word(5), 
		word_x		=> read_word_5,	-- registre à lire
		User_Data	=> user_data -- bus USB
	);

--								// Machine de lecture du Word 6 (ecriture sur bus USB)
Read_Word6 : Read_Word PORT MAP (
		reset		=> n_reset,
		n_read		=> n_read,
		selection	=> sel_word(6), 
		word_x		=> read_word_6,	-- registre à lire
		User_Data	=> user_data -- bus USB
	);

--								// Machine de lecture du Word 7 (ecriture sur bus USB)
Read_Word7 : Read_Word PORT MAP (
		reset		=> n_reset,
		n_read		=> n_read,
		selection	=> sel_word(7), 
		word_x		=> read_word_7,	-- registre à lire
		User_Data	=> user_data -- bus USB
	);

-- authorization of the writing operation into the Fifo
flipflopaclr_instmemsr : flipflopaclr_en PORT MAP (
		aclr	 => NOT (n_reset),
		clock	 => NOT (ck_usb),
		data	 => NOT (mem_w_read) AND (sel_w_sr OR mem_w_sr),
		enable	 => NOT (n_write),
		q	 	 => mem_w_sr	
		);
		
flipflopaclr_en_instmemread : flipflopaclr_en PORT MAP (
		aclr	 => NOT (n_reset),
		clock	 => NOT (ck_usb),
		data	 => NOT (sel_w_sr) AND (sel_w_read OR mem_w_read),
		enable	 => NOT (n_write),
		q	 	 => mem_w_read	
		);

decode_subadd : PROCESS (clock_machine)
BEGIN
IF clock_machine'EVENT AND clock_machine = '1' THEN
	IF subadd = "0001010" THEN	sel_w_sr <= '1'; 	-- address 10
		ELSE	sel_w_sr <= '0';
	END IF;
	IF subadd = "0001100" THEN	sel_w_read <= '1';	-- address 12
		ELSE	sel_w_read <= '0';
	END IF;	
END IF;						
END PROCESS decode_subadd;

-- Multiplexeur de sortie
out_shift_p: PROCESS(count)
BEGIN
 IF 	(count = "0001")  THEN out_shift <= q_sig(0);
 ELSIF 	(count = "0010")  THEN out_shift <= q_sig(1);
 ELSIF 	(count = "0011")  THEN out_shift <= q_sig(2);
 ELSIF 	(count = "0100")  THEN out_shift <= q_sig(3);
 ELSIF 	(count = "0101")  THEN out_shift <= q_sig(4);
 ELSIF 	(count = "0110")  THEN out_shift <= q_sig(5);
 ELSIF 	(count = "0111")  THEN out_shift <= q_sig(6);
 ELSIF 	(count = "1000")  THEN out_shift <= q_sig(7);
 ELSE out_shift <= '0';
 END IF;
END PROCESS out_shift_p;

-- authorization of the reading operation and shifting
sr_ck0		<= (clk_shift AND mem_w_sr AND StartCycleMem);
sr_ck		<= sr_ck0;
sr_in0		<= out_shift AND mem_w_sr AND StartCycleMem;
sr_in		<= sr_in0;
ck_read0 	<= (clk_shift AND mem_w_read AND StartCycleMem);
ck_read 	<= ck_read0;
srin_read0	<= out_shift AND mem_w_read AND StartCycleMem;
srin_read	<= srin_read0;

-- Chargement du nombre d'horloge à retirer suivant si on est en slowcontrol ou en readout -- 7 à enlever en debug mode
Load_shift_order: PROCESS (n_reset, clock_machine)
BEGIN
	IF n_reset = '0' THEN 
		shift_order <= "0000";
	ELSIF (clock_machine'event AND clock_machine = '1' AND (StateMachine = "0001")) THEN	
			IF word_6(7) = '1' THEN shift_order <= ShiftDebug;  -- Debug mode : 1 clock tick only
				ELSIF (mem_w_sr = '1' OR mem_w_read = '1')
					THEN shift_order <= ShiftData;
			END IF;
	END IF;
END PROCESS Load_shift_order;

 input_cor_sr <= (sr_in0 XOR sr_out);
 input_cor_read <= (srin_read0 XOR srout_read);

correlation_sr : PROCESS (word_0(7), sr_ck0)
 BEGIN
 	IF word_0(7) = '0' THEN
 		checksum_sr <= '0';
 	ELSIF sr_ck0'event AND sr_ck0 = '1' THEN
 		IF input_cor_sr = '1' THEN checksum_sr <= '1';
 		END IF;
 	END IF;
 END PROCESS correlation_sr;

correlation_read : PROCESS (word_0(6), ck_read0)
 BEGIN
 	IF word_0(6) = '0' THEN
 		checksum_read <= '0';
 	ELSIF ck_read0'event AND ck_read0 = '1' THEN
 		IF input_cor_read = '1' THEN checksum_read <= '1';
 		END IF;
 	END IF;
 END PROCESS correlation_read;

mem_startcycle: PROCESS(n_reset, end_cycle, StartCycle)
BEGIN
	IF (end_cycle = '1' OR n_reset = '0') THEN
		StartCycleMem <= '0';
	ELSIF (StartCycle'EVENT  AND StartCycle = '1') THEN
			StartCycleMem <= '1';
	END IF;
END PROCESS mem_startcycle;
		
Serialiseur: 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 StartCycleMem = '0' THEN
									StateMachine 	<= "0000";
								ELSE
									StateMachine	<= "0001";
								END IF;
				WHEN "0001"	=> 	StateMachine	<= "0011";
				WHEN "0011"	=>	StateMachine	<= "0010";
				WHEN "0010"	=>	IF (empty = '1' AND Count = shift_order) THEN
									StateMachine 	<= "1010";
								ELSE
									StateMachine	<= "0110";
								END IF;
				WHEN "0110"	=>	IF (empty = '1') THEN
									StateMachine 	<= "0010";
								ELSE
									IF (count = "1000") THEN
										StateMachine	<= "0111";
									ELSE
										StateMachine	<= "0010";
									END IF;
								END IF;
				WHEN "0111"	=>	StateMachine	<= "0011";
				WHEN "1010"	=>	StateMachine	<= "1000";
				WHEN OTHERS	=>	StateMachine	<= "0000";
			END CASE;
	END IF;
END PROCESS Serialiseur;	

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

with StateMachine select
EN_Count <=	'1' when "0011", '1' when "0110",
			'0' when  others;

with StateMachine select
Clear_Count <= '1' when "0000", '1' when "0111", '1' when "1000",
			'0' when  others;

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

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

count_shift : count4bits PORT MAP (
		aclr	 => Clear_count OR NOT(n_reset),
		clk_en	 => EN_Count,
		clock	 => clock_machine,
		cout	 => Cout,
		q	 => count
	);

make_sel_word : PROCESS(subadd)
BEGIN
	CASE subadd IS
	WHEN "0000000"	=>	sel_word <= "00000001";	-- add(word_0) = 0
	WHEN "0000001"	=>	sel_word <= "00000010";	-- add(word_1) = 1
	WHEN "0000010"	=>	sel_word <= "00000100";	-- add(word_2) = 2
	WHEN "0000011"	=>	sel_word <= "00001000";	-- add(word_3) = 3
	WHEN "0000100"	=>	sel_word <= "00010000";	-- add(word_4) = 4
	WHEN "0000101"	=>	sel_word <= "00100000";	-- add(word_5) = 5
	WHEN "0000110"	=>	sel_word <= "01000000";	-- add(word_6) = 6
	WHEN "0000111"	=>	sel_word <= "10000000";	-- add(word_7) = 7
	WHEN OTHERS	=>	sel_word <= "00000000";
END CASE;
END PROCESS make_sel_word;

test_ERO1 : PROCESS (Resetb, End_ReadOut1, StartRO)
BEGIN
	IF Resetb = '0' THEN
		ERO1 <= '0';
	ELSE
		IF End_ReadOut1 = '1' THEN
			ERO1 <= '1';
 		ELSE
			IF StartRO'event AND StartRO = '1' THEN
			ERO1 <= '0';
			END IF;
		END IF;
	END IF;
END PROCESS test_ERO1;

test_ERO2 : PROCESS (Resetb, End_ReadOut2, StartRO)
BEGIN
	IF Resetb = '0' THEN
		ERO2 <= '0';
	ELSE
		IF End_ReadOut2 = '1' THEN
			ERO2 <= '1';
 		ELSE
			IF StartRO'event AND StartRO = '1' THEN
			ERO2 <= '0';
			END IF;
		END IF;
	END IF;
END PROCESS test_ERO2;

test_SCA : PROCESS (Resetb, ChipSatb, StartAcq)
BEGIN
	IF Resetb = '0' THEN
		Sat <= '0';
	ELSE
		IF (ChipSatb = '0' AND StartAcq = '1') THEN
			Sat <= '1';
 		ELSE
			IF StartAcq'event AND StartAcq = '1' THEN
			Sat <= '0';
			END IF;
		END IF;
	END IF;
END PROCESS test_SCA;

write_word_4(4)	<= ERO2;
write_word_4(3)	<= ERO1;
write_word_4(2)	<= Sat;
SPY1 <= input_cor_sr;
SPY2 <= Sat;
SPY3 <= Clear_Count;
SPY4 <= input_cor_read;

StartCycle	<= word_1(1);
write_word_4(7)	<= checksum_sr;
write_word_4(6)	<= checksum_read;
read_word_0 <= word_0;
read_word_1 <= word_1;
read_word_2 <= word_2;
read_word_3 <= word_3;
read_word_5 <= word_5;
read_word_6 <= word_6;
read_word_7 <= word_7;

END SYN;
