--2003-12-08 widen energy path (nrg) to 12 & 14 & 14 bit
 
 -- new version with VME control via narrow port, ready for JEM1 and test module


--to do: try 3 phibins(done), insync for any pattern, stop after 1st transition(done)

LIBRARY ieee ;
USE ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.ALL; 
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.all;

library work;
--use work.all;
use work.jem_pkg.all;
use work.jemtyp_pkg.all;
use work.input_pkg.all;

Library unisim;
use UNISIM.VComponents.all;
--use UNISIM.ALL;

ENTITY input_top IS
	port (
		HEADER04	:	in std_logic;	   
		HEADER05:	in std_logic;
		HEADER06	: in std_logic;
		HEADER07: 	in std_logic;
		HEADER08: 	in std_logic;
		HEADER09:	in std_logic;
		HEADER10	: in std_logic;
		HEADER11: 	out std_logic;
		HEADER12: 	out std_logic;
		HEADER13:	out std_logic;
		HEADER14	: out std_logic;
		CLK		:	in std_logic;
		LOCAL_ADDR	:	in std_logic_vector (3 downto 0);
		TTC_DATA		:	in std_logic_vector (7 downto 0);
		--links from 8 LVDS Deserializers:
		lvds_in : arr_ten (phibins*8-1 downto 0);
		lvds_Sync	:	in std_logic_vector(phibins*8-1 downto 0);
		lvds_STROBE	:	in std_logic_vector(phibins*8-1 downto 0);
		lvds_LOCK_LOSS	:	in std_logic_vector(phibins*8-1 downto 0); --is '1' when link is down!
		--VME interface signals:
		VME_CE			:	in std_logic;
		VME_WRITE		:	in std_logic;
		VME_AD	:	in std_logic;
		RDO_BUS_in		:	in std_logic_vector(11 downto 0);
		RDO_BUS_out		:	out std_logic_vector(11 downto 0);
		--parity-error point-to-point connection to controlFPGA or special LED:
		PARITY_ERROR		:	out std_logic;	--signal is not in proposed in PDR
		--to main processor:
		JET		:	out arr_five(phibins*4-1 downto 0);  -- is cells 4 downto 1
		--fan-out to backplane:
		FIOL		:	out arr_five(phibins*2-1 downto 0);	-- is cells 2,1
		FIOR		:	out arr_five(phibins-1 downto 0);	-- is cell 4
		-- energy sums
		ENERGY_SUM	:	out std_logic_vector(39 downto 0);	  -- 12 & 14 & 14
		--fan out to all concerning LVDS deserializers:
		LVDS_REN	    : out std_logic_vector(phibins*8-1 downto 0);
		LVDS_PWRDN   : out std_logic_vector(phibins*8-1 downto 0);
		--DAQ path signals:			 
		READ_REQUEST	:	in std_logic;
		DAQ_DATA_VALID	:	out std_logic;
		DAQ_OUT		:	out std_logic_vector(phibins-1 downto 0);
		refclk : out std_logic;
		enab : out std_logic_vector(3 downto 0);
		CRAP	:	out std_logic --F20(Schematics)
		);

END input_top ;

-- hds interface_end
ARCHITECTURE input_top OF input_top IS


component daq
generic(data_width   : integer :=88;	--	rtdp data width (either 50 or 88)
		frame_width	:	integer:=88;   -- frame length excl overall parity
		pipe_depth	:	integer:=latency_pipe;   -- latency buffer : shift register length 
--		pipe_depth	:	integer:=64;   -- latency buffer : shift register length 
--		pipe_depth	:	integer:=106;
		fifo_depth	:	integer:=256);   
port(
	clk 	: in std_logic; 
	reset 	: in std_logic; -- reset fifo only
	rtd_data	 	: in std_logic_vector(data_width-1 downto 0); -- real-time data in
	read_request 	: in std_logic; -- latch piped data into fifo
	data_valid 		: out std_logic;
	daq_out 	: out std_logic; -- serial out to ROC
	full 	: out std_logic); -- buffer full, next read request might get ignored
end component;
----- Component RAMB4_S16_S16 -----
component RAMB4_S16_S16
--
  generic (
       INIT_00 : bit_vector := X"0000000000000000000000000000000000000000000000000000000000000000";
       INIT_01 : bit_vector := X"0000000000000000000000000000000000000000000000000000000000000000";
       INIT_02 : bit_vector := X"0000000000000000000000000000000000000000000000000000000000000000";
       INIT_03 : bit_vector := X"0000000000000000000000000000000000000000000000000000000000000000");

--
  port (DIA    : in STD_LOGIC_VECTOR (15 downto 0);
        DIB    : in STD_LOGIC_VECTOR (15 downto 0);
        ENA    : in STD_logic;
        ENB    : in STD_logic;
        WEA    : in STD_logic;
        WEB    : in STD_logic;
        RSTA   : in STD_logic;
        RSTB   : in STD_logic;
        CLKA   : in STD_logic;
        CLKB   : in STD_logic;
        ADDRA  : in STD_LOGIC_VECTOR (7 downto 0);
        ADDRB  : in STD_LOGIC_VECTOR (7 downto 0);
        DOA    : out STD_LOGIC_VECTOR (15 downto 0);
        DOB    : out STD_LOGIC_VECTOR (15 downto 0)); 
