[PATCH v2 6/6] sim/mips: Recognise a software interrupt request
Sebastian Huber <[email protected]>
| Newsgroups | gmane.comp.gdb.patches |
|---|---|
| Message-ID | <[email protected]> |
The simulator ignored the Cause.IP0 and Cause.IP1 software generated
interrupts of the MIPS Architecture For Programmers Volume III: The
MIPS Privileged Resource Architecture. A client which requested one
got no exception.
Check the request wherever an instruction enables the interrupts or
writes a pending bit. These places are the writes to the Status and
Cause registers, ERET, RFE and EI. Deliver the interrupt through the
event queue and not in place, because signal_exception() leaves the
handler address in the program counter for an interrupt. The
simulator would overwrite it with the result of the current
instruction.
---
sim/mips/interp.c | 51 ++++++++++++++++++++++++++++++++++++++--
sim/mips/micromips.igen | 1 +
sim/mips/mips.igen | 1 +
sim/mips/mips3264r2.igen | 1 +
sim/mips/sim-main.h | 2 ++
5 files changed, 54 insertions(+), 2 deletions(-)
diff --git a/sim/mips/interp.c b/sim/mips/interp.c
index 8118b290a17..4a461879804 100644
--- a/sim/mips/interp.c
+++ b/sim/mips/interp.c
@@ -321,6 +321,46 @@ interrupts_enabled (sim_cpu *cpu)
return (Debug & Debug_DM) == 0;
}
+/* A software interrupt is requested while the interrupts are enabled and a
+ software interrupt pending bit of the Cause register meets its mask bit in
+ the Status register. The Cause.IP bits meet the Status.IM bits. See the
+ MIPS Architecture For Programmers Volume III: The MIPS Privileged Resource
+ Architecture, the Interrupts chapter. */
+static int
+software_interrupt_requested (sim_cpu *cpu)
+{
+ if (!interrupts_enabled (cpu))
+ return 0;
+
+ /* Only the software interrupts. A hardware interrupt keeps its pending bit
+ set until its device is served. The device model delivers it. */
+ return (CAUSE & SR & (cause_SW1 | cause_SW0)) != 0;
+}
+
+static void
+software_interrupt_event (SIM_DESC sd, void *data)
+{
+ sim_cpu *cpu = STATE_CPU (sd, 0);
+ address_word cia = CPU_PC_GET (cpu);
+
+ /* Check again, because the write which scheduled this event may have been
+ undone in the meantime. */
+ if (software_interrupt_requested (cpu))
+ SignalExceptionInterrupt (0);
+}
+
+/* Deliver a requested software interrupt at the next instruction boundary.
+ The delivery cannot happen here: signal_exception() leaves the handler
+ address in the program counter for an interrupt and the instruction which
+ the simulator executes would overwrite it. This is why the hardware
+ interrupts arrive through the event queue as well. */
+void
+check_software_interrupts (SIM_DESC sd, sim_cpu *cpu)
+{
+ if (software_interrupt_requested (cpu))
+ sim_events_schedule (sd, 1, software_interrupt_event, NULL);
+}
+
void
interrupt_event (SIM_DESC sd, void *data)
{
@@ -2295,14 +2335,20 @@ decode_coproc (SIM_DESC sd,
if (op == cp0_mfc0 || op == cp0_dmfc0)
GPR[rt] = SR;
else
- SR = GPR[rt];
+ {
+ SR = GPR[rt];
+ check_software_interrupts (sd, cpu);
+ }
break;
/* 13 = Cause R4000 VR4100 VR4300 */
case 13:
if (op == cp0_mfc0 || op == cp0_dmfc0)
GPR[rt] = CAUSE;
else
- CAUSE = GPR[rt];
+ {
+ CAUSE = GPR[rt];
+ check_software_interrupts (sd, cpu);
+ }
break;
/* 14 = EPC R4000 VR4100 VR4300 */
case 14:
@@ -2427,6 +2473,7 @@ decode_coproc (SIM_DESC sd,
/* shift IE/KU history bits right */
SR = LSMASKED32(SR, 31, 4) | LSINSERTED32(LSEXTRACTED32(SR, 5, 2), 3, 0);
+ check_software_interrupts (sd, cpu);
/* TODO: CACHE register */
#endif /* SUBTARGET_R3900 */
diff --git a/sim/mips/micromips.igen b/sim/mips/micromips.igen
index 8bb48cac1e4..2149aee352f 100644
--- a/sim/mips/micromips.igen
+++ b/sim/mips/micromips.igen
@@ -995,6 +995,7 @@
NIA = EPC;
SR &= ~status_EXL;
}
+ check_software_interrupts (SD, CPU);
}
diff --git a/sim/mips/mips.igen b/sim/mips/mips.igen
index 3b52f2df43f..4becc3da31e 100644
--- a/sim/mips/mips.igen
+++ b/sim/mips/mips.igen
@@ -6715,6 +6715,7 @@
NIA = EPC;
SR &= ~status_EXL;
}
+ check_software_interrupts (SD, CPU);
}
diff --git a/sim/mips/mips3264r2.igen b/sim/mips/mips3264r2.igen
index 67598e84433..2864d9b77de 100644
--- a/sim/mips/mips3264r2.igen
+++ b/sim/mips/mips3264r2.igen
@@ -94,6 +94,7 @@
TRACE_ALU_INPUT0 ();
GPR[rt] = EXTEND32 (SR);
SR |= status_IE;
+ check_software_interrupts (SD, CPU);
TRACE_ALU_RESULT1 (GPR[rt]);
}
diff --git a/sim/mips/sim-main.h b/sim/mips/sim-main.h
index 28a4221dfd5..73a3f9c992b 100644
--- a/sim/mips/sim-main.h
+++ b/sim/mips/sim-main.h
@@ -655,6 +655,8 @@ enum ExceptionCause {
void interrupt_event (SIM_DESC sd, void *data);
+void check_software_interrupts (SIM_DESC sd, sim_cpu *cpu);
+
void signal_exception (SIM_DESC sd, sim_cpu *cpu, address_word cia, int exception, ...);
#define SignalException(exc,instruction) signal_exception (SD, CPU, cia, (exc), (instruction))
#define SignalExceptionInterrupt(level) signal_exception (SD, CPU, cia, Interrupt, level)
--
2.51.0