library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_misc.all;
use work.pack.all;

entity ceros is
	port (
	clkin_p, load_paepaf, mrs, reset, clk_slow: in std_logic;
	clk20_p, locked_p: out std_logic;
-- vme
	etr_x, enw, cs: in std_logic;
	add: in std_logic_vector(5 downto 0);
	db: inout std_logic_vector (15 downto 0);
-- fifos
	ef, ff, paf, lock: in std_logic_vector (5 downto 0);
	par: in std_logic_vector (1 downto 0);
	fout: in std_logic_vector (15 downto 0);
	hasul: out std_logic_vector (5 downto 0);
	fmrs, fsi, fsen, fld, wclkena_p, recoff_p: out std_logic;
	oe, ren: out std_logic_vector(5 downto 0);
-- transmiter + control
	valen, token: in std_logic;
	txena_p, ceros_done_p: out std_logic;
	evid: in std_logic_vector (11 downto 0);
	dout: out std_logic_vector (15 downto 0);
	spaf_p, sff: out std_logic;  -- ambos act. alto
	ceros_id: in std_logic_vector (1 downto 0);
	tp: out std_logic_vector (3 downto 0);
	lives_p:out std_logic;
	vspare_0,vspare_1: in std_logic;	 --vspare0 =soft reset
	cspare_0, cspare_1: in std_logic;
	led: out std_logic_vector (1 downto 0);
	donein: in std_logic;
	doneout: out std_logic
	);				
end ceros;

architecture arch of ceros is
attribute	box_type: string;
signal db_in, db_out: std_logic_vector (15 downto 0);
signal spaf: std_logic;

-- cr_registros
signal hasunlock, mask, ff_reg: std_logic_vector (5 downto 0);
signal dis_lock_mask, dis_hul_mask, dis_timo_mask: std_logic;
signal dis_ffreg_mask, dis_paf_warn, dis_evid_wrong: std_logic;
signal recoff: std_logic;
signal enw_word_par, enw_byte_par0, enw_byte_par1, enw_dispar,
       etr_fifo, per_fifo, etr_paepaf, per_paepaf, enw_paf_value,
	  enw_timed_out: std_logic;
signal timeout_value: std_logic_vector (11 downto 0);	

-- cr_fifos
signal wclkena, parcheck: std_logic;
signal paf_value: std_logic_vector (10 downto 0);
signal word_par: std_logic_vector(15 downto 0); 
signal byte_par: std_logic_vector(31 downto 0); 
signal disparity: std_logic_vector(15 downto 0);

-- ros & token
signal read, txena, ceros_done: std_logic;
signal sel_read: std_logic_vector (5 downto 0);
signal s_data: std_logic_vector (15 downto 0);
signal timed_out: std_logic_vector (5 downto 0);
signal txena_reg: std_logic;                        -- modif
signal s_data_reg: std_logic_vector (15 downto 0);  -- modif

-- leds
signal disp_led, led_pulse: std_logic_vector (1 downto 0);
signal dis_head_trail:std_logic;
signal lives:std_logic;
signal blocked, notblocked: std_logic_vector(5 downto 0);

signal reset1, reset2, reset_largo: std_logic;
signal dis_evid_bloq: std_logic;
signal evid_mis: std_logic_vector(5 downto 0);
signal enw_evid_mis: std_logic;

signal maxw_reached_p:  std_logic_vector (5 downto 0);
signal nmaxwords_p:  std_logic_vector (8 downto 0);
signal enw_maxw: std_logic;

--components
component cr_fifos port (
	clk, reset: in std_logic;
	read, load_paepaf, mrs: in std_logic;
	sel_etr: in std_logic_vector (2 downto 0);
	sel_read: in std_logic_vector (5 downto 0);
	fout, db_in: in std_logic_vector (15 downto 0);
	par: in std_logic_vector (1 downto 0);
	fmrs, fsi, fsen, fld, wclkena: out std_logic;
	oe, ren: out std_logic_vector(5 downto 0);
-- cr_registros
	etr_fifo, per_fifo, etr_paepaf, per_paepaf, enw_paf_value: in std_logic;
	enw_word_par, enw_byte_par0, enw_byte_par1, enw_dispar: in std_logic;
	paf_value: out std_logic_vector (10 downto 0);
	word_par_p: out std_logic_vector(15 downto 0); 
	byte_par_p: out std_logic_vector(31 downto 0); 
	disparity_p: out std_logic_vector(15 downto 0);
	parcheck_p: out std_logic
	);		