end component;



component CLKDLL
port(
	CLKIN	:	in std_logic;
	CLKFB	:	in std_logic;
	RST		:	in std_logic;
	CLK0		:	out std_logic;
	CLK90	:	out std_logic;
	CLK180	:	out std_logic;
	CLK270	:	out std_logic;
	CLK2X	:	out std_logic;
	CLKDV	:	out std_logic;
	LOCKED	:	out std_logic);
end component;


component BUFG
port(
	I	:	in std_logic;
	O	:	out std_logic);
end component;

component IBUFG
port(
	I	:	in std_logic;
	O	:	out std_logic);
end component;


-- constants
constant channels : integer :=phibins*8;
constant jetels : integer :=phibins*4;

-- attributes
--attribute iob: string;
--attribute iob of data_80 : label is "true";
--attribute iob of NoIOB: label is "false";

attribute maxdelay: string;
--attribute maxdelay of phasedet : signal is "500ps";
attribute maxdelay of lvds_in : signal is "500ps";
attribute maxskew: string;
attribute maxskew of lvds_in : signal is "500ps";
--attribute loc of header04 : signal is "Y18";

-- signals
signal parity_error_int, pat_error_int	: std_logic_vector(channels-1 downto 0);
signal pERROR_int : std_logic;
signal DESER_LOCK,DESERIAL_LOCK,des_lock, des_lock1 : std_logic_vector(channels-1 downto 0);
signal READ_REQUEST_TMP	:	std_logic;
signal RDO_BUS_out_tmp,RDO_BUS_out_int, RDO_BUS_in_tmp,RDO_BUS_in_tmp_1 : std_logic_vector(11 downto 0);
signal S_CE,WRITE_EN : std_logic;
signal ADDR_IN : std_logic_vector(10 downto 0);
signal DATA_READ,data_read1,DATA_WRITE : std_logic_vector(11 downto 0);
signal CLK0_h,CLK0_w,CLK2X_h,CLK2X_w : std_logic;
signal CLKIN_w,CLK40,CLK80,DLL_LOCK : std_logic;
signal DLL_RST : std_logic;
signal PLAY_ENABLE : std_logic;
signal PLAYBACK_DATA : std_logic_vector(9*channels-1 downto 0);
signal RESET : std_logic;
signal START_PLAY,STOP_PLAY,START_PLAY_256 : std_logic;	--start/stop playback loop
signal START_PHASE_DET,START_SPY_256 : std_logic;	--start/stop lvds synchronisation
signal Phasedet		: std_logic_vector (channels-1 downto 0);
signal ttc_cmd : std_logic_vector(3 downto 0);
signal clk90,clk90_w : std_logic;
signal 	READ_REQUEST_int : std_logic;
signal 	DAQ_DATA_VALID_int, DAQ_OUT_int,DAQ_DATA_VALID_TMP,DAQ_OUT_TMP : std_logic_vector(phibins-1 downto 0);


signal IADDR_VME : std_logic_vector(7 downto 0);
signal phase_det : std_logic_vector(channels-1 downto 0);
signal indat,indat1 : arr_ten(channels-1 downto 0);		  
signal lat_corr : arr_two(channels-1 downto 0);

type arr_daq is array (integer range <>) of std_logic_vector (87 downto 0);
signal DATA_DAQ	:	arr_daq(phibins-1 downto 0);

signal des_phase,p_pos,p_neg : std_logic_vector(channels-1 downto 0);
signal phase_set : std_logic_vector(channels-1 downto 0);
--signal ppipe,npipe : arr2ten (channels-1 downto 0,3 downto 0);
signal inpipe : arr2ten (channels-1 downto 0,2 downto 0);
signal I_neg,ineg,i_pos : arr_ten(channels-1 downto 0);
signal jet_elm,jet_elm_int,jet_elm_tmp : arr_ten(jetels-1 downto 0);
signal fiol_elm : arr_ten(phibins*2-1 downto 0);
signal fior_elm : arr_ten(phibins-1 downto 0);
signal THRESHOLD,threshhigh : std_logic_vector(9 downto 0);
signal OUTMASK_int : std_logic_vector(channels-1 downto 0);
signal llc_enable : std_logic_vector(channels-1 downto 0);
signal rrq,cmd : std_logic;
signal last_cmd : std_logic_vector(3 downto 0); 
signal vme_done : std_logic;
signal reset_ps : std_logic;
signal v_play_mem:std_logic_vector(9 downto 0);

signal WEA,ENA,RSTA,ENB	: std_logic;
signal DIB	:	STD_LOGIC_VECTOR (15 downto 0);								  
signal DIA,DOA,DOB : arr_sixteen(spychn-1 downto 0);															 
signal ADDRA,ADDRB : STD_LOGIC_VECTOR (7 downto 0);
signal WEB,RSTB : STD_LOGIC_VECTOR(spychn-1 downto 0);

--signal sync_spy_out: std_logic_vector(channels-1 downto 0);
signal enable_play,spy_int,play_int : std_logic;

