#ifndef morpheo_Morpheo_h
#define morpheo_Morpheo_h

/*
 * $Id: Morpheo.h 110 2009-02-19 16:31:47Z rosiere $
 *
 * [ Description ]
 * 
 */

#ifdef SYSTEMC
#include "systemc.h"
#endif

#include "Behavioural/Core/include/Core.h"
#include "Behavioural/Custom/include/Custom.h"
#include "Behavioural/Core/include/Parameters.h"
#include "Behavioural/Configuration/include/Configuration.h"

#include "TopLevel/include/Types.h"

#ifdef STATISTICS
#include "Behavioural/include/Stat.h"
#endif
#include "Behavioural/include/Component.h"
#ifdef VHDL
#include "Behavioural/include/Vhdl.h"
#endif
#include "Behavioural/include/Usage.h"

#include "Common/include/ToString.h"
#include "Common/include/Debug.h"

#include <iostream>
#include <csignal>
#include <unistd.h>

namespace morpheo {

  class Morpheo 
#if SYSTEMC
    : public sc_module
#endif
  {
    // -----[ fields ]----------------------------------------------------
    // Parameters
  private   : std::string                                          _name;
  private   : behavioural::Tusage_t                                _usage;
  private   : morpheo::behavioural::configuration::Configuration * _config;
  private   : morpheo::behavioural::core::Parameters             * _param_core;
#ifdef STATISTICS
  private   : morpheo::behavioural::Parameters_Statistics        * _param_statistics;
  private   : behavioural::Stat                                  * _stat;
#endif

  private   : behavioural::Component                             * _component;
  private   : behavioural::Interfaces                            * _interfaces;

    // -----[ interface parameters ]--------------------------------------
  public    : uint32_t                                             _nb_thread                 ;

  public    : uint32_t                                             _nb_icache_port            ;
  public    : uint32_t                                             _size_icache_thread_id     ;
  public    : uint32_t                                             _size_icache_packet_id     ;
  public    : uint32_t                                             _size_icache_address       ;
  public    : uint32_t                                             _size_icache_type          ;
  public    : uint32_t                                             _size_icache_error         ;
  public    : uint32_t                                           * _icache_nb_instruction     ;//[nb_icache_port]
  public    : uint32_t                                             _size_icache_instruction   ;

  public    : uint32_t                                             _nb_dcache_port            ;
  public    : uint32_t                                             _size_dcache_thread_id     ;
  public    : uint32_t                                             _size_dcache_packet_id     ;
  public    : uint32_t                                             _size_dcache_address       ;
  public    : uint32_t                                             _size_dcache_data          ;
  public    : uint32_t                                             _size_dcache_type          ;
  public    : uint32_t                                             _size_dcache_error         ;
  
  public    : bool                                                 _have_port_icache_thread_id;
  public    : bool                                                 _have_port_icache_packet_id;
  public    : bool                                                 _have_port_dcache_thread_id;
  public    : bool                                                 _have_port_dcache_packet_id;

#ifdef SYSTEMC
    // ~~~~~[ Interface ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // ~~~~~[ Interface : "" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  public    : SC_CLOCK                         *  in_CLOCK        ;
  public    : SC_IN (Tcontrol_t)               *  in_NRESET       ;

    // ~~~~~[ Interface "icache_req" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  public    : SC_OUT(Tcontrol_t           )   ** out_ICACHE_REQ_VAL         ;//[nb_icache_port]
  public    : SC_IN (Tcontrol_t           )   **  in_ICACHE_REQ_ACK         ;//[nb_icache_port]
  public    : SC_OUT(Ticache_context_t    )   ** out_ICACHE_REQ_THREAD_ID   ;//[nb_icache_port]
  public    : SC_OUT(Ticache_packet_t     )   ** out_ICACHE_REQ_PACKET_ID   ;//[nb_icache_port]
  public    : SC_OUT(Ticache_address_t    )   ** out_ICACHE_REQ_ADDRESS     ;//[nb_icache_port]
  public    : SC_OUT(Ticache_type_t       )   ** out_ICACHE_REQ_TYPE        ;//[nb_icache_port]

    // ~~~~~[ Interface "icache_rsp" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
  public    : SC_IN (Tcontrol_t           )   **  in_ICACHE_RSP_VAL         ;//[nb_icache_port]
  public    : SC_OUT(Tcontrol_t           )   ** out_ICACHE_RSP_ACK         ;//[nb_icache_port]
  public    : SC_IN (Ticache_context_t    )   **  in_ICACHE_RSP_THREAD_ID   ;//[nb_icache_port]
  public    : SC_IN (Ticache_packet_t     )   **  in_ICACHE_RSP_PACKET_ID   ;//[nb_icache_port]
  public    : SC_IN (Ticache_instruction_t)  ***  in_ICACHE_RSP_INSTRUCTION ;//[nb_icache_port][icache_nb_instruction]
  public    : SC_IN (Ticache_error_t      )   **  in_ICACHE_RSP_ERROR       ;//[nb_icache_port]

    // ~~~~~[ Interface "dcache_req" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  public    : SC_OUT(Tcontrol_t           )   ** out_DCACHE_REQ_VAL         ;//[nb_dcache_port]
  public    : SC_IN (Tcontrol_t           )   **  in_DCACHE_REQ_ACK         ;//[nb_dcache_port]
  public    : SC_OUT(Tdcache_context_t    )   ** out_DCACHE_REQ_THREAD_ID   ;//[nb_dcache_port]
  public    : SC_OUT(Tdcache_packet_t     )   ** out_DCACHE_REQ_PACKET_ID   ;//[nb_dcache_port]
  public    : SC_OUT(Tdcache_address_t    )   ** out_DCACHE_REQ_ADDRESS     ;//[nb_dcache_port]
  public    : SC_OUT(Tdcache_data_t       )   ** out_DCACHE_REQ_WDATA       ;//[nb_dcache_port]
  public    : SC_OUT(Tdcache_type_t       )   ** out_DCACHE_REQ_TYPE        ;//[nb_dcache_port]
									    
    // ~~~~~[ Interface "dcache_rsp" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
  public    : SC_IN (Tcontrol_t           )   **  in_DCACHE_RSP_VAL         ;//[nb_dcache_port]
  public    : SC_OUT(Tcontrol_t           )   ** out_DCACHE_RSP_ACK         ;//[nb_dcache_port]
  public    : SC_IN (Tdcache_context_t    )   **  in_DCACHE_RSP_THREAD_ID   ;//[nb_dcache_port]
  public    : SC_IN (Tdcache_packet_t     )   **  in_DCACHE_RSP_PACKET_ID   ;//[nb_dcache_port]
  public    : SC_IN (Tdcache_data_t       )   **  in_DCACHE_RSP_RDATA       ;//[nb_dcache_port]
  public    : SC_IN (Tdcache_error_t      )   **  in_DCACHE_RSP_ERROR       ;//[nb_dcache_port]

    // ~~~~~[ Interface : "interrupt" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  public    : SC_IN (Tcontrol_t           )   **  in_INTERRUPT_ENABLE       ;//[nb_thread] - Interrupt Exception

    // ~~~~~[ Component ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    
  private   : morpheo::behavioural::core::Core * _component_core            ;
    
    // ~~~~~[ Register ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    

    // ~~~~~[ Internal ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#endif

    // -----[ Methods ]---------------------------------------------------

#ifdef SYSTEMC
    SC_HAS_PROCESS (Morpheo);
#endif
  public  :          Morpheo              
  (
#ifdef SYSTEMC
   sc_module_name name,
#else		  
   std::string    name,
#endif		               
   std::string    filename_simulator,
   std::string    filename_generator, 
   std::string    filename_instance ,
   morpheo::behavioural::custom::custom_information_t (*get_custom_information) (void)
   );
  public  :            ~Morpheo                   (void);

  private : void        configuration             (std::string filename_simulator, 
                                                   std::string filename_generator, 
                                                   std::string filename_instance ,
                                                   morpheo::behavioural::custom::custom_information_t (*get_custom_information) (void));
					       
  private : void        allocation                (
#ifdef STATISTICS
						   morpheo::behavioural::Parameters_Statistics * param_statistics
#else
						   void
#endif
						   );
  private : void        deallocation              (void);
					       
#ifdef SYSTEMC				       
# if defined(STATISTICS) or defined(VHDL_TESTBENCH)
  private : void        transition                (void);
# endif					       
#endif					       

#if VHDL				       
  private : void        vhdl                      (void);
#endif					       

#ifdef STATISTICS
  private : void        statistics_allocation     (morpheo::behavioural::Parameters_Statistics * param_statistics);
  private : void        statistics_deallocation   (void);
#endif
#if defined(STATISTICS) or defined(VHDL_TESTBENCH)
  private : void        end_cycle                 (void);
#endif

#ifdef SYSTEMC
  public  : bool        simulation_end            (void);
  private : void        signal_init               (void);
//private : void        signal_handler            (int value);
#endif
  };

  void signal_handler (int value);

}; // end namespace morpheo

#endif
