----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    20:05:07 11/19/2011 
-- Design Name: 
-- Module Name:    MPI_NOC - 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 ;

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

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

entity MPI_NOC is
generic (NPROC : positive:=4);
 port(
 
 MPI_Node_in : in Ar_MPIPort_in(1 to NPROC);
 MPI_Node_Out : out Ar_MPIPort_out(1 to NPROC)
 );
end MPI_NOC;

architecture structural of MPI_NOC is
-- Declare signals for interconnections
 
--constant NPROC : positive :=8 ;
   --Inputs
   signal noc_portOut :typ_portio(1 to NPROC);
   signal noc_portIn  :typ_portio(1 to NPROC);
	   
   signal noc_fifo_in_full :  std_logic_vector(NPROC downto 1):= (others => '0');
   signal noc_data_available :   std_logic_vector(NPROC downto 1):= (others => '0');
   signal noc_fifo_in_empty : std_logic_vector(NPROC downto 1):= (others => '0');
	signal noc_data_in_en : std_logic_vector(NPROC downto 1) := (others => '0');
	signal noc_cmd_in_en : std_logic_vector(NPROC downto 1) := (others => '0');
   signal noc_data_out_en : std_logic_vector(NPROC downto 1) := (others => '0');
  -- signal noc_clk : std_logic := '0';
   --signal noc_reset : std_logic := '0';
	
-- Declare components
COMPONENT SWITCH_GEN
	 GENERIC (number_of_ports : positive := NPROC);
    PORT(
         Port_in : IN  typ_PortIO(1 to number_of_ports);
         Port_out : OUT    typ_PortIO(1 to number_of_ports);
         data_in_en : IN  std_logic_vector(NPROC downto 1);
			cmd_in_en : IN  std_logic_vector(NPROC downto 1);
         data_out_en : IN  std_logic_vector(NPROC downto 1);
         fifo_in_full : OUT  std_logic_vector(NPROC downto 1);
         fifo_in_empty : OUT  std_logic_vector(NPROC downto 1);
         data_available : OUT  std_logic_vector(NPROC downto 1);
         clk : IN  std_logic;
         reset : IN  std_logic
        );
    END COMPONENT;
	COMPONENT CORE_MPI is
    Port ( instruction : in  STD_LOGIC_VECTOR (Word-1 downto 0);
           instruction_en : in  STD_LOGIC;
           
           barrier_completed : out  STD_LOGIC;
           packet_received : out  STD_LOGIC;
			  packet_ack : in std_logic;
           PushOut : out  STD_LOGIC_VECTOR (Word-1 downto 0);
           ram_we : out  STD_LOGIC;
			  hold_req       : out STD_Logic;  --requete vers application
			  hold_ack       : in  STD_Logic;  --autorisation par l'application
           ram_address_rd : out  STD_LOGIC_VECTOR (ADRLEN-1 downto 0);
			  ram_address_wr : out  STD_LOGIC_VECTOR (ADRLEN-1 downto 0);
           ram_data_out : in  STD_LOGIC_VECTOR (Word-1 downto 0);
			  ram_data_in : out  STD_LOGIC_VECTOR (Word-1 downto 0);
           switch_port_in_wr_en : out  STD_LOGIC;   -- OK (au switch) pour lire les données 
           switch_port_in_empty : in STD_LOGIC;
			  switch_port_in_cmd_en : out STD_LOGIC;
			  switch_port_in_full : in  STD_LOGIC;  -- port d'entréendu switch saturé
           switch_port_in_data : out  STD_LOGIC_VECTOR (Word-1 downto 0); -- port de donées d'entrée
           switch_port_out_rd_en : out  STD_LOGIC;    -- OK (au switch) pour écrire les données
           switch_port_out_data_vailaible : in  STD_LOGIC; -- Donnée disponible à la sortie (du switch)
			  clk : in  STD_LOGIC;
			  clkout : out std_logic;
           reset : in  STD_LOGIC;
           ram_en : out  STD_LOGIC;
           instruction_fifo_full : out  STD_LOGIC;
           switch_port_out_data : in  STD_LOGIC_VECTOR (Word-1 downto 0));
	end COMPONENT;
-- cette fonction met en place l'architecture d'exécution de l'environnement
-- elle permet de construire le Noc et de connecter les différents core MPI
-- chaque core reçoit un ID qui sera son Rank lors de l'appel à MPI_GET_Rank
-- faut il créer une petite mémoire chargée de stocker les IDs ?
-- Oui car cette mémoire sera consultée par la fonction MPI_Init pour associer
-- un communicateur au MPI Core



  begin
Socsyst: if nproc >  1   generate  --nproc
      -- instancier le switch et connecter les différents ports
				 
switch_gen1: SWITCH_GEN generic map (NPROC)
		 PORT MAP (
          Port_in => Noc_PortIn,

          Port_out => noc_Portout,

          --signaux de contrôle de la lecture des ports
			 data_in_en => noc_data_in_en,
			 cmd_in_en => noc_cmd_in_en,
          data_out_en => noc_data_out_en,
          fifo_in_full => noc_fifo_in_full,
          fifo_in_empty => noc_fifo_in_empty,
          data_available => noc_data_available,
          clk => MPI_Node_in(1).clk,
          reset => MPI_Node_in(1).reset
			 );
		end generate;
 connect_core:		for i in 1 to nproc generate  -- nproc
		hardmpi:core_mpi port map (
		
			 
			  PushOut=>MPI_Node_out(i).PushOut, 
           ram_we=> MPI_Node_out(i).ram_we,
			  ram_en=>MPI_Node_out(i).ram_en ,
			  hold_req=>MPI_NODE_out(i).hold_req,
			  packet_received=>MPI_Node_out(i).packet_received ,
			  packet_ack=>MPI_Node_in(i).packet_ack,
			  hold_ack=>MPI_NODE_in(i).hold_ack,
           ram_address_rd => MPI_Node_out(i).ram_address_rd ,
			  ram_address_wr => MPI_Node_out(i).ram_address_wr ,
           ram_data_in=>MPI_Node_out(i).ram_data_in ,
			  ram_data_out=>MPI_Node_in(i).ram_data_out,
			  barrier_completed =>MPI_Node_out(i).barrier_completed, 			 
			  instruction => MPI_Node_in(i).instruction,
			  instruction_en => MPI_Node_in(i).instruction_en,
			  instruction_fifo_full =>MPI_Node_Out(i).instruction_fifo_full,
			  switch_port_in_wr_en => noc_data_in_en(i),
			  switch_port_in_cmd_en=>noc_cmd_in_en(i),
           switch_port_in_full => noc_fifo_in_full(i),
			  switch_port_in_empty => noc_fifo_in_empty(i),
           switch_port_in_data => noc_PortIn(i),
           switch_port_out_rd_en => noc_data_out_en(i),
           switch_port_out_data_vailaible => noc_data_available(i),
			  switch_port_out_data => noc_PortOut(i),
			  clk =>MPI_Node_in(1).clk,
           reset =>MPI_Node_in(1).reset
           
			  );
		end generate;
	
	


end Structural;

