--------------------------------------------------------------------------------
-- Company: 
-- Engineer:	GAMOM NGOUNOU
--
-- Create Date:   19:03:05 07/11/2011
-- Design Name:   
-- Module Name:   C:/Xilinx/SWITCH_GENERIC_16_16/test_xbar_8x8.vhd
-- Project Name:  GENERIC_16_16
-- Target Device:  
-- Tool versions:  
-- Description:   
-- 
-- VHDL Test Bench Created by ISE for module: SWITCH_GENERIQUE
-- 
-- Dependencies:
-- 
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
-- Notes: 
-- This testbench has been automatically generated using types std_logic and
-- std_logic_vector for the ports of the unit under test.  Xilinx recommends
-- that these types always be used for the top-level I/O of a design in order
-- to guarantee that the testbench will bind correctly to the post-implementation 
-- simulation model.
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
--use IEEE.std_logic_textio.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
USE ieee.numeric_std.ALL;
use work.Coretypes.all;


ENTITY test_xbar_8x8 IS
END test_xbar_8x8;
 
ARCHITECTURE behavior OF test_xbar_8x8 IS 
 CONSTANT MAXPORT :natural:=8; 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT SWITCH_GEN
	 GENERIC (number_of_ports : positive := MAXPORT);
    PORT(
	      clk : IN  std_logic;
			reset : IN  std_logic;
			
			Port_in : in typ_portIO(1 to MAXPORT) ;
			Port_out : out  typ_portIO(1 to MAXPORT);

         cmd_in_en : IN  std_logic_vector(MAXPORT downto 1);
			data_in_en : IN  std_logic_vector(MAXPORT downto 1);
			data_out_en : IN  std_logic_vector(MAXPORT downto 1);
         fifo_in_full : OUT  std_logic_vector(MAXPORT downto 1);
         fifo_in_empty : OUT  std_logic_vector(MAXPORT downto 1);
         data_available : OUT  std_logic_vector(MAXPORT downto 1)
         
        );
    END COMPONENT;
    COMPONENT Stimport5
	 port (
			 clk : in std_logic;
			 reset : in std_logic;
			 clk_en : in std_logic;
			 wr_en : out std_logic;
			 data : out std_logic_vector (7 downto 0)
			 );
	 
	 END COMPONENT;
	type naturel is array (natural range <>) of natural  range 0 to 511; 
	type typ_send is (s_head,s_len,s_len2,s_data,s_end);
	type typ_receiv is (r_wait,r_head,r_dlen,r_glen,r_start,r_end);
	type typ_cmd is (cmdstart,cmdpost,cmdpostidle,cmdread,cmdlen,cmdglen,cmddata,cmdend,cmdtimeout);

		signal etsnd1,etsnd2,etsnd3 : typ_send;
		signal etrec:typ_receiv;   --pour la machine à état de réception
		signal etcmd :typ_cmd;     --pour la machine à état de commande
   --Inputs
  signal PortIn : Typ_portio (1 to MAXPORT);  
  --Outputs
	signal portOut : Typ_portio(1 to maxport);
	
   signal data_in_en : std_logic_vector(MAXPORT downto 1) := (others => '0');
	signal cmd_in_en : std_logic_vector(MAXPORT downto 1) := (others => '0');
   signal data_out_en : std_logic_vector(MAXPORT downto 1) := (others => '0');
	signal rdata_out_en : std_logic_vector(MAXPORT downto 1) := (others => '0');
	signal rcount : naturel(1 to MAXPORT) ;
	
	signal cdata_out_en : std_logic_vector(MAXPORT downto 1) := (others => '0');
   signal clk : std_logic := '0';
   signal reset : std_logic := '0';
	signal din1,din2,din3,din4: std_logic_vector(MAXPORT downto 1):= (others => '0');
 	--signaux utiliser pour la mise à jour des MAE
	signal sdestport,rdestport,rorigport:natural range 0 to 15;
	signal csend1,csend2,csend3,csend4:natural;
	signal sorigport :natural range 0 to 15:=1;
	

   signal fifo_in_full : std_logic_vector(MAXPORT downto 1);
   signal fifo_in_empty : std_logic_vector(MAXPORT downto 1);
   signal data_available : std_logic_vector(MAXPORT downto 1);

   -- Clock period definitions
   constant clk_period : time := 10 ns;
   -- autres signaux de simulation
	-- ici nous mettons les signaux permettant de gérer le processus de simulation
	signal time_out:std_logic_vector(8 downto 1);
	signal header : std_logic_vector(7 downto 0);
	signal tosend1,tosend2,tosend3,tosend4 : std_logic_vector(7 downto 0);
	
