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

#include "Behavioural/Core/Multi_Front_end/Front_end/Context_State/include/Context_State.h"

namespace morpheo                    {
namespace behavioural {
namespace core {
namespace multi_front_end {
namespace front_end {
namespace context_state {

// #define MANAGE_EVENT MANAGE_EVENT_WAIT_ALL
// #define MANAGE_EVENT MANAGE_EVENT_WAIT_DECODE
#define MANAGE_EVENT MANAGE_EVENT_NO_WAIT

#define PRIORITY_MISS_LOAD   3
#define PRIORITY_MISS_BRANCH 2
#define PRIORITY_EXCEPTION   1
#define PRIORITY_NONE        0

#define get_priority(x) \
  (((state == CONTEXT_STATE_KO_MISS_LOAD_ADDR                  ) or  \
    (state == CONTEXT_STATE_KO_MISS_LOAD_WAITEND               ) or  \
    (state == CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_ADDR       ) or  \
    (state == CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_WAITEND    ) or  \
    (state == CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_WAIT_UPDATE))?PRIORITY_MISS_LOAD: \
  (((state == CONTEXT_STATE_KO_MISS_BRANCH_ADDR                ) or  \
    (state == CONTEXT_STATE_KO_MISS_BRANCH_WAITEND             ) or  \
    (state == CONTEXT_STATE_KO_MISS_BRANCH_WAIT_UPDATE         ))?PRIORITY_MISS_BRANCH: \
   ((state == EVENT_TYPE_EXCEPTION)?PRIORITY_EXCEPTION:                           \
    0)))

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

