----------------------------------------------------------------------------------
-- Company: 
-- Engineer: GAMOM 
-- 
-- Create Date:    14:44:36 03/07/2012 
-- Design Name: 
-- Module Name:    EX4_FSM - Behavioral 
-- Project Name: MPI_CORE_COMPONENTS
-- Target Devices: SPARTAN 3E xc3s1200e
-- Tool versions: 
-- Description: Ce module renferme les fonctions permettant d'initialiser la 
-- bibliothèque matériel MPI
-- Dependencies:
--
-- Revision: 25/juin/2012 au 24/Octobre/2012
-- Revision 0.03 - File updated
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;
Library NocLib;
use NoCLib.CoreTypes.all;
use work.packet_type.all;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity EX4_FSM is
    Port ( Instruction : in  STD_LOGIC_VECTOR (Word-1 downto 0);
           Instruction_En : in  STD_LOGIC;
           clk : in  STD_LOGIC;
           reset : in  STD_LOGIC;
           ResultOut : out  STD_LOGIC_VECTOR (Word-1 downto 0):=(others=>'0');
           Result_En : out  STD_LOGIC:='0';
           NocSize : out  STD_LOGIC_VECTOR(3 downto 0);
			  PortId : out  STD_LOGIC_VECTOR(3 downto 0):=(others=>'0');
           AppRank : out  STD_LOGIC_VECTOR(3 downto 0):=(others=>'0');
           AppSize : out  STD_LOGIC_VECTOR(3 downto 0):=(others=>'0');
           IsMain : out  STD_LOGIC:='0';
			  Initialized : out STD_LOGIC:='0';
			  dma_wr_req : out std_logic:='0';
			  dma_wr_grant : in std_logic;
           AdrRam : out  STD_LOGIC_VECTOR (ADRLEN-1 downto 0):=(others=>'0'); --accès au stockage
           WeRam : out  STD_LOGIC:='0'; --activation de l'écriture en RAM
           DataRam : out  STD_LOGIC_VECTOR (Word-1 downto 0):=(others=>'Z');--données des ports
           AppAck : in  STD_LOGIC;
           AppReq : in  STD_LOGIC;
			  port_in_cmd_en : out  STD_LOGIC:='0';
			  port_in_wr_en : out  STD_LOGIC:='0';
			  port_in_empty : in  STD_LOGIC;
           port_in_full : in  STD_LOGIC;
           port_in_data : out  STD_LOGIC_VECTOR (Word-1 downto 0):=(others=>'Z');
			  port_out_data : in  STD_LOGIC_VECTOR (Word-1 downto 0);
           port_out_rd_en : out  STD_LOGIC:='0';
           port_out_data_available : in  STD_LOGIC);
end EX4_FSM;

architecture Behavioral of EX4_FSM is


Type Ar_MPIPort_In is array (positive range <>) of Typ_MPIPort_in;
Type Ar_MPIPort_out is array (positive range <>) of Typ_MPIPort_out;

	--MAE pour emission de init
   --type init1_type is (init,NocSize,InitToNoc,NextPort,EndBCast); 
	--	MAE pour affectation des rangs aux différentes librairies MPI
	type init2_type is (init,GetPortNum,DecodeData,IsPortZero,SeekMain1,SeekMain2,StoreMain,SetMainFlag,ReadNoc,GetMainReq,StoreRank,NewRank,SendRank,RegRank,SendPeerStat,GetPeerStat,SendApp,EndInit);
   -- MAE pour réception de init depuis le réseau;
	type init3_type is  (init,GetNocSize,ReadInitHead,StorePort,EndInit); 
	type typ_send is (s_init,s_head,s_len,s_len2,s_data,s_end);
	type typ_receiv is (r_wait,r_dlen,r_drop,r_glen,r_data,r_pulse,r_end);
	type typ_cmd is (cmdstart,cmdpost,cmdpostidle,cmdread,cmdlen,cmdglen,cmddata,cmdend,cmdtimeout);

		signal etsnd : typ_send;
		signal etrec:typ_receiv;   --pour la machine à état de réception
		signal etcmd :typ_cmd;     --pour la machine à état de commande
--	signal stInit1, next_stInit1 : init1_type; 
	signal stInit2, next_stInit2 : init2_type; 
	--signal stInit3, next_stInit3 : init3_type; 
	--signaux pour l'interface avec les ports
	signal cport_in_wr_en,sport_in_wr_en:std_logic;
	signal cport_out_rd_en,rport_out_rd_en:std_logic;
	signal tosend,tosend4 :std_logic_vector(Word-1 downto 0);
	signal PeerStat : std_logic_vector(15 downto 0):=(others=>'0'); --état des autres Lib initialisées
	signal selector : std_logic_vector (2 downto 0); -- pour le MUX des signaux vers le port
	--signaux pour les états des MAE
	signal  NocSizeOk,PortCountFlag : std_logic;
	signal PortNumFlag,EquFlag,MainResp,RankAsked,RankSent:std_logic;
	
   signal RTS_cmd,RTS_dat,CTR,BCast,Send_Ack,DS_Ack,CM_Ack:std_logic:='0';
	signal Rcv_On,Snd_On,Cmd_On : std_logic:='0'; --status des MAE d'envoie et de réception
	signal DS_RDY ,BCast_Rdy,Send_RDY,CM_RDY:std_logic:='0';
	signal ExecTime_out:std_logic;
	--signaux de gestion de la RAM
	signal Ram_NextAdress : std_logic_vector(ADRLEN-1 downto 0):=std_logic_vector(to_unsigned(Core_BASE_ADR+CORE_Rank2port_BASE,16));
	signal Ram_NExtAdress_i :std_logic_vector(ADRLEN-1 downto 0):=std_logic_vector(to_unsigned(Core_BASE_ADR+CORE_Rank2port_BASE,16));
	--Signaux des résultats et de l'état
   signal PortNum_i,MyPort : std_logic_vector(3 downto 0);  -- 
	signal NocMax : std_logic_vector(3 downto 0); -- Nombre de ports du réseau -1 ?
	signal MyRank : std_logic_vector(3 downto 0) ; --rang du PE
	signal MainPort : std_logic_vector(3 downto 0) ; --Port de la lib main
	signal NextRank,NextRank_i : std_logic_vector(3 downto 0):=(others=>'0'); --utiliser pour gérer les affectations de rangs MPI
   signal DataToSend : Typ_PortIo(0 to 3):=((others=>'0'),(others=>'0'),(others=>'0'),(others=>'0')); -- permet d'empiler les données à envoyer
	signal CmdReceived,DataReceived : Typ_PortIO(0 to 3):=((others=>'0'),(others=>'0'),(others=>'0'),(others=>'0'));
	signal Datalen : natural range 0 to 3 :=0; --indique la longueur des données
	--other outputs
	signal RankAsked_i,EquFlag_i,MainResp_i,RankSent_i,IsMain_i,Result_i:std_logic;
   --signal BCast_Rdy_i : std_logic;
	signal cdlen,dcount,timeout,timeout_i : natural range 0 to 255:=0; --longueur du paquet reçu par le process pcmd
	signal PortStat : std_logic_vector(3 downto 0):=(others=>'0');
	signal PeerPort : natural range 0 to 15:=0; -- désigne le port qui emet une requête
	signal PeerRTS,PeerCTR:std_logic:='0';
	signal cpt,cpt_peer : natural range 0 to 15:=0; --compteur pour le nombre de HT initialisés
	signal clk_cyl,clk_cyl_i : natural range 0 to 15:=0;
