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

entity rc_reg_ctrl is
	port (
	clk, reset: in std_logic;
	--reset_largo: in std_logic;
	soft_reset: in std_logic;
-- 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);
-- control de registros
	enw_crtimed_out: out std_logic;
	enw_bcnt, enw_evcnt_h, enw_evcnt_l, enw_trg_fblock: out std_logic;
	fblock_count_2, fblock_count_1, fblock_count_0:in std_logic_vector (7 downto 0); 
	sc_fblock_count: in std_logic_vector (8 downto 0);
	bunch_number: in std_logic_vector (11 downto 0);
	event_number: in std_logic_vector (23 downto 0);	  
	enw_trg_counter: out std_logic; 
--	enw_orbit_counter_h, enw_orbit_counter_l: out std_logic;
	enw_evint_counter:out std_logic;
	trigger_counter: in std_logic_vector(15 downto 0);
	orbit_counter: in std_logic_vector(23 downto 0);--(29 downto 0);
	event_int_counter: in std_logic_vector(11 downto 0);
	fblock_full_p: in std_logic_vector(2 downto 0);
	resynch_L1A_FF_p:out std_logic;
	resynch_ceros_to_p:out std_logic;
-- mascaras, time out e inhabilitacion de mascaras
 	read_int_scfifo_p: out std_logic;

	cmd: in std_logic_vector (3 downto 0);

	dis_crtimo_mask_p, ena_sc_trigger_p, dis_L1A_p, local_L1A: out std_logic;
	ena_send_bunch_p, ena_send_orbit_p, sel_local_evid_p: out std_logic; 
	ceros_mask_p: out std_logic_vector(5 downto 0);
	cr_timeout_value_p: out std_logic_vector (11 downto 0);
	sc_fblock_full: in std_logic; --domingo 9-04-06
	ceros_timed_out: in std_logic_vector(5 downto 0)--el timeout del sc se mete aqui en rc_control.vhd
	);		
end rc_reg_ctrl;

architecture arch of rc_reg_ctrl is

constant timedout_add: std_logic_vector(5 downto 0):= "000000";  -- timed out
constant mask_add: std_logic_vector(5 downto 0):=     "000001";  -- mask value
constant toval_add: std_logic_vector(5 downto 0):=    "000010";  -- timeout value
constant bcnt_add: std_logic_vector(5 downto 0):=     "000011";  -- bunch counter value -> fifo
constant evcntl_add: std_logic_vector(5 downto 0):=   "000100";  -- event low counter value -> fifo
constant evcnth_add: std_logic_vector(5 downto 0):=   "000101";  -- event high counter value -> fifo
constant trgfb_add: std_logic_vector(5 downto 0):=    "000110";  -- trigger data -> fifo
constant bcocc_add: std_logic_vector(5 downto 0):=    "000111";  -- BC fifo occupancy
constant evocc_add: std_logic_vector(5 downto 0):=    "001000";  -- EV counter fifos (2) occupancy
constant trgcnt_add: std_logic_vector(5 downto 0):=   "001001";  -- L1A counter
constant orbcntl_add: std_logic_vector(5 downto 0):=  "001010";  -- orbit counter low
constant orbcnth_add: std_logic_vector(5 downto 0):=  "001011";  -- orbit counter high
constant evint_add: std_logic_vector(5 downto 0):=  "001100";  -- event ID counter
constant cmd_reg_add: std_logic_vector(5 downto 0):=  "001101";  -- cmd reg
--constant scfifo_add: std_logic_vector(5 downto 0):=  "001100";  -- orbit counter high

--
signal ceros_mask: std_logic_vector (5 downto 0);
signal dis_crtimo_mask, ena_sc_trigger, dis_L1A: std_logic;
signal ena_send_bunch, ena_send_orbit, sel_local_evid: std_logic; 
signal cr_timeout_value: std_logic_vector (11 downto 0);
signal ffull_reg: std_logic_vector(2 downto 0);
signal read_int_scfifo, sc_fblock_full_reg:std_logic;

--signal low_add: std_logic_vector (2 downto 0);
--signal high_add: std_logic_vector (2 downto 0);

signal fblock_count_reg_0, fblock_count_reg_1, fblock_count_reg_2: std_logic_vector(7 downto 0);
signal cmd_reg: std_logic_vector (3 downto 0);
signal cmd_or_strobe: std_logic;
signal resynch_L1A_FF:std_logic;
signal resynch_ceros_to: std_logic;

begin

ceros_mask_p <= ceros_mask;
cr_timeout_value_p <= cr_timeout_value;
read_int_scfifo_p <= read_int_scfifo;