signal readport_int, WRITEport_int,WRITEport_int_h,WRITEport_int_c	:	std_logic_vector(3 downto 0);
signal start_int,start_int_h,start_int_c, write_int,write_int_h,write_int_c,vclock_int : std_logic;
signal rcnt_int : std_logic_vector(1 downto 0);
signal read_start : std_logic;
signal clock_vec_tmp,clock_vec : std_logic_vector(11 downto 0);
signal clock_tmp : std_logic;
signal local_addr_0 : std_logic_vector(3 downto 0);

signal pulse_REG,CONTROL_REG:	std_logic_vector(11 downto 0);
signal chan_con,coeff	:arr_twelve(channels-1 downto 0);		
signal clk90a : std_logic;

signal crap0 : std_logic_vector(4+channels downto 0);
signal phase_in:	std_logic_vector(channels-1 downto 0);
signal clk_aux : std_logic;
signal esum_int : std_logic_vector(39 downto 0);
signal en_sum : arr_fourteen(2 downto 0);
signal nrgv: std_logic_vector(39 downto 0);										
signal ofl,oflp:std_logic;
signal sumarrv : arr2sixteen(2 downto 0, 2*jetels-2 downto 0);
signal clk180,clk180_w : std_logic;

signal dbg : std_logic;
signal rck : std_logic_vector(3 downto 0);

signal modnum : integer range 0 to 3;
signal inchan,inchan1 : arr_twelve(channels-1 downto 0);
signal lac : std_logic;


BEGIN
-----------------------
--new clock generation:
-----------------------
--INACTIVE<='0';
clkpad	:	IBUFG	port map (I=>CLK,O=>CLKIN_w);
dll		:	CLKDLL	port map (CLKIN=>CLKIN_w,CLKFB=>CLK2X_h,RST=>DLL_RST,
     CLK0=>CLK0_w,CLK2X=>CLK2X_w,LOCKED=>DLL_LOCK);
a1		:	BUFG 	port map (I=>CLK0_w,O=>CLK0_h);
a2		:	BUFG	port map (I=>CLK2X_w,O=>CLK2X_h);
CLK40<=CLK0_h;
CLK80<=CLK2X_h;
--HEADER4<=CLK40;

refclk<='Z' when jem0 else clk40;
enab<="ZZZZ" when jem0 else control_reg(7 downto 4);


-----------------
---VME_Handling:
-----------------
--synchronise

process(CLK40)				-- I/O FFs
variable s_ce_vec: std_logic_vector(5 downto 0);
variable vme_done_tmp: std_logic;
begin 
	if falling_edge(CLK40) then
		RDO_BUS_in_tmp <= RDO_BUS_in;
	end if;
	if rising_edge(CLK40) then
		RDO_BUS_in_tmp_1 <= RDO_BUS_in_tmp;
		RDO_BUS_out <= RDO_BUS_out_tmp;	
		S_CE<=VME_CE;
	end if;
end process;


RDO_BUS_out_int(3 downto 0) <= readport_int;
RDO_BUS_out_int(4) <= read_start;
RDO_BUS_out_int(11 downto 10) <= rcnt_int ;			


RDO_BUS_out_tmp <= rdo_bus_out_int when s_CE='1' else RDO_BUS_in_tmp;			




start_int_c<=RDO_BUS_IN_tmp_1(5) when s_CE='1' else '0';
write_int_c<=RDO_BUS_IN_tmp_1(4) when s_CE='1' else '0';
WRITEport_int_c<=RDO_BUS_IN_tmp_1(3 downto 0); 

WRITEport_int <= WRITEport_int_c when s_ce='1' else WRITEport_int_h;
start_int <= start_int_c when s_ce='1' else start_int_h;
write_int <=  write_int_c when s_ce='1' else write_int_h;
  

process(CLK40)				-- I/O FFs
begin 
	if rising_edge(CLK40) then

-- frame start,write,4 bit A/D

WRITEport_int_h(0)<=header04; 
WRITEport_int_h(1)<=header05; 
WRITEport_int_h(2)<=header06; 
WRITEport_int_h(3)<=header07; 
write_int_h<=header08 ;
start_int_h<=header09 ;
vclock_int<=header10 ;	
header11 <= readport_int(0) ;
header12 <= readport_int(1) ;
header13 <= readport_int(2) ;
header14 <= readport_int(3) ;
	end if;
end process;





vport_lab:process(CLK40)
-- VME ports : WRITEport_int, readport_int, start_int, write_int
-- generate  addr_in,  data_write, write_en and multiplex data_read to readport_int
variable wcnt,rcnt,ioffset: integer range 0 to 8;
variable addr_tmp: std_logic_vector(7 downto 0);
variable write_tmp,read_tmp: std_logic_vector(11 downto 0);
variable read_tmp1,addr_low_tmp: std_logic_vector(3 downto 0);
variable write_en_tmp,vme_done_tmp,rs_tmp: std_logic;



begin
	if rising_edge(CLK40) then


