#ifndef morpheo_behavioural_Types_h
#define morpheo_behavioural_Types_h

#include "Common/include/Types.h"
#include "Common/include/ToString.h"
#include "Common/include/FromString.h"
#include "Common/include/ErrorMorpheo.h"
#include "Behavioural/include/Constants.h"

namespace morpheo {
namespace behavioural {
  
  //============================================
  // Type definition
  //============================================

  // ***** general
  typedef uint32_t           Tinstruction_t;
  typedef bool               Tcontrol_t;
  typedef uint8_t            Texception_t;
  typedef uint8_t            Tcontext_t;
  typedef uint16_t           Tpacket_t;
  typedef uint8_t            Toperation_t;
  typedef uint8_t            Ttype_t;
  typedef uint32_t           Tcounter_t; // universal counter
  typedef uint32_t           Tptr_t;     // universal pointer
  typedef uint32_t           Tspr_t;
  typedef uint16_t           Tspr_address_t;

//typedef uint32_t           Tdestination1_t;
//typedef uint32_t           Tdestination2_t;
//typedef uint32_t           Texec_flag_t;
//typedef bool               Texec_excep_t;
			     
  // ***** Event	     
  typedef uint8_t            Tevent_state_t;
  typedef uint8_t            Tevent_type_t;
			     
  // ***** Register	     
  typedef uint32_t           Tgeneral_address_t;
  typedef uint32_t           Tgeneral_data_t;
  typedef uint32_t           Tspecial_address_t;
  typedef uint32_t           Tspecial_data_t;
			     
  // ~~~~~ prediction_unit   
  typedef uint64_t           Thistory_t;
  typedef Tptr_t             Tprediction_ptr_t;
  typedef uint8_t            Tbranch_state_t;
  typedef uint8_t            Tbranch_condition_t;
  typedef Tprediction_ptr_t  Tdepth_t;
  typedef Tgeneral_data_t    Taddress_t;

  // ***** component dependant
  // ~~~~~ load store queue
  typedef uint8_t            Taccess_t;
  typedef Tptr_t             Tlsq_ptr_t;
  typedef Tgeneral_address_t Tdcache_address_t;
  typedef Tgeneral_data_t    Tdcache_data_t;
  typedef bool               Tdcache_error_t;
  typedef uint8_t            Tdcache_type_t;
			     
			     
  // ~~~~~ ifetch	     
  typedef Tptr_t             Tinst_ifetch_ptr_t;
  typedef Tptr_t             Tifetch_queue_ptr_t;
  typedef Tgeneral_address_t Ticache_address_t;
  typedef Tgeneral_data_t    Ticache_instruction_t;
  typedef bool               Ticache_error_t;
  typedef uint8_t            Ticache_type_t;

  typedef enum
    {
      ORBIS32,
      ORBIS64,
      ORFPX32,
      ORFPX64,
      ORVDX64
    } ISA;

  typedef enum
    {
      PRIORITY_STATIC,
      PRIORITY_ROUND_ROBIN
    } Tpriority_t;

  typedef enum
    {
      LOAD_BALANCING_BALANCE,
      LOAD_BALANCING_MAXIMUM_FOR_PRIORITY
    } Tload_balancing_t;

  typedef enum
    {
      VICTIM_RANDOM     , // Random
      VICTIM_ROUND_ROBIN, // Round Robin
      VICTIM_NLU        , // Not Last Used
      VICTIM_PSEUDO_LRU , // Pseudo Least Recently Used
      VICTIM_LRU        , // Least Recently Used
      VICTIM_FIFO         // First IN First OUT
    } Tvictim_t;

  typedef enum
    {
      PREDICTOR_NEVER_TAKE      , // Branch is never  Take
      PREDICTOR_ALWAYS_TAKE     , // Branch is always Take
      PREDICTOR_STATIC          , // If the address of destination is previous, then the branch is take
      PREDICTOR_LAST_TAKE       , // The direction is as the last time (if is the first time : static)
      PREDICTOR_COUNTER         , // Counter table
      PREDICTOR_LOCAL           , // Counter bank indexed with history bank
      PREDICTOR_GLOBAL          , // Counter bank indexed with history table
      PREDICTOR_META            , // A meta_predictor choose between 2 predictor : the local or the global
      PREDICTOR_CUSTOM            // Not predefined scheme
    } Tpredictor_t;