begin
--=======================================================================================
--fonctions du module
--=======================================================================================
--=======================================================================================
 
 
 
   -- Gestion de l'initialisation du Core MPI
  sync_Init2 : process (clk,reset)
  begin
	if reset='1' then
		stinit2<=init;
	elsif rising_edge(clk) then
		stinit2<=next_stinit2;
		--ajout des autres affectations ici
		Ram_NextAdress<=Ram_NextAdress_i  ;
		
		RankAsked<=RankAsked_i;
		RankSent<=RankSent_i;
		AppRank<=MyRank;
		timeout<=timeout_i;
		cpt<=cpt_peer;
		clk_cyl<=clk_cyl_i;
		NextRank<=NextRank_i;
	end if;
end process;

  Init2_DECODE: process (stinit2, CmdReceived, EquFlag, MyPort, DS_RDY, MainResp, DataReceived, Ram_NextAdress,PeerRTS)
   variable nextr,nextadr : natural :=to_integer(unsigned(Ram_NextAdress));
	variable nport : natural range 0 to 15:=0;
	begin
      
      Case stInit2 is
		When Init =>
			RTS_cmd<='0';
			RTS_dat<='0';
			BCast<='0';
			Result_En<='0';
			Initialized<='0';
			CM_Ack <='0';
			CTR<='0' ;
			DS_ACK<='0';
			Send_Ack<='0';
			WeRam<='0';
			ResultOut<=(others=>'0');
			PortNum_i<=(others=>'Z');
			IsMain<='0';
			EquFlag<='0';
			RankAsked_i<='0';
			dma_wr_req<='0';

		When GetPortNum =>
			RTS_cmd<='1';
			RTS_dat<='0';
			Result_En<='0';
			Initialized<='0';
			BCast<='0';   --réalise un envoie non collectif
			CM_Ack<='0';   -- les données sont maintenant attendues
			CTR<='0' ;
			DataToSend(0)<=X"0" & GETPORTID;
			DS_ACK<='0';
			Send_Ack<='0';
			WeRam<='0';
			IsMain<='0';
			ResultOut<=(others=>'0');
			PortNum_i<=(others=>'Z');
			RankAsked_i<='0';
			dma_wr_req<='0';
		When DecodeData =>
			EquFlag<=(All_zeros(Cmdreceived(2)(3 downto 0)));
			RTS_cmd<='0';
			RTS_dat<='0';
			BCast<='0';
			IsMain<='0';
			Result_En<='0';
			Initialized<='0';
			CM_Ack <='1'; --les données ont été reçues
			MyPort<=Cmdreceived(2)(3 downto 0);
			PortNum_i<=Cmdreceived(2)(3 downto 0); --récupère les valeurs de port
			PeerPort<=To_integer(unsigned(Cmdreceived(2)(3 downto 0)));
			NocMax<=Cmdreceived(2)(7 downto 4);  -- et la taille du réseau
			PortNumFlag<='1';  -- le numéro du port est maintenant connu
			CTR<='0' ;
			DS_ACK<='0';
			Send_Ack<='0';
			WeRam<='0';
			RankAsked_i<='0';
			ResultOut<=(others=>'0');
			dma_wr_req<='0';
		When IsPortZero => --Ce port est-il le n° 0 du NoC ?
			BCast<='0';
			Result_En<='0';
			Initialized<='0';
			RTS_cmd<='0';
			RTS_dat<='0';
			NextRank_i<="0001"; -- le prochain rang à affecter sera le n° 1
			nextr:=1;
			IsMain<=EquFlag;
			MyRank<="0000";
			MainPort<="0000";
			--MainAdr<="0000";   -- le port 0 est le main Lib par défaut;
			CTR<='0' ;
			DS_ACK<='0';
			WeRam<='0';
			RankAsked_i<='0';
			ResultOut<=(others=>'0');
			dma_wr_req<='0';
		When SeekMain1 =>    -- recherche de la lib main
				RTS_cmd<='0';
				RTS_DAT<='1';
				CTR<='1' ; -- prêt à recevoir les données Clear To Receive
				DS_ACK<='0'; --les données sont attendus
				Send_Ack<=BCast_rdy;
				DataToSend(0)<=INIT_SEEKMAIN & MyPort ;
				DataToSend(1)<="00000011"; -- la longueur du packet =3
				DataToSend(2)<="0000" & MyPort; --propose sa propre adresse
				DataLen<=3;
				BCast<='1';
				IsMain<='0';
				Result_En<='0';
				Initialized<='0';
				WeRam<='0';
				ResultOut<=(others=>'0');
				EquFlag<='0';
				RankAsked_i<='0';
				dma_wr_req<='0';
		When SeekMain2 =>    -- recherche de la lib main
				RTS_cmd<='0';
				RTS_DAT<='0';
				CTR<='1' ; -- prêt à recevoir les données Clear To Receive
				DS_ACK<= DS_RDY; --les données sont acquittées aussitôt reçues
				Send_Ack<=BCast_rdy;