    if (PORT_READ(in_NRESET) == 0)
      {
        for (uint32_t i=0; i<_param->_nb_context; i++)
          {
            reg_STATE            [i] = CONTEXT_STATE_OK;
            reg_INTERRUPT_ENABLE [i] = 0;
            reg_EVENT_DEPTH      [i] = 0; // unacessary
          }
      }
    else
      {
        // -------------------------------------------------------------------
        // -----[ next state ]------------------------------------------------
        // -------------------------------------------------------------------
        for (uint32_t i=0; i<_param->_nb_context; i++)
          {
//             uint32_t x = _param->_link_context_to_decod_unit    [i];

            Tcounter_t inst_commit_all = PORT_READ(in_NB_INST_COMMIT_ALL[i]);
//          Tcounter_t inst_commit_mem = PORT_READ(in_NB_INST_COMMIT_MEM[i]);
            Tcounter_t inst_decod_all  = PORT_READ(in_NB_INST_DECOD_ALL [i]);
            Tcounter_t inst_all        = inst_commit_all + inst_decod_all;
//          Tcounter_t inst_mem        = inst_commit_mem + inst_decod_all;
            bool       condition       = ( (MANAGE_EVENT == MANAGE_EVENT_WAIT_ALL   )?(inst_all       == 0):
                                          ((MANAGE_EVENT == MANAGE_EVENT_WAIT_DECODE)?(inst_decod_all == 0):
                                            true));

            context_state_t state = reg_STATE [i];

            switch (state)
              {
              case CONTEXT_STATE_OK              :
                {
                  // nothing, wait an event
                  break;
                }
              case CONTEXT_STATE_KO_EXCEP        :
                {
                  // Wait end of all instruction
                  if (inst_all == 0)
//                if (inst_decod_all == 0)
                    state = CONTEXT_STATE_KO_EXCEP_ADDR;
                  break;
                }
              case CONTEXT_STATE_KO_EXCEP_ADDR   :
                {
                  // nothing, wait the update of internal register (pc)
                  break;
                }
              case CONTEXT_STATE_KO_MISS_BRANCH_WAIT_UPDATE :
                {
                  // nothing : wait end of update upt
                  break;
                }
              case CONTEXT_STATE_KO_MISS_BRANCH_WAITEND :
                {
                  if (condition)
//                  state = CONTEXT_STATE_OK;
                    state = CONTEXT_STATE_KO_MISS_BRANCH_ADDR;
                  break;
                }
              case CONTEXT_STATE_KO_MISS_LOAD_WAITEND :
                {
                  // Wait end of all instruction
                  if (condition)
                    state = CONTEXT_STATE_KO_MISS_LOAD_ADDR;

                  break;
                }
              case CONTEXT_STATE_KO_EXCEP_SPR    :
                {
                  // nothing, wait the update of internal register (epcr, eear, sr, esr)
                  break;
                }
              case CONTEXT_STATE_KO_MISS_BRANCH_ADDR    :
                {
                  // nothing, wait the update of internal register (pc)
                  break;
                }
              case CONTEXT_STATE_KO_MISS_LOAD_ADDR    :
                {
                  // nothing, wait the update of internal register (pc)
                  break;
                }
              case CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_WAIT_UPDATE :
                {
                  // nothing : wait end of update upt
                  break;
                }
              case CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_ADDR    :
                {
                  // nothing, wait the update of internal register (pc)
                  break;
                }
              case CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_WAITEND :
                {
                  // Wait end of all instruction
                  if (condition)
//                  state = CONTEXT_STATE_OK; // @@@ TODO : make MISS fast (miss decod)
                    state = CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_ADDR;
                  break;
                }
//               case CONTEXT_STATE_KO_PSYNC        :
//                 {
//                   // Wait end of all instruction
//                   if (inst_all == 0)
//                     state = CONTEXT_STATE_KO_PSYNC_FLUSH;
//                   break;
//                 }
              case CONTEXT_STATE_KO_PSYNC_FLUSH  :
                {
                  // nothing, wait end of flush (ifetch)
                  if (inst_all == 0)
//                  state = CONTEXT_STATE_KO_PSYNC_ADDR;
                    state = CONTEXT_STATE_OK;
                    
                  break;
                }
              case CONTEXT_STATE_KO_PSYNC_ADDR   :
                {
                  // nothing, wait the pc write
                  break;
                }
//               case CONTEXT_STATE_KO_CSYNC        :
//                 {
//                   // Wait end of all instruction
//                   if (inst_all == 0)
//                     state = CONTEXT_STATE_KO_CSYNC_FLUSH;
//                   break;
//                 }
              case CONTEXT_STATE_KO_CSYNC_FLUSH  :
                {
                  // nothing, wait end of flush (all internal structure)
                  if (inst_all == 0)
                    state = CONTEXT_STATE_KO_CSYNC_ADDR;
                  break;
                }
              case CONTEXT_STATE_KO_CSYNC_ADDR   :
                {
                  // nothing, wait the pc write
                  break;
                }
//               case CONTEXT_STATE_KO_MSYNC        :
//                 {
//                   // Wait end of memory instruction
//                   if (inst_mem == 0)
//                     state = CONTEXT_STATE_KO_MSYNC_ISSUE;
//                   break;
//                 }
//               case CONTEXT_STATE_KO_MSYNC_ISSUE  :
//                 {
//                   // Wait the msync issue
//                   if (inst_mem != 0)
//                     state = CONTEXT_STATE_KO_MSYNC_EXEC;
//                   break;
//                 }
              case CONTEXT_STATE_KO_MSYNC_EXEC   :
                {
                  // Wait the end of msync
                  if (inst_all == 0)
                    state = CONTEXT_STATE_OK;
                  break;
                }
//               case CONTEXT_STATE_KO_SPR          :
//                 {
//                   // Wait end of all instruction
//                   if (inst_all == 0)
//                     state = CONTEXT_STATE_KO_SPR_ISSUE;
//                   break;
//                 }
//               case CONTEXT_STATE_KO_SPR_ISSUE    :
//                 {
//                   // Wait the spr_access issue
//                   if (inst_all != 0)
//                     state = CONTEXT_STATE_KO_SPR_EXEC;
//                   break;
//                 }
              case CONTEXT_STATE_KO_SPR_EXEC     :
                {
                  // Wait the spr_access execution
                  if (inst_all == 0)
                    state = CONTEXT_STATE_OK;
                  break;
                }

              default :
                {
                  throw ERRORMORPHEO(FUNCTION,toString(_("Context[%d], Unknow state : %s.\n"),i,toString(state).c_str()));
                }
              }
            reg_STATE [i] = state;
          }

        // -------------------------------------------------------------------
        // -----[ EVENT ]-----------------------------------------------------
        // -------------------------------------------------------------------
        for (uint32_t i=0; i<_param->_nb_context; i++)
          if (internal_EVENT_VAL [i] and PORT_READ(in_EVENT_ACK [i]))
            {
              log_printf(TRACE,Context_State,FUNCTION,"  * EVENT [%d]",i);
              // Write pc
              context_state_t state = reg_STATE [i];

              switch (state)
                {
                case CONTEXT_STATE_KO_EXCEP_ADDR :
                  {
                    reg_STATE [i] = CONTEXT_STATE_KO_EXCEP_SPR;
                    break;
                  }
                case CONTEXT_STATE_KO_MISS_BRANCH_ADDR:

//                   {
//                     reg_STATE [i] = CONTEXT_STATE_KO_MISS_WAITEND; //@@@ TODO : make MISS fast (miss decod)
//                     break;
//                   }
                case CONTEXT_STATE_KO_MISS_LOAD_ADDR  :
                case CONTEXT_STATE_KO_PSYNC_ADDR :
                case CONTEXT_STATE_KO_CSYNC_ADDR :
                  {
                    reg_STATE [i] = CONTEXT_STATE_OK;
                    break;
                  }
                case CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_ADDR:
                  {
                    reg_STATE [i] = CONTEXT_STATE_KO_MISS_LOAD_ADDR;
                    break;
                  }
                default :
                  {
#ifdef DEBUG_TEST
                    throw ERRORMORPHEO(FUNCTION,toString(_("SPR[%d], Invalid state : %s.\n"),i,toString(state).c_str()));
#endif
                    break;
                  }
                }
            }

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

              context_state_t state = reg_STATE [i];

              Tdepth_t   depth      = (_param->_have_port_depth)?PORT_READ(in_BRANCH_EVENT_DEPTH [i]):0;
              Tdepth_t   depth_cur  = reg_EVENT_DEPTH [i];
              Tdepth_t   depth_min  = (_param->_have_port_depth)?PORT_READ(in_DEPTH_MIN [i]):0;
              Tdepth_t   depth_max  = _param->_nb_inst_branch_speculated [i];
              
              Tdepth_t   depth0     = (depth_cur>=depth_min)?(depth_cur-depth_min):((depth_cur+depth_max-depth_min));
              Tdepth_t   depth1     = (depth    >=depth_min)?(depth    -depth_min):((depth    +depth_max-depth_min));
//               Tdepth_t   depth0     = (depth_cur>=depth_min)?(depth_cur):((depth_cur+depth_max));
//               Tdepth_t   depth1     = (depth    >=depth_min)?(depth    ):((depth    +depth_max));

              // priority : miss_load > miss_branch > excep > spr/sync
              uint8_t    priority0  = get_priority(state);
              uint8_t    priority1  = PRIORITY_MISS_BRANCH; // miss

              // is_valid = can modify local information
              //   if context_state_ok : yes
              //   if context_state_ko : test the depth, and the priority of event
              bool       is_valid   = ((state == CONTEXT_STATE_OK) or
                                       (state == CONTEXT_STATE_KO_MISS_BRANCH_WAIT_UPDATE) or
//                                     (state == CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_WAIT_UPDATE) or
                                       (depth1< depth0) or
                                       ((depth1==depth0) and (priority1>=priority0))); // >= because another branch can be a miss prediction with same depth

              bool       is_invalid = priority0 == PRIORITY_MISS_LOAD;

#ifdef DEBUG_TEST
              if ((state == CONTEXT_STATE_KO_MISS_BRANCH_WAIT_UPDATE) and
                  (depth0 != depth1))
                throw ERRORMORPHEO(FUNCTION,toString(_("BRANCH_EVENT[%d] : Invalid state : %s.\n"),i,toString(state).c_str()));
#endif

              log_printf(TRACE,Context_State,FUNCTION,"    * state     : %s",toString(state).c_str());
              log_printf(TRACE,Context_State,FUNCTION,"    * depth     : %d",depth     );
              log_printf(TRACE,Context_State,FUNCTION,"    * depth_cur : %d",depth_cur );
              log_printf(TRACE,Context_State,FUNCTION,"    * depth_min : %d",depth_min );
              log_printf(TRACE,Context_State,FUNCTION,"    * depth_max : %d",depth_max );
              log_printf(TRACE,Context_State,FUNCTION,"    * depth0    : %d",depth0    );
              log_printf(TRACE,Context_State,FUNCTION,"    * depth1    : %d",depth1    );
              log_printf(TRACE,Context_State,FUNCTION,"    * priority0 : %d",priority0 );
              log_printf(TRACE,Context_State,FUNCTION,"    * priority1 : %d",priority1 );
              log_printf(TRACE,Context_State,FUNCTION,"  * is_valid    : %d",is_valid  );

              if (is_valid and not is_invalid)
                {
//                reg_STATE                  [i] =  CONTEXT_STATE_KO_MISS_BRANCH_ADDR;

                  if (state == CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_WAIT_UPDATE)
                    {
// #if (MANAGE_EVENT == MANAGE_EVENT_NO_WAIT)
//                       reg_STATE                  [i] =  CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_ADDR;
// #else
                      reg_STATE                  [i] =  CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_WAITEND;
// #endif
                    }
                  else
                    {
                      Tcontrol_t can_continue = PORT_READ(in_BRANCH_EVENT_CAN_CONTINUE    [i]);
                      Tcontrol_t dest_val     = PORT_READ(in_BRANCH_EVENT_ADDRESS_DEST_VAL[i]);

                      log_printf(TRACE,Context_State,FUNCTION,"  * dest_val    : %d",dest_val    );
                      log_printf(TRACE,Context_State,FUNCTION,"  * can_continue: %d",can_continue);

                      if (can_continue)
                        reg_STATE                [i] =  CONTEXT_STATE_KO_MISS_BRANCH_ADDR;
                      else
                        {
// #if (MANAGE_EVENT == MANAGE_EVENT_NO_WAIT)
//                           reg_STATE                [i] =  CONTEXT_STATE_KO_MISS_BRANCH_ADDR;
// #else
                          reg_STATE                [i] =  CONTEXT_STATE_KO_MISS_BRANCH_WAITEND;
// #endif
                        }

                      reg_EVENT_ADDRESS          [i] = PORT_READ(in_BRANCH_EVENT_ADDRESS_SRC  [i])+1; // address delay slot
                      reg_EVENT_ADDRESS_EPCR     [i] = PORT_READ(in_BRANCH_EVENT_ADDRESS_DEST [i]);   // address_next
                      reg_EVENT_ADDRESS_EPCR_VAL [i] = dest_val;
                    //reg_EVENT_ADDRESS_EEAR     [i] = 0; 
                      reg_EVENT_ADDRESS_EEAR_VAL [i] = 0;
                      reg_EVENT_IS_DELAY_SLOT    [i] = 1;
                      reg_EVENT_IS_DS_TAKE       [i] = dest_val;
                      reg_EVENT_DEPTH            [i] = depth;
                      reg_EVENT_FLUSH_ONLY       [i] = can_continue;
                    }
                }
            }

