#ifdef SYSTEMC
/*
 * $Id: Reexecute_unit_transition.cpp 101 2009-01-15 17:19:08Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_OOO_Engine/OOO_Engine/Reexecute_unit/include/Reexecute_unit.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_ooo_engine {
namespace ooo_engine {
namespace reexecute_unit {


#undef  FUNCTION
#define FUNCTION "Reexecute_unit::transition"
  void Reexecute_unit::transition (void)
  {
    log_begin(Reexecute_unit,FUNCTION);
    log_function(Reexecute_unit,FUNCTION,_name.c_str());

    if (PORT_READ(in_NRESET) == 0)
      {
	_priority_execute_loop->reset();
	_priority_queue_in    ->reset();

	for (uint32_t i=0; i<_param->_nb_bank; i++)
	  _reexecute_queue [i].clear();
      }
    else
      {
	_priority_execute_loop->transition();
	_priority_queue_in    ->transition();

	// ===================================================================
	// =====[ EXECUTE_LOOP / COMMIT ]=====================================
	// ===================================================================
	for (uint32_t i=0; i<_param->_nb_bank; ++i)
	  if (internal_QUEUE_PUSH [i])
	    {
	      entry_t * entry = new entry_t;
	      _reexecute_queue [i].push_back(entry);

	      uint32_t x = internal_QUEUE_NUM_EXECUTE_LOOP [i];
	      uint32_t y = internal_QUEUE_NUM_INST_EXECUTE [i];
	      uint32_t z = internal_QUEUE_NUM_INST_COMMIT  [i];
	      
	      entry->state        = STATE_SPR_ACCESS;
	      entry->context_id   = (_param->_have_port_context_id  )?PORT_READ(in_EXECUTE_LOOP_CONTEXT_ID   [x][y]):0;
	      entry->front_end_id = (_param->_have_port_front_end_id)?PORT_READ(in_EXECUTE_LOOP_FRONT_END_ID [x][y]):0;
	      entry->packet_id    = (_param->_have_port_rob_ptr     )?PORT_READ(in_EXECUTE_LOOP_PACKET_ID    [x][y]):0;
	      entry->address      = PORT_READ(in_EXECUTE_LOOP_ADDRESS [x][y]);
	      entry->data         = PORT_READ(in_EXECUTE_LOOP_DATA    [x][y]);
	      entry->num_reg_rd   = PORT_READ(in_COMMIT_NUM_REG_RD    [z]);
	      entry->spr_wen      = internal_QUEUE_INFO [i].spr_wen  ;
	      entry->reexecute    = internal_QUEUE_INFO [i].reexecute;
	      entry->type         = internal_QUEUE_INFO [i].type     ;
	      entry->operation    = internal_QUEUE_INFO [i].operation;
	      entry->write_rd     = internal_QUEUE_INFO [i].write_rd ;
	    }

#ifdef STATISTICS
        if (usage_is_set(_usage,USE_STATISTICS))
          for (uint32_t i=0; i<_param->_nb_inst_commit; i++)
            if (internal_COMMIT_VAL [i] and PORT_READ(in_COMMIT_ACK[i]))
              (*_stat_nb_inst_commit) ++;
#endif

	// ===================================================================
	// =====[ SPR ]=======================================================
	// ===================================================================
	for (uint32_t i=0; i<_param->_nb_inst_reexecute; i++)
	  if (internal_SPR_VAL [i] and PORT_READ(in_SPR_ACK [i]))
	    {
#ifdef STATISTICS
              if (usage_is_set(_usage,USE_STATISTICS))
                (*_stat_nb_spr_access) ++;
#endif
	      entry_t * entry = _reexecute_queue [i].front();

	      if (not entry->spr_wen)
		{
		  entry->data     =     PORT_READ(in_SPR_RDATA   [i]);
// 		  entry->write_rd = not PORT_READ(in_SPR_INVALID [i]); // in all case write value
		}

	      if (entry->reexecute)
		entry->state = STATE_REEXECUTE;
	      else
		entry->state = STATE_EMPTY;
	    }

	// ===================================================================
	// =====[ REEXECUTE ]=================================================
	// ===================================================================
	for (uint32_t i=0; i<_param->_nb_inst_reexecute; i++)
	  if (internal_REEXECUTE_VAL [i] and PORT_READ(in_REEXECUTE_ACK [i]))
	    // test source
	    if (not internal_REEXECUTE_ROB_ACK [i])
	      {
#ifdef STATISTICS
                if (usage_is_set(_usage,USE_STATISTICS))
                  (*_stat_nb_inst_reexecute) ++;
#endif

		// invalid entry
		_reexecute_queue [i].front()->state = STATE_EMPTY;		
	      }
#ifdef DEBUG_TEST
	    else
	      {
		if (not PORT_READ(in_REEXECUTE_ROB_VAL [i]))
		  throw ERRORMORPHEO(FUNCTION,toString(_("in_REEXECUTE_ROB_VAL [%d] must be = 1.\n"),i));
	      }
#endif
	
	// ===================================================================
	// =====[ End cycle ]=================================================
	// ===================================================================
	for (uint32_t i=0; i<_param->_nb_bank; i++)
	  if (not _reexecute_queue [i].empty() and (_reexecute_queue [i].front()->state == STATE_EMPTY))
	    {
	      entry_t * entry = _reexecute_queue [i].front();
	      _reexecute_queue [i].pop_front();
	      delete entry;

#ifdef STATISTICS
              if (usage_is_set(_usage,USE_STATISTICS))
                (*(_stat_bank_nb_inst [i])) += _reexecute_queue [i].size();
#endif
	    }
      }

#if ((DEBUG >= DEBUG_TRACE) and DEBUG_Reexecute_unit)
    log_printf(TRACE,Reexecute_unit,FUNCTION,"  * Dump Reexecute_queue");

    for (uint32_t i=0; i<_param->_nb_bank; ++i)
      {
        uint32_t j=0;
        for (std::list<entry_t *>::iterator it=_reexecute_queue[i].begin();
             it!=_reexecute_queue[i].end();
             ++it)
          {
            log_printf(TRACE,Reexecute_unit,FUNCTION,"  [%.4d][%.4d] %.4d %.4d %.4d, %.1d %.1d, %.4d %.4d, %.8x (%.2d %.4d) %.8x, %.1d %.5d, %s",
                       i,
                       j,
                       (*it)->context_id    ,
                       (*it)->front_end_id  ,
                       (*it)->packet_id     ,
                       (*it)->spr_wen       ,
                       (*it)->reexecute     ,
                       (*it)->type          ,
                       (*it)->operation     ,
                       (*it)->address       ,
                      ((*it)->address >> _param->_shift_spr_num_group) & _param->_mask_spr_num_group,
                      ((*it)->address                                ) & _param->_mask_spr_num_reg  ,
                       (*it)->data          ,
                       (*it)->write_rd      ,
                       (*it)->num_reg_rd    ,
                       toString((*it)->state).c_str());

            ++j;
          }
      }
//     // ~~~~~[ Register ]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    
//   private   : std::list<entry_t *>          * _reexecute_queue                         ;//[nb_bank]
  typedef struct 
  {
  } entry_t;

#endif

#if defined(STATISTICS) or defined(VHDL_TESTBENCH)
    end_cycle ();
#endif

    log_end(Reexecute_unit,FUNCTION);
  };

}; // end namespace reexecute_unit
}; // end namespace ooo_engine
}; // end namespace multi_ooo_engine
}; // end namespace core

}; // end namespace behavioural
}; // end namespace morpheo              
#endif
