----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    21:20:54 07/16/2012 
-- Design Name: 
-- Module Name:    PE - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library NocLib ;
library Std;
--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;
-- synthesis translate_off 
use std.textio.all;
-- synthesis translate_on
use IEEE.NUMERIC_STD.ALL;


entity PE is
	Generic (DestId : natural:=0 );
    Port ( Instruction : out  STD_LOGIC_VECTOR (Word-1 downto 0);
           Instruction_en : out  STD_LOGIC;
			  Core_PushOut : in STD_LOGIC_VECTOR (Word-1 downto 0);
           clk : in  STD_LOGIC;
           reset : in  STD_LOGIC;
           Core_RAM_Data_Out : out  STD_LOGIC_VECTOR (Word-1 downto 0);
           Core_RAM_Data_In : in  STD_LOGIC_VECTOR (Word-1 downto 0);
           Core_RAM_WE : in  STD_LOGIC;
           Core_RAM_EN : in  STD_LOGIC;
           --Core_RAM_ENB : in  STD_LOGIC;
           Core_RAM_ADDRESS_WR : in  STD_LOGIC_VECTOR (ADRLEN-1 downto 0);
           Core_RAM_ADDRESS_RD : in  STD_LOGIC_VECTOR (ADRLEN-1 downto 0);
           Core_Hold_req : in  STD_LOGIC;
           Core_Hold_Ack : out  STD_LOGIC);
end PE;

architecture Behavioral of PE is
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 Hold_FSM is
    Port ( Hold_Req : in  STD_LOGIC;
           Ram_busy : in  STD_LOGIC;
           Clk : in  STD_LOGIC;
           Reset : in  STD_LOGIC;
           Ramsel : out  STD_LOGIC;
           Hold_Ack : out  STD_LOGIC);
end COMPONENT Hold_FSM;
--données du programme PE
	   --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 pe_instr_en,pe_hold_ack: std_logic:='0';
	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 sram : typ_dpram;
	signal MyGroup:mpi_group;
	signal MyWin : mpi_win;
	signal SrcAdr0,SrcAdr1,destAdr0,destAdr1,Datalen:std_logic_vector(word-1 downto 0);
	signal dpid,dpid_i : natural range 0 to 15:=DestId;
	signal MyRank :std_logic_vector(3 downto 0);
	signal Libr : Core_io;  --regroupe tous les signaux IO de la bibliothèque
	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 
	signal Hold_Ack : std_logic;
 --signaux pour la gestion de la MAE
 type typ_mae is (start,Fillmem,NextFill,InitApp,GetRank,WInCreate,WinStart, putdata,getdata,WinCompleted,finalize,st_timeout);
	type typ_Hld is (Ht_Lock,Core_Lock,Ht_free);
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 RunState : typ_mae;
		signal Hld_state :typ_hld;
		signal Ram_busy :std_logic:='0';
