#ifdef SYSTEMC
/*
 * $Id: Update_Prediction_Table_transition.cpp 124 2009-06-17 12:11:25Z rosiere $
 *
 * [ Description ]
 * 
 */

#include "Behavioural/Core/Multi_Front_end/Front_end/Prediction_unit/Update_Prediction_Table/include/Update_Prediction_Table.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_front_end {
namespace front_end {
namespace prediction_unit {
namespace update_prediction_table {

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

    if (PORT_READ(in_NRESET) == 0)
      {
        // Initialisation

        reg_UPDATE_PRIORITY = 0;

        // All pointer is set at 0
	for (uint32_t i=0; i<_param->_nb_context; i++)
	  {
            for (uint32_t j=0; j<_param->_size_ufpt_queue[i]; ++j)
              reg_UPDATE_FETCH_PREDICTION_TABLE [i][j]._state = UPDATE_FETCH_PREDICTION_STATE_EMPTY;
            reg_UFPT_BOTTOM          [i] = 0;
            reg_UFPT_TOP             [i] = 0;
            reg_UFPT_UPDATE          [i] = 0;
            reg_UFPT_NB_NEED_UPDATE  [i] = 0;
            reg_UFPT_NB_UPDATE       [i] = 0;
                                                                
            for (uint32_t j=0; j<_param->_size_upt_queue[i]; ++j)
              reg_UPDATE_PREDICTION_TABLE [i][j]._state = UPDATE_PREDICTION_STATE_EMPTY;
            reg_UPT_BOTTOM           [i] = 0;
            reg_UPT_TOP              [i] = 0;
            reg_UPT_TOP_EVENT        [i] = 0;
            reg_UPT_UPDATE           [i] = 0;
            reg_UPT_EMPTY            [i] = true;
                                                                                    
            reg_IS_ACCURATE          [i] = true;
            
            reg_UFPT_EVENT_STATE     [i] = UFPT_EVENT_STATE_OK;
            reg_UPT_EVENT_STATE      [i] = UPT_EVENT_STATE_OK;

//             reg_EVENT_VAL            [i] = false;
//             reg_EVENT_STATE          [i] = EVENT_STATE_OK;
//             reg_EVENT_IS_BRANCH      [i] = true;
          }
      }
    else
      {
        bool flush_UFPT    [_param->_nb_context];
	for (uint32_t i=0; i<_param->_nb_context; i++)
          {
            flush_UFPT    [i] = false;
          }

	// ===================================================================
	// =====[ GARBAGE COLLECTOR ]=========================================
	// ===================================================================

        // Each cycle, if the most lastest branch have update all prediction struction (state = end), free this slot
        //   * Update state -> new status is "empty"
        //   * Update pointer (bottom and accurate)
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * GARBAGE COLLECTOR (BEGIN)");
	for (uint32_t i=0; i<_param->_nb_context; i++)
	  {
            // -----------------------------
            // UPDATE_FETCH_PREDICTION_TABLE
            // -----------------------------
            {
              uint32_t bottom = reg_UFPT_BOTTOM [i];
              bool     end    = (reg_UPDATE_FETCH_PREDICTION_TABLE [i][bottom]._state == UPDATE_FETCH_PREDICTION_STATE_END);

              // Test if bottom slot can be remove
              if (end)
                {
                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UFPT [%d][%d]",i,bottom);
                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UFPT [%d][%d].state =  UPDATE_FETCH_PREDICTION_STATE_EMPTY",i,bottom);
                  
                  // Free slot
                  reg_UPDATE_FETCH_PREDICTION_TABLE [i][bottom]._state = UPDATE_FETCH_PREDICTION_STATE_EMPTY;
                  // Update pointer
                  bottom = (bottom+1)%_param->_size_ufpt_queue[i];

                  reg_UFPT_BOTTOM [i] = bottom;
                }
            }

            // -----------------------
            // UPDATE_PREDICTION_TABLE
            // -----------------------
            {
              uint32_t bottom = reg_UPT_BOTTOM [i];

//               if (reg_UPT_EVENT_STATE [i] == UPT_EVENT_STATE_OK)
                {
                  bool     end    = (reg_UPDATE_PREDICTION_TABLE [i][bottom]._state == UPDATE_PREDICTION_STATE_END);
                  
                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UPT_BOTTOM (before) : %d",bottom);
                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * state is STATE_END      : %d",end);
                  
                  if (end)
                    {
#if defined(DEBUG) and defined(DEBUG_Update_Prediction_Table) and (DEBUG_Update_Prediction_Table == true)
                      if (reg_UPDATE_PREDICTION_TABLE [i][bottom]._retire_ok)
                        {
                          uint32_t num_thread = _param->_translate_num_context_to_num_thread [i];
                          branchement_log_file [num_thread] 
                            << std::hex
                            << "0x" << std::setfill('0') << std::setw(_param->_size_general_data/4) << reg_UPDATE_PREDICTION_TABLE [i][bottom]._address_src  << " "
                            << "0x" << std::setfill('0') << std::setw(_param->_size_general_data/4) << reg_UPDATE_PREDICTION_TABLE [i][bottom]._address_dest << " "
                            << std::dec
                            <<         reg_UPDATE_PREDICTION_TABLE [i][bottom]._good_take         << " - "
                            << "["  << simulation_cycle() << "] " << " "
                            <<         reg_UPDATE_PREDICTION_TABLE [i][bottom]._miss_prediction   << " "
                            <<         reg_UPDATE_PREDICTION_TABLE [i][bottom]._ifetch_prediction << " "
                            << "("  << toString(reg_UPDATE_PREDICTION_TABLE [i][bottom]._condition) << ")"
                            << std::endl;
                        }
#endif
                      
                      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UPT [%d][%d]",i,bottom);
                      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UPT [%d][%d]._state =  UPDATE_PREDICTION_STATE_EMPTY",i,bottom);
                      // Free slot
                      reg_UPDATE_PREDICTION_TABLE [i][bottom]._state = UPDATE_PREDICTION_STATE_EMPTY;
                      
                      // Update pointer
                      reg_UPT_BOTTOM [i] = (bottom+1)%_param->_size_upt_queue[i];
                      
                      // Free a slot, test if bottom pointer overtake the top pointer
                      if (reg_UPT_BOTTOM [i] == reg_UPT_TOP [i])
                        reg_UPT_EMPTY [i] = true; // free a slot
                      
                      reg_EVENT_UPT_FULL [i] = false;
                    }
                  
                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UPT_BOTTOM (after ) : %d",reg_UPT_BOTTOM         [i]);
                }
            }
	  }

        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * GARBAGE COLLECTOR (END)");

	// ===================================================================
	// =====[ PREDICT ]===================================================
	// ===================================================================
        
        // An ifetch_unit compute next cycle and have an branch : predict_val is set
        //   * Alloc new entry -> new status is "wait decod"
        //   * Save input (to restore in miss or error)
        //   * Update pointer

	for (uint32_t i=0; i<_param->_nb_inst_predict; i++)
          // Test if have a transaction
	  if (PORT_READ(in_PREDICT_VAL[i]) and internal_PREDICT_ACK [i])
	    {
              // get transaction information
	      Tcontext_t          context     = (_param->_have_port_context_id)?PORT_READ(in_PREDICT_CONTEXT_ID [i]):0;
	      uint32_t            top         = internal_PREDICT_UPDATE_PREDICTION_ID [i];
              Tbranch_condition_t condition   = PORT_READ(in_PREDICT_BTB_CONDITION [i]);
              bool                is_accurate = (_param->_always_accurate_predict or 
                                                 (_param->_can_accurate_predict and PORT_READ(in_PREDICT_BTB_IS_ACCURATE [i])));


	      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * PREDICT[%d] - Accepted",i);
	      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * context     : %d",context);
	      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * top         : %d",top);
	      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * condition   : %d",condition);
	      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * is_accurate : %d",is_accurate);

#ifdef DEBUG_TEST
              if (reg_UPDATE_FETCH_PREDICTION_TABLE [context][top]._state != UPDATE_FETCH_PREDICTION_STATE_EMPTY)
                throw ERRORMORPHEO(FUNCTION,_("Predict : invalid state."));
#endif

              // Ifetch unit have fetch an instruction bundle with a branchement.
              // Insert in UFPT
              log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UFPT [%d][%d].state <- UPDATE_FETCH_PREDICTION_STATE_WAIT_DECOD (predict)",context,top);
 	      reg_UPDATE_FETCH_PREDICTION_TABLE [context][top]._state        = UPDATE_FETCH_PREDICTION_STATE_WAIT_DECOD;

              // Write information
	      reg_UPDATE_FETCH_PREDICTION_TABLE [context][top]._condition    = condition;
	      reg_UPDATE_FETCH_PREDICTION_TABLE [context][top]._address_src  = PORT_READ(in_PREDICT_BTB_ADDRESS_SRC  [i]);
	      reg_UPDATE_FETCH_PREDICTION_TABLE [context][top]._address_dest = PORT_READ(in_PREDICT_BTB_ADDRESS_DEST [i]);
	      reg_UPDATE_FETCH_PREDICTION_TABLE [context][top]._last_take    = PORT_READ(in_PREDICT_BTB_LAST_TAKE    [i]);
	      reg_UPDATE_FETCH_PREDICTION_TABLE [context][top]._is_accurate  = is_accurate;
	      reg_UPDATE_FETCH_PREDICTION_TABLE [context][top]._history      = (_param->_have_port_history)?PORT_READ(in_PREDICT_DIR_HISTORY [i]):0;
	      reg_UPDATE_FETCH_PREDICTION_TABLE [context][top]._address_ras  = PORT_READ(in_PREDICT_RAS_ADDRESS      [i]);
	      reg_UPDATE_FETCH_PREDICTION_TABLE [context][top]._index_ras    = PORT_READ(in_PREDICT_RAS_INDEX        [i]);

              // Update pointer
              reg_UFPT_TOP     [context] = (top+1)%_param->_size_ufpt_queue [context];

              // Test if this branchement need update
              if (need_update(condition))
                {
                  reg_UFPT_NB_NEED_UPDATE [context] ++;
                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UFPT_NB_NEED_UPDATE (after) : %d",reg_UFPT_NB_NEED_UPDATE [context]);
                }
	    }

	// ===================================================================
	// =====[ DECOD ]=====================================================
	// ===================================================================


        // An decod is detected by decod stage
        //   1) Hit prediction : The instruction bundle have a branch predicted in ifetch stage and it is this branch
        //      * Update state, wait_decod -> wait_end
        //      * Pop ufpt -> push upt
        //      * Update accurate register : if the predict stage have tagged this branch as not accurate, stop decod
        //   2) Miss           : The instruction bundle have a branch but it is not predicted
        //      * Flush ufpt
        //      * decod information is write in upt

	for (uint32_t i=0; i<_param->_nb_inst_decod; i++)
          // Test if have a decod transaction
	  if (PORT_READ(in_DECOD_VAL[i]) and internal_DECOD_ACK [i])
	    {
              // Read information
	      Tcontext_t          context       = (_param->_have_port_context_id)?PORT_READ(in_DECOD_CONTEXT_ID [i]):0;
	      Tcontrol_t          miss_ifetch   = PORT_READ(in_DECOD_MISS_IFETCH [i]);
	      Tcontrol_t          miss_decod    = PORT_READ(in_DECOD_MISS_DECOD  [i]);
              uint32_t            upt_ptr_write = internal_DECOD_UPT_PTR_WRITE [i];
              uint32_t            top_next      = (upt_ptr_write+1)%_param->_size_upt_queue [context];
              Tbranch_condition_t condition  ;
              Tcontrol_t          is_accurate;
              Taddress_t          address_src   = PORT_READ(in_DECOD_BTB_ADDRESS_SRC  [i]);
              Taddress_t          address_dest  = PORT_READ(in_DECOD_BTB_ADDRESS_DEST [i]);
              Tcontrol_t          direction     = PORT_READ(in_DECOD_BTB_LAST_TAKE    [i]);

              log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * DECOD[%d] - Accepted",i);
	      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * context       : %d",context);
	      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * miss_ifetch   : %d",miss_ifetch);
	      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * miss_decod    : %d",miss_decod);
	      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * upt_ptr_write : %d",upt_ptr_write);

              // In decod step, two miss type :
              // miss_ifetch = branch is previously predict (predict interface), but it's not the good
              // miss_decod  = branch was not detected
              if (not (miss_ifetch or miss_decod))
		{
		  // Normal case : branch is previous predicted, change state of branch

                  // Read ufpt_ptr (send in predic step)
                  uint32_t ufpt_ptr_read = (_param->_have_port_depth)?PORT_READ(in_DECOD_UPDATE_PREDICTION_ID [i]):0;

                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * ufpt_ptr_read : %d",ufpt_ptr_read);

#ifdef DEBUG_TEST
                  if (reg_UPDATE_FETCH_PREDICTION_TABLE [context][ufpt_ptr_read]._state != UPDATE_FETCH_PREDICTION_STATE_WAIT_DECOD)
                    throw ERRORMORPHEO(FUNCTION,_("Decod : invalid ufpt state."));
#endif
                  // Change state
                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UFPT [%d][%d].state <- UPDATE_FETCH_PREDICTION_STATE_END (decod - hit)",context,ufpt_ptr_read);
                  reg_UPDATE_FETCH_PREDICTION_TABLE [context][ufpt_ptr_read]._state = UPDATE_FETCH_PREDICTION_STATE_END;

                  // Push upt (from Pop ufpt)
                  condition   = reg_UPDATE_FETCH_PREDICTION_TABLE [context][ufpt_ptr_read]._condition;
                  is_accurate = reg_UPDATE_FETCH_PREDICTION_TABLE [context][ufpt_ptr_read]._is_accurate;

                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._condition         = condition;
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._address_src       = reg_UPDATE_FETCH_PREDICTION_TABLE [context][ufpt_ptr_read]._address_src ;
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._address_dest      = reg_UPDATE_FETCH_PREDICTION_TABLE [context][ufpt_ptr_read]._address_dest;
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._last_take         = reg_UPDATE_FETCH_PREDICTION_TABLE [context][ufpt_ptr_read]._last_take   ;
//                reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._good_take;
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._is_accurate       = is_accurate;
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._history           = reg_UPDATE_FETCH_PREDICTION_TABLE [context][ufpt_ptr_read]._history     ;
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._address_ras       = reg_UPDATE_FETCH_PREDICTION_TABLE [context][ufpt_ptr_read]._address_ras ;
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._index_ras         = reg_UPDATE_FETCH_PREDICTION_TABLE [context][ufpt_ptr_read]._index_ras   ;
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._ifetch_prediction = true ; // prediction from ifetch

                  // Update pointer (now, this instruction is not in ufpt)
                  if (need_update(condition))
                    {
                      reg_UFPT_NB_NEED_UPDATE [context] --;
                      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UFPT_NB_NEED_UPDATE (after) : %d",reg_UFPT_NB_NEED_UPDATE [context]);
                    }
		}
              else
                {
                  // Have a miss !!!
                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * miss !!!");

                  condition   = PORT_READ(in_DECOD_BTB_CONDITION [i]);
                  is_accurate = (_param->_always_accurate_decod or 
                                 (_param->_can_accurate_decod and PORT_READ(in_DECOD_IS_ACCURATE [i])));

                  // if can_continue, don't wait the end of all instruction 
                  // (can_continue = not miss_commit and the destination is accurate (know))
                  Tcontrol_t can_continue = is_accurate;

#ifdef DEBUG_TEST
                  if (reg_UPT_EVENT_STATE [context] != UPT_EVENT_STATE_OK)
                    throw ERRORMORPHEO(FUNCTION,_("Decod : invalid upt event state."));
                  if (reg_UFPT_EVENT_STATE [context] != UFPT_EVENT_STATE_OK)
                    throw ERRORMORPHEO(FUNCTION,_("Decod : invalid ufpt event state."));
#endif

                  // miss_ifetch -> need flush ufpt
                  // miss_decod  -> not necessary
                  // if can_continue (destination is know) and direction is not take (instruction in ifetch_queue can be valid)
                  bool flush_ufpt = (not (can_continue and not direction and not miss_ifetch));

                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * can_continue: %d",can_continue);
                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * direction   : %d",direction   );
                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * miss_ifetch : %d",miss_ifetch );
                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * flush_ufpt: %d",flush_ufpt  );

                  // Test if can continue without flushing the ufpt (and ifetch_queue)
                  if (flush_ufpt)
                    {
//                       // Optimisation : Test if ufpt have entry that need update prediction struction (as Return Address Stack)
//                       if (reg_UFPT_NB_NEED_UPDATE [context] == 0)
//                         {
//                           // Change state
//                           log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UPT_EVENT [%d] <- UPT_EVENT_STATE_KO_COMMIT_UPDATE_CONTEXT (decod - miss - no flush ufpt)",context);
//                           reg_UPT_EVENT_STATE [context] = UPT_EVENT_STATE_KO_COMMIT_UPDATE_CONTEXT;

//                           // @@@
// //                           // Have an actual event ?
// //                           if (not reg_EVENT_VAL [context])
// //                             reg_EVENT_UPT_PTR  [context] = upt_ptr_write;
//                         }
//                       else
//                         {
//                           log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * EVENT [%d] <- UPT_EVENT_STATE_KO_MISS_WAIT_UFPT (decod - miss - flush ufpt)",context);
//                           // just wait ufpt, don't flush upt
//                           reg_UPT_EVENT_STATE [context] = UPT_EVENT_STATE_KO_MISS_WAIT_UFPT;
//                         }

                      reg_UPT_EVENT_STATE [context] = UPT_EVENT_STATE_KO_DECODE_UPDATE_CONTEXT;
                      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UPT_EVENT_STATE [%d] <- %s (decod, miss)",context,toString(reg_UPT_EVENT_STATE [context]).c_str());

                      // Need Flush UPFT
                      flush_UFPT [context] = true;

                      // Write information
//                       reg_EVENT_IS_BRANCH       [context] = true;
                      reg_EVENT_DEPTH           [context] = upt_ptr_write;
                      reg_EVENT_ADDRESS_SRC     [context] = address_src; // delay_slot is compute in Context_State
                      reg_EVENT_ADDRESS_DEST_VAL[context] = direction;
                      reg_EVENT_ADDRESS_DEST    [context] = address_dest;
                      reg_EVENT_CAN_CONTINUE    [context] = can_continue;
                    }
                  // else can continue

                  // Push upt (from decod interface)
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._condition         = condition;
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._address_src       = address_src ;
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._address_dest      = address_dest;
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._last_take         = direction   ;
//                reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._good_take;
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._is_accurate       = is_accurate;
//                reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._history           = ; // static prediction
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._address_ras       = PORT_READ(in_DECOD_RAS_ADDRESS [i]);
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._index_ras         = PORT_READ(in_DECOD_RAS_INDEX   [i]);
                  reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._ifetch_prediction = false; // static prediction
		}

              // In all case !!!
#ifdef DEBUG_TEST
              if (reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._state != UPDATE_PREDICTION_STATE_EMPTY)
                throw ERRORMORPHEO(FUNCTION,_("Decod : invalid upt state."));
#endif
              
              // Change state
              log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UPT  [%d][%d].state <- UPDATE_PREDICTION_STATE_WAIT_END (decod - hit)",context,upt_ptr_write);
              reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._state       = UPDATE_PREDICTION_STATE_WAIT_END;
              reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._retire_ok   = false;
              reg_UPDATE_PREDICTION_TABLE [context][upt_ptr_write]._miss_commit = false;

              // Write new accurate 
#ifdef DEBUG_TEST
              if (not reg_IS_ACCURATE [context]  and not is_accurate)
                throw ERRORMORPHEO(FUNCTION,_("Decod : invalid accurate flag."));
#endif

              log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * is_accurate : %d",is_accurate);

              reg_IS_ACCURATE [context] = is_accurate;
              
              // Update pointer
              reg_UPT_TOP     [context] = top_next;
              reg_UPT_EMPTY   [context] = false; // new instruction
	    }

	// ===================================================================
	// =====[ UPDATE ]====================================================
	// ===================================================================
        {
          bool can_continue [_param->_nb_context];
          for (uint32_t i=0; i<_param->_nb_context; ++i)
            can_continue [i] = true;

          // For each updated instruction
          for (uint32_t i=0; i<_param->_nb_inst_update; i++)
            {
	      Tcontext_t context   = internal_UPDATE_CONTEXT_ID [i];

              // Test if transaction
              // (an val_with_out is an update and don't need update prediction structure
              if ((internal_UPDATE_VAL[i] and PORT_READ(in_UPDATE_ACK [i])) or
                  (internal_UPDATE_VAL_WITHOUT_ACK [i] and can_continue [context]))
                {
                  Tdepth_t   depth     = internal_UPDATE_DEPTH [i];
                  
                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * UPDATE[%d] - Accepted",i);
                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * context : %d",context);
                  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * depth   : %d",depth);
                  
                  upt_event_state_t upt_event_state = reg_UPT_EVENT_STATE [context];

                  // One interface to two source : 
                  //   * from ufpt -> newest prediction
                  //   * from upt  -> oldest prediction
                  if (internal_UPDATE_FROM_UFPT [i])
                    {
                      // if free a slot, also all queue is updated
                      // Last slot ?
                      if ((--reg_UFPT_NB_UPDATE [context])==0)
                        {
                          log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UFPT_EVENT [%d] <- UFPT_EVENT_STATE_OK (update - end flush ufpt)",context);
                          reg_UFPT_EVENT_STATE    [context] = UFPT_EVENT_STATE_OK;
                          reg_UFPT_NB_NEED_UPDATE [context] = 0;

//                           // Test upt event to change state
//                           // test if upt wait ufpt
//                           switch (upt_event_state)
//                             {
//                               // this case when don't need flush upt (miss decod and can continue)
//                             case UPT_EVENT_STATE_KO_MISS_WAIT_UFPT  : upt_event_state = UPT_EVENT_STATE_KO_COMMIT_UPDATE_CONTEXT; break;
//                             case UPT_EVENT_STATE_KO_EVENT_WAIT_UFPT : upt_event_state = UPT_EVENT_STATE_OK               ; break;
//                             default : break;
//                             }

//                           reg_UPT_EVENT_STATE [context] = upt_event_state;
                        }
                      
                      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * Update Fetch Prediction Table");
                      
                      // Change state
#ifdef DEBUG_TEST
                      if (reg_UPDATE_FETCH_PREDICTION_TABLE [context][depth]._state != UPDATE_FETCH_PREDICTION_STATE_EVENT)
                        throw ERRORMORPHEO(FUNCTION,_("Update : invalid ufpt state."));
#endif
                      
                      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UFPT [%d][%d].state <- UPDATE_FETCH_PREDICTION_STATE_END (update)",context,depth);
                      
                      reg_UPDATE_FETCH_PREDICTION_TABLE [context][depth]._state = UPDATE_FETCH_PREDICTION_STATE_END;
                                            
                      // Update pointer
                      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UFPT_UPDATE (before) : %d",reg_UFPT_UPDATE [context]);
                      reg_UFPT_UPDATE [context] = ((depth==0)?_param->_size_ufpt_queue[context]:depth)-1;
                      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UFPT_UPDATE (after ) : %d",reg_UFPT_UPDATE [context]);
                    }
                  else
                    {
                      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * Update Prediction Table");
                      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UPT_UPDATE (before) : %d",reg_UPT_UPDATE [context]);
                      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UPT_EVENT_STATE     : %s",toString(upt_event_state).c_str());
 
                      // Change state
#ifdef DEBUG_TEST 
                      if (internal_UPDATE_RAS [i])
                        {
                          if ((reg_UPDATE_PREDICTION_TABLE [context][depth]._state != UPDATE_PREDICTION_STATE_EVENT) and
                              (reg_UPDATE_PREDICTION_TABLE [context][depth]._state != UPDATE_PREDICTION_STATE_KO   ) )
                            throw ERRORMORPHEO(FUNCTION,_("Update : invalid upt state."));
                        }
                      else
                        {
                          if (reg_UPDATE_PREDICTION_TABLE [context][depth]._state != UPDATE_PREDICTION_STATE_OK   )
                            throw ERRORMORPHEO(FUNCTION,_("Update : invalid upt state."));
                        }
#endif

#ifdef STATISTICS
                      Tbranch_condition_t condition = reg_UPDATE_PREDICTION_TABLE [context][depth]._condition;
#endif
                      bool ok = (reg_UPDATE_PREDICTION_TABLE [context][depth]._state == UPDATE_PREDICTION_STATE_OK);
                      bool ko = (reg_UPDATE_PREDICTION_TABLE [context][depth]._state == UPDATE_PREDICTION_STATE_KO);

                      // Test if branch is valid (prediction can be incorrect)
                      if (ok or ko)
                        {
                          reg_UPDATE_PREDICTION_TABLE [context][depth]._retire_ok       = true;
                          reg_UPDATE_PREDICTION_TABLE [context][depth]._miss_prediction = ko;

#ifdef STATISTICS
                          if (usage_is_set(_usage,USE_STATISTICS))
			    {
			      if (reg_UPDATE_PREDICTION_TABLE [context][depth]._ifetch_prediction)
				(*_stat_nb_branch_ifetch_prediction [context])++;
			      if (reg_UPDATE_PREDICTION_TABLE [context][depth]._is_accurate)
				(*_stat_nb_branch_accurate          [context])++;
			    }
#endif
                        }

                      // Have an update, test the state to transiste to the good state
                      if (ko)
                        {
                          // Ko
                          log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UPT  [%d][%d].state <- UPDATE_PREDICTION_STATE_END_KO (update)",context,depth);
                          
                          // Wait update of context_state
                          reg_UPDATE_PREDICTION_TABLE [context][depth]._state = UPDATE_PREDICTION_STATE_END_KO;

                          reg_EVENT_UPT_PTR  [context] = depth;

#ifdef STATISTICS
                          if (usage_is_set(_usage,USE_STATISTICS))
                            (*_stat_nb_branch_miss [context][condition])++;
#endif
                        }
                      else
                        {
                          // ok or event

                          log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UPT  [%d][%d].state <- UPDATE_PREDICTION_STATE_END (update)",context,depth);
                          reg_UPDATE_PREDICTION_TABLE [context][depth]._state = UPDATE_PREDICTION_STATE_END;

#ifdef STATISTICS
                          if (usage_is_set(_usage,USE_STATISTICS))
                            {
                              if (ok)
                                (*_stat_nb_branch_hit    [context][condition]) ++;
                              else
                                (*_stat_nb_branch_unused [context]) ++;
                            }
#endif
                        }
                      
                      // Test if freeing the branch with no accurate ?
                      if ((reg_UPDATE_PREDICTION_TABLE [context][depth]._is_accurate == false) and not ko)
                        reg_IS_ACCURATE [context] = true;

                      // Update pointer
                      //  * if update RAS : update pointer is decreaste until it equal at top pointer
                      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * internal_UPDATE_RAS [%d] : %d",i,internal_UPDATE_RAS [i]);
                      
                      if (internal_UPDATE_RAS [i])
                        {
                          // if end_event, restart too bottom, else decrease pointer
                          bool end_event  = (reg_UPT_UPDATE [context] == reg_UPT_TOP [context]);

                          log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * end_event               : %d",end_event);
                          log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * bottom                  : %d",reg_UPT_BOTTOM[context]);
                          
                          if (end_event)
                            {
                              reg_UPT_UPDATE [context] = (end_event)?reg_UPT_BOTTOM[context]:(((depth==0)?_param->_size_upt_queue[context]:depth)-1);
//                            reg_UPT_UPDATE [context] = reg_UPT_BOTTOM[context];

                              switch (upt_event_state)
                                {
                                  // this case when don't need flush upt (miss decod and can continue)
                                case UPT_EVENT_STATE_KO_MISS_FLUSH_UPT  : upt_event_state = UPT_EVENT_STATE_KO_COMMIT_UPDATE_CONTEXT; break;
                                case UPT_EVENT_STATE_KO_EVENT_FLUSH_UPT : 
                                  {
                                    upt_event_state = UPT_EVENT_STATE_OK;
                                    reg_UPT_TOP    [context] = reg_UPT_TOP_EVENT [context];
                                    reg_UPT_UPDATE [context] = reg_UPT_TOP_EVENT [context];

                                    break;
                                  }
                                default : break;
                                }
                              
                            }
                          else
                            {
                              // else, decrease update pointer
                              reg_UPT_UPDATE [context] = (((depth==0)?_param->_size_upt_queue[context]:depth)-1);
                            }
                        }
                      else
                        {
                          log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * next update");
                          
                          // increase pointer
                          reg_UPT_UPDATE [context] = (depth+1)%_param->_size_upt_queue[context];
                        }
                      
                      // special case :
                      if ((upt_event_state == UPT_EVENT_STATE_KO_COMMIT_WAIT_END_UPDATE) and
                          (reg_UPT_UPDATE [context] == reg_EVENT_UPT_PTR [context]))
                        {
                          reg_UPT_TOP     [context] = reg_UPT_TOP_EVENT [context];
                          reg_UPT_UPDATE  [context] = reg_UPT_TOP_EVENT [context];
                          reg_IS_ACCURATE [context] = true;

                          upt_event_state = UPT_EVENT_STATE_OK;
                        }

                      reg_UPT_EVENT_STATE [context] = upt_event_state;

                      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UPT_UPDATE (after ) : %d",reg_UPT_UPDATE[context]);
                      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UPT_EVENT_STATE     : %s",toString(reg_UPT_EVENT_STATE [context]).c_str());
                    }
                }
              else
                can_continue [context] = false;
            }
	
          // Round robin
          reg_UPDATE_PRIORITY = (reg_UPDATE_PRIORITY+1)%_param->_nb_context;
        }

	// ===================================================================
	// =====[ BRANCH_COMPLETE ]===========================================
	// ===================================================================
        
        // The branch is complete
        //   * Hit  prediction : 
        //     * update status
        //   * Miss prediction :
        {
          bool branch_complete_miss [_param->_nb_context];
          for (uint32_t i=0; i<_param->_nb_context; ++i)
            branch_complete_miss [i] = false;

          for (uint32_t i=0; i<_param->_nb_inst_branch_complete; i++)
            if (PORT_READ(in_BRANCH_COMPLETE_VAL[i]) and internal_BRANCH_COMPLETE_ACK [i])
              {
                // Read information
                Tcontext_t context   = (_param->_have_port_context_id)?PORT_READ(in_BRANCH_COMPLETE_CONTEXT_ID [i]):0;
                Tdepth_t   depth     = (_param->_have_port_depth     )?PORT_READ(in_BRANCH_COMPLETE_DEPTH      [i]):0;
                Tcontrol_t miss      = internal_BRANCH_COMPLETE_MISS_PREDICTION [i];
                Tcontrol_t good_take = internal_BRANCH_COMPLETE_TAKE            [i];
                Taddress_t good_addr = internal_BRANCH_COMPLETE_ADDRESS_DEST    [i];
                
                upt_event_state_t upt_event_state  = reg_UPT_EVENT_STATE [context];
                
                log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * BRANCH_COMPLETE[%d] - Accepted",i);
                log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * context             : %d",context);
                log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * depth               : %d",depth);
                log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * miss                : %d",miss);
                log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UPT_EVENT_STATE : %s",toString(upt_event_state).c_str());
                
                // Test if the completed branch is a speculation miss
                if (miss)
                  {
                    // special case : two branch complete on the same context.
                    // when the re order keep the order, the branch complete j is most speculative that the branch comple i if i < j
                    if (not branch_complete_miss [context])
                      {
                        branch_complete_miss [context] = true;
                        // Flush UPT
                        // get information
                        uint32_t          top                 = reg_UPT_TOP [context];
                        uint32_t          new_update          = ((top==0)?_param->_size_upt_queue[context]:top)-1; 
                        
                        Taddress_t        address_src         = reg_UPDATE_PREDICTION_TABLE [context][depth]._address_src;
                        upt_state_t       top_state           = reg_UPDATE_PREDICTION_TABLE [context][top]._state;
                        
                        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * upt_event_state     : %s",toString(upt_event_state).c_str());
                        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * top_state           : %s",toString(top_state).c_str());
                        
                        bool              previous_ufpt_event = (reg_UFPT_EVENT_STATE [context] == UFPT_EVENT_STATE_KO_FLUSH);
                        
                        
                        bool              previous_upt_event  = (false
                                                                 or (upt_event_state == UPT_EVENT_STATE_KO_MISS_WAIT_UFPT )
                                                                 or (upt_event_state == UPT_EVENT_STATE_KO_MISS_FLUSH_UPT )
                                                                 or (upt_event_state == UPT_EVENT_STATE_KO_EVENT_WAIT_UFPT)
                                                                 or (upt_event_state == UPT_EVENT_STATE_KO_EVENT_FLUSH_UPT)
                                                                 or (upt_event_state == UPT_EVENT_STATE_KO_COMMIT_WAIT_END_UPDATE)
                                                                 or (top_state       == UPDATE_PREDICTION_STATE_END_KO    )
                                                                 or (top_state       == UPDATE_PREDICTION_STATE_KO        )
                                                                 );
                        
                        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * top                 : %d",top);
                        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * new_update          : %d",new_update);
                        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * previous_upt_event  : %d",previous_upt_event);
                        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * previous_ufpt_event : %d",previous_ufpt_event);
                        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UPT_UPDATE      : %d",reg_UPT_UPDATE [context]);
                        
                        // Have a miss !!!
                        // Flush UPFT
                        flush_UFPT [context] |= not previous_ufpt_event;
                        
                        // Test if the entry wait the branchment (else, they have a previous event)
                        if (reg_UPDATE_PREDICTION_TABLE [context][depth]._state == UPDATE_PREDICTION_STATE_WAIT_END)
                          {
                            // All instruction between the instruction and the top is disable
                            for (uint32_t j=(depth+1)%_param->_size_upt_queue[context];
                                 j!=top; 
                                 j=(j+1)%_param->_size_upt_queue[context])
                              {
                                reg_UPDATE_PREDICTION_TABLE [context][j]._state     = UPDATE_PREDICTION_STATE_EVENT;
                                reg_UPDATE_PREDICTION_TABLE [context][j]._retire_ok = false; // event
                              }
                            
                            // New top
                            reg_UPT_TOP       [context] = depth;
                            
                            if (not previous_upt_event)
                              {
                                reg_UPT_TOP_EVENT [context] = top;
                                reg_UPT_UPDATE    [context] = new_update;
                              }
                            else
                              {
                                // Have event. Top index this slot
                                reg_UPDATE_PREDICTION_TABLE [context][top]._retire_ok = false;
                                
                                switch (top_state)
                                  {
                                  case UPDATE_PREDICTION_STATE_END_KO : 
                                  case UPDATE_PREDICTION_STATE_END    : 
                                    {
                                      // Have already update predictor
                                      reg_UPDATE_PREDICTION_TABLE [context][top]._state = UPDATE_PREDICTION_STATE_END;
                                      reg_UPT_UPDATE              [context] = new_update;
                                      break;
                                    }
                                  case UPDATE_PREDICTION_STATE_KO :
                                    {
                                      // Doesn't have update predictor
                                      reg_UPDATE_PREDICTION_TABLE [context][top]._state = UPDATE_PREDICTION_STATE_EVENT;
                                      break;
                                    }
                                  default :
                                    {
                                      //                                 reg_UPDATE_PREDICTION_TABLE [context][top]._state = UPDATE_PREDICTION_STATE_EVENT;
//                                 break;
                                      
#ifdef DEBUG_TEST
                                      throw ERRORMORPHEO(FUNCTION,_("Branch complete : invalid upt state."));
#endif
                                    }
                                  }
                              }
                            
                            if (reg_UPT_BOTTOM [context] == reg_UPT_TOP [context])
                              reg_UPT_EMPTY [context] = true;
                            
                            log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UPT  [%d][%d].state <- UPDATE_PREDICTION_STATE_KO (branch_complete, ifetch hit)",context,depth);
                            reg_UPDATE_PREDICTION_TABLE [context][depth]._state = UPDATE_PREDICTION_STATE_KO;
                            
                            log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UFPT_NB_NEED_UPDATE [%d] : %d",context,reg_UFPT_NB_NEED_UPDATE [context]);
                            
//                       if ( (reg_UFPT_NB_NEED_UPDATE [context] > 0) or
//                            (reg_UFPT_NB_UPDATE      [context] > 0))
//                         {
//                           log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * EVENT [%d] <- EVENT_STATE_MISS_FLUSH_UFPT_AND_UPT (branch_complete - miss)",context);
//                           reg_EVENT_STATE [context] = EVENT_STATE_MISS_FLUSH_UFPT_AND_UPT;
//                         }
//                       else
//                         {
// //                        if (not previous_update_ras)
//                           {
//                             // have ras prediction ?
//                             log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * EVENT [%d] <- EVENT_STATE_MISS_FLUSH_UPT (branch_complete - miss)",context);
                            
//                             reg_EVENT_STATE [context] = EVENT_STATE_MISS_FLUSH_UPT;
                            
//                           }
//                         }

                            reg_UPT_EVENT_STATE [context] = UPT_EVENT_STATE_KO_MISS_FLUSH_UPT;
                            log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UPT_EVENT_STATE [%d] <- %s (branch_complete, ifetch hit)",context,toString(reg_UPT_EVENT_STATE [context]).c_str());
                            
                            //                       reg_EVENT_SOURCE          [context] = EVENT_SOURCE_UPT;
                            
                            // else no update
                            
                            //                       reg_EVENT_IS_BRANCH       [context] = true;
                            reg_EVENT_DEPTH           [context] = depth;
                            reg_EVENT_ADDRESS_SRC     [context] = address_src; // delay_slot is compute in Context_State
                            reg_EVENT_ADDRESS_DEST_VAL[context] = good_take;
                            reg_EVENT_ADDRESS_DEST    [context] = good_addr;
                            reg_EVENT_CAN_CONTINUE    [context] = false;
                            
                          }
                        
                        reg_UPDATE_PREDICTION_TABLE [context][depth]._miss_commit = true;
                      }
                  }
                else
                  {
                  // Hit case

// #ifdef DEBUG_TEST
//                   if (reg_UPDATE_PREDICTION_TABLE [context][depth]._state != UPDATE_PREDICTION_STATE_WAIT_END)
//                     throw ERRORMORPHEO(FUNCTION,_("Branch complete : invalid upt state."));
// #endif

                  // In same cycle, can have a previous branch_complete
                    if (reg_UPDATE_PREDICTION_TABLE [context][depth]._state == UPDATE_PREDICTION_STATE_WAIT_END)
                      {
                        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UPT  [%d][%d].state <- UPDATE_PREDICTION_STATE_OK (branch_complete, ifetch hit)",context,depth);
                        reg_UPDATE_PREDICTION_TABLE [context][depth]._state = UPDATE_PREDICTION_STATE_OK;
                      }
                  }
                
                log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UPT_EVENT_STATE : %s",toString(reg_UPT_EVENT_STATE [context]).c_str());
                
                // In all case : update good_take
                reg_UPDATE_PREDICTION_TABLE [context][depth]._good_take    = good_take;
                
                // Write address_dest if need read register
                Tbranch_condition_t condition = reg_UPDATE_PREDICTION_TABLE [context][depth]._condition;
                
                if ((condition == BRANCH_CONDITION_READ_REGISTER_WITHOUT_WRITE_STACK) or
                    (condition == BRANCH_CONDITION_READ_REGISTER_WITH_WRITE_STACK   ) or
                    (condition == BRANCH_CONDITION_READ_STACK                       ) )
                  reg_UPDATE_PREDICTION_TABLE [context][depth]._address_dest = good_addr;
              }
        }

 	// ===================================================================
	// =====[ BRANCH_EVENT ]==============================================
	// ===================================================================
	for (uint32_t i=0; i<_param->_nb_context; i++)
	  if (internal_BRANCH_EVENT_VAL [i] and PORT_READ(in_BRANCH_EVENT_ACK [i]))
            {
	      log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * BRANCH_EVENT [%d] - Accepted",i);

              upt_event_state_t upt_event_state  = reg_UPT_EVENT_STATE [i];
              
              switch (upt_event_state)
                {
                case UPT_EVENT_STATE_KO_DECODE_UPDATE_CONTEXT : upt_event_state = UPT_EVENT_STATE_KO_DECODE_WAIT_END_EVENT; break;
                case UPT_EVENT_STATE_KO_COMMIT_UPDATE_CONTEXT : upt_event_state = UPT_EVENT_STATE_KO_COMMIT_WAIT_END_EVENT; break;
                default : break; // an other branch is occured
                }

              reg_UPT_EVENT_STATE [i] = upt_event_state;
              log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UPT_EVENT_STATE : %s (branch_event)",toString(upt_event_state).c_str());
            }

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

              //----------------------------------------------------------------
              // Cases
              //----------------------------------------------------------------
              //   * EVENT_TYPE_NONE               - nothing
              //   * EVENT_TYPE_MISS_SPECULATION   - Change state, reset pointer
              //   * EVENT_TYPE_EXCEPTION          - Flush upft and upt, Change state, reset pointer
              //   * EVENT_TYPE_BRANCH_NO_ACCURATE - nothing : manage in decod and update
              //   * EVENT_TYPE_SPR_ACCESS         - nothing
              //   * EVENT_TYPE_MSYNC              - nothing
              //   * EVENT_TYPE_PSYNC              - nothing
              //   * EVENT_TYPE_CSYNC              - nothing
              
              Tevent_type_t     event_type      = PORT_READ(in_EVENT_TYPE  [i]);
              upt_event_state_t upt_event_state = reg_UPT_EVENT_STATE [i];

              // Test if end of miss -> all previous branch is complete
              //                     -> all next     branch is finish

              switch (event_type)
                {
                case EVENT_TYPE_BRANCH_MISS_SPECULATION :
                  {
                    log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * type  : EVENT_TYPE_BRANCH_MISS_SPECULATION");

                    switch (upt_event_state)
                      {
                      case UPT_EVENT_STATE_KO_COMMIT_WAIT_END_EVENT :
                        {
                          Tdepth_t depth  = reg_EVENT_UPT_PTR [i];
                          Tdepth_t update = reg_UPT_UPDATE    [i];
                          
                          log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * depth : %d",depth);
                          
                          if (reg_UPDATE_PREDICTION_TABLE [i][depth]._state == UPDATE_PREDICTION_STATE_END_KO)
                            {
                              log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UPT  [%d][%d].state <- UPDATE_PREDICTION_STATE_END (event)",i,depth);
                              
                              reg_UPDATE_PREDICTION_TABLE [i][depth]._state = UPDATE_PREDICTION_STATE_END;
                            }

                          // Special case : branch_complete a speculative branch and the context_state signal the end of this event before the complete of previous branch
                          if (depth != update)
                            {
                              log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * EVENT [%d] <- EVENT_STATE_COMMIT_WAIT_END_UPDATE (event)",i);
                              upt_event_state = UPT_EVENT_STATE_KO_COMMIT_WAIT_END_UPDATE;

                              break; // stop here
                             }

                          reg_UPT_TOP    [i] = reg_UPT_TOP_EVENT [i];
                          reg_UPT_UPDATE [i] = reg_UPT_TOP_EVENT [i];

//                             break; continue
                        }
                      case UPT_EVENT_STATE_KO_DECODE_WAIT_END_EVENT :
                        {
                          // Change state
                          log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * EVENT [%d] <- EVENT_STATE_OK (event)",i);
                          
                          upt_event_state = UPT_EVENT_STATE_OK;
                          reg_IS_ACCURATE [i] = true;

                          break;
                        }
                      default : break; // an other branch is occured
                      }

                    break;
                  }
                case EVENT_TYPE_LOAD_MISS_SPECULATION :
                case EVENT_TYPE_EXCEPTION             :
                  {
                    log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * type  : EVENT_TYPE_LOAD_MISS_SPECULATION");

                    // Have a miss !!!
                    // Flush UPFT
                    flush_UFPT [i] = true;

                    if (upt_event_state == UPT_EVENT_STATE_KO_COMMIT_WAIT_END_UPDATE)
                      {
                        reg_UPT_TOP     [i] = reg_UPT_TOP_EVENT [i];
                        reg_UPT_UPDATE  [i] = reg_UPT_TOP_EVENT [i];
                        reg_IS_ACCURATE [i] = true;
                        
                        upt_event_state = UPT_EVENT_STATE_OK;
                      }
                    
                    // Flush UPT
                    uint32_t bottom = reg_UPT_BOTTOM [i];

                    log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * bottom     : %d",bottom);

//                     event_state_t event_state         = reg_EVENT_STATE [i];
//                     bool          previous_update_ras = ((event_state == EVENT_STATE_MISS_FLUSH_UFPT_AND_UPT ) or
//                                                          (event_state == EVENT_STATE_MISS_FLUSH_UPT          ) or
//                                                          (event_state == EVENT_STATE_EVENT_FLUSH_UFPT_AND_UPT) or
//                                                          (event_state == EVENT_STATE_EVENT_FLUSH_UPT));

                    bool     find     = false; // have slot to update ???
                    bool     find_top = false;
                    Tdepth_t top      = bottom;
                    Tdepth_t update   = bottom;
                    bool     empty    = reg_UPT_EMPTY [i];

                    // flush all slot, because this event is in head of rob
                    for (uint32_t j=0; j<_param->_size_upt_queue[i]; ++j)
                      {
                        Tdepth_t x = (bottom+j)%_param->_size_upt_queue[i];

                        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * UPT [%d] : %s",x,toString(reg_UPDATE_PREDICTION_TABLE [i][x]._state).c_str());
                        
                        if ((reg_UPDATE_PREDICTION_TABLE [i][x]._state != UPDATE_PREDICTION_STATE_END) and
                            (reg_UPDATE_PREDICTION_TABLE [i][x]._state != UPDATE_PREDICTION_STATE_EMPTY))
                          {
                            log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * find at UPT[%d]",x);

                            find = true; // find a not empty slot
                            reg_UPDATE_PREDICTION_TABLE [i][x]._state     = UPDATE_PREDICTION_STATE_EVENT;
                            reg_UPDATE_PREDICTION_TABLE [i][x]._retire_ok = false;
                            update = x;
                          }

                        if (reg_UPDATE_PREDICTION_TABLE [i][x]._state != UPDATE_PREDICTION_STATE_EMPTY)
                          if (not find_top)
                            {
                              top = x;
                              find_top = true;
                            }
                      }

                    log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * find       : %d",find);
                    log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * top        : %d",top);
                    log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * update     : %d",update);
                    
                    // Test if have update slot
                    reg_UPT_TOP_EVENT [i] = reg_UPT_TOP[i];
                    if (find)
                      {
                        // TODO : special case : event is an exception on branch, also depth is not valid
                        reg_UPT_TOP       [i] = top; // depth is again valid
                        
                        if (bottom == reg_UPT_TOP [i])
                          reg_UPT_EMPTY [i] = true;

                        reg_UPT_UPDATE [i]  = update;
                      }
              
                    // new state :
                    //   * test if ufpt is empty
                    //     * ok : flush upft and upt
                    //     * ko : test if have previous flush upt
                    //            * ok : nothing
                    //            * ko : flush upt
//                     reg_EVENT_VAL             [i] = find;
//                     reg_EVENT_IS_BRANCH       [i] = false;
//                     reg_EVENT_UPT_PTR         [i] = ((top==0)?_param->_size_upt_queue[i]:top)-1; ///// ZE MODIF
                    reg_EVENT_UPT_PTR         [i] = top;
                    reg_EVENT_UPT_FULL        [i] = (not empty and (bottom == reg_UPT_TOP [i]));
//                  reg_EVENT_DEPTH           [i] = PORT_READ(in_EVENT_DEPTH [i]);//(top+1)%_param->_size_upt_queue[i];
                    reg_EVENT_DEPTH           [i] = top;

//                  reg_EVENT_ADDRESS_SRC     [i] = address_src; // delay_slot is compute in I_State
//                  reg_EVENT_ADDRESS_DEST_VAL[i] = good_take;
//                  reg_EVENT_ADDRESS_DEST    [i] = good_addr;

                    log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UPT_BOTTOM                   : %d",reg_UPT_BOTTOM          [i]);
                    log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UPT_TOP                      : %d",reg_UPT_TOP             [i]);
                    log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UPT_EMPTY                    : %d",reg_UPT_EMPTY           [i]);

//                     log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_EVENT_VAL                    : %d",reg_EVENT_VAL           [i]);
                    log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_EVENT_UPT_PTR                : %d",reg_EVENT_UPT_PTR       [i]);
                    log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_EVENT_UPT_FULL               : %d",reg_EVENT_UPT_FULL      [i]);
                    log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UFPT_NB_NEED_UPDATE          : %d",reg_UFPT_NB_NEED_UPDATE [i]);
                    log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UFPT_NB_UPDATE               : %d",reg_UFPT_NB_UPDATE      [i]);

                    if (find)
                      {
                        // have ras prediction ?
                        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UPT_EVENT [%d] <- UPT_EVENT_STATE_KO_EVENT_FLUSH_UPT (event - find)",i);
                        
                        upt_event_state = UPT_EVENT_STATE_KO_EVENT_FLUSH_UPT;
                      }
                    else
                      {
                        // special case : nothing
                        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * UPT_EVENT [%d] <- UPT_EVENT_STATE_KO_EVENT_WAIT_UFPT (event - not find)",i);
                        
//                      reg_EVENT_VAL     [i] = false;
                        
                        upt_event_state = UPT_EVENT_STATE_KO_EVENT_WAIT_UFPT;
                      }

                    break;
                  }
                default :
                  {
                    // nothing
                    break;
                  }
                }

              reg_UPT_EVENT_STATE [i] = upt_event_state;
              log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UPT_EVENT_STATE : %s (branch_event)",toString(upt_event_state).c_str());
            }

