#ifdef SYSTEMC
/*
 * $Id: Context_State_transition.cpp 83 2008-05-09 18:00:21Z 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 {


#undef  FUNCTION
#define FUNCTION "Context_State::transition"
  void Context_State::transition (void)
  {
    log_begin(Context_State,FUNCTION);

    if (PORT_READ(in_NRESET) == 0)
      {
	for (uint32_t i=0; i<_param->_nb_context; i++)
	  reg_STATE [i] = CONTEXT_STATE_OK;
      }
    else
      {
	// -------------------------------------------------------------------
	// -----[ 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])
	    {
	      Tcontext_t context    = (_param->_have_port_context_id     )?PORT_READ(in_DECOD_EVENT_CONTEXT_ID [i]):0;
	      Tdepth_t   depth      = (_param->_have_port_max_depth      )?PORT_READ(in_DECOD_EVENT_DEPTH      [i]):0;
	      Tdepth_t   depth_cur  = reg_EVENT_DEPTH [context];
	      Tdepth_t   depth_base = (_param->_have_port_depth [context])?PORT_READ(in_DEPTH_TAIL       [context]):0;
	      Tdepth_t   depth_max  = _param->_size_depth [context];
	      
	      Tdepth_t   depth0     = (depth_cur>=depth_base)?(depth_cur-depth_base):((depth_cur+depth_max-depth_base));
	      Tdepth_t   depth1     = (depth    >=depth_base)?(depth    -depth_base):((depth    +depth_max-depth_base));

	      context_state_t state = reg_STATE [context];
	      Tevent_type_t   type  = PORT_READ(in_DECOD_EVENT_TYPE [i]);
	      
	      // miss > excep > spr/sync
	      uint8_t    priority0  = (state == CONTEXT_STATE_KO_MISS)?2:((state == CONTEXT_STATE_KO_EXCEP)?1:0);
	      uint8_t    priority1  = (state == EVENT_TYPE_EXCEPTION)?1:0;

	      // 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 (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          : 
		      {
			state_next = CONTEXT_STATE_KO_EXCEP; 
			break;
		      }
		    case EVENT_TYPE_SPR_ACCESS         : 
		      {
			state_next = CONTEXT_STATE_KO_SPR  ; 
			address++; // take next address
			if (is_delay_slot)
			  throw ERRORMORPHEO(FUNCTION,"SPR access in delay slot, not supported.\n");
			break;
		      }
		    case EVENT_TYPE_MSYNC              : 
		      {
			state_next = CONTEXT_STATE_KO_MSYNC;
			address++;  // take next address
			if (is_delay_slot)
			  throw ERRORMORPHEO(FUNCTION,"SPR access in delay slot, not supported.\n");
			break;
		      }
		    case EVENT_TYPE_PSYNC              :
		      {
			state_next = CONTEXT_STATE_KO_PSYNC;
			address++;  // take next address
			if (is_delay_slot)
			  throw ERRORMORPHEO(FUNCTION,"SPR access in delay slot, not supported.\n");
			break;
		      }
		    case EVENT_TYPE_CSYNC              :
		      {
			state_next = CONTEXT_STATE_KO_CSYNC;
			address++;  // take next address
			if (is_delay_slot)
			  throw ERRORMORPHEO(FUNCTION,"SPR access in delay slot, not supported.\n");
			break;
		      }		      
		    case EVENT_TYPE_NONE               :
		    case EVENT_TYPE_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;
		}
	    }

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

	for (uint32_t i=0; i<_param->_nb_ooo_engine; i++)
	  if (PORT_READ(in_COMMIT_EVENT_VAL [i]) and internal_COMMIT_EVENT_ACK [i])
	    {
	      Tcontext_t context    = (_param->_have_port_context_id     )?PORT_READ(in_COMMIT_EVENT_CONTEXT_ID [i]):0;
	      Tdepth_t   depth      = (_param->_have_port_max_depth      )?PORT_READ(in_COMMIT_EVENT_DEPTH      [i]):0;
	      Tdepth_t   depth_cur  = reg_EVENT_DEPTH [context];
	      Tdepth_t   depth_base = (_param->_have_port_depth [context])?PORT_READ(in_DEPTH_TAIL        [context]):0;
	      Tdepth_t   depth_max  = _param->_size_depth [context];
	      
	      Tdepth_t   depth0     = (depth_cur>=depth_base)?(depth_cur-depth_base):((depth_cur+depth_max-depth_base));
	      Tdepth_t   depth1     = (depth    >=depth_base)?(depth    -depth_base):((depth    +depth_max-depth_base));

	      context_state_t state = reg_STATE [context];
	      Tevent_type_t   type  = PORT_READ(in_COMMIT_EVENT_TYPE [i]);
	      
	      // miss > excep > spr/sync
	      uint8_t    priority0  = (state == CONTEXT_STATE_KO_MISS)?2:((state == CONTEXT_STATE_KO_EXCEP)?1:0);
	      uint8_t    priority1  = 1;

	      // 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 (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_SPR_ACCESS         :
		    case EVENT_TYPE_MSYNC              :
		    case EVENT_TYPE_PSYNC              :
		    case EVENT_TYPE_CSYNC              :
		    case EVENT_TYPE_NONE               :
		    case EVENT_TYPE_MISS_SPECULATION   :
		    case EVENT_TYPE_BRANCH_NO_ACCURATE :
		    default :
		      {
			throw ERRORMORPHEO(FUNCTION,toString(_("COMMIT_EVENT [%d] : invalid event_type : %s.\n"),i,toString(type).c_str()));
		      }
		    }
		  reg_STATE                  [context] = state_next;
		  reg_EVENT_ADDRESS          [context] = PORT_READ(in_COMMIT_EVENT_ADDRESS          [i]);
		  reg_EVENT_ADDRESS_EPCR     [context] = PORT_READ(in_COMMIT_EVENT_ADDRESS_EPCR     [i]); 
		  reg_EVENT_ADDRESS_EPCR_VAL [context] = 1;
		  reg_EVENT_ADDRESS_EEAR     [context] = PORT_READ(in_COMMIT_EVENT_ADDRESS_EEAR     [i]); 
		  reg_EVENT_ADDRESS_EEAR_VAL [context] = PORT_READ(in_COMMIT_EVENT_ADDRESS_EEAR_VAL [i]);
		  reg_EVENT_IS_DELAY_SLOT    [context] = PORT_READ(in_COMMIT_EVENT_IS_DELAY_SLOT    [i]);
		//reg_EVENT_IS_DS_TAKE       [context] = 0;
		  reg_EVENT_DEPTH            [context] = depth;
		}
	    }

	// -------------------------------------------------------------------
	// -----[ 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])
	    {
	      if (PORT_READ(in_BRANCH_COMPLETE_MISS_PREDICTION [i]))
		{
		  Tcontext_t context    = (_param->_have_port_context_id     )?PORT_READ(in_BRANCH_COMPLETE_CONTEXT_ID [i]):0;
		  Tdepth_t   depth      = (_param->_have_port_max_depth      )?PORT_READ(in_BRANCH_COMPLETE_DEPTH      [i]):0;
		  Tdepth_t   depth_cur  = reg_EVENT_DEPTH [context];
		  Tdepth_t   depth_base = (_param->_have_port_depth [context])?PORT_READ(in_DEPTH_TAIL        [context]):0;
		  Tdepth_t   depth_max  = _param->_size_depth [context];
		  
		  Tdepth_t   depth0     = (depth_cur>=depth_base)?(depth_cur-depth_base):((depth_cur+depth_max-depth_base));
		  Tdepth_t   depth1     = (depth    >=depth_base)?(depth    -depth_base):((depth    +depth_max-depth_base));
		  
		  context_state_t state = reg_STATE [context];
		  
		  // miss > excep > spr/sync
		  uint8_t    priority0  = (state == CONTEXT_STATE_KO_MISS)?2:((state == CONTEXT_STATE_KO_EXCEP)?1:0);
		  uint8_t    priority1  = 2;
		  
		  // 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 (is_valid)
		    {
		      // commit
		      Tcontrol_t take = PORT_READ(in_BRANCH_COMPLETE_TAKE [i]);
		      reg_STATE                  [context] = CONTEXT_STATE_KO_MISS;
		      reg_EVENT_ADDRESS          [context] = PORT_READ(in_BRANCH_COMPLETE_ADDRESS_SRC  [i])+1; //DELAY_SLOT
		      reg_EVENT_ADDRESS_EPCR     [context] = PORT_READ(in_BRANCH_COMPLETE_ADDRESS_DEST [i]); 
		      reg_EVENT_ADDRESS_EPCR_VAL [context] = take; // if not take : in sequence
		    //reg_EVENT_ADDRESS_EEAR     [context]; 
		    //reg_EVENT_ADDRESS_EEAR_VAL [context];
		      reg_EVENT_IS_DELAY_SLOT    [context] = take;
		      reg_EVENT_IS_DS_TAKE       [context] = take;
		      reg_EVENT_DEPTH            [context] = depth;
		    }
		}
	    }

	// -------------------------------------------------------------------
	// -----[ EVENT ]-----------------------------------------------------
	// -------------------------------------------------------------------
	for (uint32_t i=0; i<_param->_nb_context; i++)
	  if (internal_EVENT_VAL [i] and PORT_READ(in_EVENT_ACK [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_ADDR  :
		case CONTEXT_STATE_KO_PSYNC_ADDR :
		case CONTEXT_STATE_KO_CSYNC_ADDR :
		  {
		    reg_STATE [i] = CONTEXT_STATE_OK;
		    break;
		  }
		default :
		  {
#ifdef DEBUG_TEST
		    throw ERRORMORPHEO(FUNCTION,toString(_("SPR[%d], Invalid state : %s.\n"),i,toString(state).c_str()));
#endif
		    break;
		  }
		}
	    }

	// -------------------------------------------------------------------
	// -----[ SPR ]-------------------------------------------------------
	// -------------------------------------------------------------------
	for (uint32_t i=0; i<_param->_nb_context; i++)
	  if (internal_SPR_VAL [i] and PORT_READ(in_SPR_ACK [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[%d], Invalid state : %s.\n"),i,toString(state).c_str()));
#endif
	      
	      reg_STATE [i] = CONTEXT_STATE_OK;
	    }

	// -------------------------------------------------------------------
	// -----[ next state ]------------------------------------------------
	// -------------------------------------------------------------------
	for (uint32_t i=0; i<_param->_nb_context; i++)
	  {
	    uint32_t x = _param->_link_context_to_decod_unit    [i];
	    uint32_t y = _param->_link_decod_unit_to_ooo_engine [x];

	    Tcounter_t inst_all = PORT_READ(in_NB_INST_COMMIT_ALL [y]) + PORT_READ(in_NB_INST_DECOD_ALL [x]);
	    Tcounter_t inst_mem = PORT_READ(in_NB_INST_COMMIT_MEM [y]) + PORT_READ(in_NB_INST_DECOD_ALL [x]);

	    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)
		    state = CONTEXT_STATE_KO_EXCEP_ADDR;
		  break;
		}
	      case CONTEXT_STATE_KO_MISS         :
		{
		  // Wait end of all instruction
		  if (inst_all == 0)
		    state = CONTEXT_STATE_KO_MISS_ADDR;
		  break;
		}
	      case CONTEXT_STATE_KO_EXCEP_ADDR   :
		{
		  // nothing, wait the update of internal register (pc)
		  break;
		}
	      case CONTEXT_STATE_KO_EXCEP_SPR    :
		{
		  // nothing, wait the update of internal register (epcr, eear, sr, esr)
		  break;
		}
	      case CONTEXT_STATE_KO_MISS_ADDR    :
		{
		  // nothing, wait the update of internal register (pc)
		  break;
		}
	      case CONTEXT_STATE_KO_PSYNC        :
		{
		  // Wait end of all instruction
		  if (inst_all == 0)
// 		    state = CONTEXT_STATE_KO_PSYNC_FLUSH;
		    state = CONTEXT_STATE_KO_PSYNC_ADDR ;
		  break;
		}
// 	      case CONTEXT_STATE_KO_PSYNC_FLUSH  :
// 		{
// 		  // nothing, wait end of flush (ifetch)
// 		  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_ADDR ;
// 		    state = CONTEXT_STATE_KO_CSYNC_FLUSH;
		  break;
		}
// 	      case CONTEXT_STATE_KO_CSYNC_FLUSH  :
// 		{
// 		  // nothing, wait end of flush (all internal structure)
// 		  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_mem == 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;
	  }
      }

#if DEBUG >= DEBUG_TRACE
    for (uint32_t i=0; i<_param->_nb_context; i++)
      {
	log_printf(TRACE,Context_State,FUNCTION,"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",reg_EVENT_ADDRESS          [i]);
	log_printf(TRACE,Context_State,FUNCTION," * reg_EVENT_ADDRESS_EPCR     : 0x%x",reg_EVENT_ADDRESS_EPCR     [i]); 
	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",reg_EVENT_ADDRESS_EEAR     [i]); 
	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]);
      }
#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