--new--v
clock_vec_tmp<=clock_vec_tmp(10 downto 0) & vclock_int;
if clock_vec_tmp="000000000001" or clock_vec_tmp="111111111110" then clock_tmp<='1'; else clock_tmp<='0'; end if;
clock_vec<=clock_vec(10 downto 0) & clock_tmp;
--new--^

	 rcnt:=3;
	 rs_tmp:='0';
	  
	 if s_ce='1' then ioffset:=3; else ioffset:=0; end if;
	 write_en_tmp:='0';
	 vme_done_tmp:='0';

	 if clock_tmp='1' or s_ce='1' then	  -- valid data window after clock only unless	RDO controlled				  2-oct a

		if start_int='1' then
			wcnt:=0;
		elsif wcnt/= 8  then
			wcnt:=wcnt+1;
		end if;

		for i in 0 to 2 loop
			if i+2+ioffset=wcnt then  
				read_tmp1:=data_read(4*i+3 downto 4*i);	
				rcnt:=i;
				if i=0 then rs_tmp:='1'; end if;
			end if;
		end loop;


	 end if;

	 if clock_vec(11)='1' or s_ce='1' then	  -- valid data window after clock only unless	RDO controlled				  2-oct a

-- keep addr_tmp at old value while updating to allow for proper vme_done timing
		if wcnt=0 then addr_low_tmp :=writeport_int; end if;
		if wcnt=1 then addr_tmp :=writeport_int & addr_low_tmp; end if;

		for i in 0 to 2 loop
			if i+2=wcnt then  write_tmp(4*i+3 downto 4*i):=writeport_int; end if;
--			if i+2=wcnt then  read_tmp1:=read_tmp(4*i+3 downto 4*i);	end if;
		end loop;
		if wcnt=0 then vme_done_tmp:='1'; end if;
		if wcnt=4 and write_int='1' then write_en_tmp:='1'; end if;
	 end if;
	 ADDR_IN<="00" & addr_tmp&"0";
	 data_write<=write_tmp;
	 write_en<=write_en_tmp;
	 readport_int <=read_tmp1;
	 vme_done<=vme_done_tmp;
	 rcnt_int<= conv_std_logic_vector(rcnt,2);
	 read_start<=rs_tmp;
	end if;
end process;


--dbg <= clock_tmp;		--- debug


--re-map RTDP I/O
PROCESS(clk40)
	variable tmp: std_logic;
  BEGIN
   IF rising_edge(clk40) THEN 
	CRAP0<=lvds_strobe & TTC_DATa(7 downto 6) & vme_ad & vme_write & s_ce; 
		for i in 0 to 12 loop
			tmp:=tmp or crap0(i);
		end loop;
	 crap <=tmp;
	LOCAL_ADDR_0 <= local_addr;
	END IF;
  END PROCESS;

gl1:	for i in 0 to channels -1 generate
--		phase_in(i)<= lvds_in(i)(1) ;
		lvds_REN(i)<='1';  
		lvds_PWRDN(i)<= '1';  
	end generate;

	READ_REQUEST_int<= READ_REQUEST;
	DAQ_DATA_VALID<=DAQ_DATA_VALID_int(0);

	DAQ_OUT <= DAQ_OUT_int;


	DLL_RST<=TTC_DATA(0);

PROCESS(clk40)
  BEGIN
   IF rising_edge(clk40) THEN 
	reset<=ttc_data(5);
		parity_error <= perror_int;
	END IF;
  END PROCESS;


----------------------------------------------------------------------------------------
--Input FFs @ 80MHz:
process(CLK80)	 
begin	 
if falling_edge(CLK80) then  
	for i in 0 to channels-1 loop
--		phasedet(i)<= lvds_in(i)(1);
-- use clock for insync
		phasedet<=lvds_strobe;
	end loop;
end if;
if rising_edge(CLK80) then
	for i in 0 to channels-1 loop
		inchan(i)<= LVDS_LOCK_LOSS(i) & phasedet(i) & lvds_in(i);
	end loop;
end if;
end process;
--re-order channels at 80-40 domain boundary
lab_porder: for i in 0 to channels-1 generate

lab_p1:	with modnum select -- force synthesis tool to build muxes
	inchan1(i)<=
		inchan(inporder(i)) when 0,
		inchan(inporder(i+channels)) when 1,
		inchan(inporder(i+2*channels)) when 2,
		inchan(inporder(i+3*channels)) when others;

--lab_p1: for j in 0 to 3 generate	 --enforce muxes
--lab_p2 : if j=modnum generate indat(i)<=inchan(inporder(i+j*channels));	end generate;
--end generate;

	indat(i) <=inchan1(i)(9 downto 0);
	des_phase(i) <= inchan1(i)(10);
	DESER_LOCK(i) <=inchan1(i)(11);

end generate;

-- output FFs no DDR registers!
energy_sum <= esum_int when not jem0 else (others =>'Z');

PROCESS(clk40)
variable lacx,lacy : std_logic :='0'; --initialise (for simulation)
  BEGIN
   IF rising_edge(clk40) THEN lacx := not lacx; END IF;
   IF falling_edge(clk40) THEN lacy := lacx;  END IF;
	lac <= lacx xor lacy;
  END PROCESS;


process(Clk80)
begin	 
	if rising_edge(Clk80) then
		for i in 0 to 4 loop -- bits
		 for j in 0 to jetels-1 loop 
			if lac='1' then jet(j)(i)<= jet_elm(j)(i); else jet(j)(i)<=jet_elm(j)(i+5); end if;
		 end loop;

		 for j in 0 to phibins*2-1 loop 
			if lac='1' then fiol(j)(i)<= fiol_elm(j)(i); else fiol(j)(i)<=fiol_elm(j)(i+5); end if;
		 end loop;

		 for j in 0 to phibins-1 loop 
			if lac='1' then fior(j)(i)<= fior_elm(j)(i); else fior(j)(i)<=fior_elm(j)(i+5); end if;
		 end loop;
		end loop;
	end if;
