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; }
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); }