  typedef enum
    {
      MANAGE_EVENT_WAIT_ALL,
      MANAGE_EVENT_WAIT_DECODE,
      MANAGE_EVENT_NO_WAIT
    } Tmanage_event_t;

  //--------------------------------------------------[ instruction ]-----
  class instruction_t
  {
  public :
    Ttype_t      _type      ;
    Toperation_t _operation ;
    ISA          _isa_subset;
    uint8_t      _isa_class ;

    instruction_t (Ttype_t      type      ,
                   Toperation_t operation ,
                   ISA          isa_subset,
                   uint8_t      isa_class )
    {
      _type       = type      ;
      _operation  = operation ;
      _isa_subset = isa_subset;
      _isa_class  = isa_class ;
    }
  };

  instruction_t instruction_information (uint32_t instruction);
  uint32_t      instruction_size_data   (uint32_t instruction);

  //----------------------------------------------[ spr_mode_access ]-----
  class spr_access_mode_t
  {
  public : uint8_t _user_access_mode      ;
  public : uint8_t _supervisor_access_mode;
    
  public : spr_access_mode_t (uint32_t user_access_mode       = SPR_ACCESS_MODE_NONE,
			      uint32_t supervisor_access_mode = SPR_ACCESS_MODE_NONE)
    {
      _user_access_mode       = user_access_mode      ;
      _supervisor_access_mode = supervisor_access_mode;
    }
  };

}; // end namespace behavioural

  template<> inline std::string toString<morpheo::behavioural::Tpriority_t>(const morpheo::behavioural::Tpriority_t& x)
  {
    switch (x)
      {
      case morpheo::behavioural::PRIORITY_STATIC      : return "priority_static"; break;
      case morpheo::behavioural::PRIORITY_ROUND_ROBIN : return "priority_round_robin"; break;
      default    : return ""      ; break;
      }
  };