        // -------------------------------------------------------------------
        // -----[ BRANCH_COMPLETE ]----------------------------------------------
        // -------------------------------------------------------------------
        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] 
              and PORT_READ(in_BRANCH_COMPLETE_MISS_PREDICTION [i]))
            {
              log_printf(TRACE,Context_State,FUNCTION,"  * BRANCH_COMPLETE [%d]",i);

              Tcontext_t context_id = (_param->_have_port_context_id)?PORT_READ(in_BRANCH_COMPLETE_CONTEXT_ID [i]):0;

              context_state_t state = reg_STATE [context_id];

              Tdepth_t   depth      = (_param->_have_port_depth)?PORT_READ(in_BRANCH_COMPLETE_DEPTH [i]):0;
              Tdepth_t   depth_cur  = reg_EVENT_DEPTH [context_id];
              Tdepth_t   depth_min  = (_param->_have_port_depth)?PORT_READ(in_DEPTH_MIN [context_id]):0;
              Tdepth_t   depth_max  = _param->_nb_inst_branch_speculated [context_id];
              
              Tdepth_t   depth0     = (depth_cur>=depth_min)?(depth_cur-depth_min):((depth_cur+depth_max-depth_min));
              Tdepth_t   depth1     = (depth    >=depth_min)?(depth    -depth_min):((depth    +depth_max-depth_min));
//            Tdepth_t   depth0     = (depth_cur>=depth_min)?(depth_cur):((depth_cur+depth_max));
//            Tdepth_t   depth1     = (depth    >=depth_min)?(depth    ):((depth    +depth_max));

              // priority : miss_load > miss_branch > excep > spr/sync
              uint8_t    priority0  = get_priority(state);
              uint8_t    priority1  = PRIORITY_MISS_BRANCH; // miss

              // is_valid = can modify local information
              //   if context_state_ok : yes
              //   if context_state_ko : test the depth, and the priority of event
              bool       is_valid   = ((state == CONTEXT_STATE_OK) or
                                       (depth1< depth0) or
                                       ((depth1==depth0) and (priority1>=priority0))); // >= because another branch can be a miss prediction with same depth

              log_printf(TRACE,Context_State,FUNCTION,"    * context_id: %d",context_id);
              log_printf(TRACE,Context_State,FUNCTION,"    * depth     : %d",depth     );
              log_printf(TRACE,Context_State,FUNCTION,"    * depth_cur : %d",depth_cur );
              log_printf(TRACE,Context_State,FUNCTION,"    * depth_min : %d",depth_min );
              log_printf(TRACE,Context_State,FUNCTION,"    * depth_max : %d",depth_max );
              log_printf(TRACE,Context_State,FUNCTION,"    * depth0    : %d",depth0    );
              log_printf(TRACE,Context_State,FUNCTION,"    * depth1    : %d",depth1    );
              log_printf(TRACE,Context_State,FUNCTION,"    * priority0 : %d",priority0 );
              log_printf(TRACE,Context_State,FUNCTION,"    * priority1 : %d",priority1 );
              log_printf(TRACE,Context_State,FUNCTION,"  * is_valid    : %d",is_valid  );

              if (is_valid)
                {
//                reg_STATE                  [context_id] = CONTEXT_STATE_KO_MISS_BRANCH_ADDR;
                  reg_STATE                  [context_id] = CONTEXT_STATE_KO_MISS_BRANCH_WAIT_UPDATE;
                  reg_EVENT_DEPTH            [context_id] = depth;
                  reg_EVENT_FLUSH_ONLY       [context_id] = false;
                }
            }
        
