aboutsummaryrefslogtreecommitdiff
path: root/hw/sun4u.c
diff options
context:
space:
mode:
authorIgor V. Kovalenko <igor.v.kovalenko@gmail.com>2010-01-07 23:28:31 +0300
committerBlue Swirl <blauwirbel@gmail.com>2010-01-08 17:25:13 +0000
commitd532b26c9dee0fb5b2186572f921b1e413963ec2 (patch)
tree75eef4cbe9034f96b98c176db0e8eeb03923f652 /hw/sun4u.c
parent2df6c2d0de31461f18d97f8a4d122bdb003297db (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>
Diffstat (limited to 'hw/sun4u.c')
-rw-r--r--hw/sun4u.c48
1 files changed, 35 insertions, 13 deletions
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);
}
}