EIC is required for pic32 microcontroller. Signed-off-by: Serge Vakulenko <serge.vakule...@gmail.com> --- hw/mips/cputimer.c | 17 +++++++++++++++-- hw/mips/mips_int.c | 8 +++++++- target-mips/cpu.h | 8 +++++++- target-mips/helper.c | 18 ++++++++++++------ 4 files changed, 41 insertions(+), 10 deletions(-)
diff --git a/hw/mips/cputimer.c b/hw/mips/cputimer.c index 58707ed..dab532d 100644 --- a/hw/mips/cputimer.c +++ b/hw/mips/cputimer.c @@ -63,7 +63,13 @@ static void cpu_mips_timer_expire(CPUMIPSState *env) if (env->insn_flags & ISA_MIPS32R2) { env->CP0_Cause |= 1 << CP0Ca_TI; } - qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); + if (env->CP0_Config3 & (1 << CP0C3_VEIC)) { + /* External interrupt controller mode. */ + qemu_irq_raise(env->eic_timer_irq); + } else { + /* Legacy or vectored interrupt mode. */ + qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); + } } uint32_t cpu_mips_get_count (CPUMIPSState *env) @@ -111,7 +117,14 @@ void cpu_mips_store_compare (CPUMIPSState *env, uint32_t value) cpu_mips_timer_update(env); if (env->insn_flags & ISA_MIPS32R2) env->CP0_Cause &= ~(1 << CP0Ca_TI); - qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); + + if (env->CP0_Config3 & (1 << CP0C3_VEIC)) { + /* External interrupt controller mode. */ + qemu_irq_lower(env->eic_timer_irq); + } else { + /* Legacy or vectored interrupt mode. */ + qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]); + } } void cpu_mips_start_count(CPUMIPSState *env) diff --git a/hw/mips/mips_int.c b/hw/mips/mips_int.c index d740046..eb92439 100644 --- a/hw/mips/mips_int.c +++ b/hw/mips/mips_int.c @@ -74,5 +74,11 @@ void cpu_mips_soft_irq(CPUMIPSState *env, int irq, int level) return; } - qemu_set_irq(env->irq[irq], level); + if (env->CP0_Config3 & (1 << CP0C3_VEIC)) { + /* External interrupt controller mode. */ + qemu_set_irq(env->eic_soft_irq[irq], level); + } else { + /* Legacy or vectored interrupt mode. */ + qemu_set_irq(env->irq[irq], level); + } } diff --git a/target-mips/cpu.h b/target-mips/cpu.h index c476166..9513f02 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -596,6 +596,10 @@ struct CPUMIPSState { void *irq[8]; QEMUTimer *timer; /* Internal timer */ unsigned count_freq; /* rate of Count register */ + + /* Fields for external interrupt controller. */ + void *eic_timer_irq; + void *eic_soft_irq[2]; }; #include "cpu-qom.h" @@ -664,7 +668,9 @@ static inline int cpu_mips_hw_interrupts_pending(CPUMIPSState *env) if (env->CP0_Config3 & (1 << CP0C3_VEIC)) { /* A MIPS configured with a vectorizing external interrupt controller will feed a vector into the Cause pending lines. The core treats - the status lines as a vector level, not as indiviual masks. */ + the status lines as a vector level, not as individual masks. */ + pending >>= CP0Ca_IP + 2; + status >>= CP0Ca_IP + 2; r = pending > status; } else { /* A MIPS configured with compatibility or VInt (Vectored Interrupts) diff --git a/target-mips/helper.c b/target-mips/helper.c index 8e3204a..6fe5212 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -574,23 +574,29 @@ void mips_cpu_do_interrupt(CPUState *cs) unsigned int vector; unsigned int pending = (env->CP0_Cause & CP0Ca_IP_mask) >> 8; - pending &= env->CP0_Status >> 8; /* Compute the Vector Spacing. */ spacing = (env->CP0_IntCtl >> CP0IntCtl_VS) & ((1 << 6) - 1); spacing <<= 5; - if (env->CP0_Config3 & (1 << CP0C3_VInt)) { + if (env->CP0_Config3 & (1 << CP0C3_VEIC)) { + /* For VEIC mode, the external interrupt controller feeds the + * vector through the CP0Cause IP lines. */ + vector = pending; + + /* Architecturally, this is chip-specific behavior. + * Some processors, like PIC32, have a separate + * bit INTCON.MVEC to explicitly enable vectored mode, + * disabled by default. */ + spacing = 0; + } else { /* For VInt mode, the MIPS computes the vector internally. */ + pending &= env->CP0_Status >> 8; for (vector = 7; vector > 0; vector--) { if (pending & (1 << vector)) { /* Found it. */ break; } } - } else { - /* For VEIC mode, the external interrupt controller feeds the - vector through the CP0Cause IP lines. */ - vector = pending; } offset = 0x200 + vector * spacing; } -- 2.2.2