--				DataToSend(0)<=INIT_SEEKMAIN & MyPort ;
--				DataToSend(1)<="00000011"; -- la longueur du packet =3
--				DataToSend(2)<="0000" & MyPort; --propose sa propre adresse
--				DataLen<=3;
				BCast<='0';
				IsMain<='0';
				Result_En<='0';
				Initialized<='0';
				WeRam<='0';
				ResultOut<=(others=>'0');
				EquFlag<='0';
				RankAsked_i<='0';
				dma_wr_req<='0';
		When StoreMain =>     -- la Main Lib est une autre
				BCAST<='0';
				Result_En<='0';
				IsMain<='0';
				Initialized<='0';
				DS_ACK<=DS_RDY;
				Send_Ack<='0';
				RTS_cmd<='0';
				RTS_DAT<='0';
				CTR<=not(MainResp);  -- essayer de recevoir tant que le main n'a pas répondu
				WeRam<='1';
				ResultOut<=(others=>'0');
				RankAsked_i<='0';
				EquFlag<='0';
				MainPort<=DataReceived(0)(3 downto 0);
				AdrRam<= STD_logic_vector(to_unsigned(Core_init_adr+1,16));
				DataRam<=DataReceived(0)(3 downto 0)& DataReceived(2)(3 downto 0);  --MainPort & MyRank
				dma_wr_req<= '0';  ---pas très sûr
		When SetMainFlag =>   -- Cette Lib est la Main Lib 
				if (Datareceived(0)(7 downto 4) = INIT_SEEKMAIN) then 
					RankAsked_i<='1';
				else 
					RankAsked_i<='0';
				end if;
				RTS_cmd<='0';
				Initialized<='0';
		      RTS_DAT<='0';
				BCast<='0';
				IsMain<='0';
				Result_En<='0';
				MyRank<="0000";
				MainPort<="0000";
				PeerStat(0)<='1'; --la main lib est initialisée
				CTR<='1';
				DS_ACK<='0';
				WeRam<='1';
				ResultOut<=(others=>'0');
				EquFlag<='1';
				AdrRam<= STD_logic_vector(to_unsigned(Core_init_adr+1,16));
				DataRam<=(others =>'0');  -- le port vaut 0 et la mainlib est aussi à 0
				dma_wr_req<='1';
		When ReadNoc =>
				if (Datareceived(0)(7 downto 4) = INIT_SEEKMAIN) then
					RankAsked_i<='1' ;
				else 
					RankAsked_i<='0';
				end if;
				WeRam<='0';  -- pas d'écriture en RAM
				BCast<='0';
				DS_ACK<='0';
				--IsMain<='0';
				Result_En<='0';
				Initialized<='0';
				RTS_cmd<='0';
				RTS_DAT<='0';
				CTR<='1';
				ResultOut<=(others=>'0');
				PortNum_i<=DataReceived(2)(3 downto 0); -- le port qui demande un rang;
				PeerPort<= To_integer(unsigned(DataReceived(2)(3 downto 0)));
				--EquFlag<='1';
				dma_wr_req<='0';
		When GetMainReq  =>
				--RankAsked_i<='1';
				WeRam<='0';  -- pas
				BCast<='0';
				DS_ACK<='1';
				IsMain<='0';
				Result_En<='0';
				Initialized<='0';
				RTS_cmd<='0';
				RTS_DAT<='0';
				CTR<='1';
				ResultOut<=(others=>'0');
				PortNum_i<=DataReceived(0)(3 downto 0); -- le port qui demande un rang;
				EquFlag<='1';
				dma_wr_req<='0';
		When GetPeerStat  =>
				--RankAsked_i<='1';
				WeRam<='0';  -- pas
				BCast<='0';
				DS_ACK<='1';
				IsMain<='0';
				Result_En<='0';
				Initialized<='0';
				RTS_cmd<='0';
				RTS_DAT<='0';
				CTR<='1';
				ResultOut<=(others=>'0');
				PortNum_i<=DataReceived(0)(3 downto 0); --adresse du Main Port
				EquFlag<='1';
				dma_wr_req<='0';
		When NewRank =>
				nport:=to_integer(Unsigned(PortNum_i)); --port ayant sollicité le rang
				if PeerStat(nport)='0' then -- si le rang n'a pas encore été affecté à ce port
				nextrank_i<=incr_vec(nextrank,'1');
				NextAdr:=NextAdr+1;
				end if;
				--NextRank<=incr_vec(NextRank,'1');
				nextr:=to_integer(unsigned(nextrank));
				DataToSend(0)<=INIT_SETRANK & PortNum_i ;
				DataToSend(1)<="00000011";
				DataToSend(2)<="0000" & NextRank;  --ici c'est la valeur avant incrémentation !
				PeerStat(nport)<='1'; -- mise à jour du status
				DataLen<=3;
				BCast<='0';
				DS_ACK<='0';
				Result_En<='0';
				Initialized<='0';
				EquFlag<='1';
				RTS_cmd<='0';
				Rts_DAT<='1';
				IsMain<='0';
				CTR<='0' ;
				WeRam<='0';
				RankAsked_i<='1';
				ResultOut<=(others=>'0');
				dma_wr_req<='0';
		When SendRank =>
				BCast<='0';
				Result_En<='0';
				EquFlag<='1';
				Rts_DAT<='1';
				RTS_cmd<='0';
				DS_ACK<='0';
				Send_Ack<='0';
				IsMain<='0';
				CTR<='0' ;
				WeRam<='0';
				Ram_NextAdress_i<= STD_logic_vector(to_unsigned(CORE_RANK_ADR+Nextr-1,16));
				ResultOut<=(others=>'0');
				RankAsked_i<='1';
				Initialized<='0';
				dma_wr_req<='0';
		When RegRank =>