dis_crtimo_mask_p <= dis_crtimo_mask;
ena_sc_trigger_p <= ena_sc_trigger;
dis_L1A_p <= dis_L1A;
ena_send_bunch_p <= ena_send_bunch;
ena_send_orbit_p <= ena_send_orbit;
sel_local_evid_p <= sel_local_evid;
resynch_L1A_FF_p <= resynch_L1A_FF;
resynch_ceros_to_p <= resynch_ceros_to;

-- CEROS & SC timed out y SC fifo full 
db_out <= "000000" & ffull_reg & sc_fblock_full_reg & ceros_timed_out when  --domingo 9-4-06
		cs='1' and add=timedout_add and etr_x='0' else (others => 'Z');

enw_crtimed_out <= enw_x when cs='1' and add=timedout_add else '0';

--reg SC fifo full	  --domingo 9-4-06
process (clk, soft_reset)
begin
	if soft_reset='1' then
		sc_fblock_full_reg <= '0';
	elsif clk'event and clk='1' then 
	  if enw_x='1' and cs='1' and add=timedout_add then
		sc_fblock_full_reg <= db_in(6);
	  elsif sc_fblock_full='1' then
	  	sc_fblock_full_reg <= '1';
	  end if;
	end if;
end process;

-- CEROS & SC masks 
--bits description	                         acc  signal
--0-4 Mask CEROS                             R/W  ceros_mask
--5  Enable SC TRIGGER DATA readout          R/W  ena_trg_data
--6  Disable TIMED OUT to mask CEROS or SC   R/W  dis_ crtimo_mask
--7  Enable SC_L1A trigger                   R/W  ena_sc_trigger
--8  Disable L1A trigger                     R/W  dis_L1A
--9  Select local EVID counter               R/W  sel_local_evid
--10 Enable send BUNCH NUMBER                R/W  ena_send_bunch
--11 Enable send BUNCH RESET COUNTER         R/W  ena_send_orbit
--15 Generate local trigger                    W  gen_local_trigger

-- ceros_mask(5) es "enable SC trigger data", por lo que se registra invertido
db_out <= '0' & resynch_ceros_to & read_int_scfifo & resynch_L1A_FF & ena_send_orbit & ena_send_bunch & sel_local_evid & dis_L1A 
                 & ena_sc_trigger & dis_crtimo_mask & not ceros_mask(5)                 
                 & ceros_mask(4 downto 0) when 
               cs='1' and add=mask_add and etr_x='0' else (others => 'Z');

local_L1A<= enw_x when add=mask_add and cs='1' and enw_x='1' and db_in(15)='1' else '0';									  --dura 25ns

process (clk, reset)
begin
	if reset='1' then
	    ceros_mask <= (5=> '1', others => '0');
	    dis_crtimo_mask <= '1';
	    ena_sc_trigger  <= '0';
	    dis_L1A <= '1';
	    sel_local_evid <= '0';
	    ena_send_bunch <= '1';
	    ena_send_orbit <= '1';
	    resynch_L1A_FF <= '1';
	    read_int_scfifo <= '0';
	    resynch_ceros_to <= '1';
	elsif clk'event and clk='1' then 
	  if add=mask_add and cs='1' and enw_x='1' then
	    ceros_mask (4 downto 0)  <= db_in (4 downto 0);
	    ceros_mask (5)  <= not db_in (5);
	    dis_crtimo_mask <= db_in (6);
	    ena_sc_trigger  <= db_in (7);
	    dis_L1A <= db_in (8);
	    sel_local_evid <= db_in (9);
	    ena_send_bunch <= db_in (10);
	    ena_send_orbit <= db_in (11);
	    resynch_L1A_FF <= db_in(12);
		 read_int_scfifo <= db_in(13);
	    resynch_ceros_to <= db_in(14);
	  end if;
	end if;
end process;

-- CEROS timeout value
db_out <= "0000" & cr_timeout_value when cs='1' and add=toval_add and etr_x='0' else (others => 'Z');

