#ifndef morpheo_behavioural_core_multi_execute_loop_execute_loop_multi_execute_unit_execute_unit_load_store_unit_Types_h
#define morpheo_behavioural_core_multi_execute_loop_execute_loop_multi_execute_unit_execute_unit_load_store_unit_Types_h

/*
 * $Id: Types.h 122 2009-06-03 08:15:51Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/include/Types.h"
#include "Common/include/ToString.h"
#include "Common/include/FromString.h"
#include "Common/include/ErrorMorpheo.h"
#include <ostream>

namespace morpheo {
namespace behavioural {
namespace core {
namespace multi_execute_loop {
namespace execute_loop {
namespace multi_execute_unit {
namespace execute_unit {
namespace load_store_unit {

#define DCACHE_REQ_IS_LOAD(x)   (x<<1)
#define DCACHE_REQ_IS_STORE(x) ((x<<1)|1)

#define DCACHE_RSP_IS_LOAD(x)  ((x&1)==0)
#define DCACHE_RSP_IS_STORE(x) ((x&1)==1)


  typedef enum 
    {
       NO_SPECULATIVE_LOAD     //each load wait all previous store before the data cache access
      ,SPECULATIVE_LOAD_ACCESS //each load wait all previous store before the commiting
      ,SPECULATIVE_LOAD_COMMIT //each load commit the result before the end of dependence's check
    //,SPECULATIVE_LOAD_BYPASS //each load bypass the result before the end of dependence's check
    } Tspeculative_load_t; 
  
  typedef enum
    {
      SELECT_STORE_QUEUE,
      SELECT_LOAD_QUEUE ,
      SELECT_LOAD_QUEUE_SPECULATIVE
    } Tselect_queue_t;
  
  // ----------------------------------------------------------
  // Store Queue
  // ----------------------------------------------------------

  typedef enum
    {
      STORE_QUEUE_EMPTY                   //entry is empty
      ,STORE_QUEUE_NO_VALID_NO_SPECULATIVE //entry is the top of rob, and operation isn't arrive
      ,STORE_QUEUE_VALID_SPECULATIVE       //entry is arrive and wait the top of rob
      ,STORE_QUEUE_VALID_NO_SPECULATIVE    //entry is ok, can be access at a dcache port.
      ,STORE_QUEUE_COMMIT                  //entry have access at dcache
    } Tstore_queue_state_t;

  class Tstore_queue_entry_t
  {
  public    : Tstore_queue_state_t _state               ;
  public    : Tcontext_t           _context_id          ;
  public    : Tcontext_t           _front_end_id        ;
  public    : Tcontext_t           _ooo_engine_id       ;
  public    : Tpacket_t            _packet_id           ;
  public    : Toperation_t         _operation           ;
  public    : Tlsq_ptr_t           _load_queue_ptr_write;
  public    : Tdcache_address_t    _address             ;
  public    : Tgeneral_data_t      _wdata               ;
//public    : Tcontrol_t           _write_rd            ;
//public    : Tgeneral_address_t   _num_reg_rd          ;
  public    : Texception_t         _exception           ;
  public    : bool                 _send_commit         ;

    friend std::ostream & operator << (std::ostream& os, const Tstore_queue_entry_t & x) 
    {
      return os << " * state                               : " << x._state << std::endl
		<< "   * packet                            : " << toString(x._packet_id) << std::endl
		<< "   * context, front_end, ooo_engine_id : " << toString(x._context_id) << " - " << toString(x._front_end_id) << " - " << toString(x._ooo_engine_id) << std::endl
		<< "   * operation                         : " << toString(x._operation) << std::endl
		<< "   * load_ptr                          : " << toString(x._load_queue_ptr_write) << std::endl
		<< "   * exception                         : " << toString(x._exception) << std::endl
		<< std::hex
		<< "   * address                           : " << toString(x._address)<< std::endl
		<< "   * wdata                             : " << toString(x._wdata) << std::endl
		<< std::dec;
    }
  };
  
  

  // ----------------------------------------------------------
  // Speculative_Access  Queue
  // ----------------------------------------------------------

  typedef enum
    {
      SPECULATIVE_ACCESS_QUEUE_EMPTY            //entry is empty
      ,SPECULATIVE_ACCESS_QUEUE_WAIT_CACHE      //entry is valid and can access at the dcache
      ,SPECULATIVE_ACCESS_QUEUE_WAIT_LOAD_QUEUE //entry wait an empty slot in load queue
    } Tspeculative_access_queue_state_t;

  class Tspeculative_access_queue_entry_t
  {
  public    : Tspeculative_access_queue_state_t  _state                ;
  public    : Tcontext_t                         _context_id           ;
  public    : Tcontext_t                         _front_end_id         ;
  public    : Tcontext_t                         _ooo_engine_id        ;
  public    : Tpacket_t                          _packet_id            ;
  public    : Toperation_t                       _operation            ;
  public    : Tlsq_ptr_t                         _load_queue_ptr_write ;
  public    : Tlsq_ptr_t                         _store_queue_ptr_write;
  public    : Tlsq_ptr_t                         _store_queue_ptr_read ;
  public    : Tcontrol_t                         _store_queue_empty    ;
  public    : Tdcache_address_t                  _address              ;
  public    : Tcontrol_t                         _write_rd             ;
  public    : Tgeneral_address_t                 _num_reg_rd           ;
  public    : Texception_t                       _exception            ;

    friend std::ostream & operator << (std::ostream& os, const Tspeculative_access_queue_entry_t & x)
    {
      return os << " * state                               : " << x._state << std::endl
		<< "   * packet                            : " << toString(x._packet_id) << std::endl
		<< "   * context, front_end, ooo_engine_id : " << toString(x._context_id) << " - " << toString(x._front_end_id) << " - " << toString(x._ooo_engine_id) << std::endl
		<< "   * operation                         : " << toString(x._operation) << std::endl
		<< "   * load, store ptr_(write/read) empty: " << toString(x._load_queue_ptr_write) << " - " << toString(x._store_queue_ptr_write) << " - " << toString(x._store_queue_ptr_read) << " - " << toString(x._store_queue_empty) << std::endl
		<< "   * exception                         : " << toString(x._exception) << std::endl
		<< std::hex
		<< "   * address                           : " << toString(x._address)<< std::endl
		<< std::dec
		<< "   * write_rd, num_reg_rd              : " << toString(x._write_rd) << " - " << toString(x._num_reg_rd)<< std::endl;
    }
  };

  // ----------------------------------------------------------
  // Load  Queue
  // ----------------------------------------------------------

  //                                   HAVE_DCACHE_RSP MUST_CHECK DECOD_BARRIER
  // OPERATION_MEMORY_LOAD             X               X          -
  // OPERATION_MEMORY_LOCK             -               -          -
  // OPERATION_MEMORY_INVALIDATE       -               -          X (mtspr)
  // OPERATION_MEMORY_PREFETCH         -               -          -
  // OPERATION_MEMORY_FLUSH            -               -          X (mtspr)
  // OPERATION_MEMORY_SYNCHRONIZATION  X               -          X (msync, psync, csync)
  
#define have_dcache_rsp(x) (is_operation_memory_load(x) or (x==OPERATION_MEMORY_SYNCHRONIZATION))
#define must_check(x)      (is_operation_memory_load(x))

  typedef enum
    {
      LOAD_QUEUE_EMPTY         //entry is empty
      ,LOAD_QUEUE_WAIT_CHECK   //entry must wait the respons and check dependence with store
      ,LOAD_QUEUE_WAIT         //entry must wait the respons
      ,LOAD_QUEUE_COMMIT_CHECK //entry must check dependence and can commit speculative
      ,LOAD_QUEUE_CHECK        //entry must check dependence with store
      ,LOAD_QUEUE_COMMIT       //entry must commit the instruction
    } Tload_queue_state_t;

  class Tload_queue_entry_t
  {
  public    : Tload_queue_state_t  _state            ;
  public    : Tcontext_t           _context_id       ;
  public    : Tcontext_t           _front_end_id     ;
  public    : Tcontext_t           _ooo_engine_id    ;
  public    : Tpacket_t            _packet_id        ;
  public    : Toperation_t         _operation        ;
  public    : Tlsq_ptr_t           _store_queue_ptr_write;
  public    : Tlsq_ptr_t           _store_queue_ptr_read ;
  public    : Tcontrol_t           _store_queue_empty    ;
  public    : Tdcache_address_t    _address          ;
  public    : Tdcache_address_t    _check_hit_byte   ; 
  public    : Tcontrol_t           _check_hit        ;
  public    : Tdcache_address_t    _shift            ;
  public    : Tcontrol_t           _is_load_signed   ;
  public    : Taccess_t            _access_size      ;
  public    : Tgeneral_data_t      _rdata            ;
  public    : Tcontrol_t           _write_rd         ;
  public    : Tgeneral_address_t   _num_reg_rd       ;
  public    : Texception_t         _exception        ;

    friend std::ostream & operator << (std::ostream& os, const Tload_queue_entry_t & x)
    {
      return os << " * state                               : " << x._state << std::endl
		<< "   * packet                            : " << toString(x._packet_id) << std::endl
		<< "   * context, front_end, ooo_engine_id : " << toString(x._context_id) << " - " << toString(x._front_end_id) << " - " << toString(x._ooo_engine_id) << std::endl
		<< "   * operation                         : " << toString(x._operation) << std::endl
		<< "   * store_queue ptr_(write,read) empty: " << toString(x._store_queue_ptr_write) << " - " << toString(x._store_queue_ptr_read) << " - " << toString(x._store_queue_empty) <<std::endl
		<< "   * exception                         : " << toString(x._exception) << std::endl
		<< "   * check_hit, check_hit_byte         : " << toString(x._check_hit) << " - " << toString(x._check_hit_byte) << std::endl
		<< std::hex
		<< "   * address                           : " << toString(x._address)<< std::endl
		<< "   * rdata                             : " << toString(x._rdata) << std::endl
		<< std::dec
		<< "   * write_rd, num_reg_rd              : " << toString(x._write_rd) << " - " << toString(x._num_reg_rd)<< std::endl;
    }

  };

}; // end namespace load_store_unit
}; // end namespace execute_unit
}; // end namespace multi_execute_unit
}; // end namespace execute_loop
}; // end namespace multi_execute_loop
}; // end namespace core
}; // end namespace behavioural

  template<> inline std::string toString<morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::Tspeculative_load_t>(const morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::Tspeculative_load_t& x)
  {
    switch (x)
      {
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::NO_SPECULATIVE_LOAD     : return "no_speculative_load"    ; break;
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::SPECULATIVE_LOAD_ACCESS : return "speculative_load_access"; break;
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::SPECULATIVE_LOAD_COMMIT : return "speculative_load_commit"; break;
//       case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::SPECULATIVE_LOAD_BYPASS : return "speculative_load_bypass"; break;
      default    : return ""      ; break;
      }
  };

  template<> inline morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::Tspeculative_load_t fromString<morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::Tspeculative_load_t>(const std::string& x)
  {
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::NO_SPECULATIVE_LOAD    ))) == 0) or
         (x.compare("no_speculative_load")     == 0))
      return morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::NO_SPECULATIVE_LOAD;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::SPECULATIVE_LOAD_ACCESS))) == 0) or
         (x.compare("speculative_load_access") == 0))
      return morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::SPECULATIVE_LOAD_ACCESS;
    if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::SPECULATIVE_LOAD_COMMIT))) == 0) or
         (x.compare("speculative_load_commit") == 0))
      return morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::SPECULATIVE_LOAD_COMMIT;
//     if ( (x.compare(toString(static_cast<uint32_t>(morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::SPECULATIVE_LOAD_BYPASS)))) or
//          (x.compare("speculative_load_bypass") == 0))
//       return morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::SPECULATIVE_LOAD_BYPASS;
    
    throw (ErrorMorpheo ("<fromString> : Unknow string : \""+x+"\""));
  };


  template<> inline std::string toString<morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::Tstore_queue_state_t>(const morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::Tstore_queue_state_t& x)
  {
    switch (x)
      {
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::STORE_QUEUE_EMPTY                   : return "empty"                  ; break;
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::STORE_QUEUE_NO_VALID_NO_SPECULATIVE : return "no_valid_no_speculative"; break;
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::STORE_QUEUE_VALID_SPECULATIVE       : return "valid_speculative"      ; break;
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::STORE_QUEUE_VALID_NO_SPECULATIVE    : return "valid_no_speculative"   ; break;
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::STORE_QUEUE_COMMIT                  : return "commit"                 ; break;
      default    : return ""      ; break;
      }
  };

  template<> inline std::string toString<morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::Tspeculative_access_queue_state_t>(const morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::Tspeculative_access_queue_state_t& x)
  {
    switch (x)
      {
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::SPECULATIVE_ACCESS_QUEUE_EMPTY           : return "empty"          ; break;
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::SPECULATIVE_ACCESS_QUEUE_WAIT_CACHE      : return "wait_cache"     ; break;
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::SPECULATIVE_ACCESS_QUEUE_WAIT_LOAD_QUEUE : return "wait_load_queue"; break;
      default    : return ""      ; break;
      }
  };

  template<> inline std::string toString<morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::Tload_queue_state_t>(const morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::Tload_queue_state_t& x)
  {
    switch (x)
      {
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::LOAD_QUEUE_EMPTY        : return "empty"       ; break;
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::LOAD_QUEUE_WAIT_CHECK   : return "wait_check"  ; break;
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::LOAD_QUEUE_WAIT         : return "wait"        ; break;
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::LOAD_QUEUE_COMMIT_CHECK : return "commit_check"; break;
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::LOAD_QUEUE_CHECK        : return "check"       ; break;
      case morpheo::behavioural::core::multi_execute_loop::execute_loop::multi_execute_unit::execute_unit::load_store_unit::LOAD_QUEUE_COMMIT       : return "commit"      ; break;
      default    : return ""      ; break;
      }
  };

}; // end namespace morpheo              

#endif