end process;
---------------------------------------------------------------------------------

---------------------------------------------------
--TTC_DATA handling:
---------------------

process(CLK40)		 --input FFs
begin
	if rising_edge(CLK40) then
	TTC_CMD<=TTC_DATA(4 downto 1);
	end if;
end process;

STOP_PLAY<='1' 		when TTC_cmd=in_STOP_PLAY 			else '0';	  --stop playback
START_PLAY<='1' 		when TTC_cmd=in_START_PLAY 		else '0';	  --start playback	
START_PLAY_256<='1' 	when TTC_cmd=in_START_PLAY_256 	else '0';     --do 256 playback/spy cycles and stop
START_SPY_256<='1' 	when TTC_cmd=in_START_SPY_256 	else '0';	  --do 256 spy cycles and stop (input delay scan and main also)
START_PHASE_DET<='1' when TTC_cmd=in_START_PHASE_DET 	else '0';	  --start input phase determination
----------------------------------------------

process(CLK40)				-- added for Cano 15.08.03
variable cmdcnt,l1cnt : integer range 0 to 4000000 :=0;
begin
	if rising_edge(CLK40) then
		READ_REQUEST_TMP<=READ_REQUEST_int;
		if TTC_CMD/=in_no_cmd then 		 --ttc command
			last_cmd<=TTC_CMD;	
			cmdcnt:=cmdcnt+1;
		end if;
		if cmdcnt /=0 then   
			cmdcnt:=cmdcnt+1; 
			cmd<='1' ;
		else
			cmd<='0'	;
		end if;

		if READ_REQUEST_TMP = '1' then   
			l1cnt:=l1cnt+1; 
		end if;		--l1acc
		if l1cnt /=0 then   
			l1cnt:=l1cnt+1;
			rrq<='1';
		else
			rrq<='0';
		end if;	

	end if;																							 
end process;
														
--------------------------------------------------------------------------------
---------------------- DAQ PATH ------------------------------------------------
--------------------------------------------------------------------------------
gedaq: for i in 0 to phibins-1 generate
DAQ0:daq port map
		(--general signals:
		clk=>CLK40,reset=>RESET,
		---Input:
		rtd_data=>DATA_DAQ(i),read_request=>READ_REQUEST_int,
		---Output:
		data_valid=>DAQ_DATA_VALID_TMP(i),daq_out=>DAQ_OUT_TMP(i),
		---VME_Signals:
		full=>open
		);	
end generate;

--process(CLK40)		 -- will in future go into ihe instance !!!!! check total ff cnt required and check w.	main & ROC
--begin
--	if CLK40'event and CLK40='1' then
		DAQ_OUT_int<=DAQ_OUT_TMP;
		DAQ_DATA_VALID_int<=DAQ_DATA_VALID_TMP;
--		READ_REQUEST_TMP<=READ_REQUEST_int;
--	end if;
--end process;

---------------------------------------
--- rtdp  ============================================

process(CLK40)
--process(ppipe,npipe,playback_data,outmask_int,des_lock,des_lock1,lat_corr,p_pos,p_neg,play_enable,threshold,phase_set)
-- bring into 'event loop again since there is no latency issue on jem1 jet algorithm
variable i: integer range 0 to channels-1;
variable par_err_vec: std_logic_vector(channels-1 downto 0);
variable parerr,perrtot,lockerr:std_logic;
variable itmp:integer range 0 to 3;
variable etmp,esum : std_logic_vector(9 downto 0);
variable earr : arr_ten(jetels-1 downto 0);
variable sumarr : arr2sixteen(2 downto 0, 2*jetels-2 downto 0);
variable farrl : arr_ten(phibins*2-1 downto 0);
variable farrr : arr_ten(phibins-1 downto 0);
variable synced_tmp : arr_ten(channels-1 downto 0);
variable daq_tmp : arr_daq(phibins-1 downto 0);
variable llc_tmp,des_lock_tmp: std_logic_vector(channels-1 downto 0);
variable estmp :std_logic_vector(21 downto 0);
variable ex, ey, et :std_logic_vector(13 downto 0);
variable ofls,oflj: std_logic;
variable esum_tmp : std_logic_vector(39 downto 0);
variable etp : arr_sixteen(2 downto 0);
variable nrg: std_logic_vector(39 downto 0);

variable tmptmp : arr_nine(channels-1 downto 0);	--debug