begin
Inst_RAM_v: RAM_v generic map(width=>word,size=>ADRLEN)
	PORT MAP(
		clka =>clk,
		clkb => clk,
		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_mux: process (ramsel,pe_ram_addra,pe_ram_addrb,Core_ram_address_rd,Core_ram_address_wr,
						Core_ram_en,Core_ram_we,Core_ram_data_in,pe_ram_ena,pe_ram_enb,Ram_do,
						Pe_ram_din,Pe_ram_we	)
 begin 				
 case ramsel is
	
	when '1' =>
		ram_addra <= Core_ram_address_wr ;
		ram_addrb <= Core_ram_address_rd ;
		ram_ena <= Core_ram_en;
		ram_enb <= Core_ram_en;
		ram_we<= Core_ram_we;
		ram_din <= Core_ram_data_in;
		pe_ram_do<=(others=>'Z');
		Core_ram_data_out<=ram_do;
		
	when others =>
		ram_addra <=  pe_ram_addra;
		ram_addrb <=  pe_ram_addrb;
		ram_ena <= pe_ram_ena;
		ram_enb <= pe_ram_enb;
		ram_we<= pe_ram_we;
		ram_din <=pe_ram_din;
		Core_ram_data_out<=(others=>'Z');
		pe_ram_do<=ram_do;
end case ;
end process ;



Instruction_En<=PE_instr_EN; -- Libr.Instr_en; --********A changer **********
--=== !!!!! attention la suppression de la ligne ci-dessous empêche ce 
-- composant de bien fonctionner !!! !!!!!!!!!!!!!!!!!!!!!!!
instruction<=std_logic_vector(to_unsigned(Core_upper_adr,8));

dpid<=dpid_i;

Lib_Instr_ack<=Core_Pushout(0); --l'instruction a été copié
Lib_init<=Core_Pushout(4); -- Initialized

Hold1: Hold_fsm port map (
clk=>clk,
reset =>reset,
Ram_Busy=>Libr.membusy,
Hold_Ack=>Hold_Ack,
Hold_req =>Core_Hold_Req,
RamSel => RamSel);
Core_Hold_Ack<=Hold_Ack;


--=======================================================================
--MAE du PE
--=======================================================================

 pPutGet:process(clk,Core_Pushout,Core_Hold_req,PE_hold_Ack,RamSel,PE_Ram_do)
 
	constant DATAPTR : natural :=256;
	variable bfill,destrank,pid,mport : natural range 0 to 15;
	variable fsrc,ret : natural range 0 to 15:=0;
	variable timeout,ct,dlen : natural range 0 to 255;
	variable adrToset,SrcAdr,DestAdr : std_logic_vector(ADRLEN-1 downto 0);
	variable mywin : Mpi_win;
	variable iack : std_logic:='0';
	variable  adresse,adresse_rd :natural range 0 to 65536;
	variable status_reg,config_reg :std_logic_vector(Word-1 downto 0):=(others=>'0');
	--=======================================================
	--variables pour la création du fichier de résultats
		-- synthesis translate_off 
		type char_file is file of character;
        file f: text;
        variable status :file_open_status ;
        variable char_count: integer range 0 to 65536 := 0;
		  variable str: string (1 to 79) ;
		  variable L: line; 
		  variable fopened: std_logic:='0';
		 -- synthesis translate_on
--======================================================
	begin
	--=== Partie combinatoire du process ===================================
			
	--=== Fin de la partie combinatoire du process ==========================	
		
		    
           
        --end loop;
        
	if (clk'event and clk='1') then 
			Libr.Instr_ack<=Core_pushout(0);
			Libr.InitOk<=Core_pushout(4);
			Libr.Hold_Req<=Core_Hold_req;
			Libr.Hold_Ack<=Hold_Ack;
			Libr.RamSel<=RamSel;
			sram.data_out<=PE_ram_do;
			
		if reset='1' then
					RunState<=start;
					
		else
			
			Libr.Instr_ack<=Core_pushout(0);
			Libr.InitOk<=Core_pushout(4);
			Libr.Hold_Req<=Core_Hold_req;
			Libr.Hold_Ack<=Hold_Ack;
			Libr.RamSel<=RamSel;
			sram.data_out<=PE_ram_do;
			
			case  RunState is
			when start =>
				Dcount<=0;
				if bfill=0 then -- si le nombre de bloc de mémoire remplis est vide
						RunState<=Fillmem;
				 end if;
				 Ram_busy<='0';
				 Libr.MemBusy<='0';
				 PE_Instr_En<='0';
				iack:='0';
				adresse:=DATAPTR;
				
				adresse_rd:=0;
				timeout:=0;
				dcount<=0;
			-- synthesis translate_off 
			if fopened='0' then 
			file_open(status,f, integer'image(destid) & "test_file0.txt", APPEND_MODE);
        --while not endfile(c_file_handle) loop
			--end if;
		
				--write (l,string'("Ce fichier contient des resultats de la simulation ; ;" & " started at time ; " & time'image(now)));
				--report l.all;
           -- writeline (f, l) ;
				fopened:='1';
			end if;
			 -- synthesis translate_on
			 when Fillmem =>
				if Ramsel='0' then 
					
					
					
					PE_Ram_din<=std_logic_vector(to_unsigned(dcount,8)); -- x"0f";
					PE_Instr_En<='0';
					dcount<=dcount+1;
					
					if dcount=100 then
						 bfill:=bfill+1;
						 
						 if bfill=4 then
						  RunState<=InitApp;
						 else
							RunState<=nextfill;
						end if;
					else
						adresse:=adresse+1;
						RunState<=Fillmem;
					end if;
			else -- attente de la libéraion de la mémoire
			        timeout:=timeout+1;
					  if timeout=100 then
						RunState<=st_timeout;
					  end if;
							
			end if;
		when nextfill  =>   --prépare le prochain bloc mémoire qui sera rempli
				adresse:=200*bfill+1;
				dcount<=0;
				ct:=0;
				RunState<=Fillmem;
				PE_Instr_En<='0';
		when InitApp =>
				--code pour Init 
				dlen:=139;
				if ct=0 then
				-- synthesis translate_off 
				write (l,string'("Dlen; ;INIT1 " &  integer'image(Dlen)& "; " & image(MyRank) & "; started at ; " & time'image(now)));
				
				report l.all;
            writeline (f, l) ;
				-- synthesis translate_on
				end if;
				pMPI_Init(ct,Libr,Clk,SRam);
				PE_Instr_EN<=Libr.instr_en;
				adresse:=to_integer(unsigned(sram.addr_wr));
				adresse_rd:=to_integer(unsigned(sram.addr_rd));
				PE_ram_din<=sram.data_in;
				Ram_busy<=Libr.membusy;
				--if Libr.InitOk='1' then 
				if ct=0 then 
					RunState<=GetRank;
					-- synthesis translate_off 
					write (l,string'("Dlen; ;INIT2 " &  integer'image(Dlen) & ";" & image(MyRank) & ";  ended at  ; " & time'image(now)));
					report l.all;
					writeline (f, l) ;  
					-- synthesis translate_on
				end if;
				
		
		
		when GetRank =>
		if ct=0 then
				-- synthesis translate_off 
				write (l,string'("Dlen; ;Rank1 " &  integer'image(Dlen) & "; ; started  ; " & time'image(now)));
				report l.all;
            writeline (f, l) ;  
				-- synthesis translate_on
			end if;
			pMPI_Comm_rank(ct,Libr,sram,MPI_COMM_WORLD,MyRank);
			adresse_rd:=to_integer(unsigned(sram.addr_rd));
			Ram_busy<=Libr.membusy;
			
			if ct=0 then
				RunState<=WinStart;
				-- synthesis translate_off
				write (l,string'("Dlen; ;Rank2 " &  integer'image(Dlen) & ";" & image(MyRank) & "; ended at  ; " & time'image(now)));
				report l.all;
            writeline (f, l) ; 
				-- synthesis translate_on
			end if;
			
		
		when Wincreate =>
		
		when WinStart =>
			if ct=0 then
				-- synthesis translate_off 
				write (l,string'("Dlen; ;WStart1 " &  integer'image(Dlen) & "; ; started  ; " & time'image(now)));
				report l.all;
            writeline (f, l) ;  
				-- synthesis translate_on
			end if;
				pMPI_Win_start(ct,Libr,sram,MyGroup,0,MyWin);
					adresse:=to_integer(unsigned(sram.addr_wr));
					adresse_rd:=to_integer(unsigned(sram.addr_rd));
					--PE_Instr_EN<=Libr.instr_en;
					PE_ram_din<=sram.data_in;
					Ram_busy<=Libr.membusy;
					dcount<=ct;
			
			if ct=0 then
				RunState<=PutData;
				-- synthesis translate_off
				write (l,string'("Dlen; ;WStart2 " &  integer'image(Dlen) & ";" & image(MyRank) & "; ended at  ; " & time'image(now)));
				report l.all;
            writeline (f, l) ; 
				-- synthesis translate_on
			end if;
			
		
		when putdata => --construire le packet pour le Put
				
					--dlen:=251; ---
					if ct=0 then
					-- synthesis translate_off 
					write (l,string'("Dlen;" & integer'image(dlen) & ";PUT1 " & integer'image(dlen) & ";" & image(MyRank) & "; started at ; " & time'image(now)));
					report l.all;
					writeline (f, l) ; 
					-- synthesis translate_on
					end if;
					if unsigned(MyRank) = 0 then 
						Destrank:=2;
						
					elsif unsigned(MyRank) = 1 then
						Destrank:=0;
					elsif unsigned(MyRank) = 2 then
						Destrank:=1;
					elsif unsigned(MyRank) = 3 then
						Destrank:=2;
					else
						DestRank:=0;
					end if;
					 
					SrcAdr:=std_logic_vector(to_unsigned(DATAPTR,ADRLEN));
					DestAdr:=X"0340";
					pMPI_put(ct,Libr,Clk,Sram,SrcAdr,Dlen,MPI_int,destrank,DestAdr,Dlen,Mpi_int,Default_win);
					
					adresse:=to_integer(unsigned(sram.addr_wr));
					adresse_rd:=to_integer(unsigned(sram.addr_rd));
					PE_Instr_EN<=Libr.instr_en;
					PE_ram_din<=sram.data_in;
					Ram_busy<=Libr.membusy;
					dcount<=ct;
					
					if ct=0 then
						RunState<=GetData;
					-- synthesis translate_off 
					report "Put of Process n°; " & image(MyRank) & "; ended at ; " & time'image(now);
					write (l,string'("Dlen;" & integer'image(dlen) & ";PUT2 " & integer'image(dlen) & ";" & image(MyRank) & "; ended at time ; " & time'image(now)));
					report l.all;
					writeline (f, l) ;
					-- synthesis translate_on
					end if;
					
				
			when getdata =>   --positionnement du mot de longueur des données
					--dlen:=251; --- 
					if ct=0 then
					-- synthesis translate_off 
					write (l,string'("Dlen;" & integer'image(dlen) & ";GET1; " & image(MyRank) & "; started at ; " & time'image(now)));
					report l.all;
					writeline (f, l) ; 
					-- synthesis translate_on
					end if;
					
					SrcAdr:=X"0120";
					DestAdr:=X"1400";
					if unsigned(MyRank) /= 2 then 
						pMPI_GET(ct,Libr,Clk,Sram,SrcAdr,Dlen,MPI_int,destrank,DestAdr,Dlen,Mpi_int,Default_win);
					else
						RunState<=wincompleted;
					end if;
					adresse:=to_integer(unsigned(sram.addr_wr));
					adresse_rd:=to_integer(unsigned(sram.addr_rd));
					PE_Instr_EN<=Libr.instr_en;
					PE_ram_din<=sram.data_in;
					Ram_busy<=Libr.membusy;
					dcount<=ct;
					
					if ct=0 then
						RunState<=wincompleted;
						-- synthesis translate_off 
						assert ct/=0 report "GET_END " & integer'image(destrank)
								severity Warning ;
						write (l,string'("Dlen ;" & integer'image(dlen) & ";GET2 " & integer'image(dlen) & ";" & image(MyRank) & "; ended at ; " & time'image(now)));
					report l.all;
					
					writeline (f, l) ; 
						-- synthesis translate_on
					end if;
				
				when WinCompleted =>
				if ct=0 then
						-- synthesis translate_off 
						write (l,string'("Dlen ;" & integer'image(dlen) & ";WAIT1 " & integer'image(dlen) & ";" & image(MyRank) & "; started at ; " & time'image(now)));
						report l.all;
						writeline (f, l) ; 
						-- synthesis translate_on 
					end if;	
					 pMPI_Win_wait(ct,Libr,sram,MyWin );
					 adresse:=to_integer(unsigned(sram.addr_wr));
					adresse_rd:=to_integer(unsigned(sram.addr_rd));
					Ram_busy<=Libr.membusy;
					if ct=0 then
						RunState<=finalize;	
						-- synthesis translate_off 
						write (l,string'("Dlen ;" & integer'image(dlen) & ";WAIT2 " & integer'image(dlen) & ";" & image(MyRank) & "; ended at ; " & time'image(now)));
						report l.all;
						writeline (f, l) ;
						-- synthesis translate_on
						
					end if;	  
					
						
			when finalize =>
					if ct=0 then
						-- synthesis translate_off 
						write (l,string'("Dlen ;" & integer'image(dlen) & ";FINALIZE1 " & integer'image(dlen) & ";" & image(MyRank) & "; started at ; " & time'image(now)));
						report l.all;
						writeline (f, l) ; 
						-- synthesis translate_on
					end if;	
					 
					if ct=0 then
						RunState<=start;	
						-- synthesis translate_off 
						write (l,string'("Dlen ;" & integer'image(dlen) & ";FINALIZE2 " & integer'image(dlen) & ";" & image(MyRank) & "; ended at ; " & time'image(now)));
						report l.all;
						writeline (f, l) ;
						file_close(f);	
						-- synthesis translate_on 
					end if;	  
		
			when st_timeout =>
			  
			  --if ram_busy='1' then
				 RunState<=start;
			  --end if
		
			  RunState<=start;
			end case;
			pe_Ram_addra<=STD_LOGIC_VECTOR(to_unsigned(adresse,16));
			pe_Ram_addrb<=STD_LOGIC_VECTOR(to_unsigned(adresse_rd,16));
		end if;
	end if;

  end process pPutGet;	

majPutGet:process (RunState,pe_ram_do,sram,Lib_Init)

	begin
			case  RunState 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';
					
	    when InitApp =>
--				   PE_Ram_we<='1';
--					PE_Ram_ena<='1';
--					PE_Ram_enb<='0';
					PE_Ram_we<=sram.we;
					PE_Ram_ena<=sram.ena;
					PE_Ram_enb<=sram.enb;
					
		 					
			when GetRank =>

					PE_Ram_we<=sram.we;
					PE_Ram_ena<=sram.ena;
					PE_Ram_enb<=sram.enb;
			when WinCreate =>
					
					PE_Ram_we<=sram.we;
					PE_Ram_ena<=sram.ena;
					PE_Ram_enb<=sram.enb;

		when WinStart =>
					
					PE_Ram_we<=sram.we;
					PE_Ram_ena<=sram.ena;
					PE_Ram_enb<=sram.enb;
			  --positionnement du mot de longueur des données
				
				
			when putdata =>
					srcadr0<=X"00";
					srcadr1<=X"01";
					destadr0<=X"00";
					destadr1<=X"02";
					PE_Ram_we<=sram.we;
					PE_Ram_ena<=sram.ena;
					PE_Ram_enb<=sram.enb;
		
			when getdata =>
				PE_Ram_we<=sram.we;
				PE_Ram_ena<=sram.ena;
				PE_Ram_enb<=sram.enb;
				
			when Wincompleted =>				
					PE_Ram_we<=sram.we;
					PE_Ram_ena<=sram.ena;
					PE_Ram_enb<=sram.enb;
				
			when finalize =>
			
				   PE_Ram_we<='0';
					PE_Ram_ena<='0';
					PE_Ram_enb<='0';
				
			
			when st_timeout =>
				  PE_Ram_we<='0';
					PE_Ram_ena<='0';
					PE_Ram_enb<='0';
					
			  
			end case;
		
end process majPutGet ; 
end Behavioral;

