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;
--
-- VERSION REDUCIDA DE CEROS REGISTROS
--
entity cr_registros is
	port (
	clk, reset, 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);
	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;
	per_fifo_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;
--
	timeout_value_p: out std_logic_vector (11 downto 0);
	enw_maxw: out std_logic;
	maxw_reached_p: in std_logic;
	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;
	lock, timed_out, paf, ef, ff, evid_mis: in std_logic;
	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 cr_registros;

architecture arch of cr_registros is

constant mask_add: std_logic_vector(5 downto 0):=     "000000";	-- mask & lock & disable masks
constant disable_add: std_logic_vector(5 downto 0):=  "000001";	-- disable register
constant timedout_add: std_logic_vector(5 downto 0):= "000010";	-- timed_out & hasunlock
constant paf_add: std_logic_vector(5 downto 0):=      "000011";  -- paf & paf_reg
constant ef_add: std_logic_vector(5 downto 0):=       "000100";  -- ef
constant ff_add: std_logic_vector(5 downto 0):=       "000101";  -- maxw & ff_reg
constant paf_val_add: std_logic_vector(5 downto 0):=  "000110";  -- paf value & recoff & dis_paf_warn
constant wpar_add: std_logic_vector(5 downto 0):=	    "000111";  -- word parity
constant bpar0_add: std_logic_vector(5 downto 0):=    "001000";  -- byte parity	0
constant bpar1_add: std_logic_vector(5 downto 0):=    "001001";  -- byte parity	1
constant disp_add: std_logic_vector(5 downto 0):=     "001010";  -- disparity counter
constant toval_add: std_logic_vector(5 downto 0):=    "001011";  -- timeout value
constant maxw_reg: std_logic_vector(5 downto 0):=    "001100";  -- maxw value
constant tts_reg: std_logic_vector(5 downto 0):=    "101000";  -- $50 TTS reg
constant pcnt_add: std_logic_vector(2 downto 0):=     "010";     -- paf counter
constant fifo_add: std_logic_vector(2 downto 0):=     "011";	-- fifo data
constant pp_add: std_logic_vector(2 downto 0):=       "100";	-- pae/paf data
constant fill: std_logic_vector (4 downto 0):= "00000";

signal mask, hasunlock, paf_reg, ff_reg: std_logic;
signal dis_lock_mask, dis_hul_mask, dis_timo_mask, recoff: std_logic;
signal dis_ffreg_mask, dis_paf_warn, dis_evid_wrong: std_logic;
signal timeout_value: std_logic_vector (11 downto 0);
signal etr_fifo, per_fifo, etr_paepaf, per_paepaf, etr_paf_counter: std_logic;
signal enw_paf_counter, enw_paf_value: std_logic;
--signal etr_fifo_reg, etr_paepaf_reg: std_logic;
signal etr_fifo_reg: std_logic;
signal paf_counter: std_logic_vector (15 downto 0);

signal paf_cnt_set: std_logic;
signal low_add: std_logic_vector (2 downto 0);
signal high_add: std_logic_vector (2 downto 0);
signal fout_reg: std_logic_vector (15 downto 0);
signal per_fifo_aux, per_fifo_aux_2: std_logic;
signal dis_head_trail: std_logic;
signal etr_paepaf_reg_1, etr_paepaf_reg_2: std_logic;
signal per_paepaf_reg: std_logic;
signal dis_evid_bloq: std_logic;

signal nmaxwords: std_logic_vector (8 downto 0);
signal resynch_to, resynch_evidmis, warn_PAF:std_logic;
signal resynch_FF, resynch_maxw : std_logic;

begin

