--------------------------------------------------------------------------------
-- Company: 
-- Engineer:
--
-- Create Date:   01:27:32 04/20/2012
-- Design Name:   
-- Module Name:   C:/Core MPI/CORE_MPI/MPICORETEST.vhd
-- Project Name:  MPI_CORE_COMPONENTS
-- Target Device:  
-- Tool versions:  
-- Description:   
-- 
-- VHDL Test Bench Created by ISE for module: MPI_NOC
-- 
-- Dependencies:
-- 
-- Revision: 11 Juillet 2012
-- Revision 0.01 - File Created
-- Additional Comments:Permet de tester le composant MPI
-- en simulant deux PE qui s'échangent des données.
-- Notes: 
-- 
-- 
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
library NocLib ;
--use IEEE.STD_LOGIC_ARITH.ALL;
--use IEEE.STD_LOGIC_UNSIGNED.ALL;
use NocLib.CoreTypes.all;
use work.Packet_type.all;
use work.MPI_RMA.all;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
USE ieee.numeric_std.ALL;
 
ENTITY MPICORETEST IS
--port (clkm : in std_logic;
--reset : in std_logic;
--result : out std_logic_vector(Word-1 downto 0));
END MPICORETEST;
 
ARCHITECTURE behavior OF MPICORETEST IS 
--constant WORD :positive:=8;
constant MEMSIZE:positive:=65535;
 -- Components declaration
 COMPONENT RAM_v
  generic (width : positive;size :positive);
	PORT(
		clka : IN std_logic;
		clkb : IN std_logic;
		wea : IN std_logic;
		ena : IN std_logic;
		enb : IN std_logic;
		addra : IN std_logic_vector;
		addrb : IN std_logic_vector;
		dia : IN std_logic_vector;          
		dob : OUT std_logic_vector
		);
	END COMPONENT;

	
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT MPI_NOC
	 generic (NPROC : positive:=2);
    PORT(
         MPI_Node_in : IN  Ar_MPIPort_in(1 to 2);
         MPI_Node_Out : OUT  Ar_MPIPort_out(1 to 2)
        );
    END COMPONENT;
   
	constant clk_period : time := 10 ns;

--===================signaux pour l'horloge ==============================
signal reset,clkm : std_logic := '0';
--========================================================================
	   --signaux pour l'interconnexionsignal datain :std_logic_vector(word-1 downto 0):= (others => '0');
	signal ram_we ,ram_ena,ram_enb,ramsel: std_logic:='0';
	signal pe_ram_we ,pe_ram_ena,pe_ram_enb: std_logic;
	signal ram_do,ram_din:std_logic_vector(word-1 downto 0):= (others => '0');
	signal pe_ram_do,pe_ram_din:std_logic_vector(word-1 downto 0):= (others => '0');
	signal ram_addra,ram_addrb :std_logic_vector(ADRLEN-1 downto 0);
	signal pe_ram_addra,pe_ram_addrb :std_logic_vector(ADRLEN-1 downto 0);
	signal PE_Instr_en : std_logic:='0';
	signal sram : typ_dpram;
   signal pe_hold_ack,pe_hold_req : std_logic;
	--signal pe_putadr:std_logic_vector(MEMSIZE-1 downto 0);-- adresse du bloc pour Put
	--signal pe_getadr:std_logic_vector(MEMSIZE-1 downto 0);-- adresse du bloc pour get
	signal Lib_Ready:std_logic; --indique que l'exécution de la fonction est terminée
	signal Lib_instr_ack : std_logic; -- l'instruction est copiée dans le tampon FIFO
	signal Lib_Init : std_logic; -- l'initialisation est terminée
	
	--données du programme PE
	signal SrcAdr0,SrcAdr1,destAdr0,destAdr1,Datalen:std_logic_vector(word-1 downto 0);
	signal dpid,dpid_i : natural range 0 to 15:=1;
	--Inputs
   signal MPI_Node_in : Ar_MPIPort_in(1 to 2) ;
