--	Package File Template
--
--	Purpose: This package defines supplemental types, subtypes, 
--		 constants, and functions 


library IEEE;
use IEEE.STD_LOGIC_1164.all;
use ieee.numeric_std.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
Library NocLib;
use NocLib.CoreTypes.all;
use work.PACKET_TYPE.all;

package Mpi_Rma is
procedure WritePtr(AdrVect:in std_logic_vector; count: inout natural;signal SysRam :out typ_dpram);
procedure pMPI_INIT(NextCtx : inout natural;signal Interf:inout Core_io;signal clkin:std_logic;signal SysRam :inout typ_dpram);
procedure pMPI_PUT(NextCtx : inout natural;signal Interf:inout Core_io;signal clkin:std_logic;signal SysRam :inout typ_dpram;
 Orig_Addr: std_logic_vector;Orig_Count : natural; Orig_DataType: natural;
  Target_Rank : natural; Target_disp : std_logic_vector; Target_Count : natural;
  Target_Datatype :natural; Win : natural);

procedure pMPI_GET(NextCtx : inout natural;signal Interf:inout Core_io;signal clkin:std_logic;signal SysRam :inout typ_dpram;
 Orig_Addr: std_logic_vector;Orig_Count : natural; Orig_DataType: natural;
  Target_Rank : natural; Target_disp : std_logic_vector; Target_Count : natural;
  Target_Datatype :natural; Win : natural);
procedure pMPI_Comm_Rank(NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam :inout typ_dpram; COMM :in natural; signal Rank : out std_logic_vector );

procedure pMPI_Win_create(NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam :inout typ_dpram;
									base :std_logic_vector; size : Mpi_Aint;disp_unit:natural; 
									info:natural; comm:Mpi_Comm; Win: inout MPI_Win );
procedure pMPI_Win_wait( NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam :inout typ_dpram; Win :MPI_Win);
-- declare functions and procedure	 
 procedure ReadMem(NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam :inout typ_dpram;
						AdrVect:in std_logic_vector; data: out std_logic_vector);
procedure WriteMem(NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam :inout typ_dpram;
						AdrVect:in std_logic_vector; Data:in std_logic_vector);						
end MPI_Rma;


package body MPI_Rma is
----int MPI_Put(
--  void *origin_addr,
--  int origin_count,
--  MPI_Datatype origin_datatype,
--  int target_rank,
--  MPI_Aint target_disp,
--  int target_count,
--  MPI_Datatype target_datatype,
--  MPI_Win win
--);
-- Example 1
procedure pMPI_PUT(NextCtx : inout natural;signal Interf:inout Core_io;signal clkin:std_logic;signal SysRam :inout typ_dpram;
 Orig_Addr: std_logic_vector;Orig_Count : natural; Orig_DataType: natural;
  Target_Rank : natural; Target_disp : std_logic_vector; Target_Count : natural;
  Target_Datatype :natural; Win : natural) is
