library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;

entity rosmem is port(
-- vme
     -- A16
     clk, clk_slow, cs, etr, enw_x, reset: in std_logic;
     add: in std_logic_vector (17 downto 0);
     db: inout std_logic_vector(15 downto 0);
     -- A24
     iack, ds0, ds1, as, write, lword, brdsel24: in std_logic;
     am: in std_logic_vector (5 downto 0);
     ds_out, dtack_mem, g245_mem: out std_logic;
     dsdly: in std_logic_vector(1 downto 0);

-- control
     is_trigger: in std_logic;  
     trigger_led, mem_done_p: out std_logic;  	

-- memory
     madd: out std_logic_vector (17 downto 0);
     mdat: inout std_logic_vector (15 downto 0);
     we, oe: out std_logic;

-- fifos
     txena: inout std_logic;
     dout: inout std_logic_vector (15 downto 0);

-- varios
     tp5,tp6,tp7,tp8: out std_logic;
     led: out std_logic_vector (1 downto 0);
--     vspare: in std_logic_vector (1 downto 0);
--     fspare: in std_logic_vector (2 downto 0);
--     cspare: in std_logic_vector (1 downto 0)
     vspare_1: out std_logic;	  --vspare_0 =soft_reset
     vspare_0: in std_logic;	  --vspare_0 =soft_reset
     mspare_3,mspare_2,mspare_1,mspare_0: out std_logic;
     cspare: out std_logic_vector (11 downto 0)		--cspare_10<= soft_reset para rosctrl
	  --cspare_11 ='1' when estado=gol_test
      );
end rosmem;

architecture arch of rosmem is

-- señales
     -- buses
signal db_in, db_out, mdat_in: std_logic_vector (15 downto 0);

     -- vme
signal dtack_ifc, g245_ifc, g245_blk, dtack_blk: std_logic; 

     -- memoria
signal oe_ifc, oe_blk, acc_blk, we_ifc, we_blk, we_fifo: std_logic;

signal inc_add: std_logic;
signal mem_pointer: std_logic_vector (17 downto 0);

     --fifos
signal dout_reg_in,dout_reg_in_2, dout_reg_out: std_logic_vector (15 downto 0);
signal txena_reg_in, txena_reg_out: std_logic;

     -- control y registros
signal txena_out, inc_pointer_reg: std_logic;
     -- leds
--signal led_pulse, disp_led: std_logic_vector (2 downto 0);
signal led_pulse_2: std_logic;
signal disp_led: std_logic_vector (2 downto 0);

-- componentes
component rm_vmeifc port (
     ds0, ds1, dsdly0, dsdly1, iack: in std_logic;
     write, brdsel24: in std_logic;
     am: in std_logic_vector (5 downto 0);
     we, dtack, g245, oe: out std_logic 
     );
end component;

component rm_vmeblk port (
     ds0, ds1, dsdly0, dsdly1, iack: in std_logic;
     write, brdsel24, lword: in std_logic;
     am: in std_logic_vector (5 downto 0);
     we, dtack, g245, oe, inc_add, acc_blk: out std_logic 
     );
end component;

component rm_memadd port(
     inc_add, acc_blk, as: in std_logic;
     add: in std_logic_vector(17 downto 0);
     madd: out std_logic_vector(17 downto 0)
     );
end component;

component rm_registros port (
     clk, reset: in std_logic;
     txena_out_lfsr: out std_logic; 
	  mem_done: in std_logic;
     mem_is_full: out std_logic;

-- vme A16
     enw, 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);

     ena_word_count_p, ena_event_count_p:out std_logic;
	  ena_gol_test_p, ena_ceros_mem_p,ena_cycles_p, ena_random_p: out std_logic;
	  reset_pointer,inc_pointer: in std_logic;
	  mword_count_p: out std_logic_vector (17 downto 0);
	  mev_count_p,num_cycles_p: out std_logic_vector (15 downto 0);

-- registros
     mem_pointer_p: out std_logic_vector (17 downto 0)
     );		
end component;

component stretch port (
	clk_1, clk_2, din, reset: in std_logic;
	dout: out std_logic
	);		
