#ifdef SYSTEMC
//#if defined(STATISTICS) or defined(VHDL_TESTBENCH)
/*
 * $Id: Load_store_unit_function_speculative_load_commit_genMoore.cpp 123 2009-06-08 20:43:30Z rosiere $
 *
 * [ 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_genMoore"
  void Load_store_unit::function_speculative_load_commit_genMoore (void)
  {
    log_begin(Load_store_unit,FUNCTION);
    log_function(Load_store_unit,FUNCTION,_name.c_str());

    if (PORT_READ(in_NRESET))
      {
    // ~~~~~[ Interface "memory_out" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Tcontext_t         memory_out_context_id    = 0;
    Tcontext_t         memory_out_front_end_id  = 0;
    Tcontext_t         memory_out_ooo_engine_id = 0;
    Tpacket_t          memory_out_packet_id     = 0;
    Tcontrol_t         memory_out_write_rd      = 0;
    Tgeneral_address_t memory_out_num_reg_rd    = 0;
    Tgeneral_data_t    memory_out_data_rd       = 0;
//  Tcontrol_t         memory_out_write_re      = 0;
//  Tspecial_address_t memory_out_num_reg_re    = 0;
//  Tspecial_data_t    memory_out_data_re       = 0;
    Tcontrol_t         memory_out_no_sequence   = 0;
    Texception_t       memory_out_exception     = 0;

    internal_MEMORY_OUT_VAL = 0;

    // Test store and load queue

    log_printf(TRACE,Load_store_unit,FUNCTION,"  * Test MEMORY_OUT");

    log_printf(TRACE,Load_store_unit,FUNCTION,"    * Load  queue");
    for (internal_MEMORY_OUT_PTR=0; internal_MEMORY_OUT_PTR<_param->_size_load_queue; internal_MEMORY_OUT_PTR++)
//     for (uin32_t i=0; (i<_param->_size_load_queue) and not (find_load); i++)
      {
// 	internal_MEMORY_OUT_PTR = (reg_LOAD_QUEUE_PTR_READ+1)%_param->_size_load_queue;
	internal_MEMORY_OUT_VAL = ((_load_queue[internal_MEMORY_OUT_PTR]._state == LOAD_QUEUE_COMMIT_CHECK) or
				   (_load_queue[internal_MEMORY_OUT_PTR]._state == LOAD_QUEUE_COMMIT));
	
	if (internal_MEMORY_OUT_VAL)
	  {
	    log_printf(TRACE,Load_store_unit,FUNCTION,"    * find : %d",internal_MEMORY_OUT_PTR);
	    internal_MEMORY_OUT_SELECT_QUEUE = (_load_queue[internal_MEMORY_OUT_PTR]._state == LOAD_QUEUE_COMMIT_CHECK)?SELECT_LOAD_QUEUE_SPECULATIVE:SELECT_LOAD_QUEUE;
	    
	    memory_out_context_id    = _load_queue [internal_MEMORY_OUT_PTR]._context_id;
	    memory_out_front_end_id  = _load_queue [internal_MEMORY_OUT_PTR]._front_end_id;
	    memory_out_ooo_engine_id = _load_queue [internal_MEMORY_OUT_PTR]._ooo_engine_id;
	    memory_out_packet_id     = _load_queue [internal_MEMORY_OUT_PTR]._packet_id ;
	    memory_out_write_rd      = _load_queue [internal_MEMORY_OUT_PTR]._write_rd  ;
	    memory_out_num_reg_rd    = _load_queue [internal_MEMORY_OUT_PTR]._num_reg_rd;

	    Tdcache_data_t data_old = _load_queue [internal_MEMORY_OUT_PTR]._rdata;
	    Tdcache_data_t data_new = extend<Tdcache_data_t>(_param->_size_general_data,
							     data_old >> _load_queue [internal_MEMORY_OUT_PTR]._shift,
							     _load_queue [internal_MEMORY_OUT_PTR]._is_load_signed,
							     _load_queue [internal_MEMORY_OUT_PTR]._access_size);
	    log_printf(TRACE,Load_store_unit,FUNCTION,"    * data (old) : %.8x",data_old);
	    log_printf(TRACE,Load_store_unit,FUNCTION,"    * data (new) : %.8x",data_new);
	    log_printf(TRACE,Load_store_unit,FUNCTION,"      * address      : %.8x",_load_queue [internal_MEMORY_OUT_PTR]._address);
	    log_printf(TRACE,Load_store_unit,FUNCTION,"      * rdata        : %.8x",_load_queue [internal_MEMORY_OUT_PTR]._rdata);
	    log_printf(TRACE,Load_store_unit,FUNCTION,"      * shift        : %d",_load_queue [internal_MEMORY_OUT_PTR]._shift);
	    log_printf(TRACE,Load_store_unit,FUNCTION,"      * signed?      : %d",_load_queue [internal_MEMORY_OUT_PTR]._is_load_signed);
	    log_printf(TRACE,Load_store_unit,FUNCTION,"      * access_size  : %d",_load_queue [internal_MEMORY_OUT_PTR]._access_size);

	    Texception_t exception      = _load_queue [internal_MEMORY_OUT_PTR]._exception;
	    bool         have_exception = ((exception != EXCEPTION_MEMORY_NONE) and
					   (exception != EXCEPTION_MEMORY_MISS_SPECULATION));

	    // if exception, rdata content the address of load, else content read data.
	    memory_out_data_rd       = (have_exception)?data_old:data_new;
	    memory_out_exception     = (_load_queue[internal_MEMORY_OUT_PTR]._state == LOAD_QUEUE_COMMIT_CHECK)?EXCEPTION_MEMORY_LOAD_SPECULATIVE:exception;

	    log_printf(TRACE,Load_store_unit,FUNCTION,"      * exception    : %d",exception);
	    log_printf(TRACE,Load_store_unit,FUNCTION,"      * exception    : %d",memory_out_exception);

	    break; // we have find a entry !!! stop the search
	  }
      }

    if (not internal_MEMORY_OUT_VAL)
      {
	log_printf(TRACE,Load_store_unit,FUNCTION,"    * Store queue");

	for (uint32_t i=0; i<_param->_size_store_queue; ++i)
	  {
	    internal_MEMORY_OUT_PTR = (reg_STORE_QUEUE_PTR_READ+i)%_param->_size_store_queue;
	    // Can retire an store instruction if :
	    //  * state is commit
	    //  * none load must check this store


	    bool val_head = ((i==0) and
			     (_store_queue [internal_MEMORY_OUT_PTR]._state       == STORE_QUEUE_COMMIT) and
			     (_store_queue [internal_MEMORY_OUT_PTR]._send_commit == true) and
			     (reg_STORE_QUEUE_NB_CHECK [internal_MEMORY_OUT_PTR] == 0)
			     );

	    bool val_commit = ((_store_queue [internal_MEMORY_OUT_PTR]._state       != STORE_QUEUE_EMPTY) and
			       (_store_queue [internal_MEMORY_OUT_PTR]._send_commit == false));

	    if (val_head or val_commit)
	      {
		log_printf(TRACE,Load_store_unit,FUNCTION,"    * find : %d",internal_MEMORY_OUT_PTR);
		
		internal_MEMORY_OUT_VAL          = 1;
		internal_MEMORY_OUT_SELECT_QUEUE = SELECT_STORE_QUEUE;
		
		memory_out_context_id    = _store_queue [internal_MEMORY_OUT_PTR]._context_id;
		memory_out_front_end_id  = _store_queue [internal_MEMORY_OUT_PTR]._front_end_id;
		memory_out_ooo_engine_id = _store_queue [internal_MEMORY_OUT_PTR]._ooo_engine_id;
		memory_out_packet_id     = _store_queue [internal_MEMORY_OUT_PTR]._packet_id ;
//              memory_out_write_rd  	 
//              memory_out_num_reg_rd	 
		memory_out_data_rd       = _store_queue [internal_MEMORY_OUT_PTR]._address; // to the exception
		memory_out_exception     = _store_queue [internal_MEMORY_OUT_PTR]._exception;
		memory_out_no_sequence   = val_commit;
		break; // find an entry
	      }

	  }
      }

    // write output
    if (_param->_have_port_context_id)
    PORT_WRITE(out_MEMORY_OUT_CONTEXT_ID   [0], memory_out_context_id   );
    if (_param->_have_port_front_end_id)
    PORT_WRITE(out_MEMORY_OUT_FRONT_END_ID [0], memory_out_front_end_id );
    if (_param->_have_port_ooo_engine_id)
    PORT_WRITE(out_MEMORY_OUT_OOO_ENGINE_ID[0], memory_out_ooo_engine_id);
    if (_param->_have_port_rob_ptr)
    PORT_WRITE(out_MEMORY_OUT_PACKET_ID    [0], memory_out_packet_id    );
//  PORT_WRITE(out_MEMORY_OUT_OPERATION    [0], memory_out_operation    );
//  PORT_WRITE(out_MEMORY_OUT_TYPE         [0], TYPE_MEMORY             );
    PORT_WRITE(out_MEMORY_OUT_WRITE_RD     [0], memory_out_write_rd     );
    PORT_WRITE(out_MEMORY_OUT_NUM_REG_RD   [0], memory_out_num_reg_rd   );
    PORT_WRITE(out_MEMORY_OUT_DATA_RD      [0], memory_out_data_rd      );
//  PORT_WRITE(out_MEMORY_OUT_WRITE_RE     [0], memory_out_write_re     );
//  PORT_WRITE(out_MEMORY_OUT_NUM_REG_RE   [0], memory_out_num_reg_re   );
//  PORT_WRITE(out_MEMORY_OUT_DATA_RE      [0], memory_out_data_re      );
    PORT_WRITE(out_MEMORY_OUT_WRITE_RE     [0], 0);
    PORT_WRITE(out_MEMORY_OUT_NUM_REG_RE   [0], 0);
    PORT_WRITE(out_MEMORY_OUT_DATA_RE      [0], 0);
    PORT_WRITE(out_MEMORY_OUT_EXCEPTION    [0], memory_out_exception    );
    PORT_WRITE(out_MEMORY_OUT_NO_SEQUENCE  [0], memory_out_no_sequence  );// hack
#ifdef DEBUG
    PORT_WRITE(out_MEMORY_OUT_ADDRESS      [0], memory_out_data_rd);
#else
    PORT_WRITE(out_MEMORY_OUT_ADDRESS      [0], 0);
#endif

    // ~~~~~[ Interface "dache_req" ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    Tcontext_t        dcache_req_context_id = 0;
    Tpacket_t         dcache_req_packet_id  = 0;
    Tdcache_address_t dcache_req_address    = 0;
    Tdcache_type_t    dcache_req_type       = 0;
    Tdcache_data_t    dcache_req_wdata      = 0;

    log_printf(TRACE,Load_store_unit,FUNCTION,"  * Test DCACHE_REQ");

    internal_DCACHE_REQ_VAL = 0;

    internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ = (*_speculative_access_queue_control)[0];

    // Test store and load queue
    if (_speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._state == SPECULATIVE_ACCESS_QUEUE_WAIT_CACHE)
      {
	log_printf(TRACE,Load_store_unit,FUNCTION,"    * speculative_access_queue [%d]",internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ);

	internal_DCACHE_REQ_VAL          = 1;
	internal_DCACHE_REQ_SELECT_QUEUE = SELECT_LOAD_QUEUE_SPECULATIVE;

	if (_param->_have_port_dcache_context_id)
	  {
	    Tcontext_t context_id    = _speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._context_id;
	    Tcontext_t front_end_id  = _speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._front_end_id;
	    Tcontext_t ooo_engine_id = _speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._ooo_engine_id;
	    
	    dcache_req_context_id = ((ooo_engine_id<<(_param->_size_context_id + _param->_size_front_end_id )) |
				     (front_end_id <<(_param->_size_context_id)) |
				     (context_id));
	  }

	dcache_req_packet_id  = DCACHE_REQ_IS_LOAD(_speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._load_queue_ptr_write);
	dcache_req_address    = _speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._address;// & _param->_mask_address_msb;
	dcache_req_type       = operation_to_dcache_type(_speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._operation);

// 	log_printf(TRACE,Load_store_unit,FUNCTION,"      * address            : %.8x",_speculative_access_queue [internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ]._address);
//      log_printf(TRACE,Load_store_unit,FUNCTION,"      * mask               : %.8x",_param->_mask_address_msb);
        log_printf(TRACE,Load_store_unit,FUNCTION,"      * dcache_req_address : %.8x",dcache_req_address);

#ifdef SYSTEMC_VHDL_COMPATIBILITY
	dcache_req_wdata      = 0;
#endif
      }
    else
      {
	// Test an store must be commited.
	if (_store_queue [reg_STORE_QUEUE_PTR_READ]._state == STORE_QUEUE_VALID_NO_SPECULATIVE)
	  {
	    internal_DCACHE_REQ_VAL          = 1;
	    internal_DCACHE_REQ_SELECT_QUEUE = SELECT_STORE_QUEUE;
	    
	    if (_param->_have_port_dcache_context_id)
	      {
		Tcontext_t context_id    = _store_queue [reg_STORE_QUEUE_PTR_READ]._context_id;
		Tcontext_t front_end_id  = _store_queue [reg_STORE_QUEUE_PTR_READ]._front_end_id;
		Tcontext_t ooo_engine_id = _store_queue [reg_STORE_QUEUE_PTR_READ]._ooo_engine_id;
		
		dcache_req_context_id = ((ooo_engine_id<<(_param->_size_context_id + _param->_size_front_end_id )) |
					 (front_end_id <<(_param->_size_context_id)) |
					 (context_id));
	      }

	    // FIXME : il peut avoir plusieurs store avec le même paquet_id ... pour l'instant pas très grave car pas de retour (enfin seul les bus error sont des retours)
	    dcache_req_packet_id  = DCACHE_REQ_IS_STORE(reg_STORE_QUEUE_PTR_READ);
	    dcache_req_address    = _store_queue [reg_STORE_QUEUE_PTR_READ]._address;
	    dcache_req_type       = operation_to_dcache_type(_store_queue [reg_STORE_QUEUE_PTR_READ]._operation);
	    dcache_req_wdata      = _store_queue [reg_STORE_QUEUE_PTR_READ]._wdata;
	  }
      }

    if (_param->_have_port_dcache_context_id)
    PORT_WRITE(out_DCACHE_REQ_CONTEXT_ID[0], dcache_req_context_id);
    PORT_WRITE(out_DCACHE_REQ_PACKET_ID [0], dcache_req_packet_id );
    PORT_WRITE(out_DCACHE_REQ_ADDRESS   [0], dcache_req_address   );
    PORT_WRITE(out_DCACHE_REQ_TYPE      [0], dcache_req_type      );
    PORT_WRITE(out_DCACHE_REQ_WDATA     [0], dcache_req_wdata     );
      }
    else
      {
        // Reset
    internal_MEMORY_OUT_VAL = 0;
//  internal_MEMORY_OUT_PTR =0
//  internal_MEMORY_OUT_SELECT_QUEUE = SELECT_STORE_QUEUE;

    internal_DCACHE_REQ_VAL = 0;
    internal_SPECULATIVE_ACCESS_QUEUE_PTR_READ = 0;
//  internal_DCACHE_REQ_SELECT_QUEUE = SELECT_LOAD_QUEUE_SPECULATIVE;
      }

    // Write output
    PORT_WRITE(out_MEMORY_OUT_VAL [0], internal_MEMORY_OUT_VAL);
    PORT_WRITE(out_DCACHE_REQ_VAL [0], internal_DCACHE_REQ_VAL);


    log_end(Load_store_unit,FUNCTION);
  };

}; // 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