-- Port details
--			instruction :   STD_LOGIC_VECTOR (Word -1 downto 0);
--           instruction_en :  STD_LOGIC;
--           packet_ack : std_logic;
--           ram_data_in :  STD_LOGIC_VECTOR (Word-1 downto 0);
--			  clk :  STD_LOGIC;
--           reset :  STD_LOGIC;
 	--Outputs
   signal MPI_Node_Out : Ar_MPIPort_out(1 to 2);
--	détails des champs de Typ_MPIPORT_Out		  
--          
--			  
--         ram_we :  STD_LOGIC;
--			  ram_en :  STD_LOGIC;
--			  packet_received : STD_LOGIC;
--			  barrier_completed : STD_LOGIC;
--         instruction_fifo_full : STD_LOGIC;
--			  PushOut :  STD_LOGIC_VECTOR (WORD-1 downto 0);
--			  ram_data_out : STD_LOGIC_VECTOR (WORD-1 downto 0);
--           ram_address :  STD_LOGIC_VECTOR (ADRLEN-1 downto 0); 
--           		  
--end record;
   -- 
   -- a
 
   
 --signaux pour la gestion de la MAE
 type typ_mae is (start,Fillmem,NextFill,InitApp,InitCompleted,writeptr,InstrCopy, 
 putdata,putdata2,putcompleted,getdata,getdata2,getcompleted,terminate,st_timeout);
signal dcount : natural range 0 to 255:=0; --permet de compter le packet de données envoyées
signal count,count_i : natural range 0 to 15:=0;

--signal adresse,adresse_rd :natural range 0 to 65536;

		signal etPutGet : typ_mae;
		signal Ram_busy :std_logic:='0';
		
BEGIN
 
	-- Instantiate the Unit Under Test (UUT)
   uut: MPI_NOC GENERIC MAP (NPROC=>2)
		PORT MAP (
          MPI_Node_in => MPI_Node_in,
          MPI_Node_Out => MPI_Node_Out
        );
Inst_RAM_v: RAM_v generic map(width=>word,size=>ADRLEN)
	PORT MAP(
		clka =>clkm,
		clkb => clkm,
		wea => ram_we,
		ena => ram_ena,
		enb => ram_enb,
		addra => ram_addra,
		addrb =>ram_addrb,
		dia => ram_din,
		dob => ram_do 
	);
	
	--MUX de la RAM
                             	
  ram_addrb <= MPI_Node_out(1).ram_address_rd WHEN ramsel ='1' ELSE 
            pe_ram_addrb; 
 ram_addra <= MPI_Node_out(1).ram_address_wr WHEN ramsel ='1' ELSE 
            pe_ram_addra; 


ram_ena <= MPI_Node_out(1).ram_en WHEN ramsel ='1' ELSE 
            pe_ram_ena; 
ram_enb <= MPI_Node_out(1).ram_en WHEN ramsel ='1' ELSE 
            pe_ram_enb; 
ram_ena <= MPI_Node_out(1).ram_en WHEN ramsel ='1' ELSE 
            pe_ram_ena; 
		
ram_we<= MPI_Node_out(1).ram_we WHEN ramsel ='1' ELSE 
            pe_ram_we; 

ram_din <= MPI_Node_out(1).ram_data_in WHEN ramsel ='1' ELSE 
            pe_ram_din;
				

MPI_Node_in(1).ram_data_out<=ram_do when ramsel='1' else (others=>'Z');
pe_ram_do<=ram_do when ramsel='0' else (others=>'Z');


pe_hold_req<=MPI_Node_out(1).hold_req;
MPI_Node_in(1).hold_ack<=pe_hold_ack;
MPI_Node_in(1).reset<=reset;	
MPI_Node_in(1).clk<=clkm;
MPI_Node_in(1).instruction_en<=PE_instr_en;
MPI_Node_in(1).instruction<=std_logic_vector(to_unsigned(Core_upper_adr,8));

Lib_Instr_ack<=MPI_Node_out(1).Pushout(0); --l'instruction a été copié
Lib_init<=MPI_Node_out(1).Pushout(4); -- Initialized
--=============================================================
   -- Clock process definitions
