target/m68k: manage 680x0 stack frames
680x0 manages several stack frame formats: - format 0: four-word stack frame - format 1: four-word throwaway stack frame - format 2: six-word stack frame - format 3: Floating-Point post-instruction stack frame - format 4: eight-word stack frame - format 7: access-error stack frame Signed-off-by: Laurent Vivier <laurent@vivier.eu> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20180104012913.30763-7-laurent@vivier.eu>
This commit is contained in:
parent
5beb144e04
commit
d2f8fb8e7f
@ -178,6 +178,7 @@ int cpu_m68k_signal_handler(int host_signum, void *pinfo,
|
||||
void *puc);
|
||||
uint32_t cpu_m68k_get_ccr(CPUM68KState *env);
|
||||
void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t);
|
||||
void cpu_m68k_set_sr(CPUM68KState *env, uint32_t);
|
||||
void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val);
|
||||
|
||||
|
||||
|
@ -316,13 +316,17 @@ uint32_t HELPER(sats)(uint32_t val, uint32_t v)
|
||||
return val;
|
||||
}
|
||||
|
||||
void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
|
||||
void cpu_m68k_set_sr(CPUM68KState *env, uint32_t sr)
|
||||
{
|
||||
env->sr = val & 0xffe0;
|
||||
cpu_m68k_set_ccr(env, val);
|
||||
env->sr = sr & 0xffe0;
|
||||
cpu_m68k_set_ccr(env, sr);
|
||||
m68k_switch_sp(env);
|
||||
}
|
||||
|
||||
void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
|
||||
{
|
||||
cpu_m68k_set_sr(env, val);
|
||||
}
|
||||
|
||||
/* MAC unit. */
|
||||
/* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
|
||||
|
@ -54,7 +54,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
|
||||
}
|
||||
}
|
||||
|
||||
static void do_rte(CPUM68KState *env)
|
||||
static void cf_rte(CPUM68KState *env)
|
||||
{
|
||||
uint32_t sp;
|
||||
uint32_t fmt;
|
||||
@ -65,7 +65,46 @@ static void do_rte(CPUM68KState *env)
|
||||
sp |= (fmt >> 28) & 3;
|
||||
env->aregs[7] = sp + 8;
|
||||
|
||||
helper_set_sr(env, fmt);
|
||||
cpu_m68k_set_sr(env, fmt);
|
||||
}
|
||||
|
||||
static void m68k_rte(CPUM68KState *env)
|
||||
{
|
||||
uint32_t sp;
|
||||
uint16_t fmt;
|
||||
uint16_t sr;
|
||||
|
||||
sp = env->aregs[7];
|
||||
throwaway:
|
||||
sr = cpu_lduw_kernel(env, sp);
|
||||
sp += 2;
|
||||
env->pc = cpu_ldl_kernel(env, sp);
|
||||
sp += 4;
|
||||
if (m68k_feature(env, M68K_FEATURE_QUAD_MULDIV)) {
|
||||
/* all except 68000 */
|
||||
fmt = cpu_lduw_kernel(env, sp);
|
||||
sp += 2;
|
||||
switch (fmt >> 12) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
env->aregs[7] = sp;
|
||||
cpu_m68k_set_sr(env, sr);
|
||||
goto throwaway;
|
||||
case 2:
|
||||
case 3:
|
||||
sp += 4;
|
||||
break;
|
||||
case 4:
|
||||
sp += 8;
|
||||
break;
|
||||
case 7:
|
||||
sp += 52;
|
||||
break;
|
||||
}
|
||||
}
|
||||
env->aregs[7] = sp;
|
||||
cpu_m68k_set_sr(env, sr);
|
||||
}
|
||||
|
||||
static const char *m68k_exception_name(int index)
|
||||
@ -173,7 +212,7 @@ static const char *m68k_exception_name(int index)
|
||||
return "Unassigned";
|
||||
}
|
||||
|
||||
static void do_interrupt_all(CPUM68KState *env, int is_hw)
|
||||
static void cf_interrupt_all(CPUM68KState *env, int is_hw)
|
||||
{
|
||||
CPUState *cs = CPU(m68k_env_get_cpu(env));
|
||||
uint32_t sp;
|
||||
@ -189,7 +228,7 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw)
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_RTE:
|
||||
/* Return from an exception. */
|
||||
do_rte(env);
|
||||
cf_rte(env);
|
||||
return;
|
||||
case EXCP_HALT_INSN:
|
||||
if (semihosting_enabled()
|
||||
@ -247,6 +286,119 @@ static void do_interrupt_all(CPUM68KState *env, int is_hw)
|
||||
env->pc = cpu_ldl_kernel(env, env->vbr + vector);
|
||||
}
|
||||
|
||||
static inline void do_stack_frame(CPUM68KState *env, uint32_t *sp,
|
||||
uint16_t format, uint16_t sr,
|
||||
uint32_t addr, uint32_t retaddr)
|
||||
{
|
||||
CPUState *cs = CPU(m68k_env_get_cpu(env));
|
||||
switch (format) {
|
||||
case 4:
|
||||
*sp -= 4;
|
||||
cpu_stl_kernel(env, *sp, env->pc);
|
||||
*sp -= 4;
|
||||
cpu_stl_kernel(env, *sp, addr);
|
||||
break;
|
||||
case 3:
|
||||
case 2:
|
||||
*sp -= 4;
|
||||
cpu_stl_kernel(env, *sp, addr);
|
||||
break;
|
||||
}
|
||||
*sp -= 2;
|
||||
cpu_stw_kernel(env, *sp, (format << 12) + (cs->exception_index << 2));
|
||||
*sp -= 4;
|
||||
cpu_stl_kernel(env, *sp, retaddr);
|
||||
*sp -= 2;
|
||||
cpu_stw_kernel(env, *sp, sr);
|
||||
}
|
||||
|
||||
static void m68k_interrupt_all(CPUM68KState *env, int is_hw)
|
||||
{
|
||||
CPUState *cs = CPU(m68k_env_get_cpu(env));
|
||||
uint32_t sp;
|
||||
uint32_t retaddr;
|
||||
uint32_t vector;
|
||||
uint16_t sr, oldsr;
|
||||
|
||||
retaddr = env->pc;
|
||||
|
||||
if (!is_hw) {
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_RTE:
|
||||
/* Return from an exception. */
|
||||
m68k_rte(env);
|
||||
return;
|
||||
case EXCP_TRAP0 ... EXCP_TRAP15:
|
||||
/* Move the PC after the trap instruction. */
|
||||
retaddr += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vector = cs->exception_index << 2;
|
||||
|
||||
sr = env->sr | cpu_m68k_get_ccr(env);
|
||||
if (qemu_loglevel_mask(CPU_LOG_INT)) {
|
||||
static int count;
|
||||
qemu_log("INT %6d: %s(%#x) pc=%08x sp=%08x sr=%04x\n",
|
||||
++count, m68k_exception_name(cs->exception_index),
|
||||
vector, env->pc, env->aregs[7], sr);
|
||||
}
|
||||
|
||||
/*
|
||||
* MC68040UM/AD, chapter 9.3.10
|
||||
*/
|
||||
|
||||
/* "the processor first make an internal copy" */
|
||||
oldsr = sr;
|
||||
/* "set the mode to supervisor" */
|
||||
sr |= SR_S;
|
||||
/* "suppress tracing" */
|
||||
sr &= ~SR_T;
|
||||
/* "sets the processor interrupt mask" */
|
||||
if (is_hw) {
|
||||
sr |= (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
|
||||
}
|
||||
cpu_m68k_set_sr(env, sr);
|
||||
sp = env->aregs[7];
|
||||
|
||||
sp &= ~1;
|
||||
if (cs->exception_index == EXCP_ADDRESS) {
|
||||
do_stack_frame(env, &sp, 2, oldsr, 0, retaddr);
|
||||
} else if (cs->exception_index == EXCP_ILLEGAL ||
|
||||
cs->exception_index == EXCP_DIV0 ||
|
||||
cs->exception_index == EXCP_CHK ||
|
||||
cs->exception_index == EXCP_TRAPCC ||
|
||||
cs->exception_index == EXCP_TRACE) {
|
||||
/* FIXME: addr is not only env->pc */
|
||||
do_stack_frame(env, &sp, 2, oldsr, env->pc, retaddr);
|
||||
} else if (is_hw && oldsr & SR_M &&
|
||||
cs->exception_index >= EXCP_SPURIOUS &&
|
||||
cs->exception_index <= EXCP_INT_LEVEL_7) {
|
||||
do_stack_frame(env, &sp, 0, oldsr, 0, retaddr);
|
||||
oldsr = sr;
|
||||
env->aregs[7] = sp;
|
||||
cpu_m68k_set_sr(env, sr &= ~SR_M);
|
||||
sp = env->aregs[7] & ~1;
|
||||
do_stack_frame(env, &sp, 1, oldsr, 0, retaddr);
|
||||
} else {
|
||||
do_stack_frame(env, &sp, 0, oldsr, 0, retaddr);
|
||||
}
|
||||
|
||||
env->aregs[7] = sp;
|
||||
/* Jump to vector. */
|
||||
env->pc = cpu_ldl_kernel(env, env->vbr + vector);
|
||||
}
|
||||
|
||||
static void do_interrupt_all(CPUM68KState *env, int is_hw)
|
||||
{
|
||||
if (m68k_feature(env, M68K_FEATURE_M68000)) {
|
||||
m68k_interrupt_all(env, is_hw);
|
||||
return;
|
||||
}
|
||||
cf_interrupt_all(env, is_hw);
|
||||
}
|
||||
|
||||
void m68k_cpu_do_interrupt(CPUState *cs)
|
||||
{
|
||||
M68kCPU *cpu = M68K_CPU(cs);
|
||||
|
Loading…
Reference in New Issue
Block a user