static void bfin_initialize_cpu (SIM_DESC sd, SIM_CPU *cpu) { memset (&cpu->state, 0, sizeof (cpu->state)); PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu)) = 0; bfin_model_cpu_init (sd, cpu); /* Set default stack to top of scratch pad. */ SET_SPREG (BFIN_DEFAULT_MEM_SIZE); SET_KSPREG (BFIN_DEFAULT_MEM_SIZE); SET_USPREG (BFIN_DEFAULT_MEM_SIZE); /* This is what the hardware likes. */ SET_SYSCFGREG (0x30); }
void cec_return (SIM_CPU *cpu, int ivg) { SIM_DESC sd = CPU_STATE (cpu); struct bfin_cec *cec; bool snen; int curr_ivg; bu32 oldpc, newpc; oldpc = PCREG; BFIN_CPU_STATE.did_jump = true; if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT) { SET_PCREG (cec_read_ret_reg (cpu, ivg)); TRACE_BRANCH (cpu, oldpc, PCREG, -1, "CEC changed PC"); return; } cec = CEC_STATE (cpu); /* XXX: This isn't entirely correct ... */ cec->ipend &= ~IVG_EMU_B; curr_ivg = _cec_get_ivg (cec); if (curr_ivg == -1) curr_ivg = IVG_USER; if (ivg == -1) ivg = curr_ivg; TRACE_EVENTS (cpu, "returning from EVT%i (should be EVT%i)", curr_ivg, ivg); /* Not allowed to return from usermode. */ if (curr_ivg == IVG_USER) cec_exception (cpu, VEC_ILL_RES); if (ivg > IVG15 || ivg < 0) sim_io_error (sd, "%s: ivg %i out of range !", __func__, ivg); _cec_require_supervisor (cpu, cec); switch (ivg) { case IVG_EMU: /* RTE -- only valid in emulation mode. */ /* XXX: What does the hardware do ? */ if (curr_ivg != IVG_EMU) cec_exception (cpu, VEC_ILL_RES); break; case IVG_NMI: /* RTN -- only valid in NMI. */ /* XXX: What does the hardware do ? */ if (curr_ivg != IVG_NMI) cec_exception (cpu, VEC_ILL_RES); break; case IVG_EVX: /* RTX -- only valid in exception. */ /* XXX: What does the hardware do ? */ if (curr_ivg != IVG_EVX) cec_exception (cpu, VEC_ILL_RES); break; default: /* RTI -- not valid in emulation, nmi, exception, or user. */ /* XXX: What does the hardware do ? */ if (curr_ivg == IVG_EMU || curr_ivg == IVG_NMI || curr_ivg == IVG_EVX || curr_ivg == IVG_USER) cec_exception (cpu, VEC_ILL_RES); break; case IVG_IRPTEN: /* XXX: Is this even possible ? */ excp_to_sim_halt (sim_stopped, SIM_SIGABRT); break; } newpc = cec_read_ret_reg (cpu, ivg); /* XXX: Does this nested trick work on EMU/NMI/EVX ? */ snen = (newpc & 1); /* XXX: Delayed clear shows bad PCREG register trace above ? */ SET_PCREG (newpc & ~1); TRACE_BRANCH (cpu, oldpc, PCREG, -1, "CEC changed PC (from EVT%i)", ivg); /* Update ipend after the TRACE_BRANCH so dv-bfin_trace knows current CEC state wrt overflow. */ if (!snen) cec->ipend &= ~(1 << ivg); /* Disable global interrupt mask to let any interrupt take over, but only when we were already in a RTI level. Only way we could have raised at that point is if it was cleared in the first place. */ if (ivg >= IVG_IVHW || ivg == IVG_RST) cec_irpten_disable (cpu, cec); /* When going from super to user, we clear LSB in LB regs in case it was set on the transition up. Also need to load SP alias with USP. */ if (_cec_get_ivg (cec) == -1) { int i; for (i = 0; i < 2; ++i) if (LBREG (i) & 1) SET_LBREG (i, LBREG (i) & ~1); SET_KSPREG (SPREG); SET_SPREG (USPREG); } /* Check for pending interrupts before we return to usermode. */ _cec_check_pending (cpu, cec); }