end component;

component cr_registros port (
	clk, reset, reset_largo: in std_logic;
	soft_reset: in std_logic;
	ceros_id: std_logic_vector(1 downto 0);
-- vme
	etr_x, enw_x, cs: in std_logic;
	add: in std_logic_vector(5 downto 0);
	db_in: in std_logic_vector (15 downto 0);
	db_out: out std_logic_vector (15 downto 0);
	fout: in std_logic_vector (15 downto 0);
-- control de registros
	enw_paf_value_p, enw_word_par, enw_byte_par0 , enw_byte_par1, enw_dispar,
	etr_fifo_p, per_fifo_p, etr_paepaf_p, per_paepaf_p, enw_timed_out: out std_logic;
-- mascaras e inhabilitacion de mascaras
	dis_lock_mask_p, dis_hul_mask_p, dis_timo_mask_p, recoff_p: out std_logic;
	dis_ffreg_mask_p, dis_paf_warn_p, dis_evid_wrong_p, dis_head_trail_p: out std_logic;
   dis_evid_bloq_p, enw_evid_mis: out std_logic;
--
	mask_p, hasunlock_p, ff_reg_p: out std_logic_vector (5 downto 0);
--
	timeout_value_p: out std_logic_vector (11 downto 0);
	enw_maxw: out std_logic;
	maxw_reached_p: in std_logic_vector (5 downto 0);
	nmaxwords_p: out std_logic_vector (8 downto 0);
--
	resynch_to_p, resynch_evidmis_p, warn_PAF_p: out std_logic;
	resynch_FF_p, resynch_maxw_p: out std_logic;
--
	blocked: in std_logic_vector(5 downto 0);
	lock, timed_out, paf, ef, ff, evid_mis: in std_logic_vector (5 downto 0);
	paf_value: in std_logic_vector (10 downto 0);
	word_par: in std_logic_vector(15 downto 0); 
	byte_par: in std_logic_vector(31 downto 0); 
	disparity: in std_logic_vector(15 downto 0)
);
end component;

component cr_ros port (
	clk, reset: in std_logic;
	soft_reset: in std_logic;
-- 
	valen, hastoken, parcheck: in std_logic;
	evid: in std_logic_vector(11 downto 0);
	ceros_id: in std_logic_vector (1 downto 0);
	txena_p, read_fifo_p, ros_done: out std_logic;      -- modif
	lives: out std_logic;
	fout: in std_logic_vector(15 downto 0);
	s_data_p: out std_logic_vector(15 downto 0);        -- modif
	ef, mask: in std_logic_vector(5 downto 0);
	db_in: in std_logic_vector(5 downto 0);
	sel_read_p: out std_logic_vector(5 downto 0);
	hasunlock, paf, ff, ff_reg, lock: in std_logic_vector(5 downto 0);
	timed_out_p: out std_logic_vector(5 downto 0);
	evid_mis_p: out std_logic_vector(5 downto 0);
	enw_evid_mis: in std_logic;
	dis_timo_mask:in std_logic;
	enw_timed_out, dis_paf_warn, dis_evid_wrong, dis_head_trail: in std_logic;
	dis_evid_bloq: in std_logic;
	timeout_value: in std_logic_vector(11 downto 0);
	enw_maxw: in std_logic;
	maxw_reached_p: out std_logic_vector (5 downto 0);
	nmaxwords_p: in std_logic_vector (8 downto 0);
	--
	resynch_to_p, resynch_evidmis_p, warn_PAF_p: in std_logic;
	resynch_FF_p, resynch_maxw_p: in std_logic
	);
