#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$
 *
 * [ Description ]
 * 
 */

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

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

  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    : Tpacket_t            _packet_id           ;
  public    : Tdcache_type_t       _dcache_type         ;
  public    : Tcontrol_t           _uncached            ;
  public    : Tlsq_ptr_t           _load_queue_ptr_write;
  public    : Tdcache_data_t       _address             ;
  public    : Tgeneral_data_t      _wdata               ;
//public    : Tcontrol_t           _write_rd            ;
//public    : Tgeneral_address_t   _num_reg_rd          ;
  public    : Texception_t         _exception           ;

    friend ostream & operator << (ostream& os, const Tstore_queue_entry_t & x) 
    {
      return os << " * state                   : " << x._state << endl
		<< "   * packet   - context_id : " << toString(static_cast<uint32_t>(x._packet_id           )) << " - " << toString(static_cast<uint32_t>(x._context_id)) << endl
		<< "   * type     - uncached   : " << toString(static_cast<uint32_t>(x._dcache_type         )) << " - " << toString(static_cast<uint32_t>(x._uncached  )) << endl
		<< "   * load_ptr - execption  : " << toString(static_cast<uint32_t>(x._load_queue_ptr_write)) << " - " << toString(static_cast<uint32_t>(x._exception )) << endl
		<< "   * address  - wdata      : " << toString(static_cast<uint32_t>(x._address             )) << " - " << toString(static_cast<uint32_t>(x._wdata     )) << endl;
    }
  };
  
  

  // ----------------------------------------------------------
  // 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    : Tpacket_t                          _packet_id            ;
  public    : Taccess_t                          _access               ;
  public    : Tcontrol_t                         _uncached             ;
  public    : Tcontrol_t                         _sign_extension       ;
  public    : Tlsq_ptr_t                         _load_queue_ptr_write ;
  public    : Tlsq_ptr_t                         _store_queue_ptr_write;
  public    : Tdcache_address_t                  _address              ;
  public    : Tgeneral_data_t                    _rdata                ;
  public    : Tcontrol_t                         _write_rd             ;
  public    : Tgeneral_address_t                 _num_reg_rd           ;
  public    : Texception_t                       _exception            ;
  };

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

  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    : Tpacket_t            _packet_id           ;
  public    : Taccess_t            _access              ;
  public    : Tcontrol_t           _uncached            ;
  public    : Tcontrol_t           _sign_extension      ;
  public    : Tlsq_ptr_t           _store_queue_ptr_write;
  public    : Tdcache_address_t    _address             ;
  public    : Tgeneral_data_t      _rdata               ;
  public    : Tcontrol_t           _write_rd            ;
  public    : Tgeneral_address_t   _num_reg_rd          ;
  public    : Texception_t         _exception           ;
  };

}; // 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("0")                       == 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("1")                       == 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("2")                       == 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("3")                       == 0) 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+"\""));
  };

}; // end namespace morpheo              

#endif