dis_head_trail_p <= dis_head_trail;
mask_p <= mask;
hasunlock_p <= hasunlock;
ff_reg_p <= ff_reg;
timeout_value_p <= timeout_value;
recoff_p <= recoff;
--etr_fifo_p <= etr_fifo;
--etr_paepaf_p <= etr_paepaf;
per_fifo_p <= per_fifo;
per_paepaf_p <= per_paepaf;
dis_lock_mask_p <= dis_lock_mask;
dis_hul_mask_p <= dis_hul_mask;
dis_timo_mask_p <= dis_timo_mask;
dis_ffreg_mask_p <= dis_ffreg_mask;
enw_paf_value_p <= enw_paf_value;
dis_paf_warn_p <= dis_paf_warn;
dis_evid_wrong_p <= dis_evid_wrong;
dis_evid_bloq_p <= dis_evid_bloq;
nmaxwords_p <= nmaxwords;

resynch_to_p <= resynch_to;
resynch_evidmis_p <= resynch_evidmis;
warn_PAF_p <= warn_PAF;
resynch_FF_p <= resynch_FF;
resynch_maxw_p <= resynch_maxw;


low_add <= add(2 downto 0);
high_add <= add(5 downto 3);

-- Control & status == mask, lock, disable channel masking, receivers off
--db_out <= "0000" & mask & lock when cs='1' and add=mask_add and etr_x='0' else (others => 'Z');
db_out <= "0100" & fill & mask & fill & lock when cs='1' and add=mask_add and etr_x='0' else (others => 'Z');

process (clk, reset_largo)
begin
	if reset_largo='1' then
	  mask <= '0'; --(others => '0');
	elsif clk'event and clk='1' then
	  if add=mask_add and cs='1' and enw_x='1' then
--	    mask <= db_in (11 downto 6);
	    mask <= db_in (6);   ---a 1 es que enmascara
	  end if;
	end if;
end process;

-- Disable registers
db_out <=   "00000" & blocked & "00" & dis_evid_bloq & dis_head_trail & dis_evid_wrong & dis_paf_warn 
			& dis_ffreg_mask & dis_timo_mask & dis_hul_mask & dis_lock_mask
			when cs='1' and add=disable_add and etr_x='0' else (others => 'Z');

process (clk, reset_largo)
begin
	if reset_largo='1' then
	  dis_lock_mask <= '0';
	  dis_hul_mask  <= '0';
	  dis_timo_mask <= '1';
	  dis_ffreg_mask <= '0';
	  dis_paf_warn <= '0';
	  dis_evid_wrong <= '0';
	  dis_head_trail <= '0';
	  dis_evid_bloq <='1'; --por defecto evid mis no bloquea
	elsif clk'event and clk='1' then
	  if add=disable_add and cs='1' and enw_x='1' then
	    dis_lock_mask <= db_in (0);
	    dis_hul_mask  <= db_in (1);
	    dis_timo_mask <= db_in (2);
	    dis_ffreg_mask  <= db_in (3);
	    dis_paf_warn <= db_in (4);
	    dis_evid_wrong <= db_in (5);
	    dis_head_trail <= db_in(6);
		 dis_evid_bloq <= db_in(7);
	  end if;
	end if;
end process;

-- timed_out & hasunlock & disable ff_reg masking   
-- (timed_out se escribe en cr_ros)
--db_out <= "0000" & hasunlock & timed_out when 
db_out <= "0000" & fill & hasunlock & "00000" & timed_out when 
		cs='1' and add=timedout_add and etr_x='0' else (others => 'Z');

enw_timed_out <=  enw_x when add=timedout_add and cs='1' else '0'; 
 
process (clk, soft_reset)
begin
	if soft_reset='1' then
	  hasunlock <= '0'; --(others =>'0');
	elsif clk'event and clk='1' then
	  if add=timedout_add and cs='1' and enw_x='1' then
	    hasunlock <= db_in(6);
	  else 
	    hasunlock <= hasunlock or (lock);
	  end if;
	end if;
end process;

-- paf and paf_reg	   (FIFO PAF es activo bajo, aquí se invierte)
db_out <= "0000" & fill & paf_reg & fill & not paf when cs='1' and add=paf_add and etr_x='0' else (others => 'Z');