end component;

component stretch port (
	clk_1, clk_2, din, reset: in std_logic;
	dout: out std_logic
	);		
end component;

-- GSR
--cr signal GSR: std_logic;
--cr component startup_spartan2
--cr   port(GSR: in std_logic);
--cr end component;

-- DLL
signal CLKIN, CLK, CLK0, CLK20, LOCKED, GND : std_logic;
 
component CLKDLLE
-- synthesis translate_off
	generic map (clkdv_divide: real :=2.0)
-- synthesis translate_on
      port (CLKIN, CLKFB, RST : in STD_LOGIC;
      CLK0, CLK90, CLK180, CLK270, CLK2X, CLKDV, LOCKED : out std_logic);
end component;
attribute box_type of clkdlle: component is "black_box";

ATTRIBUTE CLKDV_DIVIDE : REAL;
-- attribute CLKDV_DIVIDE of uled2: label is 16.0;
-- (1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.5, 8.0, 9.0, 10.0, 11.0,
-- 12.0, 13.0, 14.0, 15.0, 16.0) are valid for CLKDV_DIVIDE
---------------------------------------------------------------

component IBUFG
     port (I : in STD_LOGIC; O : out std_logic);
end component;
component BUFG
    port (I : in STD_LOGIC; O : out std_logic);
end component;
component OBUF
    port (I : in STD_LOGIC; O : out std_logic);
end component;
attribute box_type of ibufg: component is "black_box";
attribute box_type of bufg: component is "black_box";
attribute box_type of obuf: component is "black_box";

signal soft_reset: std_logic;

signal resynch_to_p, resynch_evidmis_p, warn_PAF_p:  std_logic;
signal resynch_FF_p, resynch_maxw_p:  std_logic;
signal enw_x,enw1,enw2:std_logic;

begin

process (clk, reset)
begin
	if reset='1' then
			enw1 <= '0';
			enw2 <= '0';
	elsif clk'event and clk='1' then
			enw1 <= enw;
			enw2 <= enw1;
	end if;
end process;
enw_x <= enw1 and not(enw2);

GND <= '0';

tp(0) <= txena;
tp(1) <= ceros_done;
tp(2) <= token;
tp(3) <= clk when evid="000000000000" and vspare_1='0' and 
		cspare_1='0' and cspare_0='0' else '0';

process(clk)
begin
	if clk'event and clk='1' then
		reset1 <= reset;
		reset2 <= reset1;
	end if;
end process;

reset_largo <= reset1 or reset2 or reset;

--el soft reset se activa tambien con un hard reset (reset normal)
soft_reset <= vspare_0 or reset_largo; 

lives_p <= lives;

wclkena_p <= wclkena;
recoff_p <= not(recoff or wclkena);
ceros_done_p <= ceros_done;
spaf_p <= spaf;

--proceso para el done
process(clk)
begin
	if clk'event and clk='1' then
		doneout <= not(donein);
	end if;
end process;
		



-- LEDS
disp_led(0) <= ceros_done;
disp_led(1) <= spaf;
led (0) <= led_pulse(0) or ceros_done;
led (1) <= led_pulse(1);
ULED1: stretch port map(clk, clk_slow, disp_led(0), reset, led_pulse(0));
ULED2: stretch port map(clk, clk_slow, disp_led(1), reset, led_pulse(1));

---- DLL
UDLL1: IBUFG port map (I=>CLKIN_P, O=>CLKIN);
UDLL2: CLKDLLE 
-- synthesis translate_off
		generic map (dlldv_divide=>2.0);
-- synthesis translate_on
		port map (CLKIN=>CLKIN, CLKFB=>CLK, RST=>GND, CLK0=>CLK0, CLKDV=>CLK20, 
		LOCKED=>LOCKED, CLK90=>open, CLK180=>open, CLK270=>open, CLK2X=>open);
UDLL3: BUFG port map (I=>CLK0, O=>CLK);
UDDL4: OBUF port map (I=>CLK20, O=>CLK20_P);
UDDL5: OBUF port map (I=>LOCKED, O=>LOCKED_P);

