#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         Toperation_t;
//typedef uint32_t        Tdestination1_t;
//typedef uint32_t        Tdestination2_t;
//typedef uint32_t        Texec_flag_t;
//typedef bool            Texec_excep_t;
			  
  typedef uint8_t         Texception_t;
  typedef uint8_t         Tcontext_t;
  typedef uint8_t         Tpacket_t;
  typedef uint8_t         Ttype_t;
  typedef uint8_t         Tevent_state_t;
  typedef uint8_t         Tevent_type_t;
  typedef uint8_t         Tcounter_t; // universal counter
  typedef uint8_t         Tptr_t;     // universal pointer
			  
  // ***** 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;

  // ***** component dependant
  // ~~~~~ load store queue
  typedef uint8_t         Taccess_t;
  typedef uint8_t         Tlsq_ptr_t;
  typedef uint32_t        Tdcache_address_t;
  typedef uint32_t        Tdcache_data_t;
  typedef bool            Tdcache_error_t;
  typedef uint8_t         Tdcache_type_t;

  // ~~~~~ prediction_unit
  typedef uint8_t         Thistory_t;
  typedef uint8_t         Tprediction_ptr_t;
  typedef uint8_t         Tbranch_state_t;
  typedef uint8_t         Tbranch_condition_t;
  typedef uint8_t         Tdepth_t;      
  typedef Tgeneral_data_t Taddress_t;


  // ~~~~~ ifetch
  typedef uint8_t         Tinst_ifetch_ptr_t;
  typedef uint8_t         Tifetch_queue_ptr_t;
  typedef uint32_t        Ticache_address_t;
  typedef uint32_t        Ticache_instruction_t;
  typedef bool            Ticache_error_t;
  typedef uint8_t         Ticache_type_t;

  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 adress 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            // Note predefined scheme
    } Tpredictor_t;

  //----------------------------------------------[ 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

  inline std::string toString_type(const morpheo::behavioural::Ttype_t& x)
  {
    switch (x)
      {
      case TYPE_ALU     : return "ALU"    ; break;
      case TYPE_SHIFT   : return "SHIFT"  ; break;
      case TYPE_MOVE    : return "MOVE"   ; break;
      case TYPE_TEST    : return "TEST"   ; break;
      case TYPE_MUL_DIV : return "MUL_DIV"; break;
      case TYPE_EXTEND  : return "EXTEND" ; break;
      case TYPE_FIND    : return "FIND"   ; break;
      case TYPE_SPECIAL : return "SPECIAL"; break;
      case TYPE_CUSTOM  : return "CUSTOM" ; break;
      case TYPE_BRANCH  : return "BRANCH" ; break;
      case TYPE_MEMORY  : return "MEMORY" ; break;
      default           : return ""       ; break;
      }
  };

  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("0")                    == 0) or
         (x.compare("priority_static")      == 0))
      return morpheo::behavioural::PRIORITY_STATIC;
    if ( (x.compare("1")                    == 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("0")                      == 0) or
         (x.compare("load_balancing_balance") == 0))
      return morpheo::behavioural::LOAD_BALANCING_BALANCE;
    if ( (x.compare("1")                                   == 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("0")                  == 0) or
         (x.compare("victim_random")      == 0))
      return morpheo::behavioural::VICTIM_RANDOM;
    if ( (x.compare("1")                  == 0) or
         (x.compare("victim_round_robin") == 0))
      return morpheo::behavioural::VICTIM_ROUND_ROBIN;
    if ( (x.compare("2")                  == 0) or
         (x.compare("victim_nlu")         == 0))
      return morpheo::behavioural::VICTIM_NLU;
    if ( (x.compare("3")                  == 0) or
         (x.compare("victim_pseudo_lru")  == 0))
      return morpheo::behavioural::VICTIM_PSEUDO_LRU;
    if ( (x.compare("4")                  == 0) or
         (x.compare("victim_lru")         == 0))
      return morpheo::behavioural::VICTIM_LRU;
    if ( (x.compare("5")                  == 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("0")                     == 0) or
         (x.compare("predictor_never_take")  == 0))
      return morpheo::behavioural::PREDICTOR_NEVER_TAKE;
    if ( (x.compare("1")                     == 0) or
         (x.compare("predictor_always_take") == 0))
      return morpheo::behavioural::PREDICTOR_ALWAYS_TAKE;
    if ( (x.compare("2")                     == 0) or
         (x.compare("predictor_static")      == 0))
      return morpheo::behavioural::PREDICTOR_STATIC;
    if ( (x.compare("3")                     == 0) or
         (x.compare("predictor_last_take")   == 0))
      return morpheo::behavioural::PREDICTOR_LAST_TAKE;
    if ( (x.compare("4")                     == 0) or
         (x.compare("predictor_counter")     == 0))
      return morpheo::behavioural::PREDICTOR_COUNTER;
    if ( (x.compare("5")                     == 0) or
         (x.compare("predictor_local")       == 0))
      return morpheo::behavioural::PREDICTOR_LOCAL;
    if ( (x.compare("6")                     == 0) or
         (x.compare("predictor_global")      == 0))
      return morpheo::behavioural::PREDICTOR_GLOBAL;
    if ( (x.compare("7")                     == 0) or
         (x.compare("predictor_meta")        == 0))
      return morpheo::behavioural::PREDICTOR_META;
    if ( (x.compare("8")                     == 0) or
         (x.compare("predictor_custom")      == 0))
      return morpheo::behavioural::PREDICTOR_CUSTOM;
    throw (ERRORMORPHEO ("fromString","Unknow string : \""+x+"\""));
  };

}; // end namespace morpheo              
#endif
