#ifdef SYSTEMC
/*
 * $Id: Commit_unit_transition.cpp 117 2009-05-16 14:42:39Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_OOO_Engine/OOO_Engine/Commit_unit/include/Commit_unit.h"
#include "Behavioural/include/Simulation.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_ooo_engine {
namespace ooo_engine {
namespace commit_unit {

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

    if (PORT_READ(in_NRESET) == 0)
      {
        // Clear all bank 
	for (uint32_t i=0; i<_param->_nb_bank; ++i)
	  {
	    while(not _rob[i].empty())
	      {
		delete _rob[i].front();
		_rob[i].pop_front();
	      }
	    reg_BANK_PTR [i] = 0;
	  }

        // Reset pointer
	reg_NUM_BANK_HEAD = 0;
	reg_NUM_BANK_TAIL = 0;

        // Reset counter
	for (uint32_t i=0; i<_param->_nb_front_end; i++)
	  for (uint32_t j=0; j<_param->_nb_context [i]; j++)
	    {
              _nb_cycle_idle            [i][j] = 0;

	      reg_NB_INST_COMMIT_ALL    [i][j] = 0;
	      reg_NB_INST_COMMIT_MEM    [i][j] = 0;
                                        
              reg_EVENT_STATE           [i][j] = EVENT_STATE_NO_EVENT;
              reg_EVENT_FLUSH           [i][j] = false;
              reg_EVENT_STOP            [i][j] = false;

//            reg_PC_PREVIOUS           [i][j] = (0x100-4)>>2;
              reg_PC_CURRENT            [i][j] = (0x100  )>>2;
              reg_PC_CURRENT_IS_DS      [i][j] = 0;
              reg_PC_CURRENT_IS_DS_TAKE [i][j] = 0;
              reg_PC_NEXT               [i][j] = (0x100+4)>>2;
	    }

        // Reset priority algorithm
	_priority_insert->reset();
      }
    else
      {
        // Increase number idle cycle
	for (uint32_t i=0; i<_param->_nb_front_end; i++)
	  for (uint32_t j=0; j<_param->_nb_context [i]; j++)
            _nb_cycle_idle [i][j] ++;

	// Compute next priority
	_priority_insert->transition();

	// ===================================================================
	// =====[ GARBAGE COLLECTOR ]=========================================
	// ===================================================================
	for (uint32_t i=0; i<_param->_nb_front_end; i++)
	  for (uint32_t j=0; j<_param->_nb_context [i]; j++)
            switch (reg_EVENT_STATE [i][j])
              {
              case EVENT_STATE_EVENT    : 
                {
                  if (internal_RETIRE_EVENT_VAL [i][j] and in_RETIRE_EVENT_ACK [i][j])
                    reg_EVENT_STATE [i][j] = EVENT_STATE_WAITEND ; 
                  break;
                }
              case EVENT_STATE_WAITEND  : 
                {
                  Tcounter_t nb_inst_all = PORT_READ(in_NB_INST_DECOD_ALL [i][j]) + reg_NB_INST_COMMIT_ALL [i][j];
                  if (nb_inst_all == 0)
                    {
                      reg_EVENT_STATE [i][j] = EVENT_STATE_END;
                      reg_EVENT_FLUSH [i][j] = false;
                      //reg_EVENT_STOP  [i][j] = false;
                    }
                  break;
                }
              case EVENT_STATE_END      :
                {
                  reg_EVENT_STATE [i][j] = EVENT_STATE_NO_EVENT;
                  break;
                }
//            case EVENT_STATE_NO_EVENT : 
              default : break;
              }

	// ===================================================================
	// =====[ INSERT ]====================================================
	// ===================================================================
	for (uint32_t i=0; i<_param->_nb_bank; i++)
	  if (internal_BANK_INSERT_VAL [i])
	    {
              // get rename unit source and instruction.
	      uint32_t x = internal_BANK_INSERT_NUM_RENAME_UNIT [i];
	      uint32_t y = internal_BANK_INSERT_NUM_INST        [i];

	      if (PORT_READ(in_INSERT_VAL [x][y]))
		{
		  log_printf(TRACE,Commit_unit,FUNCTION,"  * INSERT            [%d][%d]",x,y);

                  // get information
		  Tcontext_t   front_end_id = (_param->_have_port_front_end_id)?PORT_READ(in_INSERT_FRONT_END_ID [x][y]):0;
		  Tcontext_t   context_id   = (_param->_have_port_context_id  )?PORT_READ(in_INSERT_CONTEXT_ID   [x][y]):0;
		  Ttype_t      type         = PORT_READ(in_INSERT_TYPE         [x][y]);
                  Toperation_t operation    = PORT_READ(in_INSERT_OPERATION    [x][y]);
                  bool         is_store     = is_operation_memory_store(operation);

		  Texception_t exception    = PORT_READ(in_INSERT_EXCEPTION    [x][y]);
		  Tcontrol_t   no_execute   = PORT_READ(in_INSERT_NO_EXECUTE   [x][y]);

		  log_printf(TRACE,Commit_unit,FUNCTION,"    * front_end_id   : %d",front_end_id);
		  log_printf(TRACE,Commit_unit,FUNCTION,"    * context_id     : %d",context_id);
		  log_printf(TRACE,Commit_unit,FUNCTION,"    * type           : %s",toString(type).c_str());
		  log_printf(TRACE,Commit_unit,FUNCTION,"    * operation      : %d",operation );
		  log_printf(TRACE,Commit_unit,FUNCTION,"    * exception      : %d",exception );
                  
                  // Create new entry.
		  entry_t * entry = new entry_t;

		  entry->ptr                     = reg_BANK_PTR [i];
		  entry->front_end_id            = front_end_id;
		  entry->context_id              = context_id  ;
		  entry->rename_unit_id          = x;
		  entry->depth                   = (_param->_have_port_depth)?PORT_READ(in_INSERT_DEPTH [x][y]):0;
		  entry->type                    = type;
		  entry->operation               = operation;
		  entry->is_delay_slot           = PORT_READ(in_INSERT_IS_DELAY_SLOT         [x][y]);
// 		  entry->address                 = PORT_READ(in_INSERT_ADDRESS               [x][y]);
		  entry->exception               = exception;
		  entry->exception_use           = PORT_READ(in_INSERT_EXCEPTION_USE         [x][y]);
		  entry->use_store_queue         = (type == TYPE_MEMORY) and (    is_store) and (not no_execute);
		  entry->use_load_queue          = (type == TYPE_MEMORY) and (not is_store) and (not no_execute);
		  entry->store_queue_ptr_write   = PORT_READ(in_INSERT_STORE_QUEUE_PTR_WRITE [x][y]);
		  entry->load_queue_ptr_write    = (_param->_have_port_load_queue_ptr)?PORT_READ(in_INSERT_LOAD_QUEUE_PTR_WRITE [x][y]):0;
		  entry->read_ra                 = PORT_READ(in_INSERT_READ_RA               [x][y]);
		  entry->num_reg_ra_log          = PORT_READ(in_INSERT_NUM_REG_RA_LOG        [x][y]);
		  entry->num_reg_ra_phy          = PORT_READ(in_INSERT_NUM_REG_RA_PHY        [x][y]);
		  entry->read_rb                 = PORT_READ(in_INSERT_READ_RB               [x][y]);
		  entry->num_reg_rb_log          = PORT_READ(in_INSERT_NUM_REG_RB_LOG        [x][y]);
		  entry->num_reg_rb_phy          = PORT_READ(in_INSERT_NUM_REG_RB_PHY        [x][y]);
		  entry->read_rc                 = PORT_READ(in_INSERT_READ_RC               [x][y]);
		  entry->num_reg_rc_log          = PORT_READ(in_INSERT_NUM_REG_RC_LOG        [x][y]);
		  entry->num_reg_rc_phy          = PORT_READ(in_INSERT_NUM_REG_RC_PHY        [x][y]);
		  entry->write_rd                = PORT_READ(in_INSERT_WRITE_RD              [x][y]);
		  entry->num_reg_rd_log          = PORT_READ(in_INSERT_NUM_REG_RD_LOG        [x][y]);
		  entry->num_reg_rd_phy_old      = PORT_READ(in_INSERT_NUM_REG_RD_PHY_OLD    [x][y]);
		  entry->num_reg_rd_phy_new      = PORT_READ(in_INSERT_NUM_REG_RD_PHY_NEW    [x][y]);
		  entry->write_re                = PORT_READ(in_INSERT_WRITE_RE              [x][y]);
		  entry->num_reg_re_log          = PORT_READ(in_INSERT_NUM_REG_RE_LOG        [x][y]);
		  entry->num_reg_re_phy_old      = PORT_READ(in_INSERT_NUM_REG_RE_PHY_OLD    [x][y]);
		  entry->num_reg_re_phy_new      = PORT_READ(in_INSERT_NUM_REG_RE_PHY_NEW    [x][y]);
                  entry->no_sequence             = type == TYPE_BRANCH;
                  entry->speculative             = true;
#ifdef DEBUG
		  entry->address                 = PORT_READ(in_INSERT_ADDRESS               [x][y]);
#endif
		  entry->address_next            = PORT_READ(in_INSERT_ADDRESS_NEXT          [x][y]);
#ifdef DEBUG
                  entry->cycle_rob_in            = simulation_cycle();
                  entry->cycle_commit            = simulation_cycle();
#endif

                  // Test if exception :
                  //  * yes : no execute instruction, wait ROB Head
                  //  * no  : test type
                  //            * BRANCH : l.j   -> branch is ended
                  //                       other -> wait the execution end of branchment
                  //            * MEMORY : store -> wait store is at head of ROB
                  //                       other -> wait end of instruction
                  //            * OTHER

//                   bool       flush      = reg_EVENT_FLUSH [front_end_id][context_id];

//                   log_printf(TRACE,Commit_unit,FUNCTION,"    * flush          : %d",flush);

//                   if (flush)
//                     {
//                       entry->state    = ROB_END_MISS; // All type (branch, memory and others), because, is not execute
//                     }
//                   else
                    {
                      if (exception == EXCEPTION_NONE)
                        {
                          // no_execute : l.j, l.nop, l.rfe
                          
                          log_printf(TRACE,Commit_unit,FUNCTION,"    * no_execute     : %d",no_execute);
                          
                          switch (type)
                            {
                            case TYPE_BRANCH : {entry->state=(no_execute==1)?ROB_BRANCH_COMPLETE:ROB_BRANCH_WAIT_END  ; break;}
                            case TYPE_MEMORY : {entry->state=(no_execute==1)?ROB_END_OK_SPECULATIVE:(entry->state=(is_store  ==1)?ROB_STORE_WAIT_HEAD_OK:ROB_OTHER_WAIT_END); break;}
                            default          : {entry->state=(no_execute==1)?ROB_END_OK_SPECULATIVE:ROB_OTHER_WAIT_END; break;}
                            }
                        }
                      else
                        {
                          // Have an exception : wait head of ROB
                          
                          // in_INSERT_NO_EXECUTE [x][y] : l.sys, l.trap
                          
                          entry->state = ROB_END_EXCEPTION_WAIT_HEAD;
                        }
                    }

#ifdef STATISTICS
                  if (usage_is_set(_usage,USE_STATISTICS))
                    (*_stat_nb_inst_insert [x]) ++;
#endif

                  // Push in rob
		  _rob[i].push_back(entry);

		  // Update counter and pointer
		  reg_NB_INST_COMMIT_ALL [front_end_id][context_id] ++;
		  if (type == TYPE_MEMORY)
		    reg_NB_INST_COMMIT_MEM [front_end_id][context_id] ++;

		  reg_NUM_BANK_TAIL = (reg_NUM_BANK_TAIL+1)%_param->_nb_bank;
		  reg_BANK_PTR [i]  = (reg_BANK_PTR [i]+1)%_param->_size_bank;
		}
	    }

	// ===================================================================
	// =====[ COMMIT ]====================================================
	// ===================================================================

#ifdef STATISTICS
        if (usage_is_set(_usage,USE_STATISTICS))
          (*_stat_nb_inst_commit_conflit_access) += internal_BANK_COMMIT_CONFLIT_ACCESS;
#endif

	for (uint32_t i=0; i<_param->_nb_bank; i++)
	  for (uint32_t j=0; j<_param->_nb_bank_access_commit; j++)
	    if (internal_BANK_COMMIT_VAL [i][j])
	      {
                // An instruction is executed. Change state of this instruction

		uint32_t x = internal_BANK_COMMIT_NUM_INST [i][j];

		if (PORT_READ(in_COMMIT_VAL [x]) and PORT_READ(in_COMMIT_WEN [x]))
		  {
		    log_printf(TRACE,Commit_unit,FUNCTION,"  * COMMIT            [%d]",x);

#ifdef STATISTICS
                    if (usage_is_set(_usage,USE_STATISTICS))
                      (*_stat_nb_inst_commit) ++;
#endif

		    log_printf(TRACE,Commit_unit,FUNCTION,"    * num_bank   : %d",i);

		    // find the good entry !!!
		    entry_t *       entry        = internal_BANK_COMMIT_ENTRY [i][j];
                                                 
		  //Toperation_t    operation    = PORT_READ(in_COMMIT_OPERATION   [x]);
		  //Ttype_t         type         = PORT_READ(in_COMMIT_TYPE        [x]);
		    Texception_t    exception    = PORT_READ(in_COMMIT_EXCEPTION   [x]);

		    rob_state_t     state        = entry->state;
		    Tcontext_t      front_end_id = entry->front_end_id;
		    Tcontext_t      context_id   = entry->context_id;

		    // change state : test exception_use
		    //  * test if exception : exception and mask
		    
		    bool have_exception        = false;
                    bool have_miss_speculation = false;

		    if (exception != EXCEPTION_NONE)
                      {
                        // Test if the instruction is a load and is a miss speculation (load is commit, but they have an dependence with a previous store)
                        have_miss_speculation  = (exception == EXCEPTION_MEMORY_MISS_SPECULATION);

                        switch (entry->exception_use)
                          {
                            // Have overflow exception if bit overflow enable is set.
                          case  EXCEPTION_USE_RANGE                    : {have_exception = ((exception == EXCEPTION_RANGE) and PORT_READ(in_SPR_READ_SR_OVE[front_end_id][context_id])); break;}
                          case  EXCEPTION_USE_MEMORY_WITH_ALIGNMENT    : {have_exception = ((exception == EXCEPTION_BUS_ERROR) or
                                                                                            (exception == EXCEPTION_DATA_TLB ) or
                                                                                            (exception == EXCEPTION_DATA_PAGE) or
                                                                                            (exception == EXCEPTION_ALIGNMENT)); break;};
                          case  EXCEPTION_USE_MEMORY_WITHOUT_ALIGNMENT : {have_exception = ((exception == EXCEPTION_BUS_ERROR) or
                                                                                            (exception == EXCEPTION_DATA_TLB ) or
                                                                                            (exception == EXCEPTION_DATA_PAGE)); break;};
                          case  EXCEPTION_USE_CUSTOM_0                 : {have_exception = (exception == EXCEPTION_CUSTOM_0); break;}; 
                          case  EXCEPTION_USE_CUSTOM_1                 : {have_exception = (exception == EXCEPTION_CUSTOM_1); break;}; 
                          case  EXCEPTION_USE_CUSTOM_2                 : {have_exception = (exception == EXCEPTION_CUSTOM_2); break;}; 
                          case  EXCEPTION_USE_CUSTOM_3                 : {have_exception = (exception == EXCEPTION_CUSTOM_3); break;}; 
                          case  EXCEPTION_USE_CUSTOM_4                 : {have_exception = (exception == EXCEPTION_CUSTOM_4); break;}; 
                          case  EXCEPTION_USE_CUSTOM_5                 : {have_exception = (exception == EXCEPTION_CUSTOM_5); break;}; 
                          case  EXCEPTION_USE_CUSTOM_6                 : {have_exception = (exception == EXCEPTION_CUSTOM_6); break;}; 
                            // Case already manage (decod stage -> in insert in ROB)
                          case  EXCEPTION_USE_TRAP                     : {have_exception = false; exception = EXCEPTION_NONE; break;};
                          case  EXCEPTION_USE_NONE                     : {have_exception = false; exception = EXCEPTION_NONE; break;}; 
                          case  EXCEPTION_USE_ILLEGAL_INSTRUCTION      : {have_exception = false; exception = EXCEPTION_NONE; break;};
                          case  EXCEPTION_USE_SYSCALL                  : {have_exception = false; exception = EXCEPTION_NONE; break;};
                          default :
                            {
                              throw ERRORMORPHEO(FUNCTION,_("Commit : invalid exception_use.\n"));
                              break;
                            }
                          }
                      }
                   
                    switch (state)
                      {
                        // Branch ...
                      case ROB_BRANCH_WAIT_END : {state = (have_exception)?ROB_END_EXCEPTION_WAIT_HEAD:ROB_BRANCH_COMPLETE; break;}
                        // Store KO
                      case ROB_EVENT_WAIT_END  : {state = ROB_END_KO_SPECULATIVE; break;}
                        // Store OK, Load and other instruction
                      case ROB_OTHER_WAIT_END  : {state = (have_exception)?ROB_END_EXCEPTION_WAIT_HEAD:((have_miss_speculation)?ROB_END_LOAD_MISS_SPECULATIVE:ROB_END_OK_SPECULATIVE); break;}
                      default :
                        {
                          throw ERRORMORPHEO(FUNCTION,toString(_("Commit [%d] : Bank [%d][%d], invalid state value (%s).\n"),x,i,j,toString(state).c_str()));
                          break;
                        }
                      }

                    if ((have_exception or have_miss_speculation) and
                        (reg_EVENT_FLUSH [entry->front_end_id][entry->context_id] == 0))
                      reg_EVENT_STOP [entry->front_end_id][entry->context_id] = true;

		    // update Re Order Buffer
		    entry->state        = state;
		    entry->exception    = exception;
		    entry->flags        = PORT_READ(in_COMMIT_FLAGS       [x]);
		    entry->no_sequence  = PORT_READ(in_COMMIT_NO_SEQUENCE [x]);
                    // jalr, jr : address_dest is in register
                    if ((entry->type      == TYPE_BRANCH) and
                        (entry->operation == OPERATION_BRANCH_L_JALR) and
                        (entry->read_rb))
		    entry->address_next = PORT_READ(in_COMMIT_ADDRESS     [x]);

#ifdef DEBUG
                  entry->cycle_commit            = simulation_cycle();
#endif
		  }
	      }

	// ===================================================================
	// =====[ RETIRE ]====================================================
	// ===================================================================
	for (uint32_t i=0; i<_param->_nb_bank; i++)
          {
            uint32_t num_bank = (internal_BANK_RETIRE_HEAD+i)%_param->_nb_bank;
            
            if (internal_BANK_RETIRE_VAL [num_bank])
              {
                uint32_t x = internal_BANK_RETIRE_NUM_RENAME_UNIT [num_bank];
                uint32_t y = internal_BANK_RETIRE_NUM_INST        [num_bank];
                
                log_printf(TRACE,Commit_unit,FUNCTION,"  * RETIRE            [%d][%d]",x,y);
                log_printf(TRACE,Commit_unit,FUNCTION,"    * num_bank     : %d",num_bank     );
                
#ifdef DEBUG_TEST
                if (not PORT_READ(in_RETIRE_ACK [x][y]))
                  throw ERRORMORPHEO(FUNCTION,_("Retire : retire_ack must be set.\n"));
#endif
                
                entry_t *  entry        =  _rob [num_bank].front();
                rob_state_t state = entry->state;
                
                Tcontext_t front_end_id = entry->front_end_id;
                Tcontext_t context_id   = entry->context_id  ;
                uint32_t   num_thread   = _param->_translate_num_context_to_num_thread [front_end_id][context_id];
                Ttype_t    type         = entry->type        ;
                bool       retire_ok    = false;

                log_printf(TRACE,Commit_unit,FUNCTION,"    * front_end_id : %d",front_end_id );
                log_printf(TRACE,Commit_unit,FUNCTION,"    * context_id   : %d",context_id   );
                log_printf(TRACE,Commit_unit,FUNCTION,"    * rob_ptr      : %d",((entry->ptr << _param->_shift_num_slot) | num_bank));
                log_printf(TRACE,Commit_unit,FUNCTION,"    * num_thread   : %d",num_thread   );
                log_printf(TRACE,Commit_unit,FUNCTION,"    * type         : %s",toString(type).c_str());
                log_printf(TRACE,Commit_unit,FUNCTION,"    * state        : %s",toString(state).c_str());

                if ((state == ROB_END_OK         ) or
// 		    (state == ROB_END_KO         ) or 
                    (state == ROB_END_BRANCH_MISS) or 
                    (state == ROB_END_LOAD_MISS  )//  or 
// 		    (state == ROB_END_MISS       ) or 
// 		    (state == ROB_END_EXCEPTION  )
                    )
                  {
                    log_printf(TRACE,Commit_unit,FUNCTION,"    * retire_ok");

                    retire_ok = true;

//                  reg_PC_PREVIOUS           [front_end_id][context_id] = reg_PC_CURRENT [front_end_id][context_id];
                    reg_PC_CURRENT            [front_end_id][context_id] = reg_PC_NEXT    [front_end_id][context_id];
                    reg_PC_CURRENT_IS_DS      [front_end_id][context_id] = entry->type == TYPE_BRANCH;
                    reg_PC_CURRENT_IS_DS_TAKE [front_end_id][context_id] = entry->no_sequence;
                    reg_PC_NEXT               [front_end_id][context_id] = (entry->no_sequence)?(entry->address_next):(reg_PC_CURRENT [front_end_id][context_id]+1);

//                   if (entry->address_next != reg_PC_NEXT [front_end_id][context_id])
//                     throw ERRORMORPHEO(FUNCTION,toString(_("Retire : Instruction's address_next (%.8x) is different of commit_unit's address_next (%.8x)"),entry->address_next,reg_PC_NEXT [front_end_id][context_id]));
                  }

                if ((state == ROB_END_BRANCH_MISS) or
                    (state == ROB_END_LOAD_MISS))
                    {
                      reg_EVENT_STATE [front_end_id][context_id] = EVENT_STATE_EVENT;
                      reg_EVENT_FLUSH [front_end_id][context_id] = true;
                      reg_EVENT_STOP  [front_end_id][context_id] = false;
                    }
                
#if defined(DEBUG) and defined(DEBUG_Commit_unit) and (DEBUG_Commit_unit == true)
                // log file
                instruction_log_file [num_thread] 
                  << "[" << simulation_cycle() << "] "
                  << std::hex
                  << (entry->address<<2) << " (" << (entry->address) << ") "
                  << std::dec
                  << "[" << entry->cycle_rob_in << ", " << entry->cycle_commit << "] "
                  << "{" << ((retire_ok)?" OK ":"!KO!") << "} "
                  << std::endl;
#endif

                // Update nb_inst
                reg_NB_INST_COMMIT_ALL [front_end_id][context_id] --;
                if (type == TYPE_MEMORY)
                  reg_NB_INST_COMMIT_MEM [front_end_id][context_id] --;
                
                reg_NUM_BANK_HEAD = (reg_NUM_BANK_HEAD+1)%_param->_nb_bank;
                
                delete entry;
                _rob [num_bank].pop_front();
                
                // Transaction on retire interface : reset watch dog timer.
                _nb_cycle_idle [front_end_id][context_id] = 0;

                // Increase stop condition
                if (retire_ok)
                  _simulation_nb_instruction_commited [num_thread] ++;

#ifdef STATISTICS
                if (usage_is_set(_usage,USE_STATISTICS))
                  {
                    (*_stat_nb_inst_retire [x]) ++;
                    
                    if (retire_ok)
                      {
                        (*_stat_nb_inst_retire_ok [num_thread]) ++;
                        (*_stat_nb_inst_type      [type]      ) ++;
                      }
                    else
                      (*_stat_nb_inst_retire_ko [num_thread]) ++;
                  }
#endif
              }
          }

	// ===================================================================
	// =====[ REEXECUTE ]=================================================
	// ===================================================================
	if (internal_REEXECUTE_VAL [0] and PORT_READ(in_REEXECUTE_ACK [0]))
	  {
            log_printf(TRACE,Commit_unit,FUNCTION,"  * REEXECUTE         [0]");

	    uint32_t num_bank = internal_REEXECUTE_NUM_BANK [0];

	    entry_t    * entry = _rob [num_bank].front();
	    rob_state_t  state = entry->state;

	    switch (state)
	      {
	      case ROB_STORE_HEAD_OK : {state = ROB_OTHER_WAIT_END; break; }
	      case ROB_STORE_HEAD_KO : {state = ROB_EVENT_WAIT_END; break; }
	      default : {throw ERRORMORPHEO(FUNCTION,_("Reexecute : invalid state value.\n"));}
	      }

	    entry->state = state;
	  }

	// ===================================================================
	// =====[ BRANCH_COMPLETE ]===========================================
	// ===================================================================
	for (uint32_t i=0; i<_param->_nb_inst_branch_complete; i++)
	  if (internal_BRANCH_COMPLETE_VAL [i] and PORT_READ(in_BRANCH_COMPLETE_ACK [i]))
	    {
              log_printf(TRACE,Commit_unit,FUNCTION,"  * BRANCH_COMPLETE   [%d]",i);
              log_printf(TRACE,Commit_unit,FUNCTION,"    * miss_prediction : %d",PORT_READ(in_BRANCH_COMPLETE_MISS_PREDICTION [i]));

	      uint32_t num_bank = internal_BRANCH_COMPLETE_NUM_BANK [i];
	      
	      entry_t   * entry = _rob [num_bank].front();

#ifdef DEBUG_TEST
	      rob_state_t  state = entry->state;
	      if (state != ROB_BRANCH_COMPLETE)
		throw ERRORMORPHEO(FUNCTION,_("Branch_complete : Invalid state value.\n"));
#endif
              Tcontrol_t miss = PORT_READ(in_BRANCH_COMPLETE_MISS_PREDICTION [i]);
              
              entry->state = (miss)?ROB_END_BRANCH_MISS_SPECULATIVE:ROB_END_OK_SPECULATIVE;
              
              if (miss and (reg_EVENT_FLUSH [entry->front_end_id][entry->context_id] == 0))
                reg_EVENT_STOP [entry->front_end_id][entry->context_id] = true;


//               entry->state = ROB_END_OK_SPECULATIVE;
	    }

	// ===================================================================
	// =====[ UPDATE ]====================================================
	// ===================================================================
        if (internal_UPDATE_VAL and PORT_READ(in_UPDATE_ACK))
          {
            log_printf(TRACE,Commit_unit,FUNCTION,"  * UPDATE");

            entry_t * entry = _rob [internal_UPDATE_NUM_BANK].front();

            switch (entry->state)
              {
//               case ROB_END_EXCEPTION_UPDATE :
//                 {
//                   entry->state = ROB_END_KO;
//                   throw ERRORMORPHEO(FUNCTION,_("Moore : exception is not yet supported (Coming Soon).\n"));
//                   break;
//                 }
              case ROB_END_LOAD_MISS_UPDATE :
                {
                  log_printf(TRACE,Commit_unit,FUNCTION,"    * ROB_END_LOAD_MISS_UPDATE");

                  entry->state = ROB_END_LOAD_MISS;
                  break;
                }
              default :
                {
                  throw ERRORMORPHEO(FUNCTION,_("Update : invalid state.\n"));
                  break;
                }
              }

          }

	// ===================================================================
	// =====[ EVENT ]=====================================================
	// ===================================================================
//         for (uint32_t i=0; i < _param->_nb_front_end; ++i)
//           for (uint32_t j=0; j < _param->_nb_context[i]; ++j)
//             if (PORT_READ(in_EVENT_VAL [i][j]) and internal_EVENT_ACK [i][j])
//               {
//                 log_printf(TRACE,Commit_unit,FUNCTION,"  * EVENT [%d][%d]",i,j);

//                 reg_PC_CURRENT            [i][j] = PORT_READ(in_EVENT_ADDRESS      [i][j]);
//                 reg_PC_CURRENT_IS_DS      [i][j] = PORT_READ(in_EVENT_IS_DS_TAKE   [i][j]); // ??
//                 reg_PC_CURRENT_IS_DS_TAKE [i][j] = PORT_READ(in_EVENT_IS_DS_TAKE   [i][j]);
//                 reg_PC_NEXT               [i][j] = PORT_READ(in_EVENT_ADDRESS_NEXT [i][j]);
//                 // PORT_READ(in_EVENT_ADDRESS_NEXT_VAL [i][j]);
//               }

	// ===================================================================
	// =====[ DEPTH - HEAD ]==============================================
	// ===================================================================
	for (uint32_t i=0; i<_param->_nb_bank; i++)
	  if (not _rob[i].empty())
	    {
	      // Scan all instruction in windows and test if instruction is speculative
	      entry_t    * entry        = _rob [i].front();
	      
	      Tcontext_t   front_end_id = entry->front_end_id;
	      Tcontext_t   context_id   = entry->context_id  ;
	      rob_state_t  state        = entry->state;
	      Tdepth_t     depth        = entry->depth;

              Tdepth_t     depth_min    = (_param->_have_port_depth)?PORT_READ(in_DEPTH_MIN[front_end_id][context_id]):0;
              Tdepth_t     depth_max    = (_param->_have_port_depth)?PORT_READ(in_DEPTH_MAX[front_end_id][context_id]):0;
              Tcontrol_t   depth_full   = PORT_READ(in_DEPTH_FULL [front_end_id][context_id]);
              
              // is a valid instruction ?
              // If DEPTH_CURRENT :
              // equal at     DEPTH_MIN            -> not speculative
              // not include ]DEPTH_MIN:DEPTH_MAX] -> previous branch miss
              //     include ]DEPTH_MIN:DEPTH_MAX] -> speculative
              
              // All case
              // ....... min ...X... max ....... OK
              // ....... min ....... max ...X... KO
              // ...X... min ....... max ....... KO
              // ....... max ....... min ...X... OK
              // ...X... max ....... min ....... OK
              // ....... max ...X... min ....... KO
              
              bool         flush         = reg_EVENT_FLUSH [front_end_id][context_id];
              bool         speculative   = entry->speculative and not (depth == depth_min);
              Tcontrol_t   is_valid      = ((not speculative or 
                                             (speculative and (depth_full or // all is valid
                                                               ((depth_min <= depth_max)? // test if depth is overflow
                                                                ((depth >= depth_min) and (depth <=depth_max)):
                                                                ((depth >= depth_min) or  (depth <=depth_max))))))
                                             and not flush);

//            Tcontrol_t   is_valid      = ((depth == depth_min) and not flush);

              log_printf(TRACE,Commit_unit,FUNCTION,"  * HEAD              [%d]",i);
              log_printf(TRACE,Commit_unit,FUNCTION,"    * is_valid        : %d ((depth == depth_min) and not flush)",is_valid);
              log_printf(TRACE,Commit_unit,FUNCTION,"    * depth           : %d",depth    );
              log_printf(TRACE,Commit_unit,FUNCTION,"    * depth_min       : %d",depth_min);
              log_printf(TRACE,Commit_unit,FUNCTION,"    * depth_max       : %d",depth_max);
              log_printf(TRACE,Commit_unit,FUNCTION,"    * depth_full      : %d",depth_full);
              log_printf(TRACE,Commit_unit,FUNCTION,"    * flush           : %d",flush);

	      //------------------------------------------------------
	      // test if instruction is miss speculative
	      //------------------------------------------------------
	      if (not is_valid)
		{
		  switch (state)
		    {
		    case ROB_BRANCH_WAIT_END             : {state = ROB_EVENT_WAIT_END; break;}
		    case ROB_BRANCH_COMPLETE             : {state = ROB_END_MISS      ; break;}
                    case ROB_END_BRANCH_MISS             :
                    case ROB_END_BRANCH_MISS_SPECULATIVE : {state = ROB_END_MISS      ; break;}
                    case ROB_END_LOAD_MISS_UPDATE        :
                    case ROB_END_LOAD_MISS               :
                    case ROB_END_LOAD_MISS_SPECULATIVE   : {state = ROB_END_MISS      ; break;}
		    case ROB_STORE_WAIT_HEAD_OK          : {state = ROB_STORE_HEAD_KO ; break;}
		  //case ROB_STORE_WAIT_HEAD_KO          : {state = ; break;}
		    case ROB_OTHER_WAIT_END              : {state = ROB_EVENT_WAIT_END; break;}
		    case ROB_END_OK                      :
		    case ROB_END_OK_SPECULATIVE          : {state = ROB_END_MISS      ; break;}
		    case ROB_END_KO                      :
		    case ROB_END_KO_SPECULATIVE          : {state = ROB_END_MISS      ; break;}
		    case ROB_END_EXCEPTION_UPDATE        :
		    case ROB_END_EXCEPTION               :
		    case ROB_END_EXCEPTION_WAIT_HEAD     : {state = ROB_END_MISS      ; break;}
		                                         
		      // don't change                    
		    case ROB_STORE_HEAD_KO               : {break;}
		    case ROB_EVENT_WAIT_END              : {break;}
		    case ROB_END_MISS                    : {break;}
		                                         
		      // can't have miss speculation     
		    case ROB_STORE_HEAD_OK               :
		    default                              : 
		      {
			throw ERRORMORPHEO(FUNCTION,toString(_("Miss Speculation : Invalide state : %s.\n"),toString(state).c_str()));
			break;
		      }
		    }
		}
	      
	      //------------------------------------------------------
	      // test if instruction is not speculative
	      //------------------------------------------------------
              entry->speculative = speculative;
// 	      if (entry->depth == depth_min)
	      if (not speculative)
		{
		  switch (state)
		    {
		    case ROB_END_OK_SPECULATIVE          : {state = ROB_END_OK                 ; break;}
		    case ROB_END_KO_SPECULATIVE          : {state = ROB_END_KO                 ; break;}
		    case ROB_END_BRANCH_MISS_SPECULATIVE : {state = ROB_END_BRANCH_MISS        ; break;}
		    case ROB_END_LOAD_MISS_SPECULATIVE   : {state = ROB_END_LOAD_MISS_UPDATE   ; break;}
		    default : {break;} // else, no change
		  }
		}
	      
	      //------------------------------------------------------
	      // test if instruction is store and head
	      //------------------------------------------------------
	      if (i == reg_NUM_BANK_HEAD)
		{
		  switch (state)
		    {
		    case ROB_STORE_WAIT_HEAD_OK      : {state = ROB_STORE_HEAD_OK;        break;}
		    case ROB_END_EXCEPTION_WAIT_HEAD : {state = ROB_END_EXCEPTION_UPDATE; break;}
                    default : {break;} // else, no change
		    }
		}
	      
	      entry->state = state;
	    }
      }

    // ===================================================================
    // =====[ OTHER ]=====================================================
    // ===================================================================

#ifdef STATISTICS
    for (uint32_t i=0; i<_param->_nb_bank; i++)
      if (usage_is_set(_usage,USE_STATISTICS))
        *(_stat_bank_nb_inst [i]) += _rob[i].size();
#endif

#if (DEBUG >= DEBUG_TRACE) and (DEBUG_Commit_unit == true)
    {
      log_printf(TRACE,Commit_unit,FUNCTION,"  * Dump ROB (Re-Order-Buffer)");
      log_printf(TRACE,Commit_unit,FUNCTION,"    * num_bank_head : %d",reg_NUM_BANK_HEAD);
      log_printf(TRACE,Commit_unit,FUNCTION,"    * num_bank_tail : %d",reg_NUM_BANK_TAIL);
      
      for (uint32_t i=0; i<_param->_nb_front_end; i++)
        for (uint32_t j=0; j<_param->_nb_context [i]; j++)
          {
            log_printf(TRACE,Commit_unit,FUNCTION,"    * [%d][%d] - %d",i,j,_param->_translate_num_context_to_num_thread [i][j]);
            log_printf(TRACE,Commit_unit,FUNCTION,"      * EVENT_STATE  : %s",toString(reg_EVENT_STATE [i][j]).c_str());
            log_printf(TRACE,Commit_unit,FUNCTION,"      * EVENT_FLUSH  : %d",reg_EVENT_FLUSH [i][j]);
            log_printf(TRACE,Commit_unit,FUNCTION,"      * EVENT_STOP   : %d",reg_EVENT_STOP  [i][j]);
            log_printf(TRACE,Commit_unit,FUNCTION,"      * NB_INST_ALL  : %d",reg_NB_INST_COMMIT_ALL[i][j]);
            log_printf(TRACE,Commit_unit,FUNCTION,"      * NB_INST_MEM  : %d",reg_NB_INST_COMMIT_MEM[i][j]);
            log_printf(TRACE,Commit_unit,FUNCTION,"      * PC_CURRENT   : %.8x (%.8x) - %d %d",reg_PC_CURRENT [i][j],reg_PC_CURRENT [i][j]<<2, reg_PC_CURRENT_IS_DS [i][j], reg_PC_CURRENT_IS_DS_TAKE [i][j]);
            log_printf(TRACE,Commit_unit,FUNCTION,"      * PC_NEXT      : %.8x (%.8x)",reg_PC_NEXT [i][j],reg_PC_NEXT [i][j]<<2);
          }

      for (uint32_t i=0; i<_param->_nb_bank; i++)
        {
          uint32_t num_bank = (reg_NUM_BANK_HEAD+i)%_param->_nb_bank;

          log_printf(TRACE,Commit_unit,FUNCTION,"      * Bank [%d] size : %d, ptr : %d",num_bank,(int)_rob[num_bank].size(), reg_BANK_PTR [i]);
          
          for (std::list<entry_t*>::iterator it=_rob[num_bank].begin();
               it!=_rob[num_bank].end();
               it++)
            {
              log_printf(TRACE,Commit_unit,FUNCTION,"        [%.4d][%.4d] (%.4d) %.4d %.4d %.4d %.4d, %.3d %.3d, %.1d, %.1d %.4d, %.1d %.4d, %s",
                         num_bank                       ,
                         (*it)->ptr                     ,
                         (((*it)->ptr << _param->_shift_num_slot) | num_bank),
                         (*it)->front_end_id            ,
                         (*it)->context_id              ,
                         (*it)->rename_unit_id          ,
                         (*it)->depth                   ,
                         (*it)->type                    ,
                         (*it)->operation               ,
                         (*it)->is_delay_slot           ,
                         (*it)->use_store_queue         ,
                         (*it)->store_queue_ptr_write   ,
                         (*it)->use_load_queue          ,
                         (*it)->load_queue_ptr_write    ,
                         toString((*it)->state).c_str() );
              log_printf(TRACE,Commit_unit,FUNCTION,"                     %.1d %.2d %.6d, %.1d %.2d %.6d, %.1d %.1d %.6d, %.1d %.2d %.6d %.6d, %.1d %.1d %.6d %.6d ",
                         (*it)->read_ra                 ,
                         (*it)->num_reg_ra_log          ,
                         (*it)->num_reg_ra_phy          ,
                         (*it)->read_rb                 ,
                         (*it)->num_reg_rb_log          ,
                         (*it)->num_reg_rb_phy          ,
                         (*it)->read_rc                 ,
                         (*it)->num_reg_rc_log          ,
                         (*it)->num_reg_rc_phy          ,
                         (*it)->write_rd                ,
                         (*it)->num_reg_rd_log          ,
                         (*it)->num_reg_rd_phy_old      ,
                         (*it)->num_reg_rd_phy_new      ,
                         (*it)->write_re                ,
                         (*it)->num_reg_re_log          ,
                         (*it)->num_reg_re_phy_old      ,
                         (*it)->num_reg_re_phy_new      );
              
              log_printf(TRACE,Commit_unit,FUNCTION,"                     %.2d %.2d %.1d %.1d %.1d - %.8x (%.8x) %.8x (%.8x)",
                         (*it)->exception_use ,
                         (*it)->exception     ,
                         (*it)->flags         ,
                         (*it)->no_sequence   ,
                         (*it)->speculative   ,
                         (*it)->address       ,
                         (*it)->address<<2    ,
                         (*it)->address_next  ,
                         (*it)->address_next<<2
                         );
            }
        }
    }
#endif

#ifdef DEBUG_TEST
    {
      uint32_t x=reg_NUM_BANK_HEAD;
      if (not _rob[x].empty())
        {
          entry_t * entry = _rob [x].front();

          if (false
//            or (entry->state == ROB_EMPTY                      )
//            or (entry->state == ROB_BRANCH_WAIT_END            )
//            or (entry->state == ROB_BRANCH_COMPLETE            )
//            or (entry->state == ROB_STORE_WAIT_HEAD_OK         )
//          //or (entry->state == ROB_STORE_WAIT_HEAD_KO         )
//            or (entry->state == ROB_STORE_HEAD_OK              )
//            or (entry->state == ROB_STORE_HEAD_KO              )
//            or (entry->state == ROB_OTHER_WAIT_END             )
//            or (entry->state == ROB_EVENT_WAIT_END             )
//            or (entry->state == ROB_END_OK_SPECULATIVE         )
              or (entry->state == ROB_END_OK                     )
//            or (entry->state == ROB_END_KO_SPECULATIVE         )
//            or (entry->state == ROB_END_KO                     )
//            or (entry->state == ROB_END_BRANCH_MISS_SPECULATIVE)
              or (entry->state == ROB_END_BRANCH_MISS            )
//            or (entry->state == ROB_END_LOAD_MISS_SPECULATIVE  )
//            or (entry->state == ROB_END_LOAD_MISS_UPDATE       )
              or (entry->state == ROB_END_LOAD_MISS              )
//            or (entry->state == ROB_END_MISS                   )
//            or (entry->state == ROB_END_EXCEPTION_WAIT_HEAD    )
//            or (entry->state == ROB_END_EXCEPTION_UPDATE       )
//            or (entry->state == ROB_END_EXCEPTION              )
              )
          if (entry->address != reg_PC_CURRENT[entry->front_end_id][entry->context_id])
            throw ERRORMORPHEO(FUNCTION,toString(_("Rob top address (%x) is different of reg_PC_CURRENT[%d][%d] (%x).\n"),
                                                 entry->address,
                                                 entry->front_end_id,
                                                 entry->context_id,
                                                 reg_PC_CURRENT[entry->front_end_id][entry->context_id]));
        }
    }
#endif

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

    // Stop Condition
    for (uint32_t i=0; i<_param->_nb_front_end; i++)
      for (uint32_t j=0; j<_param->_nb_context [i]; j++)
        if (_nb_cycle_idle [i][j] >= debug_idle_cycle)
          throw ERRORMORPHEO(FUNCTION,toString(_("Thread [%d] is idle since %.0f cycles.\n"),_param->_translate_num_context_to_num_thread[i][j],_nb_cycle_idle [i][j]));

    log_end(Commit_unit,FUNCTION);
  };

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

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