--				if (Datareceived(0)(7 downto 4) = INIT_SEEKMAIN) then 
--					RankAsked_i<='1';
--				else 
					RankAsked_i<='0';
--				end if;
				CTR<='1' ; -- continuer à recevoir les données du NoC
				Result_En<='0';
				Initialized<='0';
				RTS_cmd<='0';
				DS_ACK<='0';
				Send_Ack<=Send_RDY;
				IsMain<='0';
				Rts_Dat<='0';
				BCast<='0';
				EquFlag<='1';
				WeRam<='1';
				
				Ram_NextAdress_i<= STD_logic_vector(to_unsigned(CORE_RANK_ADR+Nextr-1,16)); --incr_vec(Ram_NextAdress,'1');
				AdrRam<=Ram_NextAdress;  -- le rang qui a été envoyé;
				-- "le motif 0001 indique juste que le port est bien activé
				DataRam<="0001" & PortNum_i; --enregistrer le port qui a fait la demande en RAM
				ResultOut<=(others=>'0');
				dma_wr_req<='1';
		When SendPeerStat =>
				BCast<='0';
				Result_En<='0';
				EquFlag<='0';
				Rts_DAT<=PeerRTS;
				RTS_cmd<='0';
				DS_ACK<='0';
				DataToSend(0)<=INIT_REGISTER & PortStat ;
				DataToSend(1)<="00000011";
				DataToSend(2)<=PeerStat(7 downto 0);
				Send_Ack<=Send_Rdy;
				IsMain<='0';
				CTR<='0' ;
				WeRam<='0';
				ResultOut<=(others=>'0');
				RankAsked_i<='1';
				Initialized<='0';
				dma_wr_req<='0';
		When StoreRank => --le processus qui écoute le Port et qui 
								--stoke les adresses des autres bib va gérer le stockage du rang
				BCAST<='0';
				DS_ACK<='1';
				Send_Ack<='0';
				RTS_cmd<='0';
				EquFlag<='0';
				RTS_DAT<='0';
				CTR<='0';
				Result_En<='0';
				Initialized<='0';
				IsMain<='0';
				
				if ExecTime_out='1' then
				MainPort<="0000";
				MyRank<=MyPort;
				else
				MainPort<=DataReceived(0)(3 downto 0);
				MyRank<=DataReceived(2)(3 downto 0);
				 
				end if;
				WeRam<='1';
				--AdrRam<=DataReceived(2);  -- le rang qui a été envoyé;
				AdrRam<= STD_logic_vector(to_unsigned(Core_init_adr+1,16));
				DataRam<=DataReceived(0)(3 downto 0)& DataReceived(2)(3 downto 0);  --MainPort & MyRank
				ResultOut<=(others=>'0');
				RankAsked_i<='0';
				dma_wr_req<='1';
		When SendApp =>  --ajouter du code pour recevoir l'adr du reg status
				Initialized<='1';
				ResultOut<="00000001"; -- Init Ok
				Result_En<='1';
				IsMain<='0';
				PortId<=MyPort;
				BCAST<='0';
				DS_ACK<='1';
				Send_Ack<='0';
				RTS_cmd<='0';
				RTS_DAT<='0';
				CTR<='0';
				WeRam<='0';
				RankAsked_i<='0';
				dma_wr_req<='0';
		When EndInit=>
				RTS_cmd<='0';
				RTS_DAT<='0';
				Result_En<='0';
				IsMain<='0';
				Initialized<='0';
				DS_ACK<='0';
				Send_Ack<='0';
				BCAST<='0';
				CTR<='0';
				WeRam<='0';
				RankAsked_i<='0';
				ResultOut<=(others=>'0');
				dma_wr_req<='0';
		end case;
   end process;
 
   NEXT_STInit2_DECODE: process (stInit2,AppReq, AppAck,PortNumFlag,EquFlag,MainResp,RankAsked,RankSent,CM_RDY, CmdReceived, 
	BCast_Rdy, DS_RDY, DataReceived, Send_RDY,TimeOut,Dma_wr_grant,cpt,clk_cyl)
   variable InitTimeOut :natural:=0;
   variable vPortStat,nulvect : std_logic_vector(3 downto 0):="0000";	
	
  begin
      --declare default state for next_state to avoid latches
      next_stInit2 <= stInit2;  --default is to stay in current state
      --insert statements to decode next_state
      --below is a simple example
      case (stInit2) is
         
			
		When Init =>If AppReq='1' then
					 If PortNumFlag='1' and RankAsked='1' then
						Next_stInit2 <=ReadNoC;
					 else
						Next_stInit2 <=GetPortNum;
					end if;
					TimeOut_i<=0;PeerRTS<='0';
				end if;
				
		When GetPortNum =>  -- récupérer le numéro du port
												
						if CM_RDY='1' then 
							Next_stInit2 <=DecodeData;
						end if;
						
		When DecodeData =>  -- cet état permet de lire les données reçues du port
							--if CM_RDY='1' then 
								if ((Cmdreceived(2)(3 downto 0) or nulvect)=nulvect) then -- teste si le n° du port est zero
								  --EquFlag<='1';
								 else
								  --EquFlag<='0';
								end if;
								
								Next_stInit2 <=IsPortZero;
							--end if;
		When IsPortZero => 
						if PortNumFlag='1' then 
						
						End if;
						if EquFlag='0'  then  --tester le numéro de port obtenu
							Next_stInit2 <=SeekMain1; -- chercher le numéro de port sur le réseau
						else 
							Next_stInit2<=SetMainFlag; -- enregistrer le numéro de port
						End If;
						TimeOut_i<=0;
		
		When SeekMain1 =>If BCast_RDY='1' then  -- si tous les envois ont été postés
									Next_stInit2<=SeekMain2;
							End if;				
		When SeekMain2 =>  
							If DS_RDY='1' then  -- Si un jeu de données a été reçu
										if (Datareceived(0)(7 downto 4) = INIT_SETRANK) then 
												MainResp<='1';
												Next_stInit2 <=StoreMain; -- de la librairie pricipale
									 else
												MainResp<='0';
												Timeout_i<=0;
									 end if;	
										
							elsif (ExecTime_Out='1') then 
									
												-- le Noc ne répond pas
												-- affecter un numéro en raport avec le port
										Next_stInit2 <=SeekMain2;
							elsif TimeOut=150 then
												--essayer de redemander l'initialisation
									Timeout_i<=0;			
									Next_stInit2 <=SeekMain2;
							else
										Timeout_i<=TimeOut+1;
							End if;
							
							 
							 
		When StoreMain =>
				if DataReceived(0)(7 downto 4)= MPI_INIT then
				--ignorer le message
				Next_stInit2 <=StoreMain; --essayer de recevoir le rang
				elsif Datareceived(0)(7 downto 4) = INIT_SEEKMAIN then 
				-- ignorer ce message
				Next_stInit2 <=StoreMain; --essayer de recevoir le rang
				elsif Datareceived(0)(7 downto 4) = INIT_SETRANK then --ok le rang a été reçu
				-- enregistrer le Main Adresse et les adresses des autres processus
				-- dans la variable prévue à cet effet
				--if dma_wr_grant='1' then 
					Next_stInit2 <=StoreRank;
				--end if;
				
				end if;
					
		When StoreRank =>
					--il faut prévoir du code pour s'assurer que la RAM a bien enregistrer
					-- la donnée ...
					if dma_wr_grant = '1' then 
						if clk_cyl=2 then --prévoir deux cycle d'horloge pour lire en RAM
							Next_stInit2 <=GetPeerStat;
							TimeOut_i<=0;
							clk_cyl_i<=0;
						else 
							clk_cyl_i<=clk_cyl+1;
						end if;
					else
							Next_stInit2 <=StoreRank;
							TimeOut_i<=0;
							clk_cyl_i<=0;
					end if;
					
		When GetPeerStat =>  
							If DS_RDY='1' then  -- Si un jeu de données a été reçu
									 if (Datareceived(0) = INIT_REGISTER & MainPort ) then 
												MainResp<='1';
												Next_stInit2 <=SendApp; -- de la librairie pricipale
									 else
												MainResp<='0';
												Timeout_i<=0;
									 end if;	
										
							elsif (ExecTime_Out='1') then 
									
								
										Next_stInit2 <=EndInit;
							elsif TimeOut=180 then
												--essayer de redemander l'initialisation
												
									Next_stInit2 <=SeekMain1;
							else
										Timeout_i<=TimeOut+1;
							End if;			
		When SetMainFlag =>
				if dma_wr_grant='1' then   
						TimeOut_i<=0;
						Next_stInit2 <=ReadNoc;
					elsif Timeout=200 then
						Next_stInit2 <=SendApp;
					else
						TimeOut_i<=TimeOut+1;