--=============================================================
   clk_process :process
   begin
		clkm <= '0' ;
		wait for 10 ns;--clk_period/2;
		clkm <= '1' ;
		wait for 10 ns;--clk_period/2;
   end process;
 stim_proc: process 
   begin		
      -- hold reset state for 100 ns.
      reset<='0';
		wait for 1 ns;	
		reset<='1';
      wait for clk_period*10;
		reset<='0';
		wait;
     
	
	end process;
--================================================================
dpid<=dpid_i;
 pPutGet:process(clkm)
	
	variable bfill,destrank,pid,mport : natural range 0 to 15;
	variable fsrc,ret : natural range 0 to 15:=0;
	variable timeout,dlen,ct : natural range 0 to 255;
	variable adrToset : std_logic_vector(ADRLEN-1 downto 0);
	variable iack : std_logic:='0';
	variable  adresse,adresse_rd :natural range 0 to 65536;
	
	begin
	
	if (clkm'event and clkm='1') then 
		if reset='1' then
					etputget<=start;
					
					
					dcount<=0;
			
		else
	
			case  etputget is
			when start =>
				if bfill=0 then -- si le nombre de bloc de mémoire remplis est vide
						etputget<=Fillmem;
				 end if;
				 Ram_busy<='0';
				 PE_Instr_En<='0';
				iack:='0';
				adresse:=256;
				adresse_rd:=0;
				timeout:=0;
				dcount<=0;
			 when Fillmem =>
				if mpi_node_out(1).hold_req='0' then 
					
					
					
					PE_Ram_din<=std_logic_vector(to_unsigned(dcount,8)); -- x"0f";
					PE_Instr_En<='0';
					dcount<=dcount+1;
					
					if dcount=50 then
						 bfill:=bfill+1;
						 
						 if bfill=4 then
						  etputget<=InitApp;
						 else
							etputget<=nextfill;
						end if;
					else
						adresse:=adresse+1;
						etputget<=Fillmem;
					end if;
			else -- attente de la libéraion de la mémoire
			        timeout:=timeout+1;
					  if timeout=100 then
						etputget<=st_timeout;
					  end if;
							
			end if;
		when nextfill  =>   --prépare le prochain bloc mémoire qui sera rempli
				adresse:=100*bfill;
				dcount<=0;
				etputget<=Fillmem;
				PE_Instr_En<='0';
		when InitApp =>
				--code pour Init ici
				--mettre mpi_init à l'adresse mpi 
				
				PE_Ram_din<=MPI_INIT & x"0" ;
				adresse:=core_init_adr;
				
				PE_Instr_En<='0';
				fsrc:=1;
				adrToSet:=std_logic_vector(to_unsigned(core_init_adr,ADRLEN));
				if ret/=fsrc then
				dcount<=0;
					etputget<=writeptr;
					adresse:=core_base_adr+2;
					PE_Instr_En<='0';
				else
				if Lib_instr_ack='1' then  -- attente de la prise en compte de l'instruction
					etputget<=InitCompleted;
					PE_instr_en<='0';
				
				else
					PE_Instr_en<='1';
				end if;
				   
				end if;
		
		when writeptr =>
				PE_Instr_En<='0';
				if PE_Hold_req = '0' then --s'assurer que le bus est disponible
					
					if dcount=0 then 
						PE_RAM_Din<=AdrToSet(Word-1 downto 0);
						dcount <=dcount+1;
						--adresse:=adresse+1; --prépare la prochaine écriture
					elsif dcount=1 then
						dcount <=dcount+1;
						adresse:=adresse+1; --prépare la prochaine écriture
						PE_RAM_Din<=AdrToSet(15 downto 8);
					elsif dcount=2 then -- ce cycle permet juste de vider le tampon d'écriture en RAM
						ret:=fsrc;
						dcount<=0;
						timeout:=0;
						
								if fsrc=1 then
								etputget <= InitApp;
								elsif fsrc=2 then
								etputget <= putdata;
								elsif fsrc=3 then
								etputget <= getdata;
								else
								etputget <= start;
								end if;
							
					end if;
					
				end if;
		When InstrCopy =>
				if Lib_instr_ack='1' then
					etputget<=Writeptr;
					PE_instr_en<='0';
					iack:='1';
					
				else
					PE_Instr_en<='1';
				end if;
		
		when InitCompleted =>
				
				if Lib_Init='1' then
					etputget<=putdata;
					PE_Instr_En<='0';
				else
					PE_Instr_En<='0';
				end if;
		when putdata => --construire le packet pour le Put
				DestRank:=1;
				adresse_rd:=core_base_adr+Core_Rank2port_base+DestRank;
				
				PE_Instr_En<='0';
				timeout:=0;
				dcount<=0;
				fsrc:=2;
				adrToSet:=std_logic_vector(to_unsigned(core_put_adr,ADRLEN));
				if ret/=fsrc then
				  adresse:=core_base_adr+2;
					etputget<=writeptr;
					ret:=0;
				else
					if Lib_instr_ack/='1' then 
						etputget<= putdata2;
					end if;
				end if;
				
		when putdata2 =>
		
			if ramsel = '0' then  --si le PE a accès à la RAM
					dlen:=to_integer(unsigned(datalen));
					pMPI_put(clkm,destrank,SrcAdr1 & Srcadr0,DestAdr1 & DestAdr0,Dlen,sram,ct);
					adresse:=to_integer(unsigned(sram.addr_wr));
					PE_ram_din<=sram.data_in;
					dcount<=ct;
					if dcount<=6 then
--						   
--							PE_Instr_En<='0';
--							if dcount=0 then 
--							adresse:=core_put_adr;
--							PE_Ram_din<=MPI_PUT & std_logic_vector(to_unsigned(Dpid,4));
--							elsif dcount=1 then 
--							adresse:=core_put_adr+dcount;
--							PE_Ram_din<=Datalen ;
--							elsif dcount=2 then
--							adresse:=core_put_adr+dcount;
--							PE_Ram_din<=SrcAdr1 ;
--							elsif dcount=3 then
--							adresse:=core_put_adr+dcount;
--							PE_Ram_din<=SrcAdr0 ;
--							elsif dcount=4 then
--							adresse:=core_put_adr+dcount;
--							PE_Ram_din<=DestAdr1 ;
--							elsif dcount=5 then
--							adresse:=core_put_adr+dcount;
--							PE_Ram_din<=DestAdr0 ;
							elsif dcount=7 then  --juste après la valeur 6 en fait
--							adresse:=core_base_adr+1;
--							adresse_rd:=core_base_adr;
--							PE_Ram_din<=x"01"; --instruction pulse enable;
							PE_Instr_En<='1';
--							
							end if;
--						dcount<=dcount+1;
--					end if;
			elsif PE_instr_En='0' then
					timeout:=timeout+1;
					if timeout>=10 then -- reprendre le contrôle du Bus de force si nécessaire
						ram_busy<='1';
						timeout:=0;
						PE_Instr_En<='0';
					end if;
			end if;
				if dcount >=6 then
						Ram_busy<='0';--libérer le bus et attendre la réponse du Core MPI
						if Lib_instr_ack='1' then -- Instruction ack
						  PE_Instr_En<='0'; 
							if Ramsel='0' then
								adresse:=core_base_adr+1;
								PE_Ram_din<=x"00"; --ramener le IPulse à 0;
								Ram_busy<='0';
								etPutGet<=putcompleted;
							else
								
								Ram_busy<='1';  --force la prise du bus
							end if;
						else
						
						  timeout:=timeout+1; 
						  if timeout=150 then 
								etputget<=st_timeout;
							end if;
						end if;
				end if;
			
			
			when putcompleted =>
				adresse_rd:=core_put_adr+6;
				if PE_Ram_do(0)='1' then  --Put completed
					etPutGet<=GetData;
				end if;
				PE_Instr_En<='0';
			when getdata =>   --positionnement du mot de longueur des données
			   
				DestRank:=1;
				timeout:=0;
				dcount<=0;
					fsrc:=3;
				adrToSet:=std_logic_vector(to_unsigned(core_get_adr,ADRLEN));
				if ret/=fsrc then
					adresse:=core_base_adr+2;
					etputget<=writeptr;
					ret:=0;
				else
					adresse:=core_get_adr;
					etputget<= getdata2;
				end if;
			    PE_Instr_En<='0';
				when getdata2 =>
					
					if ramsel='0' then
						
						pMPI_get(clkm,destrank,SrcAdr1 & Srcadr0,DestAdr1 & DestAdr0,Dlen,sram,ct);
					   adresse:=to_integer(unsigned(sram.addr_wr));
						PE_ram_din<=sram.data_in;
						dcount<=ct;
						if dcount<=6 then
							
--							if dcount<=0 then 
--								adresse:=core_get_adr;
--							PE_Ram_din<=MPI_GET & std_logic_vector(to_unsigned(Dpid,4));
--							elsif dcount=1 then
--							adresse:=core_get_adr+dcount;
--							PE_Ram_din<=Datalen ;
--							elsif dcount=2 then
--							adresse:=core_get_adr+dcount;
--							PE_Ram_din<=SrcAdr1 ;
--							elsif dcount=3 then
--							adresse:=core_get_adr+dcount;
--							PE_Ram_din<=SrcAdr0 ;
--							elsif dcount=4 then
--							adresse:=core_get_adr+dcount;
--							PE_Ram_din<=DestAdr1 ;
--							elsif dcount=5 then
--							adresse:=core_get_adr+dcount;
--							PE_Ram_din<=DestAdr0 ;
							
							elsif dcount=7 then
--							adresse:=core_base_adr+1;
							adresse_rd:=core_base_adr;
							PE_Instr_En<='1';
--							PE_Ram_din<=x"01"; --instruction pulse enable;
							timeout:=0;
							end if;
--							dcount<=dcount+1;
--					end if;
					elsif  PE_Instr_En='0'then
						timeout:=timeout+1;
						if timeout>=10 then -- reprendre le contrôle du Bus de force si nécessaire
							ram_busy<='1';
							timeout:=0;
							PE_Instr_En<='0';
						end if;
					end if;
			
				  if dcount >=6 then
						  Ram_busy<='0';--libérer le bus et attendre la réponse du Core MPI
								if Lib_instr_ack='1' then -- Instruction ack
								  PE_Instr_En<='0'; 
									if Ramsel='0' then
										adresse:=core_base_adr+1;
										PE_Ram_din<=x"00"; --ramener le IPulse à 0;
										Ram_busy<='0';
										etPutGet<=getcompleted;
									else
										
										Ram_busy<='1';  --force la prise du bus
									end if;
								else
								
									  timeout:=timeout+1; 
									  if timeout=150 then 
											etputget<=st_timeout;
										end if;
								end if;
								
								
						end if;
						
				
					
				when getcompleted =>
				adresse_rd:=core_get_adr+6;
				PE_Instr_En<='0';
				if PE_Ram_do(0)='1' then  --Put completed
				   if Ramsel='0' then
					adresse:=core_base_adr+1;
					PE_Ram_din<=x"00"; --ramener le IPulse à 0;
					etPutGet<=Terminate;
					else
						timeout:=timeout+1;
					end if;
				end if;	
					
						
			when terminate =>
			
		
					etputget<=start;
					
			when st_timeout =>
			  
			  --if ram_busy='1' then
				 etputget<=start;
			  --end if
		
			  etputget<=start;
			end case;
			pe_Ram_addra<=STD_LOGIC_VECTOR(to_unsigned(adresse,ADRLEN));
			pe_Ram_addrb<=STD_LOGIC_VECTOR(to_unsigned(adresse_rd,ADRLEN));
		end if;   --reset='1'
	end if;
  end process pPutGet;	

majPutGet:process (etputget)

	begin
			case  etputget is
			when start =>
			
				   PE_Ram_we<='0';
					PE_Ram_ena<='0';
					PE_Ram_enb<='0';
					--PE_Instr_En<='0';

		 when fillmem =>
				   PE_Ram_we<='1';
					PE_Ram_ena<='1';
					
					PE_Ram_enb<='0';
					--PE_Instr_En<='0';
		 when nextfill =>
					PE_Ram_we<='1';
					PE_Ram_ena<='1';
					PE_Ram_enb<='0';
					--PE_Instr_En<='0';
	    when InitApp =>
				   PE_Ram_we<='1';
					PE_Ram_ena<='1';
					PE_Ram_enb<='0';
					--PE_Instr_En<='0';
		 when Initcompleted =>
			      --PE_Instr_En<='1';
		 when writeptr =>
					PE_Ram_we  <='1';   --écriture dans la RAM
					PE_Ram_ena <='1';
					
					PE_Ram_enb <='0';
			--		dcount<=dcount+1;
					
					--PE_Instr_En<='0';
		when InstrCopy =>  --instruction copy
				   PE_Ram_we<='0';
					PE_Ram_ena<='0';
					PE_Ram_enb<='0';

		
		when putdata =>   --positionnement du mot de longueur des données
				--dcount<=0;
				srcadr0<=X"00";
				srcadr1<=X"01";
				destadr0<=X"00";
				destadr1<=X"02";
				   PE_Ram_we<='0';
					PE_Ram_ena<='0';
					   --lecture du n° de port de destination
					PE_Ram_enb<='1';
				datalen<=std_logic_vector(to_unsigned(50,8));
				dpid_i<=to_integer(unsigned(PE_ram_do(3 downto 0))); --le port est situé ur les 4 bits de poids faible
				--PE_Instr_En<='0';
			when putdata2 =>
					PE_Ram_we  <='1';   --écriture dans la RAM
					PE_Ram_ena <='1';
					
					PE_Ram_enb <='0';
			--		dcount<=dcount+1;
					if dcount>=5 then
					--PE_Instr_En<='1';
					else
					--PE_Instr_En<='0';
					end if;
			when putcompleted =>			
					PE_Ram_we  <='1';
					PE_Ram_ena <='1';
					  -- lecture du résultat
					PE_Ram_enb  <='1';
					--PE_Instr_En<='1';
			when getdata =>
				--dcount<=0;
				srcadr0<=X"00";
				srcadr1<=X"02";
				destadr0<=X"00";
				destadr1<=X"03";
				datalen<=std_logic_vector(to_unsigned(50,8));
				--PE_Instr_En<='0';	
			when getdata2 =>
				   PE_Ram_we  <='1';   --écriture dans la RAM
					PE_Ram_ena <='1';
					
					PE_Ram_enb <='0';
				--dcount<=dcount+1;
				   if dcount=5 then
						--PE_Instr_En<='1';
					else
						--PE_Instr_En<='0';
					end if;
			when getcompleted =>				
					PE_Ram_we  <='1';
					PE_Ram_ena <='1';
					  -- lecture du résultat
					PE_Ram_enb  <='1';
					--PE_Instr_En<='1';
			when terminate =>
			
				   PE_Ram_we<='0';
					PE_Ram_ena<='0';
					PE_Ram_enb<='0';
					--PE_Instr_En<='0';
			
			when st_timeout =>
				  PE_Ram_we<='0';
					PE_Ram_ena<='0';
					PE_Ram_enb<='0';
					--PE_Instr_En<='0';
			  
			end case;
		
end process majPutGet ;  

 hold:process (pe_hold_req,clkm,reset)
 begin
 if rising_edge(clkm) then
	if reset='1' then
		pe_hold_ack<='0';
	else
		if pe_hold_req='1' then
			ramsel<=not(ram_busy);
			pe_hold_ack<=not(ram_busy); --si la mémoire est occupé, forcé une libération
		else
			pe_hold_ack<='0';
			ramsel<='0';
		end if;
	end if;
 end if;
 end process hold;
END;
