[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.