diff options
author | blueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-08-04 10:50:30 +0000 |
---|---|---|
committer | blueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-08-04 10:50:30 +0000 |
commit | 327ac2e797ed57d7231d44c77a7473d62efe0989 (patch) | |
tree | 1809a94735d69b1ed2aa5fa39ddfdd76b0921df5 /hw | |
parent | ccf1d14a1e37abe1f0da162c00a8941963b47a4c (diff) | |
download | qemu-327ac2e797ed57d7231d44c77a7473d62efe0989.tar.gz qemu-327ac2e797ed57d7231d44c77a7473d62efe0989.tar.bz2 qemu-327ac2e797ed57d7231d44c77a7473d62efe0989.zip |
Fix Sparc32 interrupt handling
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3110 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw')
-rw-r--r-- | hw/slavio_intctl.c | 55 | ||||
-rw-r--r-- | hw/sun4m.c | 37 |
2 files changed, 49 insertions, 43 deletions
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c index acde370e5c..9550c0064f 100644 --- a/hw/slavio_intctl.c +++ b/hw/slavio_intctl.c @@ -104,6 +104,7 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint val |= 80000000; val &= 0xfffe0000; s->intreg_pending[cpu] &= ~val; + slavio_check_interrupts(s); DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); break; case 2: // set softint @@ -175,10 +176,12 @@ static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uin val &= ~0x4fb2007f; s->intregm_disabled |= val; s->intregm_pending &= ~val; + slavio_check_interrupts(s); DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); break; case 4: s->target_cpu = val & (MAX_CPUS - 1); + slavio_check_interrupts(s); DPRINTF("Set master irq cpu %d\n", s->target_cpu); break; default: @@ -227,53 +230,36 @@ void slavio_irq_info(void *opaque) #endif } -static void raise_pil(SLAVIO_INTCTLState *s, unsigned int pil, - unsigned int cpu) -{ - qemu_irq irq; - unsigned int oldmax; - - irq = s->cpu_irqs[cpu][pil]; - -#ifdef DEBUG_IRQ_COUNT - s->irq_count[pil]++; -#endif - oldmax = s->pil_out[cpu]; - if (oldmax > 0 && oldmax != pil) - qemu_irq_lower(s->cpu_irqs[cpu][oldmax]); - s->pil_out[cpu] = pil; - if (pil > 0) - qemu_irq_raise(irq); - DPRINTF("cpu %d pil %d\n", cpu, pil); -} - static void slavio_check_interrupts(void *opaque) { SLAVIO_INTCTLState *s = opaque; - uint32_t pending = s->intregm_pending; - unsigned int i, j, max = 0; + uint32_t pending = s->intregm_pending, pil_pending; + unsigned int i, j; pending &= ~s->intregm_disabled; DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled); for (i = 0; i < MAX_CPUS; i++) { - max = 0; + pil_pending = 0; if (pending && !(s->intregm_disabled & 0x80000000) && (i == s->target_cpu)) { for (j = 0; j < 32; j++) { - if (pending & (1 << j)) { - if (max < s->intbit_to_level[j]) - max = s->intbit_to_level[j]; - } + if (pending & (1 << j)) + pil_pending |= 1 << s->intbit_to_level[j]; } } - for (j = 17; j < 32; j++) { - if (s->intreg_pending[i] & (1 << j)) { - if (max < j - 16) - max = j - 16; + pil_pending |= (s->intreg_pending[i] >> 16) & 0xfffe; + + for (j = 0; j < MAX_PILS; j++) { + if (pil_pending & (1 << j)) { + if (!(s->pil_out[i] & (1 << j))) + qemu_irq_raise(s->cpu_irqs[i][j]); + } else { + if (s->pil_out[i] & (1 << j)) + qemu_irq_lower(s->cpu_irqs[i][j]); } } - raise_pil(s, max, i); + s->pil_out[i] = pil_pending; } } @@ -291,6 +277,9 @@ static void slavio_set_irq(void *opaque, int irq, int level) level); if (pil > 0) { if (level) { +#ifdef DEBUG_IRQ_COUNT + s->irq_count[pil]++; +#endif s->intregm_pending |= mask; s->intreg_pending[s->target_cpu] |= 1 << pil; } else { @@ -342,6 +331,7 @@ static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id) qemu_get_be32s(f, &s->intregm_pending); qemu_get_be32s(f, &s->intregm_disabled); qemu_get_be32s(f, &s->target_cpu); + slavio_check_interrupts(s); return 0; } @@ -356,6 +346,7 @@ static void slavio_intctl_reset(void *opaque) s->intregm_disabled = ~0xffb2007f; s->intregm_pending = 0; s->target_cpu = 0; + slavio_check_interrupts(s); } void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg, diff --git a/hw/sun4m.c b/hw/sun4m.c index eb69ef8e58..5974812670 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -240,26 +240,41 @@ void irq_info() slavio_irq_info(slavio_intctl); } +void cpu_check_irqs(CPUState *env) +{ + if (env->pil_in && (env->interrupt_index == 0 || + (env->interrupt_index & ~15) == TT_EXTINT)) { + unsigned int i; + + for (i = 15; i > 0; i--) { + if (env->pil_in & (1 << i)) { + int old_interrupt = env->interrupt_index; + + env->interrupt_index = TT_EXTINT | i; + if (old_interrupt != env->interrupt_index) + cpu_interrupt(env, CPU_INTERRUPT_HARD); + break; + } + } + } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) { + env->interrupt_index = 0; + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); + } +} + static void cpu_set_irq(void *opaque, int irq, int level) { CPUState *env = opaque; if (level) { DPRINTF("Raise CPU IRQ %d\n", irq); - env->halted = 0; - - if (env->interrupt_index == 0 || - ((env->interrupt_index & ~15) == TT_EXTINT && - (env->interrupt_index & 15) < irq)) { - env->interrupt_index = TT_EXTINT | irq; - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } else { - DPRINTF("Not triggered, pending exception %d\n", - env->interrupt_index); - } + env->pil_in |= 1 << irq; + cpu_check_irqs(env); } else { DPRINTF("Lower CPU IRQ %d\n", irq); + env->pil_in &= ~(1 << irq); + cpu_check_irqs(env); } } |