--					end if; -- il est envisagée de terminer le programme à ce point
				end if;
		when ReadNoc => if DS_RDY='1' then
									Next_stInit2 <=GetMainReq;
									Timeout_i<=0;
								elsif Timeout=80 then
									Timeout_i<=0;
									Next_stInit2 <=SendPeerStat;
								else
									TimeOut_i<=TimeOut+1;
								end if; 
				
		When GetMainReq => if RankAsked='1' and PeerStat(PeerPort)='0' then
									Next_stInit2 <=NewRank; -- un nouveau rang est demandé
								else
									Next_stInit2 <=ReadNoC; -- sinon essayer encore de lire un jeu de données.
								end if;
		When NewRank =>
				Next_stInit2 <=SendRank;
		When SendRank =>
					if Send_RDY='1' then  --RankSent
						Next_stInit2 <=RegRank;
						RankSent_i<='1';  -- le rang a été envoyé
						TimeOut_i<=0;   -- prépare le traitement de la prochaine requête
												-- d'attente des ports
					end if;
		When RegRank =>
					--il faut prévoir du code pour s'assurer que la RAM a bien enregistrer
					-- la donnée ...
					if dma_wr_grant = '1' then 
--							if DS_RDY='1' then
								RankSent_i<='0';
								if DS_RDY='0' then
									Next_stInit2 <=ReadNoc;
								end if;
							elsif Timeout=150 then
								Next_stInit2 <=SendApp;
							else
								TimeOut_i<=TimeOut+1;
--							end if; -- il est envisagée
					end if;
		When SendPeerStat =>
					
					if cpt<=(unsigned(NoCMax)) then
					if peerRts='0' then -- pas encore envoyer les données alors les préparer
						PortStat<=std_logic_vector(to_unsigned(cpt,4));--Port à contacter
						vPortStat:=std_logic_vector(to_unsigned(cpt,4));
						if (PeerStat(cpt)='1') and not(vPortStat=MyPort) then
							PeerRts<='1';
							
						end if;
							cpt_peer<=cpt+1;
							TimeOut_i<=0;
					else
							if Send_RDY='1' then  --RankSent
										--Next_stInit2 <= RegRank;
										RankSent_i<='1';  	-- les stat ont été envoyé
										TimeOut_i<=0;  	 	-- prépare le traitement de la prochaine requête
										PeerRts<='0';										-- d'attente des ports
							  elsif TimeOut_i=100 then
									Next_stInit2 <=EndInit ;-- impossible d'envoyer sur le NoC
							  else
									TimeOut_i<=TimeOut_i+1; 
							end if;
					end if;
					elsif PeerRTS='1' then -- le dernier port est il activé ?
						if Send_RDY='1' then  --RankSent
								RankSent_i<='1';  	-- les stat ont été envoyé
										TimeOut_i<=0;  	 	-- prépare le traitement de la prochaine requête
										PeerRts<='0';
								Next_stInit2<=SendApp;
						
						elsif TimeOut_i=100 then
							Next_stInit2 <=EndInit;
						else 
							TimeOut_i<=TimeOut_i+1; 
						end if;
					else
						Next_stInit2<=SendApp;
					end if;
		When SendApp =>  -- envoyer au programme un signal 
					-- et attendre un acquittement et l'adresse de base
					If AppAck='1' then
						Next_stInit2 <=EndInit;
					end if;
		
		
		When EndInit=>
		  
			
			Next_stInit2<=Init;
      end case;      
   end process;
	