        // -------------------------------------------------------------------
        // -----[ DECOD_EVENT ]-----------------------------------------------
        // -------------------------------------------------------------------

        for (uint32_t i=0; i<_param->_nb_decod_unit; i++)
          if (PORT_READ(in_DECOD_EVENT_VAL [i]) and internal_DECOD_EVENT_ACK [i])
            {
              log_printf(TRACE,Context_State,FUNCTION,"  * DECOD_EVENT [%d]",i);

              Tcontext_t context    = (_param->_have_port_context_id )?PORT_READ(in_DECOD_EVENT_CONTEXT_ID [i]):0;
              Tdepth_t   depth      = (_param->_have_port_depth      )?PORT_READ(in_DECOD_EVENT_DEPTH      [i]):0;
              Tdepth_t   depth_cur  = reg_EVENT_DEPTH [context];
              Tdepth_t   depth_min = (_param->_have_port_depth      )?PORT_READ(in_DEPTH_MIN [context]):0;
              Tdepth_t   depth_max  = _param->_nb_inst_branch_speculated [context];
              
              Tdepth_t   depth0     = (depth_cur>=depth_min)?(depth_cur-depth_min):((depth_cur+depth_max-depth_min));
              Tdepth_t   depth1     = (depth    >=depth_min)?(depth    -depth_min):((depth    +depth_max-depth_min));
//               Tdepth_t   depth0     = (depth_cur>=depth_min)?(depth_cur):((depth_cur+depth_max));
//               Tdepth_t   depth1     = (depth    >=depth_min)?(depth    ):((depth    +depth_max));

              context_state_t state = reg_STATE [context];
              Tevent_type_t   type  = PORT_READ(in_DECOD_EVENT_TYPE [i]);
              
              // miss_load > miss_branch > excep > spr/sync
              uint8_t    priority0  = get_priority(state);
              uint8_t    priority1  = (state == EVENT_TYPE_EXCEPTION)?PRIORITY_EXCEPTION:PRIORITY_NONE;

              // is_valid = can modify local information
              //  if context_state_ok : yes
              //  if context_state_ko : test the depth, and the priority of envent

              bool       is_valid   = ((state == CONTEXT_STATE_OK) or
                                       (depth1< depth0) or
                                       ((depth1==depth0) and (priority1>=priority0)));

              log_printf(TRACE,Context_State,FUNCTION,"    * depth     : %d",depth     );
              log_printf(TRACE,Context_State,FUNCTION,"    * depth_cur : %d",depth_cur );
              log_printf(TRACE,Context_State,FUNCTION,"    * depth_min : %d",depth_min );
              log_printf(TRACE,Context_State,FUNCTION,"    * depth_max : %d",depth_max );
              log_printf(TRACE,Context_State,FUNCTION,"    * depth0    : %d",depth0    );
              log_printf(TRACE,Context_State,FUNCTION,"    * depth1    : %d",depth1    );
              log_printf(TRACE,Context_State,FUNCTION,"    * priority0 : %d",priority0 );
              log_printf(TRACE,Context_State,FUNCTION,"    * priority1 : %d",priority1 );
              log_printf(TRACE,Context_State,FUNCTION,"  * is_valid    : %d",is_valid  );

              if (is_valid)
                {
                  log_printf(TRACE,Context_State,FUNCTION,"    * is_valid");

                  // decod : 
                  // type : csync, psync, msync, spr_access (l.mac, l.maci, l.macrc, l.msb, l.mfspr, l.mtspr), exception (l.sys)
                  context_state_t state_next    = state;
                  Taddress_t      address       = PORT_READ(in_DECOD_EVENT_ADDRESS       [i]);
                  Tcontrol_t      is_delay_slot = PORT_READ(in_DECOD_EVENT_IS_DELAY_SLOT [i]);

                  switch (type)
                    {
                    case EVENT_TYPE_EXCEPTION          : 
                      {
                        log_printf(TRACE,Context_State,FUNCTION,"    * EVENT_TYPE_EXCEPTION");

                        state_next = CONTEXT_STATE_KO_EXCEP; 

                        break;
                      }
                    case EVENT_TYPE_SPR_ACCESS         : 
                      {
                        log_printf(TRACE,Context_State,FUNCTION,"    * EVENT_TYPE_SPR_ACCESS");

//                      state_next = CONTEXT_STATE_KO_SPR  ; 
                        state_next = CONTEXT_STATE_KO_SPR_EXEC; 
                        address++; // take next address
//                         if (is_delay_slot)
//                           throw ERRORMORPHEO(FUNCTION,"SPR access in delay slot, not supported.\n");
                        break;
                      }
                    case EVENT_TYPE_MSYNC              : 
                      {
                        log_printf(TRACE,Context_State,FUNCTION,"    * EVENT_TYPE_MSYNC");

//                      state_next = CONTEXT_STATE_KO_MSYNC;
                        state_next = CONTEXT_STATE_KO_MSYNC_EXEC;
                        address++;  // take next address
//                         if (is_delay_slot)
//                           throw ERRORMORPHEO(FUNCTION,"MSYNC in delay slot, not supported.\n");
                        break;
                      }
                    case EVENT_TYPE_PSYNC              :
                      {
                        log_printf(TRACE,Context_State,FUNCTION,"    * EVENT_TYPE_PSYNC");

//                      state_next = CONTEXT_STATE_KO_PSYNC;
                        state_next = CONTEXT_STATE_KO_PSYNC_FLUSH;
                        address++;  // take next address
                        if (is_delay_slot)
                          throw ERRORMORPHEO(FUNCTION,"PSYNC in delay slot, not supported.\n");
                        break;
                      }
                    case EVENT_TYPE_CSYNC              :
                      {
                        log_printf(TRACE,Context_State,FUNCTION,"    * EVENT_TYPE_CSYNC");

//                      state_next = CONTEXT_STATE_KO_CSYNC;
                        state_next = CONTEXT_STATE_KO_CSYNC_FLUSH;
                        address++;  // take next address
                        if (is_delay_slot)
                          throw ERRORMORPHEO(FUNCTION,"CSYNC in delay slot, not supported.\n");
                        break;
                      }               
                    case EVENT_TYPE_NONE               :
                    case EVENT_TYPE_BRANCH_MISS_SPECULATION   :
                    case EVENT_TYPE_LOAD_MISS_SPECULATION   :
//                     case EVENT_TYPE_BRANCH_NO_ACCURATE :
                    default :
                      {
                        throw ERRORMORPHEO(FUNCTION,toString(_("DECOD_EVENT [%d] : invalid event_type : %s.\n"),i,toString(type).c_str()));
                      }
                    }

                  reg_STATE                  [context] = state_next;
                  reg_EVENT_ADDRESS          [context] = address;
                  reg_EVENT_ADDRESS_EPCR     [context] = PORT_READ(in_DECOD_EVENT_ADDRESS_EPCR  [i]); 
                  reg_EVENT_ADDRESS_EPCR_VAL [context] = 1;
                //reg_EVENT_ADDRESS_EEAR     [context]
                  reg_EVENT_ADDRESS_EEAR_VAL [context] = 0;
                  reg_EVENT_IS_DELAY_SLOT    [context] = is_delay_slot;
                //reg_EVENT_IS_DS_TAKE       [context] = 0;
                  reg_EVENT_DEPTH            [context] = depth;
                  reg_EVENT_FLUSH_ONLY       [context] = false;
                }
            }