end component;
 
signal madd_p: std_logic_vector(17 downto 0);
signal we_a24, oe_a24, mem_done: std_logic;
signal g245_mem_p: std_logic;
signal ena_word_count, ena_event_count, ena_gol_test, ena_ceros_mem,ena_cycles: std_logic;
signal ena_random, txena_out_lfsr: std_logic;
signal reset_pointer,inc_pointer,is_trigger_1, is_trigger_pulso: std_logic;
signal cycle_counter: std_logic_vector (15 downto 0);
signal counter: std_logic_vector (17 downto 0);
signal mword_count: std_logic_vector (17 downto 0);
signal mevent_count,num_cycles: std_logic_vector (15 downto 0);
signal mem_is_full: std_logic;

type estado_type is (idle, wait_l1a, ceros_to_mem,
				gol_test, gol_pull_down, ceros_fin_ev,
				fin, rst_mem_pointer);
signal estado: estado_type;

signal soft_reset:std_logic;
signal enw1,enw2,enw: std_logic;

begin


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

----- dummy signals --------------------------------------------------------------

--tp(0) <= '1' when estado=wait_l1a else '0'; --tp5
tp6 <= reset_pointer;  --tp6
tp7 <= inc_pointer_reg;  --tp7
tp8 <= clk_slow;	--tp8
--tp(0) <= ena_gol_test;
--tp(2) <= ena_ceros_mem;
tp5<= dtack_ifc;
--tp(1) <= dsdly(1);
--vspare <= (OTHERS => '0');
--fspare <= (OTHERS => '0'); 
mspare_3 <= '0';
mspare_2 <= '0';
mspare_1 <= '0';
mspare_0 <= '0';
vspare_1 <= '0';
--vspare_0 <= '0';
----------------------------------------------------------------------------------
soft_reset <= vspare_0;

cspare(11) <= '1' when estado=gol_test else '0';
cspare(10) <= soft_reset;
cspare(9 downto 0) <= (OTHERS => '0'); 



-- puertos
ds_out <= not (ds0 or ds1);

-- componentes
-- LEDS
-- inputs
disp_led(0) <= not (we_ifc and we_blk);
disp_led(1) <= not (oe_ifc and oe_blk);
disp_led(2) <= is_trigger_pulso;

--outputs
led (0) <= disp_led(0);--led_pulse(0);
led (1) <= disp_led(1);--led_pulse(1);
trigger_led <= led_pulse_2;

--ledgen: for lgen in disp_led'range generate
--ULED: stretch port map(clk, clk_slow, disp_led(lgen), reset, led_pulse(lgen));
ULED: stretch port map(clk, clk_slow, disp_led(2), reset, led_pulse_2);
--end generate;

U1: rm_vmeifc port map (
	ds0=>ds0, ds1=>ds1, dsdly0=>dsdly(0), dsdly1=>dsdly(1), iack=>iack, --: in std_logic;
	write=>write, brdsel24=>brdsel24, --: in std_logic;
	am=>am, --: in std_logic_vector (5 downto 0);
	we=>we_ifc, dtack=>dtack_ifc, g245=>g245_ifc, oe=>oe_ifc --: out std_logic 
     );

U2: rm_vmeblk port map (
	ds0=>ds0, ds1=>ds1, 
	dsdly0=>dsdly(0), dsdly1=>dsdly(1), iack=>iack, --: in std_logic;
	write=>write, brdsel24=>brdsel24, lword=>lword, --: in std_logic;
	am=>am, --: in std_logic_vector (5 downto 0);
	we=>we_blk, dtack=>dtack_blk, g245=>g245_blk, 
   oe=>oe_blk, inc_add=>inc_add, acc_blk=> acc_blk --: out std_logic 
    );

U3: rm_memadd  port map(
     inc_add=>inc_add, acc_blk=>acc_blk, as=>as, --: in std_logic;
     add=>add, --: in std_logic_vector(17 downto 0);
     madd=>madd_p --: out std_logic_vector(17 downto 0)
	);