-----------------------
-- provisional
-----------------------

-- cr STRTUP: startup_spartan2 port map(GSR => reset);

-----------------------
-----------------------

 
U1: cr_registros port map(
	clk=>clk, reset=>reset, reset_largo=>reset_largo, ceros_id=>ceros_id, --: in std_logic;
	soft_reset=>soft_reset,
-- vme
	etr_x=>etr_x, enw_x=>enw_x, cs=>cs, --: in std_logic;
	add=>add, --: in std_logic_vector(6 downto 0);
	db_in=>db_in, --: in std_logic_vector (15 downto 0);
	db_out=>db_out, --: out std_logic_vector (15 downto 0);
	fout=>fout, --: in std_logic_vector (15 downto 0);
--
	enw_paf_value_p=>enw_paf_value, enw_word_par=>enw_word_par, enw_byte_par0=>enw_byte_par0, 
	enw_byte_par1=>enw_byte_par1, enw_dispar=>enw_dispar,
	etr_fifo_p=>etr_fifo, per_fifo_p=>per_fifo, etr_paepaf_p=>etr_paepaf, 
	per_paepaf_p=>per_paepaf, enw_timed_out=>enw_timed_out,
	dis_lock_mask_p=>dis_lock_mask, dis_hul_mask_p=>dis_hul_mask, 
	dis_timo_mask_p=>dis_timo_mask, recoff_p=>recoff, --: out std_logic;
	dis_ffreg_mask_p=>dis_ffreg_mask, dis_paf_warn_p=>dis_paf_warn,
	dis_evid_wrong_p=>dis_evid_wrong, dis_head_trail_p=> dis_head_trail,
	dis_evid_bloq_p=> dis_evid_bloq,
	enw_evid_mis=>enw_evid_mis,

	mask_p=>mask , hasunlock_p=>hasunlock, ff_reg_p=>ff_reg, --: out std_logic_vector (5 downto 0);
	timeout_value_p=>timeout_value, --: out std_logic_vector ( 11 downto 0);
	enw_maxw => enw_maxw,
	maxw_reached_p => maxw_reached_p,
	nmaxwords_p=> nmaxwords_p,
--
	resynch_to_p=> resynch_to_p, resynch_evidmis_p=> resynch_evidmis_p,
	warn_PAF_p => warn_PAF_p,
	resynch_FF_p=> resynch_FF_p, resynch_maxw_p=> resynch_maxw_p,

--
	blocked=>blocked,
	lock=>lock, timed_out=>timed_out, paf=>paf, ef=>ef, ff=>ff, --: in std_logic_vector (5 downto 0);
	evid_mis=>evid_mis,
	paf_value=>paf_value, --: in std_logic_vector (10 downto 0);
	word_par=>word_par, --: in std_logic_vector(15 downto 0); 
	byte_par=>byte_par, --: in std_logic_vector(31 downto 0); 
	disparity=>disparity --: in std_logic_vector(15 downto 0);
	);
U2: cr_fifos port map(
	clk=>clk, reset=>reset, --: in std_logic;
	read=>read, load_paepaf=>load_paepaf, mrs=>mrs, --: in std_logic;
	sel_etr=>add(2 downto 0), sel_read=>sel_read, 
	fout=>fout, db_in=>db_in, --: in std_logic_vector (15 downto 0);
	par=>par, --: in std_logic_vector (1 downto 0);
	fmrs=>fmrs, fsi=>fsi, fsen=>fsen, fld=>fld, wclkena=>wclkena, --: out std_logic;
	oe=>oe, ren=>ren, --: out std_logic_vector(5 downto 0);
-- cr_registros
	etr_fifo=>etr_fifo, per_fifo=>per_fifo, etr_paepaf=>etr_paepaf,
	per_paepaf=>per_paepaf, enw_paf_value=>enw_paf_value, --: in std_logic;
	enw_word_par=>enw_word_par, enw_byte_par0=>enw_byte_par0, 
	enw_byte_par1=>enw_byte_par1, enw_dispar=>enw_dispar, --: in std_logic;
	paf_value=>paf_value, --: out std_logic_vector (10 downto 0);
	word_par_p=>word_par, --: out std_logic_vector(15 downto 0); 
	byte_par_p=>byte_par, --: out std_logic_vector(31 downto 0); 
	disparity_p=>disparity, --: out std_logic_vector(15 downto 0)
	parcheck_p=>parcheck	
	);

