[PATCH v2 4/6] sim/mips: Check all interrupt enable conditions
Sebastian Huber <[email protected]>
| Newsgroups | gmane.comp.gdb.patches |
|---|---|
| Message-ID | <[email protected]> |
interrupt_event() tested Status.IE alone. On a target with an
exception level it delivered an interrupt while Status.EXL was set.
The simulator entered the exception handler again through the vector
and left EPC at the address of the older exception. The handler lost
its resume point. The test also let an interrupt through in debug
mode.
Collect the conditions which enable an interrupt in
interrupts_enabled(). Use this function for the delivery.
---
sim/mips/interp.c | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/sim/mips/interp.c b/sim/mips/interp.c
index 5dbd1482b99..dc918bb9281 100644
--- a/sim/mips/interp.c
+++ b/sim/mips/interp.c
@@ -295,12 +295,38 @@ static const OPTION mips_options[] =
int interrupt_pending;
+/* The interrupts are enabled while the Status register enables them and the
+ processor is at no exception level, at no error level and not in debug
+ mode:
+
+ Status.IE = 1, Status.EXL = 0, Status.ERL = 0, Debug.DM = 0
+
+ MIPS Architecture For Programmers Volume III: The MIPS Privileged Resource
+ Architecture, the Interrupts chapter. The R3000 generation, which the
+ R3900 belongs to, has no exception level and no error level. It disables
+ the interrupts through the interrupt enable stack of its Status register,
+ so only the current enable takes part. See the IDT R30xx Family Software
+ Reference Manual, the Status register of the CPU control chapter. */
+static int
+interrupts_enabled (sim_cpu *cpu)
+{
+ if ((SR & status_IE) == 0)
+ return 0;
+
+#ifndef SUBTARGET_R3900
+ if ((SR & (status_EXL | status_ERL)) != 0)
+ return 0;
+#endif
+
+ return (Debug & Debug_DM) == 0;
+}
+
void
interrupt_event (SIM_DESC sd, void *data)
{
sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
address_word cia = CPU_PC_GET (cpu);
- if (SR & status_IE)
+ if (interrupts_enabled (cpu))
{
interrupt_pending = 0;
SignalExceptionInterrupt (1); /* interrupt "1" */
--
2.51.0