 	// ===================================================================
	// =====[ FLUSH ]=====================================================
	// ===================================================================

        for (uint32_t i=0; i<_param->_nb_context; ++i)
          {
            if (flush_UFPT [i])
              {
                log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * Flush Update Fetch Prediction Table");
                log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * context                          : %d",i);
                log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UFPT_NB_NEED_UPDATE          : %d",reg_UFPT_NB_NEED_UPDATE [i]);

              // It's to accelerate miss speculation -> associative access
              if (reg_UFPT_NB_NEED_UPDATE [i] == 0)
                {
                  // No entry need prediction, flush all entry -> Reset
                  for (uint32_t j=0; j<_param->_size_ufpt_queue[i]; ++j)
                    reg_UPDATE_FETCH_PREDICTION_TABLE [i][j]._state = UPDATE_FETCH_PREDICTION_STATE_EMPTY;
                  reg_UFPT_BOTTOM [i] = 0;
                  reg_UFPT_TOP    [i] = 0;
                }
              else
                {
                  uint32_t bottom = reg_UFPT_BOTTOM [i];
                  for (uint32_t j=0; j<_param->_size_ufpt_queue[i]; ++j)
                    {
                      uint32_t index = (bottom+j)%_param->_size_ufpt_queue[i];
                      // EMPTY : no event
                      // END   : already update
                      // EVENT : previous event
                      if (reg_UPDATE_FETCH_PREDICTION_TABLE [i][index]._state == UPDATE_FETCH_PREDICTION_STATE_WAIT_DECOD)
                        {
                          reg_UFPT_UPDATE    [i] = index;
                          reg_UFPT_NB_UPDATE [i] ++;
                          reg_UPDATE_FETCH_PREDICTION_TABLE [i][index]._state = UPDATE_FETCH_PREDICTION_STATE_EVENT;
                        }
                    }

                  // Change state
                  reg_UFPT_EVENT_STATE [i] = UFPT_EVENT_STATE_KO_FLUSH;
                }

              log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UFPT_UPDATE         (after ) : %d",reg_UFPT_UPDATE [i]);

              }

            // Change state on UPT
            {
              upt_event_state_t  upt_event_state  = reg_UPT_EVENT_STATE  [i];
              ufpt_event_state_t ufpt_event_state = reg_UFPT_EVENT_STATE [i];
              
              // Test upt event to change state
              // test if upt wait ufpt
              if (ufpt_event_state == UFPT_EVENT_STATE_OK)
                switch (upt_event_state)
                  {
                    // this case when don't need flush upt (miss decod and can continue)
                  case UPT_EVENT_STATE_KO_MISS_WAIT_UFPT  : upt_event_state = UPT_EVENT_STATE_KO_COMMIT_UPDATE_CONTEXT; break;
                  case UPT_EVENT_STATE_KO_EVENT_WAIT_UFPT : upt_event_state = UPT_EVENT_STATE_OK               ; break;
                  default : break;
                  }
              
              reg_UPT_EVENT_STATE [i] = upt_event_state;
            }
          }

#ifdef STATISTICS
        if (usage_is_set(_usage,USE_STATISTICS))
          for (uint32_t i=0; i<_param->_nb_context; i++)
            {
              for (uint32_t j=0; j<_param->_size_ufpt_queue[i]; j++)
                if (reg_UPDATE_FETCH_PREDICTION_TABLE [i][j]._state != UPDATE_FETCH_PREDICTION_STATE_EMPTY)
                  (*_stat_ufpt_queue_nb_elt [i]) ++;
              for (uint32_t j=0; j<_param->_size_upt_queue[i]; j++)
                if (reg_UPDATE_PREDICTION_TABLE [i][j]._state != UPDATE_PREDICTION_STATE_EMPTY)
                  (*_stat_upt_queue_nb_elt [i]) ++;
            }
#endif
        