        // -------------------------------------------------------------------
        // -----[ COMMIT_EVENT ]----------------------------------------------
        // -------------------------------------------------------------------

        if (PORT_READ(in_COMMIT_EVENT_VAL ) and internal_COMMIT_EVENT_ACK )
          {
            log_printf(TRACE,Context_State,FUNCTION,"  * COMMIT_EVENT");

            Tcontext_t context    = (_param->_have_port_context_id)?PORT_READ(in_COMMIT_EVENT_CONTEXT_ID ):0;
            Tdepth_t   depth      = (_param->_have_port_depth     )?PORT_READ(in_COMMIT_EVENT_DEPTH      ):0;
//             Tdepth_t   depth_cur  = reg_EVENT_DEPTH [context];
//             Tdepth_t   depth_min = (_param->_have_port_depth     )?PORT_READ(in_DEPTH_MIN [context]):0;
//             Tdepth_t   depth_max  = _param->_nb_inst_branch_speculated [context];
            
//             Tdepth_t   depth0     = (depth_cur>=depth_min)?(depth_cur-depth_min):((depth_cur+depth_max-depth_min));
//             Tdepth_t   depth1     = (depth    >=depth_min)?(depth    -depth_min):((depth    +depth_max-depth_min));
// //             Tdepth_t   depth0     = (depth_cur>=depth_min)?(depth_cur):((depth_cur+depth_max));
// //             Tdepth_t   depth1     = (depth    >=depth_min)?(depth    ):((depth    +depth_max));

            context_state_t state = reg_STATE [context];
            Tevent_type_t   type  = PORT_READ(in_COMMIT_EVENT_TYPE );
            
//             // miss > excep > spr/sync
//               uint8_t    priority0  = ((state == CONTEXT_STATE_KO_MISS_BRANCH_ADDR            ) or
//                                        (state == CONTEXT_STATE_KO_MISS_LOAD_ADDR              ) or
//                                        (state == CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_ADDR   ) or
//                                        (state == CONTEXT_STATE_KO_MISS_BRANCH_WAITEND         ) or
//                                        (state == CONTEXT_STATE_KO_MISS_BRANCH_WAIT_UPDATE     ) or
//                                        (state == CONTEXT_STATE_KO_MISS_LOAD_WAITEND           ) or
//                                        (state == CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_WAITEND))?2:((state == CONTEXT_STATE_KO_EXCEP)?1:0);
//             uint8_t    priority1  = (state == EVENT_TYPE_EXCEPTION)?1:2; // else load_miss_speculation (EVENT_TYPE_MISS_SPECULATION)

//             // is_valid = can modify local information
//             //  if context_state_ok : yes
//             //  if context_state_ko : test the depth, and the priority of envent

//             bool       is_valid   = ((state == CONTEXT_STATE_OK) or
//                                      (depth1< depth0) or
//                                      ((depth1==depth0) and (priority1>=priority0)));

            // if commit send an event, also they have not yet event previous this instruction
            bool       is_valid   = true;

            log_printf(TRACE,Context_State,FUNCTION,"    * depth     : %d",depth     );
//             log_printf(TRACE,Context_State,FUNCTION,"    * depth_cur : %d",depth_cur );
//             log_printf(TRACE,Context_State,FUNCTION,"    * depth_min : %d",depth_min );
//             log_printf(TRACE,Context_State,FUNCTION,"    * depth_max : %d",depth_max );
//             log_printf(TRACE,Context_State,FUNCTION,"    * depth0    : %d",depth0    );
//             log_printf(TRACE,Context_State,FUNCTION,"    * depth1    : %d",depth1    );
//             log_printf(TRACE,Context_State,FUNCTION,"    * priority0 : %d",priority0 );
//             log_printf(TRACE,Context_State,FUNCTION,"    * priority1 : %d",priority1 );
            log_printf(TRACE,Context_State,FUNCTION,"  * is_valid    : %d",is_valid  );

            if (is_valid)
              {
                // commit
                // type : exception
                context_state_t state_next = state;
                switch (type)
                  {
                  case EVENT_TYPE_EXCEPTION               : {state_next = CONTEXT_STATE_KO_EXCEP;             break;}
                  case EVENT_TYPE_LOAD_MISS_SPECULATION   : 
                    {
                      // Test if previous branch occure
                      switch (state)
                        {
                        case CONTEXT_STATE_KO_MISS_BRANCH_WAIT_UPDATE      :
                          {
                            state_next = CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_WAIT_UPDATE;
                            break;
                          }
                        case CONTEXT_STATE_KO_MISS_BRANCH_ADDR             :
                        case CONTEXT_STATE_KO_MISS_BRANCH_WAITEND          :
                        case CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_ADDR    :
                        case CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_WAITEND :
                          {
// #if (MANAGE_EVENT == MANAGE_EVENT_NO_WAIT)
//                             state_next = CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_ADDR;
// #else
                            state_next = CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_WAITEND;
// #endif
                            break;
                          }
                        default :
                          {
// #if (MANAGE_EVENT == MANAGE_EVENT_NO_WAIT)
//                             state_next = CONTEXT_STATE_KO_MISS_LOAD_ADDR;
// #else
                            state_next = CONTEXT_STATE_KO_MISS_LOAD_WAITEND;
// #endif
                            break;
                          }
                        }

                      depth = (depth+1)%_param->_nb_inst_branch_speculated[context];

                      break;
                    }
                  case EVENT_TYPE_BRANCH_MISS_SPECULATION :
                  case EVENT_TYPE_SPR_ACCESS              :
                  case EVENT_TYPE_MSYNC                   :
                  case EVENT_TYPE_PSYNC                   :
                  case EVENT_TYPE_CSYNC                   :
                  case EVENT_TYPE_NONE                    :
//                case EVENT_TYPE_BRANCH_NO_ACCURATE      :
                  default :
                    {
                      throw ERRORMORPHEO(FUNCTION,toString(_("COMMIT_EVENT : invalid event_type : %s.\n"),toString(type).c_str()));
                    }
                  }
                reg_STATE                  [context] = state_next;
                reg_EVENT_ADDRESS          [context] = PORT_READ(in_COMMIT_EVENT_ADDRESS          );
                reg_EVENT_ADDRESS_EPCR     [context] = PORT_READ(in_COMMIT_EVENT_ADDRESS_EPCR     ); 
                reg_EVENT_ADDRESS_EPCR_VAL [context] = PORT_READ(in_COMMIT_EVENT_ADDRESS_EPCR_VAL );
                reg_EVENT_ADDRESS_EEAR     [context] = PORT_READ(in_COMMIT_EVENT_ADDRESS_EEAR     ); 
                reg_EVENT_ADDRESS_EEAR_VAL [context] = PORT_READ(in_COMMIT_EVENT_ADDRESS_EEAR_VAL );
                reg_EVENT_IS_DELAY_SLOT    [context] = PORT_READ(in_COMMIT_EVENT_IS_DELAY_SLOT    );
                reg_EVENT_IS_DS_TAKE       [context] = 0;
                reg_EVENT_DEPTH            [context] = depth;
                reg_EVENT_FLUSH_ONLY       [context] = false;
              }
          }