U3: cr_ros port map (
	clk=>clk, reset=>reset, --: in std_logic;
	soft_reset=> soft_reset,
-- 
	valen=>valen, hastoken=>token, parcheck=>parcheck, --: in std_logic;
	evid=>evid, --: in std_logic_vector(11 downto 0);
	ceros_id=>ceros_id, --: in std_logic_vector (1 downto 0);
	txena_p=>txena, read_fifo_p=>read, ros_done=>ceros_done, --: out std_logic;  -- modif
	lives=>lives,
	fout=>fout, --: in std_logic_vector(15 downto 0);
	s_data_p=>s_data, --: out std_logic_vector(15 downto 0);    -- modif
	ef=>ef, mask=>mask, --: in std_logic_vector(5 downto 0);
	db_in=>db_in(5 downto 0), --: in std_logic_vector(15 downto 0);
	sel_read_p=>sel_read, --: out std_logic_vector(5 downto 0);
	hasunlock=>hasunlock, paf=>paf, ff=>ff, ff_reg=>ff_reg, lock=>lock, --: in std_logic_vector(5 downto 0);
	timed_out_p=>timed_out, --: out std_logic_vector(5 downto 0);
	evid_mis_p=>evid_mis,
	enw_evid_mis=>enw_evid_mis,
	dis_timo_mask=>dis_timo_mask,
	enw_timed_out=>enw_timed_out, dis_paf_warn=>dis_paf_warn, 
	dis_evid_wrong=>dis_evid_wrong, dis_head_trail=>dis_head_trail, --: in std_logic
	dis_evid_bloq=>dis_evid_bloq,
	timeout_value=>timeout_value, --in std_logic_vector (11 downto 0) 
	enw_maxw => enw_maxw,
	maxw_reached_p => maxw_reached_p,
	nmaxwords_p=> nmaxwords_p,
--
	resynch_to_p=> resynch_to_p, resynch_evidmis_p=> resynch_evidmis_p,
	warn_PAF_p => warn_PAF_p,
	resynch_FF_p=> resynch_FF_p, resynch_maxw_p=> resynch_maxw_p
	);

db_in <= db;
db <= db_out when cs='1' and etr_x='0' else (others => 'Z');

--hasul a 0=bloquea el canal, a 1 deja pasar
hasul<=notblocked;
blocked<=not(notblocked);
notblocked <= not(mask) and
		multi_or (not(hasunlock), dis_hul_mask) and 	 --hasunlock a 1=hasunlock
		multi_or (not(lock), dis_lock_mask) and 	-- lock a 1 = unlock
		multi_or (not(timed_out),dis_timo_mask) and	 -- a 1 timedout
		multi_or (not(maxw_reached_p),dis_timo_mask) and	 -- a 1 maxwreached_p
		multi_or (not(ff_reg), dis_ffreg_mask) and
		multi_or (not(evid_mis), dis_evid_bloq);

sff <= or_reduce(ff);	 -- FF activo alto
spaf <= not and_reduce(paf); -- PAF activo bajo

-- send data & txena
-- modif ---------------------------------------
-- primero hay que registrar, luego el 3-estados
process (clk, reset)
begin
     if reset='1' then
          s_data_reg <= (others => '0');
          txena_reg <= '0';
     elsif clk'event and clk='1' then
          s_data_reg <= s_data;
          txena_reg <= txena;
     end if;
end process;
                  
dout <= s_data_reg when token='1' else (others => 'Z');
txena_p <= txena_reg when token='1' else 'Z';

end arch;



	