BEGIN
 
	-- Instantiate the Unit Under Test (UUT)
   uut: SWITCH_GEN generic map (MAXPORT) PORT MAP (
          Port_In  => PortIn,
			 Port_Out =>PortOut,

          --signaux de contrôle de la lecture des ports
			 data_in_en => data_in_en,
			 cmd_in_en =>cmd_in_en,
          data_out_en => data_out_en,
          fifo_in_full => fifo_in_full,
          fifo_in_empty => fifo_in_empty,
          data_available => data_available,
          clk => clk,
          reset => reset
        );
--Utilisation de la ROM pour envoyer des stimulis
--stimport: stimport5 port map (clk,reset,not (fifo_in_full(5)),din3(5),port5_in);
data_in_en<=din1 or din2 or din3 or din4;
data_out_en<=rdata_out_en or cdata_out_en;					
 -- Clock process definitions
   clk_process :process
   begin
		clk <= '0';
		wait for clk_period/2;
		clk <= '1';
		wait for clk_period/2;
   end process;

 init_process:process (reset)
 
 variable i: natural range 0 to 15;
 begin
 if reset='1' then
 for i in 1 to maxport
	loop
	--Portin(i)<=(others=>'0');
end loop	;
end if ;
end process init_process;
		psend1:process(clk,reset)
		--génération des paquets à partir du premier port
		variable pactype :natural range 0 to 15;
		variable origport,destport : natural range 0 to 15;
		variable datalen,i,i_pair : natural range 0 to 255;
		
		
		
				begin
				if reset='1' then 
				 etsnd1<=s_head;
				 
				else  --reset ='0'
						origport:=6;
						if rising_edge(clk) then -- le process s'exécute sur chaque front 
															-- montant de l'horloge
						case etsnd1 is
						when s_head  =>    -- construction et envoie de l'en-tête
						pactype:=5;-- fonction put
						destport:=6; -- le port de destination
						datalen :=4;
						header<=STD_LOGIC_VECTOR(to_unsigned(pactype,4)) & STD_LOGIC_VECTOR(to_unsigned(destport,4));
						 tosend1<=STD_LOGIC_VECTOR(to_unsigned(pactype,4)) & STD_LOGIC_VECTOR(to_unsigned(destport-1,4));
						 din1(origport)<='1';   -- en fait data_in_en(origport)
						 i:=1;i_pair:=i /2;
						 etsnd1<=s_len;  -- passer à l'état suivant
						 --port1_in<=tosend1;
						when s_len => 
							--tosend1<=(STD_LOGIC_VECTOR(to_unsigned(datalen+2,8)));
							tosend1<=STD_LOGIC_VECTOR(to_unsigned(pactype,4)) & STD_LOGIC_VECTOR(to_unsigned(destport-1,4));
						
							din1(origport)<='1';

							--port1_in<=tosend1; --copie directe sur le port 
							etsnd1<=s_len2;
						when s_len2 => 
							tosend1<=(STD_LOGIC_VECTOR(to_unsigned(datalen+2,8)));
							din1(origport)<='1';

							--port1_in<=tosend1; --copie directe sur le port 
							etsnd1<=s_data;	
						when s_data =>
							
							if (fifo_in_full(origport)='0') then
								din1(origport)<='1';
								i_pair:=i_pair *2;
								if i=i_pair then        -- modulo
									tosend1<=(STD_LOGIC_VECTOR(to_unsigned(i,8)));
									--port1_in<="00001101";  --origport=1
								else
									--tosend1<="00001111";
									tosend1<=(STD_LOGIC_VECTOR(to_unsigned(i,8)));
									--port1_in<="00001111";   --origport=1
								end if;
								i:=i+1;i_pair:=i / 2;
								if i>datalen then
									etsnd1<=s_end;
									din1(origport)<='0';
								end if;
							else
								din1(origport)<='1';
							end if;
						when s_end  =>
						tosend1<="--------";
							din1(origport)<='0';
							if fifo_in_empty(origport)='1' then
								etsnd1<=s_head;
							else
								etsnd1<=s_end;
							end if;
						end case;	
						
						end if;
					 
					
						
					end if; --reset='1'
		end process psend1;
		
		Portin(6)<=tosend1 when reset='0';
		Portin(2)<=tosend2 when reset='0';
		Portin(4)<=tosend3 when reset='0';
		Portin(1)<=tosend4 when reset='0';
		psend2:process(clk,reset)
		--génération des paquets à partir du premier port
		variable pactype :natural range 0 to 15;
		variable origport,destport : natural range 0 to 15;
		variable datalen,i,i_pair : natural range 0 to 255;
		
		
		
				begin
				if reset='1' then 
				 etsnd2<=s_head;
				 
				else  --reset ='0'
						origport:=2;
						if rising_edge(clk) then -- le process s'exécute sur chaque front 
															-- montant de l'horloge
						case etsnd2 is
						when s_head  =>    -- construction et envoie de l'en-tête
						pactype:=5;-- fonction put
						destport:=2; -- le port de destination
						datalen :=9;
						header<=STD_LOGIC_VECTOR(to_unsigned(pactype,4)) & STD_LOGIC_VECTOR(to_unsigned(destport,4));
						 tosend2<=STD_LOGIC_VECTOR(to_unsigned(pactype,4)) & STD_LOGIC_VECTOR(to_unsigned(destport-1,4));
						 din2(origport)<='1';
						 i:=1;i_pair:=i /2;
						 etsnd2<=s_len;  -- passer à l'état suivant
						 
						when s_len => 
							--tosend2<=(STD_LOGIC_VECTOR(to_unsigned(datalen+2,8)));
							tosend2<=STD_LOGIC_VECTOR(to_unsigned(pactype,4)) & STD_LOGIC_VECTOR(to_unsigned(destport-1,4));
						
							din2(origport)<='1';

							--port2_in<=tosend2; --copie directe sur le port 
							etsnd2<=s_len2;
						when s_len2 => 
							tosend2<=(STD_LOGIC_VECTOR(to_unsigned(datalen+2,8)));
							din2(origport)<='1';

							--port1_in<=tosend1; --copie directe sur le port 
							etsnd2<=s_data;
						when s_data =>
							
							if (fifo_in_full(origport)='0') then
								din2(origport)<='1';
								i_pair:=i_pair * 2;
								if i=i_pair then        -- modulo
									--tosend2<="00000001";
									tosend2<=(STD_LOGIC_VECTOR(to_unsigned(i,8)));
									--port2_in<="00000001";  --origport=1
								else
									--tosend2<="00000010";
									tosend2<=(STD_LOGIC_VECTOR(to_unsigned(i,8)));
									--port2_in<="00000001";   --origport=1
								end if;
								i:=i+1;i_pair:=i / 2;
								if i>datalen then
									etsnd2<=s_end;
									din2(origport)<='0';
								else
									din2(origport)<='1';
								end if;
							else
								din2(origport)<='0';
							end if;
						when s_end  =>
							tosend2<="--------";
							din2(origport)<='0';
							if fifo_in_empty(origport)='1' then
								etsnd2<=s_head;
							else
								etsnd2<=s_end;
							end if;
						end case;	
						
						end if;
					 
					
						
					end if; --reset='1'
		end process psend2;

		psend3:process(clk,reset)
		--génération des paquets à partir du premier port
		variable pactype :natural range 0 to 15;
		variable origport,destport : natural range 0 to 15;
		variable datalen,i,i_pair : natural range 0 to 255;
		
		
		
				begin
				if reset='1' then 
				 etsnd3<=s_head;
				 
				else  --reset ='0'
						origport:=4; --attention à régler  tosend3 =Portin(....) !!!!!!!
						if rising_edge(clk) then -- le process s'exécute sur chaque front 
															-- montant de l'horloge
						case etsnd3 is
						when s_head  =>    -- construction et envoie de l'en-tête
						pactype:=5;-- fonction put
						destport:=MAXPORT; -- le port de destination
						datalen :=4;
						--header<=STD_LOGIC_VECTOR(to_unsigned(pactype,4)) & STD_LOGIC_VECTOR(to_unsigned(destport,4));
						 tosend3<=STD_LOGIC_VECTOR(to_unsigned(pactype,4)) & STD_LOGIC_VECTOR(to_unsigned(destport-1,4));
						 din3(origport)<='1';   -- en fait data_in_en(origport)
						 i:=1;i_pair:=i /2;
						 etsnd3<=s_len;  -- passer à l'état suivant
						 --port1_in<=tosend1;
						when s_len => 
							--tosend3<=(STD_LOGIC_VECTOR(to_unsigned(datalen+2,8)));
							din3(origport)<='1';
							tosend3<=STD_LOGIC_VECTOR(to_unsigned(pactype,4)) & STD_LOGIC_VECTOR(to_unsigned(destport-1,4));
						
							--port1_in<=tosend1; --copie directe sur le port 
							etsnd3<=s_len2;
						when s_len2 => 
							tosend3<=(STD_LOGIC_VECTOR(to_unsigned(datalen+2,8)));
							din3(origport)<='1';

							--port1_in<=tosend1; --copie directe sur le port 
							etsnd3<=s_data;	
						when s_data =>
							
							if (fifo_in_full(origport)='0') then
								din3(origport)<='1';
								i_pair:=i_pair * 2;
								if i=i_pair then        -- modulo
									tosend3<=(STD_LOGIC_VECTOR(to_unsigned(i,8)));
									--tosend3<="00001100";
									--port1_in<="00001101";  --origport=1
								else
									tosend3<=(STD_LOGIC_VECTOR(to_unsigned(i,8)));
									--tosend3<="00000110";
									--port1_in<="00001111";   --origport=1
								end if;
								i:=i+1;i_pair:=i / 2;
								if i>datalen then
									din3(origport)<='0';
									etsnd3<=s_end;
								else
									din3(origport)<='1';
								end if;
							else
								din3(origport)<='0';
							end if;
						when s_end  =>
						tosend3<="--------";
							din3(origport)<='0';
							if fifo_in_empty(origport)='1' then
								etsnd3<=s_head;
							else
								etsnd3<=s_end;
							end if;
						end case;	
						
						end if;				
						
					end if; --reset='1'
		end process psend3;		

	preceiv:process(clk,reset)
	
	variable origport,ptype : natural range 0 to 15;
	variable datalen,dcount ,timeout:natural range 0 to 255;
	variable destport  : natural range 0 to 15:=1;
	begin
	
	if reset='1' then
		etrec<=r_wait;
		destport:=1;
		timeout:=0;
	elsif rising_edge(clk) then
			case  etrec is
			when r_wait =>
				if destport=0 then 
					destport:=1;
				end if;
				timeout:=0;
				time_out(destport)<='0';
				if data_available(destport)='1' and cmd_in_en(destport)='0' then 
				rdata_out_en(destport)<='1';
				 etrec<=r_head;
				else
					if destport>=MAXPORT then 
					destport:=1;
					else 
						destport:=destport+1;
					end if;
				etrec<=r_wait;
				end if;
			when r_head =>
			
				ptype:=to_integer(unsigned(portout(destport)(7 downto 4)));
				origport:=to_integer(unsigned(portout(destport)(3 downto 0)));
				rdata_out_en(destport)<='1';
				if ptype=5 then 
						etrec<=r_Dlen; --identification de la signature d'en tête valide
					else
						etrec<=r_wait;
				end if;
			

			
			
			
			when r_Dlen =>   --positionnement du mot de longueur des données
			if data_available(destport)='1' then 
			
			rdata_out_en(destport)<='1';
			etrec<=r_glen;
			timeout:=0;
			else
				timeout:=timeout+1;
					if timeout>=30 then 
					time_out(destport)<='1';
						etrec<=r_end;             -- données pas prêtes
					end if;
			
			
			end if;
			when r_glen =>   --lecture effective de la longueur des données
			if data_available(destport)='1' then 
			datalen:=to_integer(unsigned(portout(destport)(7 downto 0)))-3;
			rdata_out_en(destport)<='1';
			etrec<=r_start;
			dcount:=1;  -- initialisation du compteur de reception
			else
				timeout:=timeout+1;
					if timeout>=30 then 
					time_out(destport)<='1';
						etrec<=r_end;             -- données pas prêtes
					end if;
			
			end if;
			
			when r_start =>
			if data_available(destport)='1'  then 
				
					dcount:=dcount+1;
					assert true report "Donnée lue :"; --& string(unsigned(port4_out(7 downto 0)))
					rdata_out_en(destport)<='1';
					
					--severity note;
					if datalen<=dcount then 
						etrec<=r_end;
						
					elsif dcount=255 then   --dépassement de la capacité
						etrec<=r_end;
					end if;
			else
					timeout:=timeout+1;
					if timeout>=30 then 
					   time_out(destport)<='1';
						etrec<=r_end;             -- données pas prêtes
					end if;
				
					
			end if;
			when r_end =>
			
			
			rdata_out_en(destport)<='0';
			rcount(destport)<=rcount(destport)+1;
			etrec<=r_wait;
			if destport>=MAXPORT then -- provoquer le passage au prochain port de réception
					destport:=1;
					else 
						destport:=destport+1;
					end if;
			end case;
		end if;   --reset='1'
  end process preceiv;	
	
	pcmd:process(clk,reset)
	
	variable origport,destport,pid,mport : natural range 0 to 15;
	variable datalen,dcount ,timeout:natural range 0 to 255;
	begin
	
	if reset='1' then
		etcmd<=cmdstart;
		destport:=0;
		timeout:=0;
		origport:=1;
		sorigport<=origport;
	elsif rising_edge(clk) then
			case  etcmd is
			when cmdstart =>
				if fifo_in_empty(origport)='1' then 
					
				
				
				
				etcmd<=cmdpost;
				end if;
		 when cmdpost =>
			if fifo_in_empty(origport)='1' then 
			---assignations de l'état
				--din4(origport)<='1';
				--tosend4<="00000001"; ---code pour getportid
				etcmd<=cmdpostidle;
			end if;
		when cmdpostidle  =>   --permet juste la prise en compte de la commande
				if data_available(origport)='1' then 
						etcmd<=cmdread;
				end if;
		 when cmdread =>
				
				
				timeout:=0;
				--time_out(destport)<='0';
			if data_available(origport)='1' then 
				mport:=to_integer(unsigned(portout(origport)(7 downto 4)));
				pid:=to_integer(unsigned(portout(origport)(3 downto 0)))+1;
				--cdata_out_en(origport)<='1';
				if pid=origport then --le port a été bien identifié
						etcmd<=cmdglen; --
					else
					etcmd<=cmdtimeout;
				end if;
			else