        // -------------------------------------------------------------------
        // -----[ SPR_EVENT ]-------------------------------------------------
        // -------------------------------------------------------------------
        for (uint32_t i=0; i<_param->_nb_context; i++)
          if (internal_SPR_EVENT_VAL [i] and PORT_READ(in_SPR_EVENT_ACK [i]))
            {
              log_printf(TRACE,Context_State,FUNCTION,"  * SPR_EVENT [%d]",i);

              // Write spr
#ifdef DEBUG_TEST
              context_state_t state = reg_STATE [i];
            
              if (state != CONTEXT_STATE_KO_EXCEP_SPR)
                throw ERRORMORPHEO(FUNCTION,toString(_("SPR_EVENT[%d], Invalid state : %s.\n"),i,toString(state).c_str()));
#endif
              
              reg_STATE [i] = CONTEXT_STATE_OK;
            }

        for (uint32_t i=0; i<_param->_nb_context; ++i)
          {
            reg_INTERRUPT_ENABLE [i] = PORT_READ(in_INTERRUPT_ENABLE [i]) and PORT_READ(in_SPR_SR_IEE [i]);

            if (reg_INTERRUPT_ENABLE [i])
              throw ERRORMORPHEO(FUNCTION,toString(_("Context[%d], Have an interruption, Not yet supported (Comming Soon).\n"),i));
          }


#if (MANAGE_EVENT == MANAGE_EVENT_NO_WAIT)
        for (uint32_t i=0; i<_param->_nb_context; i++)
          switch (reg_STATE [i])
            {
            case CONTEXT_STATE_KO_MISS_BRANCH_WAITEND          : reg_STATE [i] = CONTEXT_STATE_KO_MISS_BRANCH_ADDR         ; break;
            case CONTEXT_STATE_KO_MISS_LOAD_WAITEND            : reg_STATE [i] = CONTEXT_STATE_KO_MISS_LOAD_ADDR           ; break;
            case CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_WAITEND : reg_STATE [i] = CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_ADDR; break;
            default : break;
            }
#endif
      }


#ifdef STATISTICS
    if (usage_is_set(_usage,USE_STATISTICS))
      for (uint32_t i=0; i<_param->_nb_context; ++i)
        switch(reg_STATE[i])
          {
          case CONTEXT_STATE_OK                                 : (*_stat_nb_cycle_state_ok                      [i])++; break;

          case CONTEXT_STATE_KO_EXCEP                           : 
          case CONTEXT_STATE_KO_EXCEP_ADDR                      : 
          case CONTEXT_STATE_KO_EXCEP_SPR                       : (*_stat_nb_cycle_state_ko_excep                [i])++; break;

          case CONTEXT_STATE_KO_MISS_BRANCH_WAIT_UPDATE         : 
          case CONTEXT_STATE_KO_MISS_BRANCH_ADDR                : 
          case CONTEXT_STATE_KO_MISS_BRANCH_WAITEND             : (*_stat_nb_cycle_state_ko_miss_branch          [i])++; break;

          case CONTEXT_STATE_KO_MISS_LOAD_ADDR                  : 
          case CONTEXT_STATE_KO_MISS_LOAD_WAITEND               : (*_stat_nb_cycle_state_ko_miss_load            [i])++; break;

          case CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_WAIT_UPDATE: 
          case CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_ADDR       : 
          case CONTEXT_STATE_KO_MISS_LOAD_AND_BRANCH_WAITEND    : (*_stat_nb_cycle_state_ko_miss_load_and_branch [i])++; break;

//        case CONTEXT_STATE_KO_MSYNC                           : 
//        case CONTEXT_STATE_KO_MSYNC_ISSUE                     : 
          case CONTEXT_STATE_KO_MSYNC_EXEC                      : (*_stat_nb_cycle_state_ko_msync                [i])++; break;

//        case CONTEXT_STATE_KO_PSYNC                           : 
          case CONTEXT_STATE_KO_PSYNC_FLUSH                     : 
          case CONTEXT_STATE_KO_PSYNC_ADDR                      : (*_stat_nb_cycle_state_ko_psync                [i])++; break;

//        case CONTEXT_STATE_KO_CSYNC                           : 
          case CONTEXT_STATE_KO_CSYNC_FLUSH                     : 
          case CONTEXT_STATE_KO_CSYNC_ADDR                      : (*_stat_nb_cycle_state_ko_csync                [i])++; break;

//        case CONTEXT_STATE_KO_SPR                             : 
//        case CONTEXT_STATE_KO_SPR_ISSUE                       : 
          case CONTEXT_STATE_KO_SPR_EXEC                        : (*_stat_nb_cycle_state_ko_spr                  [i])++; break;
          }
#endif



#if DEBUG >= DEBUG_TRACE
    for (uint32_t i=0; i<_param->_nb_context; i++)
      {
        log_printf(TRACE,Context_State,FUNCTION,"  * Dump Context State [%d]",i);
        log_printf(TRACE,Context_State,FUNCTION,"    * reg_STATE                  : %s"         ,toString(reg_STATE [i]).c_str());
        log_printf(TRACE,Context_State,FUNCTION,"    * reg_EVENT_ADDRESS          : 0x%x (0x%x)",reg_EVENT_ADDRESS          [i],reg_EVENT_ADDRESS      [i]<<2);
        log_printf(TRACE,Context_State,FUNCTION,"    * reg_EVENT_ADDRESS_EPCR     : 0x%x (0x%x)",reg_EVENT_ADDRESS_EPCR     [i],reg_EVENT_ADDRESS_EPCR [i]<<2); 
        log_printf(TRACE,Context_State,FUNCTION,"    * reg_EVENT_ADDRESS_EPCR_VAL : %d"         ,reg_EVENT_ADDRESS_EPCR_VAL [i]);
        log_printf(TRACE,Context_State,FUNCTION,"    * reg_EVENT_ADDRESS_EEAR     : 0x%x (0x%x)",reg_EVENT_ADDRESS_EEAR     [i],reg_EVENT_ADDRESS_EEAR [i]<<2); 
        log_printf(TRACE,Context_State,FUNCTION,"    * reg_EVENT_ADDRESS_EEAR_VAL : %d"         ,reg_EVENT_ADDRESS_EEAR_VAL [i]);
        log_printf(TRACE,Context_State,FUNCTION,"    * reg_EVENT_IS_DELAY_SLOT    : %d"         ,reg_EVENT_IS_DELAY_SLOT    [i]);
        log_printf(TRACE,Context_State,FUNCTION,"    * reg_EVENT_IS_DS_TAKE       : %d"         ,reg_EVENT_IS_DS_TAKE       [i]);
        log_printf(TRACE,Context_State,FUNCTION,"    * reg_EVENT_DEPTH            : %d"         ,reg_EVENT_DEPTH            [i]);
        log_printf(TRACE,Context_State,FUNCTION,"    * reg_EVENT_FLUSH_ONLY       : %d"         ,reg_EVENT_FLUSH_ONLY       [i]);
      }
#endif

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

    log_end(Context_State,FUNCTION);
  };

}; // end namespace context_state
}; // end namespace front_end
}; // end namespace multi_front_end
}; // end namespace core

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