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 cr_fifos is
	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 cr_fifos;

architecture arch of cr_fifos is
-- shift register
signal pae_paf_reg: std_logic_vector(21 downto 0);
signal q1, q1a, q2, q3, q4, rst_ec, rst_syn: std_logic;
signal shift_rg: std_logic;
signal loadcnt: std_logic_vector(5 downto 0);
--
signal etr_any: std_logic;
signal oei: std_logic_vector(5 downto 0);
signal cpar: std_logic_vector(1 downto 0);
signal parcheck: std_logic;
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);
-- MRS
signal fwft, fwrg1, fwrg2, fwrg3, fwrg4, fwrg5: std_logic;

begin
word_par_p <= word_par; 
byte_par_p <= byte_par; 
paf_value <= pae_paf_reg (10 downto 0);
disparity_p <= disparity;
parcheck_p <= parcheck;

-- oe
oe <= oei;
etr_any <= etr_fifo and etr_paepaf;

----
--genoe: for igen in oe'range generate
--	oei(igen) <= '0' when (sel_etr=igen and etr_any='0') else
--                  '0' when (sel_read=igen and etr_any='1') else '1';
--end generate;
-------
genoe: for igen in oe'range generate
	oei(igen) <= '0' when etr_any='0' and sel_etr=igen else 
	             '0' when etr_any='1' and sel_read(igen)='1' else '1';
end generate;
-------
-------
-- REN (activo bajo)
--read viene de la máquina de estados de cr_ros
--per_fifo viene de cr_registros para leer de las fifos directamente yo creo
--falta per_paepaf para leer lo programado en los registros de offset
--ren <= oei when per_fifo='0' or read='1' else (others => '1');
--ren <= oei when per_fifo='0' or read='1' or per_paepaf='0' else (others => '1');
--per_paepaf por algún motivo es una mierda de pulso bajo que dura unos 7 ns lo cambio
-- este es el bueno ren <= oei when per_fifo='0' or read='1' or per_paepaf='0' else (others => '1');
ren <= oei when per_fifo='0' or read='1' or per_paepaf='0' else (others => '1');

--parity check, word & byte parity	& disparity
cpar(0) <= xor_reduce(fout(7 downto 0));
cpar(1) <= xor_reduce(fout(15 downto 8));
parcheck <= (cpar(0) xor par(0)) or (cpar(1) xor par(1));

process (clk, reset)
begin
	if reset='1' then
	  word_par <= (others => '0');
	  byte_par <= (others => '0');
	elsif clk'event and clk='1' then
	  if enw_word_par='1' then
	    word_par <= db_in;
	  elsif enw_byte_par0='1' then
	    byte_par (15 downto 0) <= db_in;
	  elsif enw_byte_par1='1' then
	    byte_par (31 downto 16) <= db_in;
	  elsif per_fifo='0' then
-------------------------------------------------------------------------------------
-- habria que ver si lo que se quiere es el valor de la paridad o si ha habido error
-------------------------------------------------------------------------------------
	    word_par <= word_par (14 downto 0) & parcheck;
	    byte_par <= byte_par (29 downto 0) & cpar;
	  end if;
	end if;
end process;

process (clk, reset)
begin
	if reset='1' then
	  disparity <= (others => '0');
	elsif clk'event and clk='1' then
	  if enw_dispar='1' then
	    disparity <= db_in;
	  elsif parcheck='1' and (read='1' or per_fifo='0') then
--------------------------------------------------------------------------------------
-- aquí se registra la paridad del dato actual (en FOUT), lo cual está bien, salvo que 
-- la lectura anterior haya sido PAE/PAF, en cuyo caso...  
--------------------------------------------------------------------------------------
	   disparity  <= disparity +1;
	  end if;
	end if;
end process;

-- Programmable PAE & PAF registers
--fsi <= pae_paf_reg(21) or fwft;   -- SI debe estar a 1 con MSR para seleccionar modo FWFT
  --ABRIL OJO se empieza a cargar por el bit menos significativo!!!

fsi <= pae_paf_reg(0) or fwft;   -- SI debe estar a 1 con MSR para seleccionar modo FWFT

process (clk, reset)
begin
	if reset='1' then
	  pae_paf_reg <= "01000000000" & "01000000000";	-- 25% & 75%
	elsif clk'event and clk='1' then
	  if enw_paf_value='1' then
	    pae_paf_reg <= db_in (10 downto 0) & db_in (10 downto 0); 
	  elsif shift_rg='1' then
--	    pae_paf_reg <= pae_paf_reg(20 downto 0) & pae_paf_reg(21);	--empieza a cargar por el LSB
	    pae_paf_reg <=  pae_paf_reg(0) & pae_paf_reg(21 downto 1);
	  end if;
	end if;
end process;

-- shift control
-- esta secuencia se inicia con load_paepaf=1
-- genera wclkena (habilitacion de reloj y apagado del receptor), fsen y fld (ambos act. bajo). 
-- 
wclkena <= q1;
shift_rg <= not loadcnt(5);
fsen	<= loadcnt(5);
--fld	<= loadcnt(5) and per_paepaf;	-- hace falta tambien para leer los registros
fld	<= (loadcnt(5) and per_paepaf) or fwft;	-- hace falta tambien para leer los registros
					-- tiene que estar a 1 durante el MRS para que sea carga serial

process (clk, reset)
begin
	if reset='1' then 
	  loadcnt <= "101010";	-- 32-10=22 desplazamientos
	elsif clk'event and clk='1' then
	  if rst_ec='1' then 
	    --loadcnt(5) <= '0';
	    loadcnt <= "001010";	-- 32-10=22 desplazamientos
	  elsif loadcnt(5)='0' then
	    loadcnt <= loadcnt +1;
	  end if;
	end if;
end process;

rst_ec <= q2 and not q3 and not q4;
rst_syn <= q4 and loadcnt(5);
process (clk, reset)
begin
	if reset='1' then
		q1 <= '0';
		q1a <= '0';
		q2 <= '0';
		q3 <= '0';
		q4 <= '0';
	elsif clk'event and clk='1' then
		q1 <= not rst_syn and (q1 or load_paepaf);
		q1a <= not rst_syn and q1;
		q2 <= not rst_syn and q1a;
		q3 <= not rst_syn and q2;
		q4 <= q3;
	end if;
end process;

-- Master fifo reset
-- esta secuencia se inicia con MRS=1, y genera fmrs (act. bajo) y fwft (local, act. alto) y ld a 1!!
--
fwft <= fwrg1; 
fmrs <= not (fwrg2); 

process (clk, fwrg5, reset)
begin
	if reset='1' then  --abril
	  fwrg1 <= '1';  --abril
	elsif fwrg5='1' then 
	  fwrg1 <= '0';
	elsif clk'event and clk='1' then
	  if mrs='1' then 
	    fwrg1 <= '1';
	  end if;
	end if;
end process ;

process (clk, fwrg4, reset)
begin
	if reset='1' then  --abril
	  fwrg2 <= '0';   --abril
	  fwrg3 <= '0';	-- abril
	elsif fwrg4='1' then 
	  fwrg2 <= '0';
	  fwrg3 <= '0';
	elsif clk'event and clk='1' then
	  fwrg3 <= fwrg2;
	  if fwrg1='1' then
	    fwrg2 <= '1';
	  end if;
	end if;
end process ;

process (clk, reset)
begin
	if reset='1' then 
	  fwrg4 <= '0';
	  fwrg5 <= '0';
	elsif clk'event and clk='1' then
	  fwrg5 <= fwrg4;
	  fwrg4 <= fwrg3;
	end if;
end process ;

end arch;



	