U4: rm_registros port map(
	clk=>clk, reset=>reset, --: in std_logic;
 	txena_out_lfsr=>txena_out_lfsr,
	mem_done=>mem_done,
	mem_is_full=>mem_is_full,

-- vme A16
	enw=>enw, cs=>cs, --: in std_logic;
	add=>add(5 downto 0), --: in std_logic_vector(5 downto 0);
	db_in=>db_in, --: in std_logic_vector (15 downto 0);
	db_out=>db_out, --: out std_logic_vector (15 downto 0)
	
	ena_word_count_p => ena_word_count,
   ena_event_count_p => ena_event_count,
	ena_gol_test_p => ena_gol_test,
	ena_ceros_mem_p => ena_ceros_mem,
	ena_cycles_p => ena_cycles,
	ena_random_p=> ena_random,
	reset_pointer=> reset_pointer,
	inc_pointer=> inc_pointer_reg,
	mword_count_p => mword_count,
	mev_count_p => mevent_count,
	num_cycles_p => num_cycles,

-- registros
     mem_pointer_p=>mem_pointer --: out std_logic_vector (17 downto 0)
     );

dtack_mem <= dtack_ifc or dtack_blk;
g245_mem_p <= g245_ifc and g245_blk;	 --activo bajo
g245_mem <= g245_mem_p;

--OUTPUT ENABLE DE LA MEMORIA
oe_a24 <=	oe_ifc and oe_blk; --activo bajo
oe <= '0' when estado=gol_test else oe_a24;

--WRITE ENABLE DE LA MEMORIA
we_a24 <= we_ifc and we_blk; --activo bajo
we <= we_fifo when (estado=ceros_to_mem or estado=ceros_fin_ev) else
		we_a24 when estado=idle else '1';

--Paso de un pulso de 25ns positivo a uno de 12.5ns negativo
process (clk, reset)
begin
     if reset='1' then
         we_fifo <= '1';
     elsif clk'event then
--         	we_fifo <= not(txena and not clk);
         	we_fifo <= not(txena_reg_in and not clk);
     end if;
end process;

madd <= madd_p when estado=idle else mem_pointer;

--BUS DE DATOS

db <= mdat_in when (estado=idle and g245_mem_p='0' and write='1') else
    db_out when (etr='0' and cs='1') else (others => 'Z'); --en etr ya esta controlado que sea A16
db_in <= db;

mdat <= db_in when (estado=idle and g245_mem_p='0' and write='0') else
        dout_reg_in when estado=ceros_to_mem or estado=ceros_fin_ev else (others => 'Z');
mdat_in <= mdat;

dout <= dout_reg_out when estado=gol_test else (others => 'Z');       
txena <= txena_reg_out when estado=gol_test 
		else '0' when estado=gol_pull_down else 'Z';


process (clk, reset)
begin
    if reset='1' then
       	txena_reg_in <= '0';
       	dout_reg_in <= (others => '0');
       	dout_reg_in_2 <= (others => '0');
     elsif clk'event and clk='1' then
--registro el que viene de las fifos, modo ceros_to_mem 
	   	txena_reg_in <= txena; 
      	dout_reg_in_2 <= dout;
      	dout_reg_in <= dout_reg_in_2;
 		end if;
end process;

process (clk, reset)
begin
    if reset='1' then
       	txena_reg_out <= '0';
       	dout_reg_out <= (others => '0');
     elsif clk'event and clk='1' then
--modo goltest
	 		txena_reg_out <= txena_out; 
     		dout_reg_out <= mdat_in;
 		end if;
end process;

--En ROSMEM mem_done es un pulso, pero a ROSVME tengo que mandar un nivel
process(reset,clk)
begin
	if reset='1' then
		mem_done_p <= '0';
	elsif clk'event and clk='1' then
		if mem_done='1' then
			mem_done_p <= '1';
		elsif ena_ceros_mem='1' or ena_gol_test='1' then
			mem_done_p <= '0';
		end if;
	end if;
end process;

reset_pointer<='1' when estado=rst_mem_pointer else '0';
mem_done <='1' when estado=fin else '0';
inc_pointer_reg<= '0' when (estado=gol_test and ena_random='1' and ena_word_count='1' and counter=mword_count) else inc_pointer;