--				if destport>=MAXPORT then 
--					destport:=1;
--					else 
--						destport:=destport+1;
--					end if;
				etcmd<=cmdread;
			end if;
			
			
			when cmdlen =>   --positionnement du mot de longueur des données
			if data_available(origport)='1' then 
			
			--cdata_out_en(origport)<='1';
			etcmd<=cmdglen;
			timeout:=0;
			else
				timeout:=timeout+1;
					if timeout>=30 then 
					--time_out(destport)<='1';
						etcmd<=cmdtimeout;             -- données pas prêtes
					end if;
			
			
			end if;
			when cmdglen =>   --lecture effective de la longueur des données
			if data_available(origport)='1' then 
			datalen:=to_integer(unsigned(portout(origport)(7 downto 0)))-3;
			
			etcmd<=cmddata;
			dcount:=0;  -- initialisation du compteur de reception
			else
				timeout:=timeout+1;
					if timeout>=30 then 
					--time_out(destport)<='1';
						etcmd<=cmdtimeout;             -- données pas prêtes
					end if;
			
			end if;
			
			when cmddata =>
			if data_available(origport)='1' and timeout<30 then 
					
					--cdata_out_en(origport)<='1';
					mport:=to_integer(unsigned(portout(origport)(7 downto 4)));
					--attention les ports sont numérotés à partir de 0
					pid:=to_integer(unsigned(portout(origport)(3 downto 0)))+1;
					
					--severity note;
					if Pid=origport then 
						etcmd<=cmdend;
						
					else   --dépassement de la capacité
						
						timeout:=timeout+1;
						if timeout>=30 then 
							etcmd<=cmdtimeout;
						end if;
						
					end if;
			else
					
					if timeout>=30 then 
					   time_out(origport)<='1';
						etcmd<=cmdtimeout;             -- données pas prêtes
					end if;
				   timeout:=timeout+1;
					
			end if;
			when cmdend =>
			
			
			--cdata_out_en(origport)<='0';
			