 	// ===================================================================
	// =====[ PRINT ]=====================================================
	// ===================================================================

#if (DEBUG >= DEBUG_TRACE)
    log_printf(TRACE,Update_Prediction_Table,FUNCTION,"  * Dump Update_Prediction_Table");
    log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_UPDATE_PRIORITY       : %d",reg_UPDATE_PRIORITY);
    for (uint32_t i=0; i<_param->_nb_context; i++)
      {
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_IS_ACCURATE           : %d",reg_IS_ACCURATE        [i]);
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_EVENT_UFPT_STATE      : %s"  ,toString(reg_UFPT_EVENT_STATE [i]).c_str());
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_EVENT_UPT_STATE       : %s"  ,toString(reg_UPT_EVENT_STATE [i]).c_str());
//         log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_EVENT_VAL             : %d"  ,reg_EVENT_VAL             [i]);
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_EVENT_UPT_PTR         : %d"  ,reg_EVENT_UPT_PTR         [i]);
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_EVENT_UPT_FULL        : %d"  ,reg_EVENT_UPT_FULL        [i]);
//         log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_EVENT_IS_BRANCH       : %d"  ,reg_EVENT_IS_BRANCH       [i]);
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_EVENT_DEPTH           : %d"  ,reg_EVENT_DEPTH           [i]);
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_EVENT_ADDRESS_SRC     : %.8x (%.8x)",reg_EVENT_ADDRESS_SRC     [i],reg_EVENT_ADDRESS_SRC     [i]<<2);
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_EVENT_ADDRESS_DEST_VAL: %d"  ,reg_EVENT_ADDRESS_DEST_VAL[i]);
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_EVENT_ADDRESS_DEST    : %.8x (%.8x)",reg_EVENT_ADDRESS_DEST    [i],reg_EVENT_ADDRESS_DEST    [i]<<2);
        log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * reg_EVENT_CAN_CONTINUE    : %d"  ,reg_EVENT_CAN_CONTINUE    [i]);

	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * Dump UFPT [%d] (Update_Fetch_Prediction_Table)",i);
	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UFPT_BOTTOM         : %d",reg_UFPT_BOTTOM         [i]);
	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UFPT_TOP            : %d",reg_UFPT_TOP            [i]);
	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UFPT_UPDATE         : %d",reg_UFPT_UPDATE         [i]);
	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UFPT_NB_NEED_UPDATE : %d",reg_UFPT_NB_NEED_UPDATE [i]);
	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UFPT_NB_UPDATE      : %d",reg_UFPT_NB_UPDATE      [i]);
	for (uint32_t j=0; j<_param->_size_ufpt_queue[i]; j++)
          {
	  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"        [%d] %.4d, %.8x (%.8x) %.8x (%.8x), %.1d   %.1d, %.8lld %.8x (%.8x) %.4d - %s",
                     j,
                     reg_UPDATE_FETCH_PREDICTION_TABLE [i][j]._condition,
                     reg_UPDATE_FETCH_PREDICTION_TABLE [i][j]._address_src,
                     reg_UPDATE_FETCH_PREDICTION_TABLE [i][j]._address_src<<2,
                     reg_UPDATE_FETCH_PREDICTION_TABLE [i][j]._address_dest,
                     reg_UPDATE_FETCH_PREDICTION_TABLE [i][j]._address_dest<<2,
                     reg_UPDATE_FETCH_PREDICTION_TABLE [i][j]._last_take,
                     reg_UPDATE_FETCH_PREDICTION_TABLE [i][j]._is_accurate,
                     reg_UPDATE_FETCH_PREDICTION_TABLE [i][j]._history,
                     reg_UPDATE_FETCH_PREDICTION_TABLE [i][j]._address_ras,
                     reg_UPDATE_FETCH_PREDICTION_TABLE [i][j]._address_ras<<2,
                     reg_UPDATE_FETCH_PREDICTION_TABLE [i][j]._index_ras,
                     toString(reg_UPDATE_FETCH_PREDICTION_TABLE [i][j]._state).c_str()
                     );
          }

	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"    * Dump UPT [%d] (Update_Prediction_Table)",i);
	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UPT_BOTTOM          : %d",reg_UPT_BOTTOM         [i]);
	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UPT_TOP             : %d",reg_UPT_TOP            [i]);
	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UPT_TOP_EVENT       : %d",reg_UPT_TOP_EVENT      [i]);
	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UPT_UPDATE          : %d",reg_UPT_UPDATE         [i]);
	log_printf(TRACE,Update_Prediction_Table,FUNCTION,"      * reg_UPT_EMPTY           : %d",reg_UPT_EMPTY          [i]);
	for (uint32_t j=0; j<_param->_size_upt_queue[i]; j++)
	  log_printf(TRACE,Update_Prediction_Table,FUNCTION,"        [%d] %.4d, %.8x (%.8x) %.8x (%.8x), %.1d %.1d %.1d, %.8lld %.8x (%.8x) %.4d - %s",
                     j,
                     reg_UPDATE_PREDICTION_TABLE [i][j]._condition,
                     reg_UPDATE_PREDICTION_TABLE [i][j]._address_src,
                     reg_UPDATE_PREDICTION_TABLE [i][j]._address_src<<2,
                     reg_UPDATE_PREDICTION_TABLE [i][j]._address_dest,
                     reg_UPDATE_PREDICTION_TABLE [i][j]._address_dest<<2,
                     reg_UPDATE_PREDICTION_TABLE [i][j]._last_take,
                     reg_UPDATE_PREDICTION_TABLE [i][j]._good_take,
                     reg_UPDATE_PREDICTION_TABLE [i][j]._is_accurate,
                     reg_UPDATE_PREDICTION_TABLE [i][j]._history,
                     reg_UPDATE_PREDICTION_TABLE [i][j]._address_ras,
                     reg_UPDATE_PREDICTION_TABLE [i][j]._address_ras<<2,
                     reg_UPDATE_PREDICTION_TABLE [i][j]._index_ras,
                     toString(reg_UPDATE_PREDICTION_TABLE [i][j]._state).c_str()
                     );
      }
#endif

#ifdef DEBUG_TEST
    for (uint32_t i=0; i<_param->_nb_context; i++)
      {
        if (reg_UFPT_NB_NEED_UPDATE [i] > _param->_size_ufpt_queue[i])
          throw ERRORMORPHEO(FUNCTION,toString(_("reg_UFPT_NB_NEED_UPDATE [%d] (%d) is > at size_ufpt_queue (%d).\n"),i,reg_UFPT_NB_NEED_UPDATE [i],_param->_size_ufpt_queue[i]));
        if (reg_UFPT_NB_UPDATE [i] > _param->_size_ufpt_queue[i])
          throw ERRORMORPHEO(FUNCTION,toString(_("reg_UFPT_NB_UPDATE [%d] (%d) is > at size_ufpt_queue (%d).\n"),i,reg_UFPT_NB_UPDATE [i],_param->_size_ufpt_queue[i]));
      }
#endif

      }


#if defined(STATISTICS) or defined(VHDL_TESTBENCH)
    end_cycle ();
#endif
    
    log_end(Update_Prediction_Table,FUNCTION);
  };

}; // end namespace update_prediction_table
}; // end namespace prediction_unit
}; // end namespace front_end
}; // end namespace multi_front_end
}; // end namespace core

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