--================================================
--sauvegarde du rang et du main port à l'adresse de retour de la fonction Init
--==================================================

--====================================================
--envoie des données sur le port
--===================================================
selector<=(Rcv_on,Cmd_on,Snd_on);

process (selector,Rport_out_rd_en,cport_out_rd_en,sPort_in_wr_en ,cPort_in_wr_en,
				tosend ,tosend4)
begin
   case selector is
	
      when "000" => port_in_data<=(others=>'Z');
						Port_in_wr_en<='0';
						Port_out_rd_en<='0';
      
		when "001" => port_in_data<=tosend; --envoie de données
						Port_in_wr_en<=sPort_in_wr_en ;
						Port_out_rd_en<='0';
      when "101" => port_in_data<=tosend; --envoie de données
						Port_in_wr_en<=sPort_in_wr_en ;
						Port_out_rd_en<=Rport_out_rd_en ;
		when "010" | "110" | "011" | "111" => 
						port_in_data<=tosend4; --envoie de commande GetPort
						Port_in_wr_en<=cPort_in_wr_en;
						Port_out_rd_en<=cport_out_rd_en;
     
	  when "100" => port_in_data<=(others=>'Z'); -- réception de données
						Port_in_wr_en<='0';
						Port_out_rd_en<=Rport_out_rd_en ;
      
		when others => port_in_data<=(others=>'Z');
							Port_in_wr_en<='0';							
							Port_out_rd_en<='0';
   end case;
end process;
 
--==================================================	
	
	--===============================================================
	--processus d'accès au réseau
	--===============================================================





	preceiv:process(clk,reset)
	
	variable origport,destport : natural range 0 to 15;
	variable dcount,dlen ,rtimeout:natural range 0 to 255;
	variable ptype : std_logic_vector(3 downto 0);
	variable bad_paquet :std_logic:='0';
	begin
