#ifdef SYSTEMC
/*
 * $Id: Commit_unit_transition.cpp 128 2009-06-26 08:43:23Z 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;
        reg_NUM_PTR_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] = COMMIT_EVENT_STATE_NO_EVENT;
//            reg_EVENT_FLUSH           [i][j] = false;
//            reg_EVENT_STOP            [i][j] = false;
              reg_EVENT_NUM_BANK        [i][j] = 0; // not necessary
              reg_EVENT_NUM_PTR         [i][j] = 0; // not necessary
            //reg_EVENT_CAN_RESTART     [i][j] = 0; // not necessary
              reg_EVENT_PACKET          [i][j] = 0; // not necessary
              reg_EVENT_NB_INST         [i][j] = 0;
              reg_EVENT_LAST            [i][j] = false;
              reg_EVENT_LAST_NUM_BANK   [i][j] = 0; // not necessary
              reg_EVENT_LAST_NUM_PTR    [i][j] = 0; // not necessary

              reg_EVENT_NEXT_STOP       [i][j] = false;
              reg_EVENT_NEXT_PACKET     [i][j] = 0; // not necessary

//            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++)
            {
              // Test if can_restart : (can_restart is to signal at the state than the decod_queue is empty)
              //   *     no previous can_restart (trap for one)
              //   * and decod_queue is empty
              //   * and have an event or have a futur event
//               if (not reg_EVENT_CAN_RESTART [i][j] and
//                    (PORT_READ(in_NB_INST_DECOD_ALL [i][j]) == 0) and
//                    (reg_EVENT_STOP [i][j] or (reg_EVENT_STATE [i][j] != COMMIT_EVENT_STATE_NO_EVENT)))
//                 reg_EVENT_CAN_RESTART [i][j] = true;

              // Test event state
              switch (reg_EVENT_STATE [i][j])
                {
                case COMMIT_EVENT_STATE_EVENT    : 
                  {
                    // Have an event, test if all composant have ack
                    if (internal_RETIRE_EVENT_VAL [i][j] and in_RETIRE_EVENT_ACK [i][j])
                      {
                        // A minor optimisation : test if wait_decod is previously empty.
//                         if (not reg_EVENT_CAN_RESTART [i][j])
//                           reg_EVENT_STATE [i][j] = COMMIT_EVENT_STATE_WAIT_DECOD;
//                         else
                          reg_EVENT_STATE [i][j] = COMMIT_EVENT_STATE_WAIT_END; 
                      }
                    
                    break;
                  }
//                 case COMMIT_EVENT_STATE_WAIT_DECOD : 
//                   {
//                     // Wait flush of decod_queue.
//                     // Test if can restart now
//                     if (reg_EVENT_CAN_RESTART [i][j])
//                       {
//                         //reg_EVENT_FLUSH [i][j] = false;

//                         // A minor optimisation : test if the last element is already retire
//                         if (not reg_EVENT_LAST [i][j])
//                           reg_EVENT_STATE [i][j] = COMMIT_EVENT_STATE_WAIT_END;
//                         else
//                           reg_EVENT_STATE [i][j] = COMMIT_EVENT_STATE_END; 
//                       }
//                     break;
//                   }

//                 case COMMIT_EVENT_STATE_WAIT_END : 
//                   {
//                     // Wait the flush of Re Order Buffer.
//                     // Test if the last element is retire
//                     if (reg_EVENT_LAST [i][j])
//                       reg_EVENT_STATE [i][j] = COMMIT_EVENT_STATE_END ; 
                    
//                     break;
//                   }
//                 case COMMIT_EVENT_STATE_END      :
//                   {
//                     // Just one cycle
                    
//                     // flush of re order buffer is finish
//                     reg_EVENT_LAST  [i][j] = false;

//                     if (not reg_EVENT_NEXT_STOP [i][j])
//                       reg_EVENT_STATE [i][j] = COMMIT_EVENT_STATE_NO_EVENT;
//                     else
//                       {
//                         reg_EVENT_NEXT_STOP [i][j] = false;
//                         reg_EVENT_PACKET [i][j] = reg_EVENT_NEXT_PACKET [i][j];
//                         reg_EVENT_STATE         [i][j] = COMMIT_EVENT_STATE_NOT_YET_EVENT;
// //                      reg_EVENT_STOP          [i][j] = true;
//                         reg_EVENT_LAST_NUM_BANK [i][j] = ((reg_NUM_BANK_TAIL==0)?_param->_nb_bank:reg_NUM_BANK_TAIL)-1;
//                         reg_EVENT_LAST_NUM_PTR  [i][j] = reg_NUM_PTR_TAIL;
//                       }

//                     break;
//                   }


                case COMMIT_EVENT_STATE_WAIT_END : 
                  {
                    // Wait the flush of Re Order Buffer.
                    // Test if the last element is retire
                    if (reg_EVENT_LAST [i][j])
                      {
                        // flush of re order buffer is finish
                        reg_EVENT_LAST  [i][j] = false;
                        
                        if (not reg_EVENT_NEXT_STOP [i][j])
                          reg_EVENT_STATE [i][j] = COMMIT_EVENT_STATE_NO_EVENT;
                        else
                          {
                            reg_EVENT_STATE         [i][j] = COMMIT_EVENT_STATE_NOT_YET_EVENT;

                            reg_EVENT_NEXT_STOP     [i][j] = false;
                            reg_EVENT_PACKET        [i][j] = reg_EVENT_NEXT_PACKET [i][j];
                            reg_EVENT_NB_INST       [i][j] = reg_NB_INST_COMMIT_ALL [i][j];
                          //reg_EVENT_STOP          [i][j] = true;
                            reg_EVENT_LAST_NUM_BANK [i][j] = ((reg_NUM_BANK_TAIL==0)?_param->_nb_bank:reg_NUM_BANK_TAIL)-1;
                            reg_EVENT_LAST_NUM_PTR  [i][j] = reg_NUM_PTR_TAIL;
                          }
                      }
                    break;
                  }

                  //case COMMIT_EVENT_STATE_NO_EVENT : 
                  //case COMMIT_EVENT_STATE_NOT_YET_EVENT : 
                default : break;
                }
            }

	// ===================================================================
	// =====[ INSERT ]====================================================
	// ===================================================================
        {
//           for (uint32_t i=0; i<_param->_nb_rename_unit; i++)
//             for (uint32_t j=0; j<_param->_nb_inst_insert[i]; j++)
//               log_printf(TRACE,Commit_unit,FUNCTION,"  * INSERT_VAL        [%d][%d] : %d",i,j,PORT_READ(in_INSERT_VAL [i][j]));
              
          // variable to count instruction insert
          uint32_t nb_insert = 0;
          
          for (uint32_t i=0; i<_param->_nb_bank; i++)
            {
              // compute first bank number
              uint32_t num_bank = (reg_NUM_BANK_TAIL+i)%_param->_nb_bank;
              
              if (internal_BANK_INSERT_VAL [num_bank])
                {
                  // get rename unit source and instruction.
                  uint32_t x = internal_BANK_INSERT_NUM_RENAME_UNIT [num_bank];
                  uint32_t y = internal_BANK_INSERT_NUM_INST        [num_bank];
                  
                  // Test if an instruction is valid
                  // (all in_order insert combinatory is in rename_unit )
                  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 and write information
                      entry_t * entry = new entry_t;
                      uint32_t  ptr   = reg_BANK_PTR [num_bank];

	              entry->ptr                     = ptr;
	              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;
#ifdef DEBUG        
	              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]);
#endif                
	              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->flags                   = 0; // not necessary
                      entry->no_sequence             = type == TYPE_BRANCH;
//                    entry->speculative             = true;
#ifdef DEBUG        
	              entry->address                 = PORT_READ(in_INSERT_ADDRESS               [x][y]);
#else
                      entry->address                 = 0; // not necessary
#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 if no_execute (== instruction is flushed)
                      //          else 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
            
                      {
                        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_END_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 entry in rob
                      _rob[num_bank].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] ++;
                      

                      // flush = present event or future event.
                      //  * present event = don't can restart

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

//                       bool flush = (((reg_EVENT_STATE [front_end_id][context_id] == COMMIT_EVENT_STATE_EVENT) or
//                                      (reg_EVENT_STATE [front_end_id][context_id] == COMMIT_EVENT_STATE_WAIT_DECOD)) or
//                                     (reg_EVENT_STOP [front_end_id][context_id]));
                      
                      // New instruction from decod_queue. Flush if :
                      //     * future event (instruction don't need execute because they are a previous event (miss load/branch or exception))
                      //     * or present_event 
                      //   * and not can_restart (previous empty decod queue), because between the event_stop (branch_complete) and the state event (miss in head), many cycle is occured.
//                       bool flush = ((// present event
//                                      ((reg_EVENT_STATE [front_end_id][context_id] == COMMIT_EVENT_STATE_EVENT) or
//                                       (reg_EVENT_STATE [front_end_id][context_id] == COMMIT_EVENT_STATE_WAIT_DECOD)
//                                       ) or
//                                      futur event
//                                      reg_EVENT_STOP [front_end_id][context_id])
//                                     // can't restart
//                                     and not reg_EVENT_CAN_RESTART[front_end_id][context_id]
//                                     );

//                       if (flush)
//                         {
//                           // A new invalid instruction is push in rob -> new last instruction
//                           reg_EVENT_LAST          [front_end_id][context_id] = false;
//                           reg_EVENT_LAST_NUM_BANK [front_end_id][context_id] = num_bank;
//                           reg_EVENT_LAST_NUM_PTR  [front_end_id][context_id] = ptr;
//                         }
                      
                      // Update pointer
                      reg_NUM_PTR_TAIL  = ptr;
                      reg_BANK_PTR [num_bank]  = (reg_BANK_PTR [num_bank]+1)%_param->_size_bank;
                      nb_insert ++;
                    }
                }
            }
          // Update pointer
          reg_NUM_BANK_TAIL = (reg_NUM_BANK_TAIL+nb_insert)%_param->_nb_bank;
        }

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

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

        // For each commit instruction ...
	for (uint32_t i=0; i<_param->_nb_bank; i++)
	  for (uint32_t j=0; j<_param->_nb_bank_access_commit; j++)
            // ... test if an instruction have finish this execution
	    if (internal_BANK_COMMIT_VAL [i][j])
	      {
                // An instruction is executed -> Change state of this instruction

                // Get information
		uint32_t x = internal_BANK_COMMIT_NUM_INST [i][j];

                // Test if instruction is valid and is enable
                // (can be disable if this instruction is reexecute)
		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];

		    log_printf(TRACE,Commit_unit,FUNCTION,"    * ptr                   : %d",entry->ptr);
                                                 
		  //Toperation_t    operation    = PORT_READ(in_COMMIT_OPERATION   [x]);
 		    Ttype_t         type         = entry->type;
		    Tcontrol_t      no_sequence  = PORT_READ(in_COMMIT_NO_SEQUENCE [x]);

#if 0
		    if ((type == TYPE_MEMORY) and no_sequence)
		      continue;
#endif		    

		    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
		    
		    bool have_exception        = false;
                    bool have_miss_speculation = false;

                    // Test if have an exception ...
		    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 -> need restart pipeline)

                        have_miss_speculation  = (exception == EXCEPTION_MEMORY_MISS_SPECULATION);

                        //  * Test if the exception generated can be trap by this exception
                        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;
                            }
                          }
                      }

		    log_printf(TRACE,Commit_unit,FUNCTION,"    * have_exception        : %d",have_exception       ); 
		    log_printf(TRACE,Commit_unit,FUNCTION,"    * have_miss_speculation : %d",have_miss_speculation);

                   
                    // Next state depends of previous state
                    switch (state)
                      {
                        // Branch : if no exception, the branchement can be completed
                      case ROB_BRANCH_WAIT_END : 
                        {
                          if (not have_exception)
                            state = ROB_BRANCH_COMPLETE;
                          else
                            state = ROB_END_EXCEPTION_WAIT_HEAD;
                          break;
                        }
                        // Previous event -> set state as execute
		      case ROB_STORE_KO_WAIT_END :
                      case ROB_EVENT_WAIT_END  : 
                        {
                          state = ROB_END_KO_SPECULATIVE; 
                          break;
                        }
                        // No previous event - Load and other instruction
		      case ROB_STORE_OK_WAIT_END :
                      case ROB_OTHER_WAIT_END  : 
                        {
                          if (not have_exception)
                            {
                              if (not have_miss_speculation)
                                state = ROB_END_OK_SPECULATIVE;
                              else
                                state = ROB_END_LOAD_MISS_SPECULATIVE; 
                            }
                          else
                            state = ROB_END_EXCEPTION_WAIT_HEAD;
                          break;
                        }
		      case ROB_STORE_WAIT_END_OK :
			{
			  if (not have_exception)
			    state = ROB_STORE_OK;
			  else
                            state = ROB_STORE_EVENT;
			  break;
			}
		      case ROB_STORE_WAIT_END_KO :
			{
// 			  if (not have_exception)
			    state = ROB_STORE_KO;
// 			  else
//                             state = ROB_END_EXCEPTION_WAIT_HEAD; 
			  break;
			}


                      default :
                        {
                          throw ERRORMORPHEO(FUNCTION,toString(_("Commit [%d] : Bank [%d][%d], invalid state value (%s).\n"),x,i,j,toString(state).c_str()));
                          break;
                        }
                      }

                    // Commit an instruction ... 
                    // Test if have an event (miss_speculation or exception)

                    if (have_exception or have_miss_speculation)
                      {
                        // Two case :
                        // if no previous manage event -> generate an event
                        // if    previous manage event -> next generate an event

//                      bool flush = reg_EVENT_FLUSH [front_end_id][context_id];
                        bool flush = ((reg_EVENT_STATE [front_end_id][context_id] == COMMIT_EVENT_STATE_EVENT) or
//                                    (reg_EVENT_STATE [front_end_id][context_id] == COMMIT_EVENT_STATE_WAIT_DECOD) or
                                      (reg_EVENT_STATE [front_end_id][context_id] == COMMIT_EVENT_STATE_WAIT_END)//  or
//                                       (reg_EVENT_STATE [front_end_id][context_id] == COMMIT_EVENT_STATE_END)
                                      );
                        
                        uint32_t packet = ((entry->ptr << _param->_shift_num_slot) | i);
                        uint32_t _top   = ((_rob[ reg_NUM_BANK_HEAD].front()->ptr << _param->_shift_num_slot) | reg_NUM_BANK_HEAD);

                        log_printf(TRACE,Commit_unit,FUNCTION,"    * flush                 : %d",flush); 
                        log_printf(TRACE,Commit_unit,FUNCTION,"    * packet                : %d",packet);
                            
                        if (not flush)
                          {
                            bool     can    = true;
                            // test have a previous event detected (event_stop = 1)
                            // if yes, test if the actual event if "before (in order)" that the previous event
                            if (reg_EVENT_STATE [front_end_id][context_id] == COMMIT_EVENT_STATE_NOT_YET_EVENT)
                              {
                                // Compare packet_id (by construction instruction is insert in order by increase packet_id)
                                
                                uint32_t _old = reg_EVENT_PACKET [front_end_id][context_id];
                                uint32_t _new = packet;
                                if (_old < _top) _old = _old+_param->_size_queue;
                                if (_new < _top) _new = _new+_param->_size_queue;
                                if (_new < _old) reg_EVENT_PACKET [front_end_id][context_id] = packet;
                                else can = false;
                              }
                            else
                              reg_EVENT_PACKET [front_end_id][context_id] = packet;
                            
                            if (can)
                              {
                                // have an error, stop issue instruction
                                reg_EVENT_STATE         [front_end_id][context_id] = COMMIT_EVENT_STATE_NOT_YET_EVENT;

                                reg_EVENT_NB_INST       [front_end_id][context_id] = reg_NB_INST_COMMIT_ALL [front_end_id][context_id];

                              //reg_EVENT_STOP          [front_end_id][context_id] = true;
                                
                                reg_EVENT_LAST_NUM_BANK [front_end_id][context_id] = ((reg_NUM_BANK_TAIL==0)?_param->_nb_bank:reg_NUM_BANK_TAIL)-1;
                                reg_EVENT_LAST_NUM_PTR  [front_end_id][context_id] = reg_NUM_PTR_TAIL;
                              }
                          }
                        else
                          {
                            bool find = true;

                            log_printf(TRACE,Commit_unit,FUNCTION,"    * reg_EVENT_NEXT_STOP   : %d",reg_EVENT_NEXT_STOP  [front_end_id][context_id]); 
                            log_printf(TRACE,Commit_unit,FUNCTION,"    * reg_EVENT_NEXT_PACKET : %d",reg_EVENT_NEXT_PACKET[front_end_id][context_id]); 

                            // already manage an event.
                            if (reg_EVENT_NEXT_STOP [front_end_id][context_id])
                              {
                                // after last ?
                                uint32_t _old = reg_EVENT_NEXT_PACKET [front_end_id][context_id];
                                uint32_t _new = packet;

                                log_printf(TRACE,Commit_unit,FUNCTION,"    * _top                  : %d",_top ); 
                                log_printf(TRACE,Commit_unit,FUNCTION,"    * _old (before)         : %d",_old ); 
                                log_printf(TRACE,Commit_unit,FUNCTION,"    * _new (before)         : %d",_new ); 

                                if (_old < _top) _old = _old+_param->_size_queue;
                                if (_new < _top) _new = _new+_param->_size_queue;
                                if (_new > _old) reg_EVENT_NEXT_PACKET [front_end_id][context_id] = packet;
                                else find = false;

                                log_printf(TRACE,Commit_unit,FUNCTION,"    * _old (after)          : %d",_old ); 
                                log_printf(TRACE,Commit_unit,FUNCTION,"    * _new (after)          : %d",_new ); 
                              }
                            else
                              {
                                // after last ?
                                uint32_t _old = ((reg_EVENT_LAST_NUM_PTR [front_end_id][context_id] << _param->_shift_num_slot) | reg_EVENT_LAST_NUM_BANK [front_end_id][context_id]);
                                uint32_t _new = packet;

                                log_printf(TRACE,Commit_unit,FUNCTION,"    * _top                  : %d",_top ); 
                                log_printf(TRACE,Commit_unit,FUNCTION,"    * _old (before)         : %d",_old ); 
                                log_printf(TRACE,Commit_unit,FUNCTION,"    * _new (before)         : %d",_new ); 

                                if (_old < _top) _old = _old+_param->_size_queue;
                                if (_new < _top) _new = _new+_param->_size_queue;
                                if (_new > _old) reg_EVENT_NEXT_PACKET [front_end_id][context_id] = packet;
                                else find = false;

                                log_printf(TRACE,Commit_unit,FUNCTION,"    * _old (after)          : %d",_old ); 
                                log_printf(TRACE,Commit_unit,FUNCTION,"    * _new (after)          : %d",_new ); 
                              }

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

                            if (find)
                            reg_EVENT_NEXT_STOP [front_end_id][context_id] = true; // in all case : need stop
                          }
                      }

		    // Update Re Order Buffer
		    entry->state        = state;
		    entry->exception    = exception;
		    entry->flags        = PORT_READ(in_COMMIT_FLAGS       [x]);
		    entry->no_sequence  = no_sequence;
                    // jalr, jr : address_dest is in register
                    if ((       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->load_data               = PORT_READ(in_COMMIT_ADDRESS [x]);
                    entry->cycle_commit            = simulation_cycle();
#endif
		  }
	      }

	// ===================================================================
	// =====[ RETIRE ]====================================================
	// ===================================================================
	for (uint32_t i=0; i<_param->_nb_bank; i++)
          {
            // Compute bank number
            uint32_t num_bank = (internal_BANK_RETIRE_HEAD+i)%_param->_nb_bank;
            
            // Test if have an request
            if (internal_BANK_RETIRE_VAL [num_bank])
              {
                // Take num instruction
                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


#ifdef STATISTICS
	    if (usage_is_set(_usage,USE_STATISTICS))
	      (*_stat_nb_inst_retire [x]) ++;
                
#endif
                
                // Read information
                entry_t *   entry        =  _rob [num_bank].front();

                entry->state_old = entry->state;
                entry->state     = ROB_END;
              }
          }

	for (uint32_t i=0; i<_param->_nb_bank; i++)
	  {
	    // Compute bank number
	    bool      can_continue = false;
	    uint32_t  num_bank = reg_NUM_BANK_HEAD;
	    
	    if (not _rob [num_bank].empty ())
	      {
	        entry_t * entry = _rob [num_bank].front();
	        
	        if (entry->state == ROB_END)
	          {
	            log_printf(TRACE,Commit_unit,FUNCTION,"  * RETIRE_ROB [%d]",num_bank);
	    
                    can_continue = true;

	            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];
	            rob_state_t state        = entry->state_old;
	            Ttype_t     type         = entry->type        ;
	            bool        retire_ok    = false;
	            uint32_t    packet_id    = ((entry->ptr << _param->_shift_num_slot) | num_bank);
	            
	            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",packet_id    );
	            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());
	            
                    // Test if the instruction is valid
                    // (BRANCH_MISS = instruction branch is valid, but have make an invalid prediction)
                    // (LOAD_MISS   = instruction load   is valid, but have make an invalid result)
                    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;
	            
                        // Update PC information
//                      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] = 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);
                      }
	            
                    // Test if have an event
                    if ((state == ROB_END_BRANCH_MISS) or
                        (state == ROB_END_LOAD_MISS))
	              {
                          reg_EVENT_STATE         [front_end_id][context_id] = COMMIT_EVENT_STATE_EVENT;
//                        reg_EVENT_STOP          [front_end_id][context_id] = false; // instruction flow can continue
                          reg_EVENT_LAST          [front_end_id][context_id] = false;
                          // it the head !
                          reg_EVENT_PACKET        [front_end_id][context_id] = packet_id;
	            
//                           // If event is an load_miss, many instruction can be inserted. 
//                           // -> new last instruction
//                           if (state == ROB_END_LOAD_MISS)
//                             {
// //                             reg_EVENT_CAN_RESTART   [front_end_id][context_id] = false;
                            
//                             reg_EVENT_LAST_NUM_BANK [front_end_id][context_id] = ((reg_NUM_BANK_TAIL==0)?_param->_nb_bank:reg_NUM_BANK_TAIL)-1;
//                             reg_EVENT_LAST_NUM_PTR  [front_end_id][context_id] = reg_NUM_PTR_TAIL;
//                             }
                        }
	            
                    // Test if this instruction is the last instruction of an event
                    //   * need event
                    //   * packet id = last packet id
//                     for (uint32_t x=0; x<_param->_nb_front_end; x++)
//                       for (uint32_t y=0; y<_param->_nb_context [x]; y++)
//                         if (((reg_EVENT_STATE         [x][y] != COMMIT_EVENT_STATE_NO_EVENT     ) and
//                              (reg_EVENT_STATE         [x][y] != COMMIT_EVENT_STATE_NOT_YET_EVENT)) and
//                             (reg_EVENT_LAST_NUM_BANK [x][y] == num_bank            ) and
//                             (reg_EVENT_LAST_NUM_PTR  [x][y] == entry->ptr          ))
//                           reg_EVENT_LAST [x][y] = true;


                    if (reg_EVENT_NB_INST [front_end_id][context_id] > 0)
                      {
                        reg_EVENT_NB_INST [front_end_id][context_id] --;
                        if (reg_EVENT_NB_INST [front_end_id][context_id] == 0)
                          reg_EVENT_LAST [front_end_id][context_id] = true;
                      }

                    // 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] --;
	            
	            // Update pointer
	            reg_NUM_BANK_HEAD = (num_bank+1)%_param->_nb_bank;
                    
                    // Reset watch dog timer because have transaction on retire interface
                    _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))
	              {
	            	if (retire_ok)
	            	  {
	            	    (*_stat_nb_inst_retire_ok [num_thread]) ++;
	            	    (*_stat_nb_inst_type      [type]      ) ++;
	            	  }
	            	else
	            	  (*_stat_nb_inst_retire_ko [num_thread]) ++;
	              }
#endif

#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") << "} ";
	              
	              if ((type == TYPE_MEMORY) and  is_operation_memory_load(entry->operation))
	            	instruction_log_file [num_thread] << std::hex << entry->load_data << std::dec;
	              
	              instruction_log_file [num_thread] << std::endl;
	            }
#endif	    

	            // Remove entry
	            delete entry;
	            _rob [num_bank].pop_front();
	          }
	      }
	    
	    if (not can_continue)
	      break; // stop scan
	  }

	// ===================================================================
	// =====[ REEXECUTE ]=================================================
	// ===================================================================
        // Test if have an reexecute instruction (an store in head of rob)
	for (uint32_t i=0; i<_param->_nb_inst_reexecute; ++i)
	  if (internal_REEXECUTE_VAL [i] and PORT_READ(in_REEXECUTE_ACK [i]))
	    {
	      log_printf(TRACE,Commit_unit,FUNCTION,"  * REEXECUTE         [%d]",i);
	      
	      uint32_t num_bank = internal_REEXECUTE_NUM_BANK [i];
	      
	      entry_t    * entry = _rob [num_bank].front();
	      rob_state_t  state = entry->state;
	      
	      // Change state
	      switch (state)
		{
		case ROB_STORE_OK    : {state = ROB_STORE_OK_WAIT_END; break; }
		case ROB_STORE_KO    : {state = ROB_STORE_KO_WAIT_END; break; }
		case ROB_STORE_EVENT : {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++)
          // Test if the prediction_unit have accept the branch complete transaction
	  if (internal_BRANCH_COMPLETE_VAL [i] and PORT_READ(in_BRANCH_COMPLETE_ACK [i]))
	    {
              log_printf(TRACE,Commit_unit,FUNCTION,"  * BRANCH_COMPLETE   [%d]",i);

              // Read information
	      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]);

              log_printf(TRACE,Commit_unit,FUNCTION,"    * miss_prediction : %d",miss);
              
              entry->state = (miss)?ROB_END_BRANCH_MISS_SPECULATIVE:ROB_END_OK_SPECULATIVE;

//            bool flush = reg_EVENT_FLUSH [entry->front_end_id][entry->context_id];

              // Branch_complete can be execute if
              //   * no present event
              //   * futur event and most not speculative that the event

              // Also, test if in this cycle, they have not an most recently event !!!
              if (miss)
                {
                  bool     can    = true;
                  uint32_t packet = ((entry->ptr << _param->_shift_num_slot) | num_bank);
                      
                  // test if this packet is before previous event
                  if (reg_EVENT_STATE [entry->front_end_id][entry->context_id] == COMMIT_EVENT_STATE_NOT_YET_EVENT)
                    {
                      uint32_t _top = ((_rob[ reg_NUM_BANK_HEAD].front()->ptr << _param->_shift_num_slot) | reg_NUM_BANK_HEAD);
                      uint32_t _old = reg_EVENT_PACKET [entry->front_end_id][entry->context_id];
                      uint32_t _new = packet;
                      if (_old < _top) _old = _old+_param->_size_queue;
                      if (_new < _top) _new = _new+_param->_size_queue;
                      if (_new < _old) reg_EVENT_PACKET [entry->front_end_id][entry->context_id] = packet;
                      else can = false;
                    }
                  else
                    reg_EVENT_PACKET [entry->front_end_id][entry->context_id] = packet;

                  if (can)
                    {
                      // In all case, stop instruction flow
                      reg_EVENT_STATE         [entry->front_end_id][entry->context_id] = COMMIT_EVENT_STATE_NOT_YET_EVENT;
                      reg_EVENT_NB_INST       [entry->front_end_id][entry->context_id] = reg_NB_INST_COMMIT_ALL [entry->front_end_id][entry->context_id];
                                
//                    reg_EVENT_STOP          [entry->front_end_id][entry->context_id] = true;

//                    reg_EVENT_CAN_RESTART   [entry->front_end_id][entry->context_id] = false;

                      reg_EVENT_LAST_NUM_BANK [entry->front_end_id][entry->context_id] = ((reg_NUM_BANK_TAIL==0)?_param->_nb_bank:reg_NUM_BANK_TAIL)-1;
                      reg_EVENT_LAST_NUM_PTR  [entry->front_end_id][entry->context_id] = reg_NUM_PTR_TAIL;
                    }
                }
	    }

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

            // Change state
            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 ]==============================================
	// ===================================================================

        {
          bool     can_continue   [_param->_nb_front_end][_param->_max_nb_context];
          uint32_t event_nb_inst  [_param->_nb_front_end][_param->_max_nb_context];
          bool     is_speculative [_param->_nb_front_end][_param->_max_nb_context];
          for (uint32_t i=0; i<_param->_nb_front_end; i++)
            for (uint32_t j=0; j<_param->_nb_context [i]; j++)
              {
                event_nb_inst [i][j] = 0;
                is_speculative[i][j] = false;
                can_continue  [i][j] = (((reg_EVENT_NB_INST [i][j] == 0) or
                                         (    event_nb_inst [i][j] < reg_EVENT_NB_INST [i][j])) and
                                        not reg_EVENT_LAST [i][j]);
              }

          // Read all instruction of all top bank
          for (uint32_t i=0; i<_param->_nb_bank; i++)
            {
              uint32_t num_bank = (reg_NUM_BANK_HEAD+i)%_param->_nb_bank;
              
              // Test if have an instruction
              if (not _rob[num_bank].empty())
                {
                  // Scan all instruction in windows and test if instruction is speculative
                  entry_t    * entry        = _rob [num_bank].front();

                  uint32_t     num_packet   = ((entry->ptr << _param->_shift_num_slot) | num_bank);
                  Tcontext_t   front_end_id = entry->front_end_id;
                  Tcontext_t   context_id   = entry->context_id  ;

                  log_printf(TRACE,Commit_unit,FUNCTION,"  * HEAD              [%d] - %d",num_bank,num_packet);
                  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,"    * EVENT_LAST      : %d",reg_EVENT_LAST    [front_end_id][context_id]);
                  log_printf(TRACE,Commit_unit,FUNCTION,"    * EVENT_NB_INST   : %d",reg_EVENT_NB_INST [front_end_id][context_id]);
                  log_printf(TRACE,Commit_unit,FUNCTION,"    * event_nb_inst   : %d",    event_nb_inst [front_end_id][context_id]);
                  
                  // scan while last event instruction is not retire
                  if (can_continue  [front_end_id][context_id])
                    {
                      // Read information
                      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_STATE [front_end_id][context_id] == COMMIT_EVENT_STATE_EVENT) or
//                                                  (reg_EVENT_STATE [front_end_id][context_id] == COMMIT_EVENT_STATE_WAIT_DECOD) or
                                                    (reg_EVENT_STATE [front_end_id][context_id] == COMMIT_EVENT_STATE_WAIT_END));
                      bool         speculative   = is_speculative [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); // no event

                      Tcontrol_t   is_valid      = not flush;


                      //Tcontrol_t   is_valid      = ((depth == depth_min) and not flush);
                      
                      
                      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,"    * speculative     : %d",speculative);
                      log_printf(TRACE,Commit_unit,FUNCTION,"    * flush           : %d",flush);
                      log_printf(TRACE,Commit_unit,FUNCTION,"    * state (before)  : %s",toString(state).c_str());

//                       //------------------------------------------------------
//                       // Event ?
//                       //------------------------------------------------------

//                       if ((reg_EVENT_STATE  [front_end_id][context_id] == COMMIT_EVENT_STATE_NOT_YET_EVENT) and
//                           (reg_EVENT_PACKET [front_end_id][context_id] == num_packet))
//                         {
//                           switch (state)
//                             {
//                             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;}
//                             case ROB_END_BRANCH_MISS             :
//                             case ROB_END_LOAD_MISS               : 
//                             case ROB_END                         :
//                               {break;}
//                             default : 
//                               {
//                                 throw ERRORMORPHEO(FUNCTION,toString(_("Head [%d] : invalid state (%s)"),num_packet,toString(state).c_str()));
//                                 break;
//                               }
//                             }
//                         }
                    
                      //------------------------------------------------------
                      // test if instruction is miss speculative
                      //------------------------------------------------------
                      if (not is_valid)
                        {
                          // Change state
                          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               :
                            case ROB_END_LOAD_MISS_UPDATE        :
                            case ROB_END_LOAD_MISS_SPECULATIVE   : {state = ROB_END_MISS      ; break;}
                            case ROB_STORE_OK                    : {state = ROB_STORE_KO      ; break;}
                            case ROB_STORE_WAIT_END_OK           : {state = ROB_STORE_WAIT_END_KO; break;}
			    case ROB_STORE_OK_WAIT_END           : {state = ROB_STORE_KO_WAIT_END; 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 state -> wait
                            case ROB_STORE_WAIT_END_KO           : {break;}
                            case ROB_STORE_KO                    : {break;}
                            case ROB_STORE_KO_WAIT_END           : {break;}
                            case ROB_STORE_EVENT                 : {break;}
                            case ROB_EVENT_WAIT_END              : {break;}
                            case ROB_END_MISS                    : {break;}
                            case ROB_END                         : {break;}
                              
                              // can't have miss speculation -> invalid state
                            default                              : 
                              {
                                throw ERRORMORPHEO(FUNCTION,toString(_("Miss Speculation : Invalide state : %s.\n"),toString(state).c_str()));
                                break;
                              }
                            }
                        }

                      //------------------------------------------------------
                      // test if instruction is branch not finish
                      //------------------------------------------------------
                      switch (state)
                        {
                        case ROB_BRANCH_WAIT_END :
                        case ROB_BRANCH_COMPLETE :
                          {
                            is_speculative [front_end_id][context_id] = true;
                            break;
                          }
                        default : break;
                        }
                      
                      //------------------------------------------------------
                      // test if instruction is not speculative
                      //------------------------------------------------------
//                       entry->speculative = speculative;
//                    if (entry->depth == depth_min)
                      // test if instruction is speculative (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 wait head and is the top of rob
                      //------------------------------------------------------
                      // TODO : retire OOO
                      if (i == 0)
                        {
                          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
                            }
                        }
                    
                      // Write new state
                      entry->state = state;

                      log_printf(TRACE,Commit_unit,FUNCTION,"    * state (after )  : %s",toString(state).c_str());
                      
//                    log_printf(TRACE,Commit_unit,FUNCTION,"  * Stop Scan !!!");
                          
                      event_nb_inst [front_end_id][context_id] ++;

                      // stop if : 
                      //  * begin event
                      //  * end event
                      if (((reg_EVENT_STATE [front_end_id][context_id] == COMMIT_EVENT_STATE_NOT_YET_EVENT) and
                           (reg_EVENT_PACKET[front_end_id][context_id] == num_packet)) or
                          ((reg_EVENT_NB_INST [front_end_id][context_id] > 0) and
                           (    event_nb_inst [front_end_id][context_id] >= reg_EVENT_NB_INST [front_end_id][context_id])))
                        can_continue [front_end_id][context_id] = false;
                    }
                }
            }
        }



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

	for (uint32_t i=0; i<_param->_nb_front_end; i++)
	  for (uint32_t j=0; j<_param->_nb_context [i]; j++)
            {
              uint32_t num_thread = _param->_translate_num_context_to_num_thread [i][j];
              
              switch (reg_EVENT_STATE [i][j])
                {
                case COMMIT_EVENT_STATE_NO_EVENT      : (*_stat_nb_cycle_state_no_event      [num_thread])++; break;
                case COMMIT_EVENT_STATE_NOT_YET_EVENT : (*_stat_nb_cycle_state_not_yet_event [num_thread])++; break;
                case COMMIT_EVENT_STATE_EVENT         : (*_stat_nb_cycle_state_event         [num_thread])++; break;
                case COMMIT_EVENT_STATE_WAIT_END      : (*_stat_nb_cycle_state_wait_end      [num_thread])++; break;
                }
            }
      }
#endif
      }

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

#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);
      log_printf(TRACE,Commit_unit,FUNCTION,"    * num_ptr_tail  : %d",reg_NUM_PTR_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 - %s",toString(reg_EVENT_STATE [i][j]).c_str(),toString(commit_event_state_to_event_state(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,"      * EVENT             : %d (bank %d, ptr %d)",((reg_EVENT_NUM_PTR [i][j] << _param->_shift_num_slot) | reg_EVENT_NUM_BANK [i][j]), reg_EVENT_NUM_BANK [i][j],reg_EVENT_NUM_PTR [i][j]);
//          log_printf(TRACE,Commit_unit,FUNCTION,"      * EVENT_CAN_RESTART : %d",reg_EVENT_CAN_RESTART [i][j]);
            log_printf(TRACE,Commit_unit,FUNCTION,"      * EVENT_LAST        : %d - packet %d - ptr %d (bank %d, ptr %d)",reg_EVENT_LAST [i][j],reg_EVENT_PACKET[i][j],((reg_EVENT_LAST_NUM_PTR [i][j] << _param->_shift_num_slot) | reg_EVENT_LAST_NUM_BANK [i][j]), reg_EVENT_LAST_NUM_BANK [i][j],reg_EVENT_LAST_NUM_PTR [i][j]);
            log_printf(TRACE,Commit_unit,FUNCTION,"      * EVENT_NEXT        : stop : %d - packet : %d",reg_EVENT_NEXT_STOP  [i][j],reg_EVENT_NEXT_PACKET[i][j]);
            log_printf(TRACE,Commit_unit,FUNCTION,"      * NB_INST_ALL       : all : %d - mem : %d - event : %d",reg_NB_INST_COMMIT_ALL[i][j], reg_NB_INST_COMMIT_MEM[i][j],reg_EVENT_NB_INST[i][j]);
            log_printf(TRACE,Commit_unit,FUNCTION,"      * PC                : %.8x (%.8x) - %d %d - %.8x (%.8x)",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],reg_PC_NEXT [i][j],reg_PC_NEXT [i][j]<<2);
          }

      std::list<entry_t*>::iterator iter [_param->_nb_bank];
      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]);

          iter [num_bank] = _rob[num_bank].begin();
        }

      bool     all_empty   = false;
      uint32_t nb_write_rd = 0;
      uint32_t nb_write_re = 0;

      while (not all_empty)
        {
          all_empty = true;
          
          for (uint32_t i=0; i<_param->_nb_bank; i++)
            {
              uint32_t num_bank = (reg_NUM_BANK_HEAD+i)%_param->_nb_bank;
      
              std::list<entry_t*>::iterator it = iter[num_bank];        
              if (it != _rob[num_bank].end())
                {
                  all_empty = false;

                  nb_write_rd += ((*it)->write_rd)?1:0;
                  nb_write_re += ((*it)->write_re)?1:0;

                  log_printf(TRACE,Commit_unit,FUNCTION,"        [%.4d][%.4d] %.4d %.4d %.4d %.4d, %.3d %.3d, %.1d, %.1d %.4d, %.1d %.4d, %s",
                             num_bank                       ,
                             (*it)->ptr                     ,
                             (*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,"              (%.4d) %.1d %.2d %.6d, %.1d %.2d %.6d, %.1d %.1d %.6d, %.1d %.2d %.6d %.6d, %.1d %.1d %.6d %.6d ",
                             (((*it)->ptr << _param->_shift_num_slot) | num_bank),
                             (*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 - %.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
                             );
                  
                  iter [num_bank] ++;
                }
            }
        }

      log_printf(TRACE,Commit_unit,FUNCTION,"    * nb_write_rd   : %d",nb_write_rd);
      log_printf(TRACE,Commit_unit,FUNCTION,"    * nb_write_re   : %d",nb_write_re);
    }
#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 (0x%x) is different of reg_PC_CURRENT[%d][%d] (0x%x).\n"),
                                                 entry->address,
                                                 entry->front_end_id,
                                                 entry->context_id,
                                                 reg_PC_CURRENT[entry->front_end_id][entry->context_id]));
        }
    }
    {
      uint32_t NB_INST [_param->_nb_front_end][_param->_max_nb_context];
      for (uint32_t i=0; i<_param->_nb_front_end; i++)
        for (uint32_t j=0; j<_param->_nb_context [i]; j++)
          NB_INST [i][j] = 0; //reg_EVENT_NB_INST [i][j];

      for (uint32_t i=0; i<_param->_nb_bank; ++i)
        for (std::list<entry_t*>::iterator it=_rob[i].begin();
             it!=_rob [i].end();
             ++it)
          NB_INST [(*it)->front_end_id][(*it)->context_id] ++;

      for (uint32_t i=0; i<_param->_nb_front_end; i++)
        for (uint32_t j=0; j<_param->_nb_context [i]; j++)
          if (NB_INST [i][j] != reg_NB_INST_COMMIT_ALL [i][j])
            throw ERRORMORPHEO(FUNCTION,toString(_("Context [%d][%d] have not the good nb_inst (%d in rob, %d in register).\n"),i,j,NB_INST[i][j], reg_NB_INST_COMMIT_ALL [i][j]));
    }
#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