  template<> inline morpheo::behavioural::Tpriority_t fromString<morpheo::behavioural::Tpriority_t>(const std::string& x)
  {
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::PRIORITY_STATIC))) == 0) or
         (x.compare("priority_static")      == 0))
      return morpheo::behavioural::PRIORITY_STATIC;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::PRIORITY_ROUND_ROBIN))) == 0) or
         (x.compare("priority_round_robin") == 0))
      return morpheo::behavioural::PRIORITY_ROUND_ROBIN;
    throw (ERRORMORPHEO ("fromString","Unknow string : \""+x+"\""));
  };

  template<> inline std::string toString<morpheo::behavioural::Tload_balancing_t>(const morpheo::behavioural::Tload_balancing_t& x)
  {
    switch (x)
      {
      case morpheo::behavioural::LOAD_BALANCING_BALANCE              : return "load_balancing_balance"; break;
      case morpheo::behavioural::LOAD_BALANCING_MAXIMUM_FOR_PRIORITY : return "load_balancing_maximum_for_priority"; break;
      default    : return ""      ; break;
      }
  };

  template<> inline morpheo::behavioural::Tload_balancing_t fromString<morpheo::behavioural::Tload_balancing_t>(const std::string& x)
  {
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::LOAD_BALANCING_BALANCE))) == 0) or
         (x.compare("load_balancing_balance") == 0))
      return morpheo::behavioural::LOAD_BALANCING_BALANCE;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::LOAD_BALANCING_MAXIMUM_FOR_PRIORITY))) == 0) or
         (x.compare("load_balancing_maximum_for_priority") == 0))
      return morpheo::behavioural::LOAD_BALANCING_MAXIMUM_FOR_PRIORITY;
    throw (ERRORMORPHEO ("fromString","Unknow string : \""+x+"\""));
  };

  template<> inline std::string toString<morpheo::behavioural::Tvictim_t>(const morpheo::behavioural::Tvictim_t& x)
  {
    switch (x)
      {
      case morpheo::behavioural::VICTIM_RANDOM      : return "victim_random"     ; break;
      case morpheo::behavioural::VICTIM_ROUND_ROBIN : return "victim_round_robin"; break;
      case morpheo::behavioural::VICTIM_NLU         : return "victim_nlu"        ; break;
      case morpheo::behavioural::VICTIM_PSEUDO_LRU  : return "victim_pseudo_lru" ; break;
      case morpheo::behavioural::VICTIM_LRU         : return "victim_lru"        ; break;
      case morpheo::behavioural::VICTIM_FIFO        : return "victim_fifo"       ; break;
      default    : return ""      ; break;
      }
  };

  template<> inline morpheo::behavioural::Tvictim_t fromString<morpheo::behavioural::Tvictim_t>(const std::string& x)
  {
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::VICTIM_RANDOM     ))) == 0) or
         (x.compare("victim_random")      == 0))
      return morpheo::behavioural::VICTIM_RANDOM;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::VICTIM_ROUND_ROBIN))) == 0) or
         (x.compare("victim_round_robin") == 0))
      return morpheo::behavioural::VICTIM_ROUND_ROBIN;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::VICTIM_NLU        ))) == 0) or
         (x.compare("victim_nlu")         == 0))
      return morpheo::behavioural::VICTIM_NLU;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::VICTIM_PSEUDO_LRU ))) == 0) or
         (x.compare("victim_pseudo_lru")  == 0))
      return morpheo::behavioural::VICTIM_PSEUDO_LRU;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::VICTIM_LRU        ))) == 0) or
         (x.compare("victim_lru")         == 0))
      return morpheo::behavioural::VICTIM_LRU;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::VICTIM_FIFO       ))) == 0) or
         (x.compare("victim_fifo")        == 0))
      return morpheo::behavioural::VICTIM_FIFO;
    throw (ERRORMORPHEO ("fromString","Unknow string : \""+x+"\""));
  };

  template<> inline std::string toString<morpheo::behavioural::Tpredictor_t>(const morpheo::behavioural::Tpredictor_t& x)
  {
    switch (x)
      {
      case morpheo::behavioural::PREDICTOR_NEVER_TAKE  : return "predictor_never_take" ; break;
      case morpheo::behavioural::PREDICTOR_ALWAYS_TAKE : return "predictor_always_take"; break;
      case morpheo::behavioural::PREDICTOR_STATIC      : return "predictor_static"     ; break;
      case morpheo::behavioural::PREDICTOR_LAST_TAKE   : return "predictor_last_take"  ; break;
      case morpheo::behavioural::PREDICTOR_COUNTER     : return "predictor_counter"    ; break;
      case morpheo::behavioural::PREDICTOR_LOCAL       : return "predictor_local"      ; break;
      case morpheo::behavioural::PREDICTOR_GLOBAL      : return "predictor_global"     ; break;
      case morpheo::behavioural::PREDICTOR_META        : return "predictor_meta"       ; break;
      case morpheo::behavioural::PREDICTOR_CUSTOM      : return "predictor_custom"     ; break;
      default    : return ""      ; break;
      }
  };

  template<> inline morpheo::behavioural::Tpredictor_t fromString<morpheo::behavioural::Tpredictor_t>(const std::string& x)
  {
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::PREDICTOR_NEVER_TAKE ))) == 0) or
         (x.compare("predictor_never_take")  == 0))
      return morpheo::behavioural::PREDICTOR_NEVER_TAKE;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::PREDICTOR_ALWAYS_TAKE))) == 0) or
         (x.compare("predictor_always_take") == 0))
      return morpheo::behavioural::PREDICTOR_ALWAYS_TAKE;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::PREDICTOR_STATIC     ))) == 0) or
         (x.compare("predictor_static")      == 0))
      return morpheo::behavioural::PREDICTOR_STATIC;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::PREDICTOR_LAST_TAKE  ))) == 0) or
         (x.compare("predictor_last_take")   == 0))
      return morpheo::behavioural::PREDICTOR_LAST_TAKE;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::PREDICTOR_COUNTER    ))) == 0) or
         (x.compare("predictor_counter")     == 0))
      return morpheo::behavioural::PREDICTOR_COUNTER;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::PREDICTOR_LOCAL      ))) == 0) or
         (x.compare("predictor_local")       == 0))
      return morpheo::behavioural::PREDICTOR_LOCAL;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::PREDICTOR_GLOBAL     ))) == 0) or
         (x.compare("predictor_global")      == 0))
      return morpheo::behavioural::PREDICTOR_GLOBAL;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::PREDICTOR_META       ))) == 0) or
         (x.compare("predictor_meta")        == 0))
      return morpheo::behavioural::PREDICTOR_META;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::PREDICTOR_CUSTOM     ))) == 0) or
         (x.compare("predictor_custom")      == 0))
      return morpheo::behavioural::PREDICTOR_CUSTOM;
    throw (ERRORMORPHEO ("fromString","Unknow string : \""+x+"\""));
  };

}; // end namespace morpheo              
#endif