variable i,dcount : natural:=0;
variable adresse :natural;
variable addr1 :std_logic_vector(Orig_Addr'length-1 downto 0):=Orig_Addr;
variable addr2 :std_logic_vector(Target_Disp'length-1 downto 0):=Target_Disp;
variable put_adr : std_logic_vector (ADRLEN-1 downto 0);
variable config_reg: std_logic_vector (Word-1 downto 0);
constant LeftZero: std_logic_vector(2*Word-ADRLEN to 0):=(others=>'0');
	begin   
				put_adr:=Std_logic_vector(to_unsigned(Core_put_adr,ADRLEN));
				
				addr1:=Orig_Addr;
				addr2:=Target_Disp;
				if NextCtx /=0 then --préserver la valeur de count entre les appels
				dcount:=NextCtx;
				end if;
--					
					
				if rising_edge(clkin) then		
							if dcount>=0 and dcount <=3 then 
									if interf.ramsel='0' then
											SysRam.we<='1';
											SysRam.ena<='1';
											SysRam.enb<='0';
											WritePtr (put_adr,dcount,SysRam);
											if dcount =4 then 
												-- fin de l'écriture du pointeur en mémoire 
											end if;								
									end if;
							
							elsif dcount=4 then
							if interf.ramsel='0' then
								SysRam.we<='1';
								SysRam.ena<='1';
								SysRam.enb<='0';
								adresse:=core_put_adr;
								sysRam.Data_in<=MPI_PUT & std_logic_vector(to_unsigned(Target_Rank,4)); --code fonction
								sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
								dcount:=dcount+1;
							end if;
							elsif dcount=5 then 
								if interf.ramsel='0' then
								adresse:=core_put_adr+1;
								sysRam.Data_in<=std_logic_vector(to_unsigned(Orig_Count,8)) ;--la longueur
								sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
								dcount:=dcount+1;
								end if;
							elsif dcount=6 then
								if interf.ramsel='0' then
								adresse:=core_put_adr+2;
								sysRam.Data_in<= Addr1(ADRLEN-1 downto Word) ; --source Haut
								sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
								dcount:=dcount+1;
								end if;
							elsif dcount=7 then
								if interf.ramsel='0' then
								adresse:=core_put_adr+3;
								sysRam.Data_in<=Addr1(Word-1 downto 0);  --source Bas
								sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
								dcount:=dcount+1;
								end if;
							elsif dcount=8 then
								if interf.ramsel='0' then
								adresse:=core_put_adr+4;
								sysRam.Data_in<= Addr2(ADRLEN-1 downto Word) ; -- destination haut
								sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
								dcount:=dcount+1;
								end if;
							elsif dcount=9 then
								if interf.ramsel='0' then
								adresse:=core_put_adr+5;
								sysRam.Data_in<=Addr2(Word-1 downto 0); -- destination bas
								sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
								dcount:=dcount+1;
								end if;
							elsif dcount=10 then
								
								SysRam.we<='1';
								SysRam.ena<='1';
								SysRam.enb<='1';
								if interf.ramsel='0' then
								adresse:=core_base_adr+1;
								SysRam.addr_rd<=std_logic_vector(to_unsigned(core_base_adr+1,ADRLEN));
								sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
								sysRam.Data_in<=x"01"; --instruction pulse enable via la mémoire;
								Interf.Instr_En<='1'; --active la prise en compte de l'instruction
								dcount:=dcount+1;
								end if;
							elsif dcount=11 then
								if Interf.Instr_ack='1' then -- le Core a reçu l'instruction ?
									Interf.Instr_En<='0';   --désactiver la prise en compte de l'instruction
									dcount:=dcount+1;
									config_reg:=SysRam.data_out and x"f6";
									SysRam.Data_in<=config_reg ; --ramener le IPulse à 0;
								end if;
									adresse:=core_base_adr+1;
									SysRam.addr_rd<=std_logic_vector(to_unsigned(core_base_adr+1,ADRLEN));
									SysRam.addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
									--SysRam.Ram_busy<='0'; --??
									SysRam.we<='0';
									SysRam.ena<='0';  -- préparer la lecture du résultat du Put
									SysRam.enb<='1';						
							elsif dcount=12 then
									adresse:=core_base_adr+1;
									SysRam.we<='1';
									SysRam.ena<='1';  -- préparer l'écriture du résultat du Put
									SysRam.enb<='1';
									if interf.ramsel='0' then
									config_reg:=SysRam.data_out and x"f6";
									SysRam.Data_in<=config_reg ; --ramener le IPulse à 0;
									dcount:=dcount+1;
									end if;
									SysRam.addr_rd<=std_logic_vector(to_unsigned(core_base_adr+1,ADRLEN));
									sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
							elsif dcount=13 then
									SysRam.we<='1';
									SysRam.ena<='1';  -- préparer l'écriture du résultat du Put
									SysRam.enb<='0';
									config_reg:=SysRam.data_out and x"f6";
									SysRam.Data_in<=config_reg ; --ramener le IPulse à 0;
									dcount:=dcount+1;
									adresse:=core_base_adr+1;
									sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
							elsif dcount=14 then	
									SysRam.we<='0';
									SysRam.ena<='0';
									SysRam.enb<='1';
									if Interf.RamSel='0' then 
										SysRam.addr_rd<=Std_logic_vector(to_unsigned(Core_put_adr+6,Adrlen));
										if SysRam.Data_out(0)='1' then --fin du MPI PUT ici pour l'envoie !
											dcount:=dcount+1;
										end if;
									end if;
							elsif dcount=15 then	
									dcount:=0; --fin normale de la fonction
							end if;
							
							
						  NExtCtx:=dcount;
				end if;
	end procedure;

procedure pMPI_GET(NextCtx : inout natural;signal Interf:inout Core_io;signal clkin:std_logic;signal SysRam :inout typ_dpram;
 Orig_Addr: std_logic_vector;Orig_Count : natural; Orig_DataType: natural;
  Target_Rank : natural; Target_disp : std_logic_vector; Target_Count : natural;
  Target_Datatype :natural; Win : natural) is
variable i,wcount,dcount : natural range 0 to 255:=0;
variable adresse :natural;
variable addr1 :std_logic_vector(Orig_Addr'length-1 downto 0):=Orig_Addr;
variable addr2 :std_logic_vector(Target_Disp'length-1 downto 0):=Target_Disp;
variable get_adr : std_logic_vector (ADRLEN-1 downto 0);
variable config_reg: std_logic_vector (Word-1 downto 0);
constant LeftZero: std_logic_vector(2*Word-ADRLEN to 0):=(others=>'0');
	begin   
				get_adr:=Std_logic_vector(to_unsigned(Core_get_adr,ADRLEN));
				
				addr1:=Orig_Addr;
				addr2:=Target_Disp;
				if NextCtx /=0 then --préserver la valeur de count entre les appels
				dcount:=NextCtx;
				end if;
--					
					
				if rising_edge(clkin) then		
							
						if dcount =0 then	
							dcount:=dcount+1;
						elsif dcount>=1 and dcount <=3 then 
									if interf.ramsel='0' then
											SysRam.we<='1';
											SysRam.ena<='1';
											SysRam.enb<='0';
											wcount:=interf.intstate1;
											WritePtr (get_adr,wcount,SysRam);
											interf.intstate1<=wcount;
											if wcount =0 then 
												dcount:=4;
											end if;								
									end if;
							
							elsif dcount=4 then
							if Interf.RamSel='0' then 
								SysRam.we<='1';
								SysRam.ena<='1';
								SysRam.enb<='0';
								adresse:=core_get_adr;
								sysRam.Data_in<=MPI_GET & std_logic_vector(to_unsigned(Target_Rank,4)); --code fonction
								sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
								
								dcount:=dcount+1;
							end if;
							elsif dcount=5 then 
								if Interf.RamSel='0' then	 
									SysRam.we<='1';
									SysRam.ena<='1';
									adresse:=core_get_adr+1;
									sysRam.Data_in<=std_logic_vector(to_unsigned(Orig_Count,8)) ;--la longueur
									sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
								
									dcount:=dcount+1;
								end if; 
							elsif dcount=6 then
								if Interf.RamSel='0' then 
									SysRam.we<='1';
									SysRam.ena<='1';
									adresse:=core_get_adr+2;
									sysRam.Data_in<= Addr1(ADRLEN-1 downto Word) ; --source Haut
									sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
									
									dcount:=dcount+1;
								else
									dcount:=dcount-1;
								end if;
							elsif dcount=7 then
								if Interf.RamSel='0' then
									SysRam.we<='1';
									SysRam.ena<='1';
									adresse:=core_get_adr+3;
									sysRam.Data_in<=Addr1(Word-1 downto 0);  --source Bas
									sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
									
									dcount:=dcount+1;
								else
									dcount:=dcount-1;
								end if;
							elsif dcount=8 then
								if Interf.RamSel='0' then 
									SysRam.we<='1';
									SysRam.ena<='1';					
									adresse:=core_get_adr+4;
									sysRam.Data_in<= Addr2(ADRLEN-1 downto Word) ; -- destination haut
									sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
								
									dcount:=dcount+1;
								else
									dcount:=dcount-1;
								end if;
							elsif dcount=9 then
								if Interf.RamSel='0' then
									SysRam.we<='1';
									SysRam.ena<='1';
									adresse:=core_get_adr+5;
									sysRam.Data_in<=Addr2(Word-1 downto 0); -- destination bas
									sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
								 
									dcount:=dcount+1;
								end if;
							elsif dcount=10 then
								 
									SysRam.we<='1';
									SysRam.ena<='1';
									SysRam.enb<='1';
									adresse:=core_base_adr+1;
									SysRam.addr_rd<=std_logic_vector(to_unsigned(core_base_adr+1,ADRLEN));
									sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
									sysRam.Data_in<=x"01"; --instruction pulse enable via la mémoire;
									Interf.Instr_En<='1'; --active la prise en compte de l'instruction
								if Interf.RamSel='0' then
									dcount:=dcount+1;
								end if;
							elsif dcount=11 then
								if Interf.Instr_ack='1' then -- le Core a reçu l'instruction ?
									Interf.Instr_En<='0';   --désactiver la prise en compte de l'instruction
									dcount:=dcount+1;
									config_reg:=SysRam.data_out and x"f6";
									SysRam.Data_in<=config_reg ; --ramener le IPulse à 0;
								end if;
									adresse:=core_base_adr+1;
									SysRam.addr_rd<=std_logic_vector(to_unsigned(core_base_adr+1,ADRLEN));
									SysRam.addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
									--SysRam.Ram_busy<='0'; --??
									SysRam.we<='0';
									SysRam.ena<='0';  -- préparer la lecture du résultat du get
									SysRam.enb<='1';						
							elsif dcount=12 then
								
									adresse:=core_base_adr+1;
									SysRam.we<='1';
									SysRam.ena<='1';  -- préparer l'écriture du résultat du get
									SysRam.enb<='1';
								if Interf.RamSel='0' then 	
									config_reg:=SysRam.data_out and x"f6";
									SysRam.Data_in<=config_reg ; --ramener le IPulse à 0;
									dcount:=dcount+1;
								end if;
									SysRam.addr_rd<=std_logic_vector(to_unsigned(core_base_adr+1,ADRLEN));
									sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
								
							elsif dcount=13 then
									 
										SysRam.we<='1';
										SysRam.ena<='1';  -- préparer l'écriture du résultat du GET
										SysRam.enb<='0';
										adresse:=core_base_adr+1;
										sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
									if Interf.RamSel='0' then
										config_reg:=SysRam.data_out and x"f6";
										SysRam.Data_in<=config_reg ; --ramener le IPulse à 0;
										dcount:=dcount+1;
										
									end if;
							elsif dcount=14 then	
									SysRam.we<='0';
									SysRam.ena<='0';
									SysRam.enb<='1';
									if Interf.RamSel='0' then 
										SysRam.addr_rd<=Std_logic_vector(to_unsigned(Core_get_adr+6,Adrlen));
										if SysRam.Data_out(0)='1' then --fin du MPI get ici pour l'envoie !
											dcount:=dcount+1;
										end if;
									end if;
							elsif dcount=15 then	
									dcount:=0; --fin normale de la fonction
							end if;
							
							
						  NExtCtx:=dcount;
			end if; 
	end procedure; 
Procedure pMPI_Comm_group(NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam : inout typ_dpram; COMM :in MPI_Comm; signal grp : out Mpi_group ) is 
Begin
--cette procédure permet de récupérer le groupe qui est associé à un communicateur
--dans notre cas c'est la récupération du groupe associé à COMM_WORLD
end procedure;
--int MPI_Group_incl(MPI_Group group, int n, int *ranks,
--    MPI_Group *newgroup)
Procedure pMPI_group_incl(NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam : inout typ_dpram;
									GRP: Mpi_group; n:natural;ranks :natural; newgroup: out Mpi_group) is
Begin
-- cette procedure a pour algo de parcourir les rangs qui sont dans la mémoire pointée par ranks
-- et d'activer l'un des  bits de position de newgroup. 
-- 
--
end procedure;
								
procedure pMPI_Comm_Rank(NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam :inout typ_dpram; COMM :in natural; signal Rank : out std_logic_vector ) is
variable adresse_rd : natural range 0 to 2**ADRLEN-1;	

begin

		if NextCtx =0 then
			SysRam.we<='0';
			SysRam.ena<='0';
			SysRam.enb<='1';
			adresse_rd:=CORE_INIT_ADR+1;
			sysRam.Addr_rd<=Std_logic_vector(to_unsigned(adresse_rd,ADRLEN));
			
				NextCtx:=1;
		
		elsif NextCtx=1 then
			SysRam.we<='0';
			SysRam.ena<='0';
			SysRam.enb<='1';
			adresse_rd:=CORE_INIT_ADR+1;
			sysRam.Addr_rd<=Std_logic_vector(to_unsigned(adresse_rd,ADRLEN));
			if Interf.Ramsel='0' then
				Rank<=SysRam.Data_out(3 downto 0);
				NextCtx:=2;
			end if;	
		elsif NextCtx=2 then
			SysRam.we<='0';
			SysRam.ena<='0';
			SysRam.enb<='1';
			adresse_rd:=CORE_INIT_ADR+1;
			sysRam.Addr_rd<=Std_logic_vector(to_unsigned(adresse_rd,ADRLEN));
			if Interf.Ramsel='0' then
				Rank<=SysRam.Data_out(3 downto 0);
				NextCtx:=3;
			end if;	
		elsif NextCtx=3 then
			SysRam.we<='0';
			SysRam.ena<='0';
			SysRam.enb<='1';
			adresse_rd:=CORE_INIT_ADR+1;
			sysRam.Addr_rd<=Std_logic_vector(to_unsigned(adresse_rd,ADRLEN));
			if interf.ramsel='0' then
				Rank<=SysRam.Data_out(3 downto 0);
				NextCtx:=0;
			end if;	
		end if;
end procedure;

--int MPI_Win_create(
--  void *base,
--  MPI_Aint size,
--  int disp_unit,
--  MPI_Info info,
--  MPI_Comm comm,
--  MPI_Win *win
--);
procedure pMPI_Win_create(NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam :inout typ_dpram;
									base :std_logic_vector; size : Mpi_Aint;disp_unit:natural; 
									info:natural; comm:Mpi_Comm; Win: inout MPI_Win ) is
 -- parcours de la liste des fenêtres existantes à la recherche d'un emplacement libre
 -- si fenêtre libre trouvée, et 
 -- mise à 1 du Bit WCreate du registre status
 type wtype is array (1 to 4 ) of natural range 0 to 255;
 variable AdrWin: std_logic_vector(ADRLEN-1 downto 0);
 variable adresse : std_logic_vector(ADRLEN-1 downto 0);
 variable clkin : std_logic:='1';
 variable wcreate_adr : std_logic_vector(ADRLEN-1 downto 0):=std_logic_vector(to_unsigned(Core_wcreate_adr,ADRLEN));
 variable w0 : std_logic_vector(Word-1 downto 0);
 variable adrnat : natural;
 variable sizewin : std_logic_vector(Word-1 downto 0);
 variable count : natural range 0 to 255;
 variable wdisp  :wtype:=(4,14,24,34); --stocke l'adresse de la prochaine Win libre
begin
-- création d'une fenêtre il s'agit d'affecter l'objet Win et de retourner 
-- le pointeur qui permet de le décrire 


If NextCtx=0 then 
	NExtCtx:=NextCtx+1;
	count:=0;
	Interf.Intstate1<=count;
elsif NextCtx>=1 and NextCtx <= 4 then
	count:=Interf.IntState1;
	AdrWin:=std_logic_vector(to_unsigned(Core_base_adr+Wdisp(NextCtx),16));
	 readmem(count,interf,sysRam,AdrWin,w0);
		if count=0 then
			if w0(0)/='1' then -- cette fenêtre est libre
				NextCtx:=6; --étape de la création de la fenêtre
				Win.addr:=base; --l'adresse de la fenêtre
				Win.id:=NextCtx; -- la référence provisoire de la fenêtre
				Win.size:=Size; -- la taille de la fenêtre
				
			else
				NextCtx:=NextCtx+1;
			end if;
		end if;
		Interf.intstate1<=count;--sauvegarde du statut de la sous-procédure
		
elsif NextCtx=5 then
	-- Plus de fenêtre disponible erreur
		NextCtx:=1; -- boucle sans fin :)
		Win.id:=0;
		Win.addr:=x"0000";
elsif NextCtx=6 then
		--Affectation de l'objet Windows car une place est disponible
		count:=Interf.intstate1;
		AdrWin:=std_logic_vector(to_unsigned(Core_base_adr+Wdisp(Win.id),16));
		Writemem(count,interf,SysRam,AdrWin,x"01"); --signal status pour created
		Interf.intstate1<=count;
		if count=0 then
			NextCtx:=NextCtx+1;
		end if;
		
elsif NextCtx=8 then
		AdrWin:=std_logic_vector(to_unsigned(Core_base_adr+Wdisp(Win.id),16));
		interf.winid<=interf.winid+1;
		count:=Interf.intstate1;
		Writemem(count,interf,SysRam,AdrWin+1,stdlv(interf.winid,8)); --win id de la fenêtre
		Interf.intstate1<=count;
		if count=0 then
			NextCtx:=NextCtx+1;
		end if;
elsif NextCtx=9 then

		adrnat:=Core_base_adr+Wdisp(Win.id);
		
		AdrWin:=std_logic_vector(to_unsigned(Core_base_adr+Wdisp(Win.id),16));
		count:=Interf.intstate1;
		
		
		Writemem(count,interf,SysRam,AdrWin+2,base(7 downto 0)); --adresse basse
		Interf.intstate1<=count;
		if count=0 then
			NextCtx:=NextCtx+1;
		end if;
elsif NextCtx=10 then
		AdrWin:=std_logic_vector(to_unsigned(Core_base_adr+Wdisp(Win.id),16));
		count:=Interf.intstate1;
		Writemem(count,interf,SysRam,AdrWin+3,base(15 downto 8)); --adresse haute
		Interf.intstate1<=count;
		if count=0 then
			NextCtx:=NextCtx+1;
		end if;
elsif NextCtx=11 then
		AdrWin:=std_logic_vector(to_unsigned(Core_base_adr+Wdisp(Win.id),16));
		sizewin:=std_logic_vector(to_unsigned(size,8));
		count:=Interf.intstate1;
		Writemem(count,interf,SysRam,AdrWin+4,sizewin); -- taille de la fenêtre
		Interf.intstate1<=count;
		if count=0 then
			NextCtx:=NextCtx+1;
		end if;
elsif NextCtx=12 then	
	--cette étape consiste à envoyer le message WINCREATE Sur le réseau et à récupérer
	-- les informations donnant le numéro de la fenêtre
		W0:=MPI_WINCREATE & std_logic_vector(to_unsigned(0,4)); --code fonction
		count:=Interf.intstate1;
		Writemem(count,interf,SysRam,wcreate_adr,w0);
		Interf.intstate1<=count;
		if count=0 then
			NextCtx:=NextCtx+1;
		end if;
		
	elsif NextCtx=13 then 
		w0:=std_logic_vector(to_unsigned(Win.Id,8));							-- id proposé pour la fenêtre en création
		count:=Interf.intstate1;
		Writemem(count,interf,SysRam,wcreate_adr+1,w0);
		Interf.intstate1<=count;
		if count=0 then
			NextCtx:=NextCtx+1;
		end if;
	elsif NextCtx=14 then
		SysRam.we<='1';
		SysRam.ena<='1';
		SysRam.enb<='0';
		count:=Interf.intstate1;
		if interf.Ramsel='0' then
			WritePtr (wcreate_adr,count,SysRam); --écriture du pointeur d'instruction
			Interf.intstate1<=count;
			if count=0 then
				NextCtx:=NextCtx+1;
			end if;
		end if;
	elsif NextCtx=15 then
									-- il faut mettre instruction_en à 1
				SysRam.we<='0';
				SysRam.ena<='0';
				SysRam.enb<='1';
				SysRam.we<='1';
				SysRam.ena<='1';
				SysRam.enb<='1';
				adresse:=stdlv(core_base_adr+1);
								SysRam.addr_rd<=adresse;
								sysRam.Addr_wr<=adresse;
								sysRam.Data_in<=x"01"; --instruction pulse enable via la mémoire;
		Writemem(count,interf,SysRam,adresse,x"01");
		Interf.intstate1<=count;
		if count=0 then
			NextCtx:=NextCtx+1;
		end if;
				Interf.Instr_En<='1';
				adresse:=stdlv(core_base_adr);
				sysRam.Addr_rd<=adresse;
				NextCtx:=NextCtx+1;
	elsif NextCtx=16 then --acquittement de la copie des données dans le tampon de la lib
				if Interf.Instr_ack='1' then
					Interf.Instr_En<='0';
					NextCtx:=NextCtx+1;
				end if;
				SysRam.we<='0';
				SysRam.ena<='0';
				SysRam.enb<='1';
	elsif NextCtx=17 then
			-- lecture du résultat de l'instruction
			
	
else
	
end if;
end procedure;
--int MPI_Win_start(
--  MPI_Group group,
--  int assert,
--  MPI_Win win
--);
procedure pMPI_Win_start( NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam :inout typ_dpram; pgroup:MPI_group;asser : natural; Win :MPI_Win) is
--cette fonction active les bits WStart pour chaque processus avec lequel 
-- la source veut communiquer et par la suite envoie un message de synchro sur le réseau à
--chacune de ces cibles
 begin

 -- retour de l'adresse de de la fenêtre dans la structure Win
 -- initialisation des bits concernant 
 
 
 
 end procedure;
procedure pMPI_Win_complete( NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam :inout typ_dpram; Win :MPI_Win) is
begin

end procedure;
procedure pMPI_Win_post( NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam :inout typ_dpram; pgroup:MPI_group;asser : natural; Win :MPI_Win) is
--cette fonction active les bits WStart pour chaque processus avec lequel 
-- la source veut communiquer et par la suite envoie un message de synchro sur le réseau à
--chacune de ces cibles
 begin
 
 end procedure;
 
 procedure pMPI_Win_wait( NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam :inout typ_dpram; Win :MPI_Win) is
--permet de synchroniser la fin des opérations sur une fenêtre
variable dcount : natural range 0 to 255:=0;
variable cstatus : std_logic_vector(Word-1 downto 0);

begin

	
	
		if NextCtx =0 then 
			NextCtx:=NextCtx+1;
		elsif NextCtx=1 then
			if interf.ramsel='0' then
					SysRam.we<='0';
					SysRam.ena<='0';
					SysRam.enb<='1';
					SysRam.addr_rd<=Std_logic_vector(to_unsigned(core_base_adr+4,Adrlen));
							if SysRam.Data_out(5)='1' and  SysRam.Data_out(4)='1' and SysRam.Data_out(2)='0' then 
									NextCtx:=NextCtx+1;
							end if;							
			end if;
	
	elsif NextCtx=2 then
		NextCtx:=0;
	end if;


end procedure;


 Procedure pMPI_Finalize(NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam :inout typ_dpram) is
  begin
 
 end procedure;
 
 
procedure pMPI_INIT(NextCtx : inout natural;signal Interf:inout Core_io;signal clkin:std_logic;signal SysRam :inout typ_dpram) is
variable i,dcount : natural:=0;	
variable adresse :natural;
variable init_adr : std_logic_vector(adrlen-1 downto 0):=Std_logic_vector(to_unsigned(Core_init_adr,ADRLEN));
begin
				init_adr:=Std_logic_vector(to_unsigned(Core_init_adr,ADRLEN));
				if NextCtx =0 then
					
					SysRam.we<='1';
					SysRam.ena<='1';
					SysRam.enb<='0';
					if interf.ramsel='0' then
					NextCtx:=1;
					adresse:=core_init_adr;
					sysRam.Data_in<=MPI_INIT & x"0" ;
					sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
					
					
					Interf.Instr_En<='0';
					end if;
				elsif NextCtx=1 then
					SysRam.we<='1';
					SysRam.ena<='1';
					SysRam.enb<='0';
					if interf.ramsel='0' then
					NextCtx:=2;
					adresse:=core_init_adr;
					sysRam.Data_in<=MPI_INIT & x"0" ;
					sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
					Interf.Instr_En<='0';
					end if;
				
				elsif NextCtx=2 then 
					SysRam.we<='1';
					SysRam.ena<='1';
					SysRam.enb<='0';
				
					sysRam.Data_in<=MPI_INIT & x"0" ;
					sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
					NextCtx:=3;
				elsif NextCtx=3 then
					SysRam.we<='1';
					SysRam.ena<='1';
					SysRam.enb<='0';
					dcount:=1;
					if interf.ramsel='0' then
						sysRam.Addr_rd<=Std_logic_vector(to_unsigned(Core_base_adr,ADRLEN));
						WritePtr (init_adr,dcount,SysRam);
						Interf.Instr_En<='0';
						--if dcount =0 then 
								NextCtx:=4;
						--end if;
					end if;
				elsif NextCtx>=4 and NextCtx<=7 then
							SysRam.we<='1';
							SysRam.ena<='1';
							SysRam.enb<='1';
					if interf.ramsel='0' then
						dcount:=NextCtx-3;
						WritePtr (init_adr,dcount,SysRam);
						NextCtx:=NextCtx+1;
						if dcount =4 then 
								NextCtx:=8;
						end if;
					end if;
				elsif NextCtx=8 then --fin de la fonction
							SysRam.we<='0';
							SysRam.ena<='0';
							SysRam.enb<='1';
							dcount:=0;
							Interf.Instr_En<='1';
							sysRam.Addr_rd<=Std_logic_vector(to_unsigned(Core_base_adr,AdrLen));
							NextCtx:=9;
				elsif NextCtx=9 then --acquittement de la copie des données dans le tampon
							if Interf.Instr_ack='1' then
								Interf.Instr_En<='0';
								NextCtx:=10;
							end if;
							SysRam.we<='0';
							SysRam.ena<='0';
							SysRam.enb<='1';
							
				elsif NextCtx=10 then --lecture de la fin de l'initialisation
							SysRam.we<='0';
							SysRam.ena<='0';
							SysRam.enb<='1';
							if Interf.RamSel='0' then 
								SysRam.addr_rd<=Std_logic_vector(to_unsigned(Core_base_adr,Adrlen));
								if SysRam.Data_out(4)='1' then 
									NextCtx:=11;
								end if;
							end if;								
				elsif NextCtx =11 then
							Interf.Instr_En<='0';
							SysRam.we<='0';
							SysRam.ena<='0';
							SysRam.enb<='0';
							NextCtx:=0;
				end if;
							
				
end procedure;


procedure WriteMem(NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam :inout typ_dpram;
						AdrVect:in std_logic_vector; Data:in std_logic_vector) is
--cette procédure permet d'écrire un mot dans la mémoire du PE(tâche matérielle)
--en ayant vérifié que le bus est bien disponible pour l'écriture
 variable i,dcount : natural:=0;	
variable adresse :natural;
variable AdrToSet :std_logic_vector(AdrVect'length-1 downto 0):=AdrVect;

begin
				if NextCtx /=0 then --préserver la valeur de count entre les appels
					dcount:=NextCtx;
				else
					
					
				end if;
				
							
				if dcount=0 then
					if Interf.RamSel='0' then 
						dcount :=dcount+1;
					end if;
						sysRam.Data_in<=AdrToSet(Word-1 downto 0);					
						sysRam.Addr_wr<=adrToSet;
				elsif dcount=1 then
						if Interf.RamSel='0' then 
							
							dcount :=dcount+1;
						end if;
						sysRam.Data_in<=data;
						sysRam.Addr_wr<=adrToSet;
				elsif dcount=2 then
						sysRam.Data_in<=data;
						dcount :=dcount+1;
						sysRam.Addr_wr<=AdrToSet;
				elsif dcount=3 then
				
						dcount :=dcount+1;
						sysRam.Addr_wr<=adrToSet;
						sysRam.Data_in<=data;
				elsif dcount=4 then -- ce cycle permet juste de vider le tampon d'écriture en RAM
						dcount:=0;
						sysRam.Addr_wr<=AdrToSet;		
				end if;
					
					NextCtx:=dcount;
end procedure;

-- écriture dans la mémoire
procedure ReadMem(NextCtx : inout natural;signal Interf:inout Core_io;signal SysRam :inout typ_dpram;
						AdrVect:in std_logic_vector; data: out std_logic_vector) is
--cette procédure permet d'écrire un mot dans la mémoire du PE(tâche matérielle)
--en ayant vérifié que le bus est bien disponible pour l'écriture
 variable i,dcount : natural:=0;	
variable adresse :natural;
variable AdrToSet :std_logic_vector(AdrVect'length-1 downto 0):=AdrVect;

begin
				if NextCtx /=0 then --préserver la valeur de count entre les appels
					dcount:=NextCtx;
				else
					
					
				end if;
							
				if dcount=0 then
					if Interf.RamSel='0' then 
						dcount :=dcount+1;
					end if;
											
						sysRam.Addr_rd<=adrToSet;
				elsif dcount=1 then
						data:=sysRam.Data_out;
						dcount :=dcount+1;
						sysRam.Addr_rd<=adrToSet;
				elsif dcount=2 then
						data:=sysRam.Data_out;
						dcount :=dcount+1;
						sysRam.Addr_rd<=adrToSet;
				elsif dcount=3 then
						if Interf.RamSel='0' then 
						dcount :=dcount+1;
						sysRam.Addr_rd<=adrToSet;
						data:=sysRam.Data_out;
						end if;
				elsif dcount=4 then -- ce cycle permet juste de vider le tampon d'écriture en RAM
						dcount:=0;
											
				end if;
					
					NextCtx:=dcount;
end procedure;

















procedure WritePtr(AdrVect:in std_logic_vector; count: inout natural;signal SysRam :out typ_dpram) is
--cette procédure permet d'écrire dans la mémoire du PE(tâche matérielle)
--les données de l'appel de la procédure
variable i,dcount : natural:=0;	
variable adresse :natural;
variable AdrToSet :std_logic_vector(AdrVect'length-1 downto 0):=AdrVect;
begin
				if count /=0 then --préserver la valeur de count entre les appels
					dcount:=count;
				else
					
					
				end if;
				adresse:=Core_base_adr+2;
							
				if dcount=0 then
						sysRam.Data_in<=AdrToSet(Word-1 downto 0);
						dcount :=dcount+1;
						sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
				elsif dcount=1 then
				sysRam.Data_in<=AdrToSet(Word-1 downto 0);
						dcount :=dcount+1;
						sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse,ADRLEN));
				elsif dcount=2 then
				sysRam.Data_in<=AdrToSet(ADRLEN-1 downto Word);
						dcount :=dcount+1;
						sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse+1,ADRLEN));
				elsif dcount=3 then
						dcount :=dcount+1;
						sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse+1,ADRLEN));
						sysRam.Data_in<=AdrToSet(ADRLEN-1 downto Word);
				elsif dcount=4 then -- ce cycle permet juste de vider le tampon d'écriture en RAM
						dcount:=0;
						sysRam.Addr_wr<=Std_logic_vector(to_unsigned(adresse+1,ADRLEN));		
				end if;
					
					count:=dcount;
end procedure;
end MPI_Rma;