begin
 if falling_edge(CLK40) then
	p_neg<=des_phase;
	Ineg<=indat;
 end if;

 if rising_edge(CLK40) then
	p_pos<=des_phase;

	i_pos<=indat;
	i_neg<=ineg;
	des_lock <= deser_lock;
	des_lock1 <= des_lock;

  perrtot:='0';
  ofls:='0';
  for p in 0 to phibins-1 loop		--	phi
	for e in 0 to 3 loop				-- eta
		esum:=zero10;
		oflj:='0';
		for y in 0 to 1 loop			-- energy e/h
			i:=8*p+e*2+y;				-- linear channel address,energy index lowest	used on rtdp and DAQ

			if des_lock(i)='1' and des_lock1(i)='0' then	LLC_tmp(i):='1'; else LLC_tmp(i):='0'; end if;
			lockerr:=des_lock(i);
			phase_det(i)<=not(P_POS(i) XOR p_neg(i));		-- evaluate and re-time ?? phase bits

			if phase_set(i)='0'then	  -- stick to non-delay = 0 !
				etmp:=i_pos(i);
			else
				etmp:=i_neg(i);
			end if;
			inpipe(i,0)<=etmp;
			for idepth in 0 to 1 loop						-- latency pipe 3 ticks
				inpipe(i,idepth+1) <= inpipe(i,idepth);	
			end loop;
			itmp:=conv_integer(lat_corr(i));
			if itmp /=0 then etmp:=inpipe(i,itmp-1); end if;
			synced_tmp(i):=etmp;	 -- to spy memories			 K
------------------------------synchronised now-------------------------
			parerr:='1';	-- odd parity
			for ibit in 0 to 9 loop
				parerr:=parerr xor etmp(ibit);
			end loop;
			if parerr='1' then perrtot:='1'; end if;
--debug

if tmptmp(i)/= etmp(9 downto 1) then pat_error_int(i)<='1'; end if;
if etmp(9 downto 1)=x"1FF" then 
	tmptmp(i):=(others=>'0');
else
	tmptmp(i):=	etmp(9 downto 1)+1;
end if;


			par_err_vec(i):=parerr;
			if PLAY_ENABLE='1' then parerr:='0'; lockerr:='0'; end if;
			etmp:="0" &	etmp(9 downto 1);
			if PLAY_ENABLE='1' then etmp:=  "0" & PLAYBACK_DATA(9*i+8 downto 9*i); end if;				  --K
--			daq_tmp(p)(11*i+10 downto 11*i):=lockerr & parerr & etmp(8 downto 0);
			daq_tmp(p)(11*(e*2+y)+10 downto 11*(e*2+y)):=lockerr & parerr & etmp(8 downto 0);
			if PARERR = '1' or lockerr='1' or OUTMASK_int(i)='1' then
			  etmp:=zero10; 
			end if;
			if etmp="0"&full9 then 
				ofls:='1';
				oflj:='1';
			end if;
			esum:=esum+etmp;		  
		end loop;
		etmp:=esum;
		if oflj='1' then 	etmp:=(others=>'1'); end if;
		earr(4*p+e) := etmp;
-- energy sum...
		if esum < THRESHOLD then esum:=(others=>'0'); end if;
		jet_elm_tmp(4*p+e)<=esum;	
	end loop;
	farrl(2*p):=earr(4*p); 	   --fio
	farrl(2*p+1):=earr(4*p+1); 
	farrr(p):=earr(4*p+3); 
  end loop;
--------------------------------------------------------------------
-- energy sum path																									 			
	ofl<=ofls;
	ofls:=ofl;
	oflp<=ofl;
	if jem0 then ofls:=oflp; end if;

	for i in 0 to jetels-1 loop
		etmp:= jet_elm_tmp(i);		
		for j in 0 to 1 loop 
			estmp:= etmp*coeff(2*i+j)(11 downto 0);		  					--Ex,y
			sumarr(j,i):="0000" & estmp(21 downto 10); 
		end loop;
		if etmp < threshhigh then etmp:=(others=>'0'); end if;	--Et
		sumarr(2,i):="0000" & etmp &"00"; 
	end loop;
	sumarrv<=sumarr;
	if jem0 then sumarr:=sumarrv; end if;


	for j in 0 to 2 loop
		for i in 0 to jetels-2 loop
			sumarr(j,jetels+i):=sumarr(j,2*i)+sumarr(j,2*i+1) ;
		end loop;
		etp(j):=sumarr(j,2*jetels-2);
		if ofls='1' or etp(j)(15 downto 14)/="00" then etp(j):=(others=>'1'); end if;

	end loop;
	esum_tmp:=etp(2)(13 downto 2) & etp(1)(13 downto 0) & etp(0)(13 downto 0);
	nrg:=esum_tmp;	
	esum_int<=esum_tmp;

---------------------------------------------------------------------
	for i in 0 to 3 loop
		if jem0 and control_reg(2)='1' then earr(i) :=nrg(i*10+9 downto i*10); end if;
	end loop;
	jet_elm<=earr;
	jet_elm_int<=earr;
	PARITY_ERROR_int<=par_err_vec;
	fiol_elm<=farrl;
	fior_elm<=farrr;
	data_daq<=daq_tmp;
--sync_check<=sync_tmp;
	llc_enable<=llc_tmp;
	perror_int <= perrtot;
--for i in 0 to channels-1 loop
--	dia(i) <=zero6 & synced_tmp(i);
--end loop;
	if jem0 then
	for i in 0 to 3 loop
		dia(i) <=zero6 & synced_tmp(i);
		if control_reg(1)='0' then
			dia(i+4) <=zero6 & synced_tmp(i+4);
		else
			dia(i+4) <=zero6 & jet_elm_int(i);
		end if;

	end loop;

	else
		for i in 0 to channels-1 loop
			dia(i) <=zero6 & synced_tmp(i);
		end loop;

--		for i in 0 to phibins*4-1 loop
--			dia(channels+i) <=zero6 & jet_elm_int(i);
--		end loop;

