#ifdef SYSTEMC
//#if defined(STATISTICS) or defined(VHDL_TESTBENCH)
/*
 * $Id$
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_Execute_loop/Execute_loop/Multi_Execute_unit/Execute_unit/Load_store_unit/include/Load_store_unit.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 {


#undef  FUNCTION
#define FUNCTION "Load_store_unit::function_speculative_load_commit_transition"
  void Load_store_unit::function_speculative_load_commit_transition (void)
  {
    log_printf(FUNC,Load_store_unit,FUNCTION,"Begin");

    if (PORT_READ(in_NRESET) == 0)
      {
	// Reset : clear all queue
	_speculative_access_queue_control->clear();
	internal_MEMORY_STORE_QUEUE_PTR_READ = 0;
	internal_MEMORY_LOAD_QUEUE_PTR_READ  = 0;

	for (uint32_t i=0; i< _param->_size_store_queue             ; i++)
	  _store_queue              [i]._state = STORE_QUEUE_EMPTY;

	for (uint32_t i=0; i< _param->_size_load_queue              ; i++)
	  _load_queue               [i]._state = LOAD_QUEUE_EMPTY;

	for (uint32_t i=0; i< _param->_size_speculative_access_queue; i++)
	  _speculative_access_queue [i]._state = SPECULATIVE_ACCESS_QUEUE_EMPTY;
      }
    else
      {
	//================================================================
	// Interface "MEMORY_IN"
	//================================================================

        if ((PORT_READ(in_MEMORY_IN_VAL) == 1) and
            (    internal_MEMORY_IN_ACK  == 1))
          {
	    // Test operation :
	    //~~~~~~~~~~~~~~~~~
	    //  store  in store_queue
	    //  load   in speculation_access_queue
	    //  others in speculation_access_queue

	    Toperation_t    operation            = PORT_READ(in_MEMORY_IN_OPERATION);
	    Tgeneral_data_t address              = (PORT_READ(in_MEMORY_IN_IMMEDIAT) +
						    PORT_READ(in_MEMORY_IN_DATA_RA ));
	    bool            exception_alignement = (mask_memory_access(operation) & address) != 0;
						    
	    if (is_operation_memory_store(operation) == true)
	      {
		// =======================
		// ===== STORE_QUEUE =====
		// =======================
		// There a two store request type :
		//   - first is operation with address and data
		//   - second is the information of re order buffer : the store become not speculative and can access at the data cache

		log_printf(TRACE,Load_store_unit,FUNCTION,"store_queue");
		log_printf(TRACE,Load_store_unit,FUNCTION," * PUSH");
		
		// Write pointer is define in rename stage :
		Tlsq_ptr_t           index         = PORT_READ(in_MEMORY_IN_STORE_QUEUE_PTR_WRITE);
		log_printf(TRACE,Load_store_unit,FUNCTION,"   * index         : %d",index);
		
		// Need read : state and exception.
		Tstore_queue_state_t old_state     = _store_queue [index]._state;
		Tstore_queue_state_t new_state     = old_state;
		bool                 update_info   = false;

		Texception_t         old_exception = _store_queue [index]._exception;
		Texception_t         new_exception = old_exception;

		// Compute next state
		switch (old_state)
		  {
		  case STORE_QUEUE_EMPTY                   :
		    {
		      if (is_operation_memory_store_head(operation) == true)
			{
			  new_state = STORE_QUEUE_NO_VALID_NO_SPECULATIVE;

			  // test if is a speculation
			  if (operation == OPERATION_MEMORY_STORE_HEAD_KO)
			    new_exception = EXCEPTION_MEMORY_MISS_SPECULATION;
			  else
			    new_exception = EXCEPTION_MEMORY_NONE;
			}
		      else
			{
			  new_state = STORE_QUEUE_VALID_SPECULATIVE;

			  // Test if have an exception
			  if (exception_alignement == true)
			    new_exception = EXCEPTION_MEMORY_ALIGNMENT;
			  else
			    new_exception = EXCEPTION_MEMORY_NONE;

			  update_info = true;
			}
		      break;
		    }
		  case STORE_QUEUE_NO_VALID_NO_SPECULATIVE :
		    {
// 		      if (is_operation_memory_store_head(operation) == false)
// 			{
			  new_state = STORE_QUEUE_VALID_NO_SPECULATIVE;

			  // Test if have a new exception (priority : miss_speculation)
			  if ((old_exception == EXCEPTION_MEMORY_NONE) and
			      (exception_alignement == true))
			    new_exception = EXCEPTION_MEMORY_ALIGNMENT;

			  update_info = true;
			  break;
// 			}
		    }
		  case STORE_QUEUE_VALID_SPECULATIVE       :
		    {
// 		      if (is_operation_memory_store_head(operation) == true)
// 			{
			  new_state = STORE_QUEUE_VALID_NO_SPECULATIVE;

			  if (operation == OPERATION_MEMORY_STORE_HEAD_KO)
			    new_exception = EXCEPTION_MEMORY_MISS_SPECULATION;

			  break;
// 			}
		    }
		  case STORE_QUEUE_VALID_NO_SPECULATIVE    :
		  case STORE_QUEUE_COMMIT                  :
		    {
		      ErrorMorpheo("<Load_store_unit::function_speculative_load_commit_transition> Invalid state and operation");
		    }
		  }

		_store_queue [index]._state     = new_state;
		_store_queue [index]._exception = new_exception;
		
		if (update_info == true)
		  {
		    log_printf(TRACE,Load_store_unit,FUNCTION,"   * Update information");

		    _store_queue [index]._context_id           = PORT_READ(in_MEMORY_IN_CONTEXT_ID  );
		    _store_queue [index]._packet_id            = PORT_READ(in_MEMORY_IN_PACKET_ID   );
		    _store_queue [index]._dcache_type          = operation_to_dcache_type(operation);
		    _store_queue [index]._uncached             = 0; // is the MMU that have this info
		    _store_queue [index]._load_queue_ptr_write = PORT_READ(in_MEMORY_IN_LOAD_QUEUE_PTR_WRITE);
		    _store_queue [index]._address              = address;
		    _store_queue [index]._wdata                = PORT_READ(in_MEMORY_IN_DATA_RB     );
//                  _store_queue [index]._write_rd             = PORT_READ(in_MEMORY_IN_WRITE_RD    );
//                  _store_queue [index]._num_reg_rd           = PORT_READ(in_MEMORY_IN_NUM_REG_RD  );
		  }
	      }
	    else
	      {
// 		// ====================================
// 		// ===== SPECULATIVE_ACCESS_QUEUE =====
// 		// ====================================

// 		// In speculative access queue, they are many type's request
// 		log_printf(TRACE,Load_store_unit,FUNCTION,"speculative_access_queue");
// 		log_printf(TRACE,Load_store_unit,FUNCTION," * PUSH");
		
// 		// Write in reservation station
// 		uint32_t index = _speculative_access_queue_control->push();
		
// 		log_printf(TRACE,Load_store_unit,FUNCTION,"   * index         : %d",index);
	      }
	  }

	//================================================================
	// Interface "MEMORY_OUT"
	//================================================================

        if ((    internal_MEMORY_OUT_VAL  == 1) and
            (PORT_READ(in_MEMORY_OUT_ACK) == 1))
          {
	    switch (internal_MEMORY_OUT_SELECT_QUEUE)
	      {
	      case SELECT_STORE_QUEUE :
		{
		  // =======================
		  // ===== STORE_QUEUE =====
		  // =======================
		  
		  // Entry flush and increase the read pointer
		  
		  _store_queue [internal_MEMORY_STORE_QUEUE_PTR_READ]._state = STORE_QUEUE_EMPTY;
		  
		  internal_MEMORY_STORE_QUEUE_PTR_READ = (internal_MEMORY_STORE_QUEUE_PTR_READ+1)%_param->_size_store_queue;

		  break;
		}
	      case SELECT_LOAD_QUEUE :
	      case SELECT_LOAD_QUEUE_SPECULATIVE :
		break;
	      }
	  }

	//================================================================
	// Interface "DCACHE_REQ"
	//================================================================
        if ((    internal_DCACHE_REQ_VAL  == 1) and
            (PORT_READ(in_DCACHE_REQ_ACK) == 1))
          {
	    switch (internal_DCACHE_REQ_SELECT_QUEUE)
	      {
	      case SELECT_STORE_QUEUE :
		{
		  // =======================
		  // ===== STORE_QUEUE =====
		  // =======================
		  
		  // Entry flush and increase the read pointer
		  
		  _store_queue [internal_MEMORY_STORE_QUEUE_PTR_READ]._state = STORE_QUEUE_COMMIT;

		  break;
		}
	      case SELECT_LOAD_QUEUE :
	      case SELECT_LOAD_QUEUE_SPECULATIVE :
		break;
	      }
	  }

#if DEBUG>=DEBUG_TRACE
	// ***** dump store queue
	cout << "Dump store queue" << endl
	     << "ptr_read : " << toString(static_cast<uint32_t>(internal_MEMORY_STORE_QUEUE_PTR_READ)) << endl;
	
	for (uint32_t i=0; i<_param->_size_store_queue; i++)
	  {
	    uint32_t j = (internal_MEMORY_STORE_QUEUE_PTR_READ+i)%_param->_size_store_queue;
	    cout << "{" << j << "}" << endl
		 << _store_queue[j] << endl;
	  }
#endif
      }

    log_printf(FUNC,Load_store_unit,FUNCTION,"End");
  };

}; // 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
}; // end namespace morpheo              
#endif
//#endif