process (clk, reset)
begin
	if reset='1' then
	  cr_timeout_value <= (others =>'1');
	elsif clk'event and clk='1' then
	  if add=toval_add and cs='1' and enw_x='1' then
	    cr_timeout_value <= db_in(cr_timeout_value'range);
	  end if;
	end if;
end process;

--FIFO FULL FLAGS
--fblock_full_p (0) = bunch counter fifo
--fblock_full_p (1) = event counter high fifo
--fblock_full_p (2) = event counter low fifo
process(soft_reset,clk)
begin
	if soft_reset='1' then
		ffull_reg <= (others=>'0');
	elsif clk'event and clk='1' then
	   if add=bcnt_add and cs='1' and enw_x='1' then
			ffull_reg(0)<= db_in(12);
	   elsif add=timedout_add and cs='1' and enw_x='1' then
			ffull_reg(0)<= db_in(7);
		elsif fblock_full_p(0)='1' then
			ffull_reg(0)<= '1';
		end if;
	   if add=evcnth_add and cs='1' and enw_x='1' then
			ffull_reg(1)<= db_in(12);
	   elsif add=timedout_add and cs='1' and enw_x='1' then
			ffull_reg(1)<= db_in(8);
		elsif fblock_full_p(1)='1' then
			ffull_reg(1)<= '1';
		end if;
	   if add=evcntl_add and cs='1' and enw_x='1' then
			ffull_reg(2)<= db_in(12);
	   elsif add=timedout_add and cs='1' and enw_x='1' then
			ffull_reg(2)<= db_in(9);
		elsif fblock_full_p(2)='1' then
			ffull_reg(2)<= '1';
		end if;
	end if;
end process;

-- escriture de bunch & event number values
-- y lectura de ultimos bunch y event number 
enw_bcnt <= enw_x when cs='1' and add=bcnt_add else '0';
enw_evcnt_l <= enw_x when cs='1' and add=evcntl_add else '0';
enw_evcnt_h <= enw_x when cs='1' and add=evcnth_add else '0';

db_out <= "000" & ffull_reg(0) & bunch_number when cs='1' and add=bcnt_add and etr_x='0' else (others => 'Z');
db_out <= "000" & ffull_reg(2) & event_number(11 downto 0) when cs='1' and add=evcntl_add and etr_x='0' else (others => 'Z');
db_out <= "000" & ffull_reg(1) & event_number(23 downto 12) when cs='1' and add=evcnth_add and etr_x='0' else (others => 'Z');

-- trigger fifo
enw_trg_fblock <= enw_x when cs='1' and add=trgfb_add else '0';

-- bunch & event number fifos occupancy
db_out <= "000" & sc_fblock_full_reg & "000" & sc_fblock_count when cs='1' and add=trgfb_add and etr_x='0' else (others => 'Z');
--db_out <= sc_fblock_count(7 downto 0) & fblock_count_0 when cs='1' and add=bcocc_add and etr_x='0' else (others => 'Z');
--db_out <= "00000000" & fblock_count_0 when cs='1' and add=bcocc_add and etr_x='0' else (others => 'Z');
--db_out <= fblock_count_1 & fblock_count_2 when cs='1' and add=evocc_add and etr_x='0' else (others => 'Z');
db_out <= "00000000" & fblock_count_reg_0 when cs='1' and add=bcocc_add and etr_x='0' else (others => 'Z');
db_out <= fblock_count_reg_1 & fblock_count_reg_2 when cs='1' and add=evocc_add and etr_x='0' else (others => 'Z');

process(clk,reset)
begin
	if reset='1' then
		fblock_count_reg_0 <= (others=>'0');
		fblock_count_reg_1 <= (others=>'0');
		fblock_count_reg_2 <= (others=>'0');
	elsif clk'event and clk='1' then
		if fblock_count_0 > fblock_count_reg_0 then
			fblock_count_reg_0 <= fblock_count_0;
		end if;
		if fblock_count_1 > fblock_count_reg_1 then
			fblock_count_reg_1 <= fblock_count_1;
		end if;
		if fblock_count_2 > fblock_count_reg_2 then
			fblock_count_reg_2 <= fblock_count_2;
		end if;
	end if;
end process;
-- trigger counter
db_out <= trigger_counter when cs='1' and add=trgcnt_add and etr_x='0' else (others => 'Z');
enw_trg_counter <= enw_x when cs='1' and add=trgcnt_add else '0';

-- orbit counter
db_out <= orbit_counter (15 downto 0) when cs='1' and add=orbcntl_add and etr_x='0' else (others => 'Z');
db_out <=  "00000000" & orbit_counter (23 downto 16) when cs='1' and add=orbcnth_add and etr_x='0' else (others => 'Z');
--db_out <=  x"0000"  when cs='1' and add=orbcnth_add and etr_x='0' else (others => 'Z');
--enw_orbit_counter_l <= enw_x when cs='1' and add=orbcntl_add else '0'; 
--enw_orbit_counter_h <= enw_x when cs='1' and add=orbcnth_add else '0'; 


--INTERNAL EVENT COUNTER
db_out <= "0000" & event_int_counter when cs='1' and add=evint_add and etr_x='0' else (others => 'Z');
enw_evint_counter	<= enw_x when cs='1' and add=evint_add else '0';


--REGISTRO LINEAS DE COMANDO
db_out <= "000000000000" & cmd_reg when cs='1' and add=cmd_reg_add and etr_x='0' else (others => 'Z');

cmd_or_strobe <= cmd(3) or cmd(2) or cmd(1) or cmd(0);

process(clk,reset)
begin
	if reset='1' then
		cmd_reg <= (others=>'0');
	elsif clk'event and clk='1' then
		if cmd_or_strobe='1' then
			cmd_reg<= cmd;
		end if;
	end if;
end process;

end arch;



	