--				
	if  rising_edge(clk) then 
	if reset='1' then
		etrec<=r_wait;
		destport:=1;
		rtimeout:=0;
		bad_paquet:='0';
	else
			case  etrec is
			when r_wait =>
				
				rtimeout:=0;
				bad_paquet:='0';	
			if Port_out_data_available='1' and CTR='1'  then 
				ptype:=port_out_data(7 downto 4);
				origport:=to_integer(unsigned(port_out_data(3 downto 0)));
				
				if ptype=MPI_INIT or ptype=INIT_SETRANK or ptype=INIT_SEEKMAIN or ptype=INIT_REGISTER then 
						etrec<=r_dlen; --identification de la signature d'en tête valide
						Datareceived(0)<=Port_out_data; --stocker l'entête
						bad_paquet:='0';
				else
					--une donnée non attendue est présente sur le port
					etrec<=r_dlen;
					dcount:=1;
					bad_paquet:='1';
					Datareceived(0)<=(others=>'0');
				end if;
			--elsif Port_out_data_available='1' and CTR='0' then
			--		etrec<=r_drop;
			else
				
				etrec<=r_wait;
			end if;
			DS_RDY<='0';
			When r_drop => -- ignorer les messages qui arrivent à ce noeud tant que 
								--l'application n'a pas été initialisée
						if port_out_data_available='0' then 
							etrec<=r_end;
							dcount:=0;
							
						end if;
						
						
						
						--Rport_out_rd_en<='1'; --lire les données qui sont dans le tampon de sortie		
						DS_RDY<='0';
			when r_Dlen =>   --positionnement du mot de longueur des données
			if Port_out_data_available ='1' then 
			
			--Rport_out_rd_en<='1';
			etrec<=r_glen;
			rtimeout:=0;
			else
				rtimeout:=rtimeout+1;
					if rtimeout>=30 then 
					Exectime_out<='1';  --read Noc time out
						etrec<=r_end;             -- données pas prêtes
					end if;
			
			
			end if;
			DS_RDY<='0';
			--  
			when r_glen =>   --lecture effective de la longueur des données
			if port_out_data_available='1' then 
			dlen:=to_integer(unsigned(port_out_data(Word-1 downto 0)));
			Datareceived(1)<=Port_out_data;
			--RPort_out_rd_en<='0';
			etrec<=r_data;
			dcount:=2;  -- initialisation du compteur de reception (il y a 
							-- déjà deux mots reçues
			else
				rtimeout:=rtimeout+1;
					if rtimeout>=30 then 
					ExecTime_out<='1';
						etrec<=r_end;             -- données pas prêtes
					end if;
			
			end if;
			DS_RDY<='0';
			when r_data =>    					-- lecture des données
			if port_out_data_available='1'  then 
					
					--Rport_out_rd_en<='1';   --autoriser la lecture
					if bad_paquet='0' then
						DataReceived(dcount)<=Port_out_data; --récupération des données
					else
						DataReceived(2)<=(others=>'0');
					  --ignorer ces données
					end if;
					--assert true report "Donnée lue :"; --& string(unsigned(port4_out(Word-1 downto 0)))
					DS_RDY<='0';
					dcount:=dcount+1;
					--severity note;
					if dlen <=dcount then -- ce doit être égale ici et non <= ???
						etrec<=r_end;
						DS_RDY<='1'; -- jeu de données disponibles
					elsif dcount=255 then   --dépassement de la capacité
						DS_RDY<='0';
						etrec<=r_end;
					end if;
			else
					rtimeout:=rtimeout+1;
					if rtimeout>=30 then 
					   ExecTime_out<='1';
						etrec<=r_end;             -- données pas prêtes
					end if;
					DS_RDY<='0';
					
			end if;
			when r_pulse =>
					etrec<=r_end; 
					DS_RDY<='1';
			when r_end =>
						
			--rPort_out_rd_en <='0';
			
			if DS_ACK='1' or rtimeout> 30 or CTR='0' or bad_paquet='1' then 
				DS_RDY<='0';
				etrec<=r_wait;
			else
				DS_RDY<=DS_RDY;
			end if;
			
			
			
			end case;
		 end if;--reset='1'
		end if;   
  end process preceiv;
  
 val_preceiv: process (etrec)
  begin
  case etrec is
					when r_wait  =>
--						DS_RDY<='0';
						
						Rport_out_rd_en <='0';
					when r_dlen  =>
--							DS_RDY<='0';
							Rport_out_rd_en <='1';
							rcv_On<='1';
					when r_drop  =>
--							DS_RDY<='0';
							Rport_out_rd_en <='1';
							rcv_On<='1';
					when r_glen =>
							Rport_out_rd_en <='1';
--							DS_RDY<='0';
							rcv_On<='1';
					when r_data =>
							Rport_out_rd_en <='1';
--							DS_RDY<='0';
							rcv_On<='1';
					when r_pulse =>
								Rport_out_rd_en <='0';
								rcv_On<='1';
--								DS_RDY<='1';
					when r_end =>
							Rport_out_rd_en <='0';
--							DS_RDY<='0';
							rcv_On<='0';
					when others =>
							Rport_out_rd_en <='0';
--							DS_RDY<='0';
							rcv_On<='0';
				end case;
	end process;
  
  psend:process(clk,reset)
		--génération des paquets à partir du  port courant
		variable pactype :natural range 0 to 15;
		variable destport : natural range 0 to 15:=0;
		variable realdlen, i,i_pair : natural range 0 to 255;
		variable MaxPort : natural :=to_integer(unsigned(NOCMAX)); -- en fait ne doit pas être 0
		
		
				begin
				if rising_edge(clk) then 
						 if reset='1' then 
								etsnd<=s_init;
				 
				    
						 
						else -- le process s'exécute sur chaque front 
															-- montant de l'horloge
						case etsnd is
						when s_init => tosend<=(others=>'Z');
											MaxPort :=to_integer(unsigned(NOCMAX));
								sPort_in_wr_en<='0';
							if port_in_full='0' and Rts_dat='1' then   --on peut aussi tester si le port est vide
							        BCast_RDY<='0';  -- pas la fin de du Broadcasting
									  Send_RDY<='0';
									  Snd_on<='1';
									  if Bcast='1' then -- envoyer à tous les ports le même message ?
									  DestPort :=0;
									  else
										DestPort:=to_integer(unsigned(DataToSend(0)(3 downto 0)));
									  end if;
									  etsnd<=s_head;
							end if;
						when s_head  =>    -- construction et envoie de l'en-tête
						Send_RDY<='0'; --l'envoi commence
						BCast_RDY<='0';
						Snd_on<='1';
						--pactype:=to_integer(MPI_INIT);--
						pactype:=to_integer(unsigned(DataToSend(0)(7 downto 4)));
						--realdlen:=to_integer(unsigned(Datalen));
						--? destport:=MAXPORT; -- le port de destination
						
						tosend <=STD_LOGIC_VECTOR(to_unsigned(pactype,4)) & STD_LOGIC_VECTOR(to_unsigned(destport,4));
						 sPort_in_wr_en<='1';   -- 
						 
						 i:=1;
						 etsnd<=s_len2;  -- passer à l'état suivant
						 
						when s_len => 
							BCast_RDY<='0';
							Send_RDY<='0';
							Snd_on<='1';
							--tosend<=(STD_LOGIC_VECTOR(to_unsigned(Realdlen,8)));
							tosend<=DataToSend(1);
							sPort_in_wr_en <='1';
							

							--port1_in<=tosend1; --copie directe sur le port 
							etsnd<=s_len2;
						when s_len2 => 
							--tosend<=(STD_LOGIC_VECTOR(to_unsigned(realdlen,8)));
							sPort_in_wr_en<='1';
							tosend<=DataToSend(1);

							--port1_in<=tosend1; --copie directe sur le port 
							etsnd<=s_data;	
							BCast_RDY<='0';
							Send_RDY<='0';
							Snd_on<='1';
							i:=i+1;
						when s_data =>
							Snd_on<='1';
							if Port_in_full='0'and RTS_dat='1' then
								sPort_in_wr_en<='1';
								
								     --envoie des données sur le port   
									tosend<=DataToSend(i);
								
								
								if i+1>=datalen then 
									etsnd<=s_end;
									Send_RDY<='1'; --l'envoi est terminé
									if BCast='1' and destport=MAXPort then
										BCAST_RDY<='1'; --l'envoi collectif aussi
									else 
										BCast_RDY<='0';
							
									end if;
								else
									BCast_RDY<='0';
									Send_RDY<='0';
									i:=i+1;
								end if;
							else
								sPort_in_wr_en<='0';
								BCast_RDY<='0';
								Send_RDY<='0';
							end if;
						when s_end  =>
						 tosend<=(others=>'Z');
							
							sPort_in_wr_en<='0';
							Snd_on<='0';
							if Bcast='1' then
								DestPort:=Destport+1;
								if DestPort<=MaxPort then
								etsnd<=s_head;
								else
								BCast_RDY<='1' ; -- BroadCast End=Ok
									if Send_ack='1' then
										etsnd<=s_init;
										Send_RDY<='0';
									end if;
								end if;
							else
								BCast_RDY<='0';
								if Send_ack='1' then
									etsnd<=s_init;
									Send_RDY<='0';
								end if;
								
							end if;
						end case;	
						
										
						end if;  --reset ='1'
					end if; --rising_edge...
		end process psend;	

-- envoi des commandes		
pcmd:process(clk,reset)
	
	variable origport,destport,pid,mport : natural range 0 to 15;
	variable ctimeout:natural range 0 to 255;
	begin
	
	if  rising_edge(clk) then
		if reset='1' then
			etcmd<=cmdstart;
			destport:=0;
			ctimeout:=0;
			origport:=1;
	--		sorigport<=origport;
		else
					case  etcmd is
					when cmdstart =>
						if Port_in_empty='1' and RTS_Cmd='1' then 
									etcmd<=cmdpost;
						
						end if;
				 when cmdpost =>
					if Port_in_empty='1' then 
						etcmd<=cmdread;
					end if;
					
				when cmdpostidle  =>   --permet juste la prise en compte de la commande
						etcmd<=cmdread;
						dcount<=0;-- initialisation du compteur de reception
				 when cmdread =>
						
						
						ctimeout:=0;
						
					if Port_out_data_available='1' then 
						mport:=to_integer(unsigned(port_out_data(7 downto 4)));
						pid:=to_integer(unsigned(port_out_data(3 downto 0)))+1;
						CmdReceived(dcount)<=port_out_data;
						--cdata_out_en(origport)<='1';
--						if pid=origport then --le port a été bien identifié
								etcmd<=cmdglen; --
								dcount<=dcount+1;
--							else
--							etcmd<=cmdtimeout;
--						end if;
					else

						etcmd<=cmdread;
					end if;
					
					
					when cmdlen =>   --positionnement du mot de longueur des données
					if Port_out_data_available='1' then 
					
					etcmd<=cmdglen;
					ctimeout:=0;
					else
						ctimeout:=ctimeout+1;
							if ctimeout>=30 then 
								etcmd<=cmdtimeout;             -- données pas prêtes
							end if;
					
					
					end if;
					when cmdglen =>   --lecture effective de la longueur des données
					if Port_out_data_available='1' then 
						cdlen<=to_integer(unsigned(port_out_data(Word-1 downto 0)));
						CmdReceived(dcount)<=port_out_data;
						etcmd<=cmddata;
					  dcount<=dcount+1;
					else
						ctimeout:=ctimeout+1;
							if ctimeout>=30 then 
							--time_out(destport)<='1';
								etcmd<=cmdtimeout;             -- données pas prêtes
							end if;
					
					end if;
					
					when cmddata =>
					if (port_out_data_available='1' and ctimeout<30) then 
							
							--cdata_out_en(origport)<='1';
							mport:=to_integer(unsigned(port_out_data(7 downto 4)));
							--attention les ports sont numérotés à partir de 0
							pid:=to_integer(unsigned(port_out_data(3 downto 0)))+1;
							CmdReceived(dcount)<=port_out_data;
							if (dcount>=cdlen-1 ) then--attention le compteur de données commence à 0
								etcmd<=cmdend;
								--CM_RDY<='1';
							else
								dcount<=dcount+1;
							end if;			
					Else
							
							if ctimeout>=30 then 
								--time_out(destport)<='1';
								etcmd<=cmdtimeout;             -- données pas prêtes
							else
							ctimeout:=ctimeout+1;
							etcmd<=cmdend;
							end if;
					end if;
					when cmdend =>
				
							etcmd<=cmdstart;

					when cmdtimeout =>

					  etcmd<=cmdstart;
					end case;
		--sorigport<=origport;	
		end if;   --reset='1'
	end if;
  end process pcmd;	

majetcmd: process (etcmd,DataToSend, port_out_data_available, dcount,port_out_data)
variable origport : natural;
variable i:natural:=0;
	begin
			case  etcmd is
		when cmdstart =>
				i:=0;
				Port_in_cmd_en<='0';
				tosend4<=(others=>'Z');
				cport_out_rd_en<='0';
				cport_in_wr_en<='0';
				CM_RDY<='0';
				Cmd_on<='0';
		 when cmdpost | cmdpostidle =>
				cport_in_wr_en<='1';
				tosend4<=DataToSend(0); ---code pour getportid
				Port_in_cmd_en<='1';
				cport_out_rd_en<='0';
				CM_RDY<='0';
				Cmd_on<='1';
		 when cmdread =>
				tosend4<=(others=>'Z');
				cPort_in_wr_en<='0';
				cport_out_rd_en<=port_out_data_available;
				--CmdReceived(dcount)<=port_out_data;  --mettre les données dans le tampon
				Port_in_cmd_en<='1';
				CM_RDY<='0';
				Cmd_on<='1';
		when cmdlen |cmdglen =>   --positionnement du mot de longueur des données
					tosend4<=(others=>'Z');
					cport_in_wr_en<='0';
					cport_out_rd_en<=port_out_data_available;
					Port_in_cmd_en<='1';
					--CmdReceived(dcount)<=	port_out_data;
					CM_RDY<='0';
					Cmd_on<='1';
		when cmddata =>
					tosend4<=(others=>'Z');
					cport_in_wr_en<='0';
					cport_out_rd_en<=Port_out_data_available;
					Port_in_cmd_en<='1';
					--CmdReceived(dcount)<=port_out_data;  --mettre les données dans le tampon
					i:=i+1;
					CM_RDY<='0';
					Cmd_on<='1';
			when cmdend =>
					tosend4<=(others=>'Z');
				cport_in_wr_en<='0';
				cport_out_rd_en<='0';
				--CmdReceived(dcount)<=port_out_data; 
				Port_in_cmd_en<='0';
			    CM_RDY<='1';
				 Cmd_on<='0';
			when cmdtimeout =>
					tosend4<=(others=>'Z');
				  cport_in_wr_en<='0';
				  cport_out_rd_en<='0';
				  Port_in_cmd_en<='0';
					Cmd_on<='1';				  
			end case;
		
end process majetcmd ; 
end Behavioral;

