diff options
author | Igor V. Kovalenko <igor.v.kovalenko@gmail.com> | 2010-01-07 23:28:31 +0300 |
---|---|---|
committer | Blue Swirl <blauwirbel@gmail.com> | 2010-01-08 17:25:13 +0000 |
commit | d532b26c9dee0fb5b2186572f921b1e413963ec2 (patch) | |
tree | 75eef4cbe9034f96b98c176db0e8eeb03923f652 | |
parent | 2df6c2d0de31461f18d97f8a4d122bdb003297db (diff) |
sparc64: interrupt trap handling
cpu_check_irqs
- handle SOFTINT register TICK and STICK timer bits
- only check interrupt levels greater than PIL value
- handle preemption by higher level traps
cpu_exec
- handle CPU_INTERRUPT_HARD only if interrupts are enabled
- PIL 15 is not special level on sparcv9
Signed-off-by: Igor V. Kovalenko <igor.v.kovalenko@gmail.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
-rw-r--r-- | cpu-exec.c | 28 | ||||
-rw-r--r-- | hw/sun4u.c | 48 | ||||
-rw-r--r-- | target-sparc/cpu.h | 10 |
3 files changed, 59 insertions, 27 deletions
diff --git a/cpu-exec.c b/cpu-exec.c index af4595b65a..4635be34f5 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -449,20 +449,20 @@ int cpu_exec(CPUState *env1) next_tb = 0; } #elif defined(TARGET_SPARC) - if ((interrupt_request & CPU_INTERRUPT_HARD) && - cpu_interrupts_enabled(env)) { - int pil = env->interrupt_index & 15; - int type = env->interrupt_index & 0xf0; - - if (((type == TT_EXTINT) && - (pil == 15 || pil > env->psrpil)) || - type != TT_EXTINT) { - env->interrupt_request &= ~CPU_INTERRUPT_HARD; - env->exception_index = env->interrupt_index; - do_interrupt(env); - env->interrupt_index = 0; - next_tb = 0; - } + if (interrupt_request & CPU_INTERRUPT_HARD) { + if (cpu_interrupts_enabled(env) && + env->interrupt_index > 0) { + int pil = env->interrupt_index & 0xf; + int type = env->interrupt_index & 0xf0; + + if (((type == TT_EXTINT) && + cpu_pil_allowed(env, pil)) || + type != TT_EXTINT) { + env->exception_index = env->interrupt_index; + do_interrupt(env); + next_tb = 0; + } + } } else if (interrupt_request & CPU_INTERRUPT_TIMER) { //do_interrupt(0, 0, 0, 0, 0); env->interrupt_request &= ~CPU_INTERRUPT_TIMER; diff --git a/hw/sun4u.c b/hw/sun4u.c index 029e3edc5f..ae32878104 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -232,29 +232,51 @@ void irq_info(Monitor *mon) void cpu_check_irqs(CPUState *env) { - uint32_t pil = env->pil_in | (env->softint & ~SOFTINT_TIMER) | - ((env->softint & SOFTINT_TIMER) << 14); + uint32_t pil = env->pil_in | + (env->softint & ~(SOFTINT_TIMER | SOFTINT_STIMER)); + + /* check if TM or SM in SOFTINT are set + setting these also causes interrupt 14 */ + if (env->softint & (SOFTINT_TIMER | SOFTINT_STIMER)) { + pil |= 1 << 14; + } + + if (!pil) { + if (env->interrupt_request & CPU_INTERRUPT_HARD) { + CPUIRQ_DPRINTF("Reset CPU IRQ (current interrupt %x)\n", + env->interrupt_index); + env->interrupt_index = 0; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } + return; + } + + if (cpu_interrupts_enabled(env)) { - if (pil && (env->interrupt_index == 0 || - (env->interrupt_index & ~15) == TT_EXTINT)) { unsigned int i; - for (i = 15; i > 0; i--) { + for (i = 15; i > env->psrpil; i--) { if (pil & (1 << i)) { int old_interrupt = env->interrupt_index; - - env->interrupt_index = TT_EXTINT | i; - if (old_interrupt != env->interrupt_index) { - CPUIRQ_DPRINTF("Set CPU IRQ %d\n", i); + int new_interrupt = TT_EXTINT | i; + + if (env->tl > 0 && cpu_tsptr(env)->tt > new_interrupt) { + CPUIRQ_DPRINTF("Not setting CPU IRQ: TL=%d " + "current %x >= pending %x\n", + env->tl, cpu_tsptr(env)->tt, new_interrupt); + } else if (old_interrupt != new_interrupt) { + env->interrupt_index = new_interrupt; + CPUIRQ_DPRINTF("Set CPU IRQ %d old=%x new=%x\n", i, + old_interrupt, new_interrupt); cpu_interrupt(env, CPU_INTERRUPT_HARD); } break; } } - } else if (!pil && (env->interrupt_index & ~15) == TT_EXTINT) { - CPUIRQ_DPRINTF("Reset CPU IRQ %d\n", env->interrupt_index & 15); - env->interrupt_index = 0; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } else { + CPUIRQ_DPRINTF("Interrupts disabled, pil=%08x pil_in=%08x softint=%08x " + "current interrupt %x\n", + pil, env->pil_in, env->softint, env->interrupt_index); } } diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index e5b282d391..50859c7f1f 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -577,6 +577,16 @@ static inline int cpu_interrupts_enabled(CPUState *env1) return 0; } +static inline int cpu_pil_allowed(CPUState *env1, int pil) +{ +#if !defined(TARGET_SPARC64) + /* level 15 is non-maskable on sparc v8 */ + return pil == 15 || pil > env1->psrpil; +#else + return pil > env1->psrpil; +#endif +} + static inline int cpu_fpu_enabled(CPUState *env1) { #if defined(CONFIG_USER_ONLY) |