Пример #1
0
static sim_cia
step_once (SIM_CPU *cpu)
{
  SIM_DESC sd = CPU_STATE (cpu);
  bu32 insn_len, oldpc = PCREG;
  int i;
  bool ssstep;

  if (TRACE_ANY_P (cpu))
    trace_prefix (sd, cpu, NULL_CIA, oldpc, TRACE_LINENUM_P (cpu),
		  NULL, 0, " "); /* Use a space for gcc warnings.  */

  /* Handle hardware single stepping when lower than EVT3, and when SYSCFG
     has already had the SSSTEP bit enabled.  */
  ssstep = false;
  if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT
      && (SYSCFGREG & SYSCFG_SSSTEP))
    {
      int ivg = cec_get_ivg (cpu);
      if (ivg == -1 || ivg > 3)
	ssstep = true;
    }

#if 0
  /* XXX: Is this what happens on the hardware ?  */
  if (cec_get_ivg (cpu) == EVT_EMU)
    cec_return (cpu, EVT_EMU);
#endif

  BFIN_CPU_STATE.did_jump = false;

  insn_len = interp_insn_bfin (cpu, oldpc);

  /* If we executed this insn successfully, then we always decrement
     the loop counter.  We don't want to update the PC though if the
     last insn happened to be a change in code flow (jump/etc...).  */
  if (!BFIN_CPU_STATE.did_jump)
    SET_PCREG (hwloop_get_next_pc (cpu, oldpc, insn_len));
  for (i = 1; i >= 0; --i)
    if (LCREG (i) && oldpc == LBREG (i))
      {
	SET_LCREG (i, LCREG (i) - 1);
	if (LCREG (i))
	  break;
      }

  ++ PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu));

  /* Handle hardware single stepping only if we're still lower than EVT3.
     XXX: May not be entirely correct wrt EXCPT insns.  */
  if (ssstep)
    {
      int ivg = cec_get_ivg (cpu);
      if (ivg == -1 || ivg > 3)
	{
	  INSN_LEN = 0;
	  cec_exception (cpu, VEC_STEP);
	}
    }

  return oldpc;
}
Пример #2
0
void
cec_exception (SIM_CPU *cpu, int excp)
{
  SIM_DESC sd = CPU_STATE (cpu);
  int sigrc = -1;

  TRACE_EVENTS (cpu, "processing exception %#x in EVT%i", excp,
		cec_get_ivg (cpu));

  /* Ideally what would happen here for real hardware exceptions (not
     fake sim ones) is that:
      - For service exceptions (excp <= 0x11):
         RETX is the _next_ PC which can be tricky with jumps/hardware loops/...
      - For error exceptions (excp > 0x11):
         RETX is the _current_ PC (i.e. the one causing the exception)
      - PC is loaded with EVT3 MMR
      - ILAT/IPEND in CEC is updated depending on current IVG level
      - the fault address MMRs get updated with data/instruction info
      - Execution continues on in the EVT3 handler  */

  /* Handle simulator exceptions first.  */
  switch (excp)
    {
    case VEC_SIM_HLT:
      excp_to_sim_halt (sim_exited, 0);
      return;
    case VEC_SIM_ABORT:
      excp_to_sim_halt (sim_exited, 1);
      return;
    case VEC_SIM_TRAP:
      /* GDB expects us to step over EMUEXCPT.  */
      /* XXX: What about hwloops and EMUEXCPT at the end?
              Pretty sure gdb doesn't handle this already...  */
      SET_PCREG (PCREG + 2);
      /* Only trap when we are running in gdb.  */
      if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
	excp_to_sim_halt (sim_stopped, SIM_SIGTRAP);
      return;
    case VEC_SIM_DBGA:
      /* If running in gdb, simply trap.  */
      if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG)
	excp_to_sim_halt (sim_stopped, SIM_SIGTRAP);
      else
	excp_to_sim_halt (sim_exited, 2);
    }

  if (excp <= 0x3f)
    {
      SET_EXCAUSE (excp);
      if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)
	{
	  /* ICPLB regs always get updated.  */
	  /* XXX: Should optimize this call path ...  */
	  if (excp != VEC_MISALI_I && excp != VEC_MISALI_D
	      && excp != VEC_CPLB_I_M && excp != VEC_CPLB_M
	      && excp != VEC_CPLB_I_VL && excp != VEC_CPLB_VL
	      && excp != VEC_CPLB_I_MHIT && excp != VEC_CPLB_MHIT)
	    mmu_log_ifault (cpu);
	  _cec_raise (cpu, CEC_STATE (cpu), IVG_EVX);
	  /* We need to restart the engine so that we don't return
	     and continue processing this bad insn.  */
	  if (EXCAUSE >= 0x20)
	    sim_engine_restart (sd, cpu, NULL, PCREG);
	  return;
	}
    }

  TRACE_EVENTS (cpu, "running virtual exception handler");

  switch (excp)
    {
    case VEC_SYS:
      bfin_syscall (cpu);
      break;

    case VEC_EXCPT01:	/* Userspace gdb breakpoint.  */
      sigrc = SIM_SIGTRAP;
      break;

    case VEC_UNDEF_I:	/* Undefined instruction.  */
      sigrc = SIM_SIGILL;
      break;

    case VEC_ILL_RES:	/* Illegal supervisor resource.  */
    case VEC_MISALI_I:	/* Misaligned instruction.  */
      sigrc = SIM_SIGBUS;
      break;

    case VEC_CPLB_M:
    case VEC_CPLB_I_M:
      sigrc = SIM_SIGSEGV;
      break;

    default:
      sim_io_eprintf (sd, "Unhandled exception %#x at 0x%08x (%s)\n",
		      excp, PCREG, excp_decoded[excp]);
      sigrc = SIM_SIGILL;
      break;
    }

  if (sigrc != -1)
    excp_to_sim_halt (sim_stopped, sigrc);
}