--		for i in 0 to 2 loop
--			dia(phibins*12+i) <="0000" & etp(i)(13 downto 2);
--		end loop;


	end if;


end if;
end process;


--================================================================

process(CLK40)
variable channel:integer range 0 to 31; --cover 5 address bits
variable sub_addr_g:std_logic_vector(7 downto 0);
variable sub_addr_c:std_logic_vector(3 downto 0);
variable read_tmp,pulse_reg_tmp:std_logic_vector(11 downto 0);
variable sync_count:integer range 0 to 7;
variable do_sync:std_logic;
variable link_err_REG,par_err_REG,test_pat_err_reg,chan_stat : arr_twelve(channels-1 downto 0);

begin
if rising_edge(CLK40) then
-- sync state machine
	do_sync:='0';
	if START_PHASE_DET='1' or sync_count /=0 then
		do_sync:='1';
		if sync_count=7 then sync_count:=0; else  sync_count:=sync_count+1; end if;
	end if;
-- connect bits to channel registers
	for i in 0 to channels-1 loop
-- control bits: 		  -- phase further down!
		phase_set(i)<=chan_con(i)(0);
		lat_corr(i)<=chan_con(i)(2 downto 1);
		outmask_int(i)<=chan_con(i)(3);
-- status bits: current lock status on bit 0
		chan_stat(i):=(others=>'0');
		chan_stat(i)(0):=des_lock(i);
	end loop;

--VME 
	channel:=conv_integer(addr_in(8 downto 4));
	pulse_reg_tmp:=(others=>'0');
-- reset
	if reset='1' then
		control_reg<=(others=>'0');		 --global
		threshold<=(others=>'0');
		threshhigh<=(others=>'0');
		for i in 0 to channels-1 loop		 --channel
			chan_con(i)<=(others=>'0');
			coeff(i)<=(others=>'0');
		end loop;
-- phase set
	elsif do_sync='1' then
		for i in 0 to channels-1 loop
			chan_con(i)(0)<=phase_det(i);
		end loop;
-- write
	elsif write_en='1' then
		if channel < 8
		then   -- global space
			sub_addr_g:=addr_in(7 downto 0);
			if sub_addr_g=add_control_reg then control_reg<=data_write; end if;
			if sub_addr_g=add_threshlow_reg then threshold<=data_write(9 downto 0); end if;
			if sub_addr_g=add_threshhigh_reg then threshhigh<=data_write(9 downto 0); end if;
			if sub_addr_g=add_pulse_REG then pulse_REG_tmp:=data_write;end if;
--			if sub_addr_g=add_playspy_REG then access_playspy_tmp<='1'; end if;	-- decode playspy in playspy code
		else	 -- channel space
			channel:=channel-8;
			sub_addr_c:=addr_in(3 downto 0);
			if sub_addr_c=ch_control_reg then chan_con(channel)<=data_write; end if;
			if sub_addr_c=ch_mult_REG then coeff(channel)<=data_write; end if;
		end if;
	end if;
	pulse_REG<=pulse_REG_tmp;
--read always	
	read_tmp:=zero12;
	if channel < 8
	then   -- global space
		sub_addr_g:=addr_in(7 downto 0);
		if sub_addr_g=add_VERSION_REG then read_tmp:=input_version; end if;
		if sub_addr_g=add_control_reg then read_tmp:=control_reg; end if;
		if sub_addr_g=add_STATUS_REG then read_tmp:="00" & LOCAL_ADDR_0 & RRQ & cmd &last_cmd; end if;
		if sub_addr_g=add_threshlow_reg then read_tmp:="00"&threshold; end if;
		if sub_addr_g=add_threshhigh_reg then read_tmp:="00"&threshhigh; end if;
		if sub_addr_g=add_playspy_REG then read_tmp:="00"&V_play_mem; end if;
--		if sub_addr_g=add_syncspy_REG then read_tmp:="0000"&sync_spy_out; end if;
	else	 -- channel space
		channel:=channel-8;
		sub_addr_c:=addr_in(3 downto 0);
		if sub_addr_c=ch_control_reg then read_tmp:=chan_con(channel); end if;
		if sub_addr_c=ch_status_REG then read_tmp:=chan_stat(channel); end if;
		if sub_addr_c=ch_link_err_REG then read_tmp:=link_err_REG(channel); end if;
		if sub_addr_c=ch_par_err_REG then read_tmp:=par_err_REG(channel); end if;
		if sub_addr_c=ch_mult_REG then read_tmp:=coeff(channel); end if;
		if sub_addr_c=ch_test_pat_err_REG then read_tmp:=test_pat_err_REG(channel); end if;

	end if;
	DATA_READ1<=read_tmp; -- delayed 1 tick !!!

--error counters
	for i in 0 to channels-1 loop
		if (reset or pulse_reg(0))='1' then link_err_reg(i):=zero12; end if;
		if (reset or pulse_reg(1))='1' then par_err_reg(i):=zero12;	 end if;
		if (reset or pulse_reg(3))='1' then test_pat_err_reg(i):=zero12;	 end if;
		if parity_error_int(i)='1' then										 
			if par_err_reg(i)/=full12 then par_err_reg(i):=par_err_reg(i)+'1'; end if;
		end if;
		if llc_enable(i)='1' then
			if link_err_reg(i)/=full12 then link_err_reg(i):=link_err_reg(i)+'1'; end if;
		end if;
		if pat_error_int(i)='1' then										 
			if test_pat_err_reg(i)/=full12 then test_pat_err_reg(i):=test_pat_err_reg(i)+'1'; end if;
		end if;

	end loop;