process (clk, soft_reset)
begin
	if soft_reset='1' then
	  paf_reg <= '0'; 
	elsif clk'event and clk='1' then
	  if add=paf_add and cs='1' and enw_x='1' then
	    paf_reg <= db_in(6);
	  else 
	    paf_reg <= paf_reg or (not paf);
	  end if;
	end if;
end process;

-- ef	  (EF/OR es activo alto cuando la memoria está vacía, modo FWFT)
db_out <= "000000000" & evid_mis & fill & ef when cs='1' and add=ef_add and etr_x='0' else (others => 'Z');

enw_evid_mis <= enw_x when add=ef_add and cs='1' else '0';


-- ff and ff_reg		(FIFO FF/IR es activo alto cuando la memoria está llena, modo FWFT)
db_out <= "0000" & fill & ff_reg & fill & maxw_reached_p when cs='1' and add=ff_add and etr_x='0' else (others => 'Z');

enw_maxw <= enw_x when add=ff_add and cs='1' else '0';

process (clk, soft_reset)
begin
	if soft_reset='1' then
	  ff_reg <= '0'; --(others =>'0');
	elsif clk'event and clk='1' then
	  if add=ff_add and cs='1' and enw_x='1' then
	    ff_reg <= db_in(6);
	  else 
	    ff_reg <= ff_reg or ff;
	  end if;
	end if;
end process;

-- paf_value (la escritura se hace en cr_fifo) & receivers off & disable paf warning
db_out <= "0000" & recoff & paf_value when cs='1' and add=paf_val_add and etr_x='0' else (others => 'Z');

enw_paf_value <= enw_x when cs='1' and add=paf_val_add else '0';

process (clk, reset_largo)
begin
	if reset_largo='1' then
	  recoff <= '0';
	elsif clk'event and clk='1' then
	  if enw_paf_value='1' then
	    recoff <= db_in(11);
	  end if;
	end if;
end process;

-- word & byte parity	  (la escritura se hace en cr_fifo)
db_out <= word_par when cs='1' and add=wpar_add and etr_x='0' else (others => 'Z');
db_out <= byte_par (15 downto 0)  when cs='1' and add=bpar0_add and etr_x='0' else (others => 'Z');
db_out <= byte_par (31 downto 16) when cs='1' and add=bpar1_add and etr_x='0' else (others => 'Z');

enw_word_par  <= enw_x when cs='1' and add=wpar_add else '0';
enw_byte_par0 <= enw_x when cs='1' and add=bpar0_add else '0';
enw_byte_par1 <= enw_x when cs='1' and add=bpar1_add else '0';

-- disparity counter	  (la escritura se hace en cr_fifo)
db_out <=  disparity when cs='1' and add=disp_add and etr_x='0' else (others => 'Z');

enw_dispar  <= enw_x when cs='1' and add=disp_add else '0';

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

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


--NUM MAXWORDS PROGRAMMABLE
db_out <= "0000000" & nmaxwords(8 downto 0)  when cs='1' and add=maxw_reg and etr_x='0' else (others => 'Z');

process (clk, reset_largo)
begin
	if reset_largo='1' then
	  nmaxwords (8 downto 0) <= (others =>'1'); --por defecto no hay límite
	elsif clk'event and clk='1' then
	  if add=maxw_reg and cs='1' and enw_x='1' then
	     nmaxwords <= db_in(8 downto 0);
	  end if;
	end if;
end process;

--TTS_ BITS
process (clk, reset_largo)
begin
	if reset_largo='1' then
		 resynch_to <= '1';
		 resynch_evidmis <= '1';
		 warn_PAF <= '1';
		 resynch_FF <= '1';
		 resynch_maxw <= '1';
	elsif clk'event and clk='1' then
	  if add=tts_reg and cs='1' and enw_x='1' then
		 resynch_to <= db_in(0);
		 resynch_evidmis <= db_in(1);
		 warn_PAF <= db_in(2);
		 resynch_FF <= db_in(3);
		 resynch_maxw <= db_in(4);
	  end if;
	end if;