--					if origport>=mport then -- provoquer le passage au prochain port de réception
--						origport:=1;
--					else 
--						origport:=origport+1;
--					end if;
					etcmd<=cmdstart;
					--cmd_in_en(origport)<='0';
			when cmdtimeout =>
			  etcmd<=cmdtimeout;
			  --cmd_in_en(origport)<='0';
			  etcmd<=cmdstart;
			end case;
		sorigport<=origport;	
		end if;   --reset='1'
		
  end process pcmd;	

majetcmd:process (etcmd)
variable origport : natural:=1;-- =sorigport ;
	begin
			case  etcmd is
			when cmdstart =>
			
				cmd_in_en(origport)<='1';

		 when cmdpost  =>
				din4(origport)<='1';
				tosend4<="00000001"; ---code pour getportid
				cmd_in_en(origport)<='1';
				cdata_out_en(origport)<='0';
		 when cmdpostidle =>
				din4(origport)<='0';
				cdata_out_en(origport)<=data_available(origport);
				cmd_in_en(origport)<='1';
	
		 when cmdread =>
				din4(origport)<='0';
				cdata_out_en(origport)<=data_available(origport);
				cmd_in_en(origport)<='1';
	
			when cmdlen |cmdglen =>   --positionnement du mot de longueur des données
	
					din4(origport)<='0';
					cdata_out_en(origport)<=data_available(origport);
					cmd_in_en(origport)<='1';

			when cmddata =>
			
					din4(origport)<='0';
					cdata_out_en(origport)<=data_available(origport);
					cmd_in_en(origport)<='1';
						
			
			when cmdend =>
			
				din4(origport)<='0';
				cdata_out_en(origport)<='0';
				cmd_in_en(origport)<='0';
			
			when cmdtimeout =>
				  din4(origport)<='0';
				  cdata_out_en(origport)<='0';
				  cmd_in_en(origport)<='0';
			 
			end case;
		
end process majetcmd ; 
   -- Stimulus process
   stim_proc: process 
   begin		
      -- hold reset state for 100 ns.
      reset<='1';
		wait for 1 ns;	
		reset<='1';
      wait for clk_period*10;
		reset<='0';
		wait;
      -- insert stimulus here 
	
      
		
		
	end process;

END;