end if;
end process;


enable_play <= control_reg(0);
modnum <= 0 when jem0 else conv_integer(control_reg(5 downto 4));
--pulsed signals		

reset_ps <= RESET or pulse_reg(2)or pulse_reg(3);

play_int<= pulse_reg(8);
spy_int <= pulse_reg(9);



---------------------------------------------------------------------
---------------- PlaySpy --------------------------------------------
---------------------------------------------------------------------

-- do it 10 bit wide, ignore bit 9 when playback. for spy it's 10 raw data bits
--play 256, play forever, spy256
-- single port, n*256 words, VME R/W, reset VMEcnt via control reg
process(clk40,iaddr_vme)
variable rcnt,vcnt,mcnt,int_addra : integer range 0 to bram_depth-1 :=0; -- counters for real-time data path	and VME access
variable do_play,do_spy,continuous, ps_write_acc: boolean; 
begin
	if rising_edge(clk40) then		
	-- TTC commands
		if play_int='1' or start_play_256='1' then
			continuous:=false;
			do_play:=true; 
		end if;
		if start_play='1'	 then
			continuous:=true;
			do_play:=true; 
		end if;
		if stop_play='1' then   
			continuous:=false;
			do_play:=false;
		end if;
		if spy_int='1'or (start_spy_256='1' and enable_play='0') then   
			do_spy:=true;
		end if;
	-- rtdp memory access
		int_addra:=rcnt;
		if iaddr_vme=IA_PLAY_MEM and write_en='1' then ps_write_acc:=true;else ps_write_acc:=false; end if;
	-- rtdp counter
		if rcnt=0 then				
			if do_play or do_spy then rcnt:=rcnt+1; end if;
		elsif rcnt/= bram_depth-1 then 
			rcnt:=rcnt+1; 
		else 
			rcnt :=0;
			if not continuous then do_play:=false;end if;
			do_spy:=false;
		end if;
		if (not do_spy) and (not do_play) then rcnt:=0;	end if;	-- keep zero when not in use
	-- VME counter
		if vme_done='1' and (iaddr_vme=IA_PLAY_MEM or iaddr_vme=IA_SPY_REG) then			 
			if mcnt=spychn-1 or iaddr_vme=IA_SPY_REG  then 
				mcnt :=0;
				if vcnt/= bram_depth-1 then 
					vcnt:=vcnt+1; 
				else 
					vcnt :=0;
				end if;
			else 
				mcnt:=mcnt+1; 
			end if;
		end if;
		if reset_ps='1' then 
			vcnt:=0;
			mcnt:=0;
		end if;		


-- map externals: 
	if do_play then PLAY_ENABLE<='1'; else  PLAY_ENABLE<='0' ; end if;
-- memory signals
	if do_spy then WEA <='1'; else WEA<='0'; end if;
	ADDRA	<= conv_std_logic_vector(int_addra,8);
	ADDRB	<= conv_std_logic_vector(vcnt,8);
	for i in 0 to spychn-1 loop
		if (i=mcnt) and ps_write_acc 			then WEB(i) <='1'; else WEB(i) <='0'; end if;	-- positive logic
		if  i=mcnt or iaddr_vme=IA_SPY_REG	then RSTB(i)<='0'; else RSTB(i)<='1'; end if;	-- a '1' zeroes output data
	end loop;
	end if;
end process;


ENA<='1';
ENB<='1';
RSTA<='0';
DIB<=zero6 & DATA_WRITE(9 downto 0); 

gen_ps : for i in 0 to spychn-1 generate		
-- a-port is RTDP, b-port is VME.	common wea, common addresses, separate web,rstb.
lab_ps : RAMB4_S16_S16 port map (	
			WEA=>WEA,ENA=>ENA,RSTA=>RSTA,CLKA=>CLK40,ADDRA=>ADDRA,DIA=>DIA(i),
			DOA=>DOA(i), WEB=>WEB(i),										 
			ENB=>ENB,RSTB=>RSTB(i),CLKB=>CLK40,ADDRB=>ADDRB,DIB=>DIB,DOB=>DOB(i));		
end generate;

gen_ps1 : for i in 0 to channels-1 generate		
			PLAYBACK_DATA(9*i+8 downto 9*i)<=doa(i)(8 downto 0);
end generate;

process(dob) -- OR the VME ports
variable tmp : std_logic_vector(9 downto 0);
begin
	tmp:=zero10;
	for i in 0 to spychn-1 loop
		for k in 0 to 9 loop
			tmp(k):=tmp(k) or dob(i)(k);
		end loop;
	end loop;
v_play_mem<=tmp;
end process;






IADDR_VME<=ADDR_IN(7 downto 0);

--VME read
with IADDR_VME select
DATA_READ<=	
--	 	("0000" & sync_SPY_OUT(7 downto 0)) when ia_SPY_REG,
		("00" & v_play_mem) when IA_PLAY_MEM,
		data_read1 when others;
-------------------------------------





END input_top;