process(clk,reset)
begin
	if reset='1' then
	   estado <= idle;
	   cycle_counter <= (others => '0');
	   inc_pointer <= '0';
 
	elsif clk'event and clk='1' then
		case estado is
			when idle =>
		        cycle_counter <= num_cycles;
			   if ena_ceros_mem='1' then
			      estado <= wait_l1a;
			   elsif ena_gol_test='1' then
					estado<= rst_mem_pointer;
			   end if;
  			   inc_pointer <= '0';

			when rst_mem_pointer =>
			   cycle_counter <= cycle_counter-1;
			   estado <= gol_test;
  			   inc_pointer <= '0';

			when gol_test =>  
				if ena_gol_test='0' or (ena_word_count='1' and counter=mword_count) then
					estado <= gol_pull_down;
					inc_pointer <= '0';
				else
 	           if ena_random='0' then
          		inc_pointer <= txena_out;
			     else
            	inc_pointer <= txena_out_lfsr;
			     end if;
			end if;
				
			when gol_pull_down =>
				if ena_cycles='1' then
					 if cycle_counter=X"0000" then
					 	estado<= fin;
					 else
						estado <= rst_mem_pointer;
					 end if;
			   	else
			   		estado <= fin;
				end if;
 
			when wait_l1a =>
				if is_trigger_pulso='1' then
				   if ena_event_count='1' and mevent_count=X"0000" then
						estado <= fin;
						inc_pointer <= '0';
					else
			      	estado <= ceros_to_mem;
						inc_pointer <= txena_reg_in;
					end if;
			   else
					inc_pointer <= '0';
				end if;

 			when ceros_to_mem =>
				if ena_ceros_mem='0' or mem_is_full='1' then
--				if ena_ceros_mem='0' then
						estado <= ceros_fin_ev;
						inc_pointer <= '0';
				elsif ena_event_count='1' then
					if counter=mevent_count then
						estado <= ceros_fin_ev;
					end if;
					inc_pointer <= txena_reg_in;
				elsif ena_word_count='1' then
					if counter=mword_count then
						estado <= fin;
						inc_pointer <= '0';
					else
						inc_pointer <= txena_reg_in;
					end if;
				else 
						inc_pointer <= txena_reg_in;
				end if;

			when ceros_fin_ev =>
				if is_trigger='0' then
					estado <= fin;
					inc_pointer <= '0';
				--else
				elsif mem_is_full='1' then
					inc_pointer <= '0';
				else
				 	inc_pointer <= txena_reg_in;
				end if;

			when fin=>
				if ena_ceros_mem='0' and ena_gol_test='0' then
					estado<= idle;
				end if;

			when others=>
			   estado <= idle;
		end case;
	end if;
end process;
 
-- Contador de número máximo de triggeres y de palabras
process (clk, reset)
begin
     if reset='1' then
       	  counter <= (others => '0');
     elsif clk'event and clk='1' then
       if estado=idle or estado=rst_mem_pointer then
	       counter <= (others => '0');
       elsif (ena_event_count='1' and (estado=ceros_to_mem or estado=wait_l1a) and is_trigger_pulso='1') then
	       counter <= counter +1;
       elsif (ena_word_count='1') then
	  	if ((estado=ceros_to_mem and txena_reg_in='1') or
      			(estado=gol_test and txena_out='1')) then
	 		counter <= counter+1;
		end if;
      end if;
    end if;
end process;

process(clk,reset)
begin
	if reset='1' then
		is_trigger_1 <= '0';
	elsif clk'event and clk='1' then
		is_trigger_1 <= is_trigger;
	end if;
end process;

is_trigger_pulso <= is_trigger and not(is_trigger_1);


process (clk, reset)
begin
     if reset='1' then
          txena_out <= '0';
     elsif clk'event and clk='1' then
      if estado=gol_test then
		     if ena_random='0' then
          	   txena_out <= not txena_out;
           else
               txena_out <= txena_out_lfsr;
           end if;
		else
		 	   txena_out <= '0';
		end if;
     end if;
end process;

end arch;
	