end process;

db_out <=  "00000000000" & resynch_maxw & resynch_FF & warn_PAF & resynch_evidmis & resynch_to when cs='1' and add=tts_reg and etr_x='0' else (others => 'Z');

------------------------------------------------------------------------------------
-- lectura de FIFO y de PAE/PAF programados
------------------------------------------------------------------------------------
-- per_fifo registra el valor de salida de la fifo (fout) y avanzan el puntero en la fifo 
-- para la siguiente lectura. 
-- per_paepaf solo selecciona y avanza los registros PAE/PAF, el valor de fout se pasa
-- directamente al bus vme.  
------------------------------------------------------------------------------------
--
db_out <= fout_reg when cs='1' and etr_fifo='0'   else (others => 'Z');

etr_fifo <=   etr_x when cs='1' and high_add=fifo_add else '1';
per_fifo_aux <=   etr_fifo or not etr_fifo_reg;	-- activos bajos


process (clk, reset)
begin
	if reset='1' then
	  etr_fifo_reg <= '1';
--	  etr_paepaf_reg <= '1';
	  per_fifo_aux_2 <='1';
	  per_fifo <= '1';
	elsif clk'event and clk='1' then
	  etr_fifo_reg <= etr_fifo;
--	  etr_paepaf_reg <= etr_paepaf;
	  per_fifo_aux_2 <=per_fifo_aux;
	  per_fifo <= per_fifo_aux_2;
	end if;
end process;


--db_out <= fout     when cs='1' and etr_paepaf='0' else (others => 'Z');
db_out <= fout_reg     when cs='1' and etr_paepaf='0' else (others => 'Z');

etr_paepaf <= etr_x when cs='1' and high_add=pp_add else '1';
--per_paepaf <= etr_paepaf or not etr_paepaf_reg;
per_paepaf <= etr_paepaf_reg_1 or not etr_paepaf_reg_2;

process (clk, reset)
begin
	if reset='1' then
	  etr_paepaf_reg_1 <= '1';
	  etr_paepaf_reg_2 <= '1';
	  per_paepaf_reg <= '1';
	elsif clk'event and clk='1' then
	  if cs='1' and high_add=pp_add and etr_x='0' then
			etr_paepaf_reg_1 <= '0';
	  else etr_paepaf_reg_1 <='1';
	  end if;
	  etr_paepaf_reg_2 <= etr_paepaf_reg_1;
	  per_paepaf_reg <= per_paepaf;
	end if;
end process;



process (clk, reset)
begin
	if reset='1' then
	  fout_reg <= (others => '0');
	elsif clk'event and clk='1' then
--	  if per_fifo='0' then
	  if per_fifo_aux_2='0' or per_paepaf_reg='0' then
	    fout_reg <= fout;
	  end if;
	end if;
end process;

-- paf_counters
db_out <= paf_counter when cs='1' and etr_paf_counter='0' and low_add="000" else (others => 'Z');

etr_paf_counter <= etr_x when cs='1' and high_add=pcnt_add else '1';
enw_paf_counter <= enw_x when cs='1' and high_add=pcnt_add else '0';


process (clk, soft_reset)
begin
	if soft_reset='1' then
	  paf_counter <= (others =>'0');

	elsif clk'event and clk='1' then
	  if enw_paf_counter='1' then
	    
	    case low_add is
	    when "000" => paf_counter <= db_in;

	    when others => null;
	    end case;
	  else
	    if paf='0' then 
	      if paf_cnt_set='0' then
		   paf_counter <= paf_counter +1; 
		   paf_cnt_set <= '1';
		 end if;
	    else
		 paf_cnt_set <= '0';
	    end if;
	  end if;
	end if;
end process;

end arch;



	
