drc: handle regs-not-in-psxRegs case better
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / events.c
diff --git a/libpcsxcore/new_dynarec/events.c b/libpcsxcore/new_dynarec/events.c
new file mode 100644 (file)
index 0000000..5d981f8
--- /dev/null
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include "../r3000a.h"
+#include "../cdrom.h"
+#include "../psxdma.h"
+#include "../mdec.h"
+#include "events.h"
+
+extern int pending_exception;
+
+//#define evprintf printf
+#define evprintf(...)
+
+u32 event_cycles[PSXINT_COUNT];
+
+void schedule_timeslice(void)
+{
+       u32 i, c = psxRegs.cycle;
+       u32 irqs = psxRegs.interrupt;
+       s32 min, dif;
+
+       min = PSXCLK;
+       for (i = 0; irqs != 0; i++, irqs >>= 1) {
+               if (!(irqs & 1))
+                       continue;
+               dif = event_cycles[i] - c;
+               //evprintf("  ev %d\n", dif);
+               if (0 < dif && dif < min)
+                       min = dif;
+       }
+       next_interupt = c + min;
+}
+
+static void unusedInterrupt()
+{
+}
+
+typedef void (irq_func)();
+
+static irq_func * const irq_funcs[] = {
+       [PSXINT_SIO]    = sioInterrupt,
+       [PSXINT_CDR]    = cdrInterrupt,
+       [PSXINT_CDREAD] = cdrPlayReadInterrupt,
+       [PSXINT_GPUDMA] = gpuInterrupt,
+       [PSXINT_MDECOUTDMA] = mdec1Interrupt,
+       [PSXINT_SPUDMA] = spuInterrupt,
+       [PSXINT_MDECINDMA] = mdec0Interrupt,
+       [PSXINT_GPUOTCDMA] = gpuotcInterrupt,
+       [PSXINT_CDRDMA] = cdrDmaInterrupt,
+       [PSXINT_CDRLID] = cdrLidSeekInterrupt,
+       [PSXINT_CDRPLAY_OLD] = unusedInterrupt,
+       [PSXINT_SPU_UPDATE] = spuUpdate,
+       [PSXINT_RCNT] = psxRcntUpdate,
+};
+
+/* local dupe of psxBranchTest, using event_cycles */
+static void irq_test(psxCP0Regs *cp0)
+{
+       u32 cycle = psxRegs.cycle;
+       u32 irq, irq_bits;
+
+       for (irq = 0, irq_bits = psxRegs.interrupt; irq_bits != 0; irq++, irq_bits >>= 1) {
+               if (!(irq_bits & 1))
+                       continue;
+               if ((s32)(cycle - event_cycles[irq]) >= 0) {
+                       // note: irq_funcs() also modify psxRegs.interrupt
+                       psxRegs.interrupt &= ~(1u << irq);
+                       irq_funcs[irq]();
+               }
+       }
+
+       if ((psxHu32(0x1070) & psxHu32(0x1074)) && (cp0->n.Status & 0x401) == 0x401) {
+               psxException(0x400, 0, cp0);
+               pending_exception = 1;
+       }
+}
+
+void gen_interupt(psxCP0Regs *cp0)
+{
+       evprintf("  +ge %08x, %u->%u (%d)\n", psxRegs.pc, psxRegs.cycle,
+               next_interupt, next_interupt - psxRegs.cycle);
+
+       irq_test(cp0);
+       //pending_exception = 1;
+
+       schedule_timeslice();
+
+       evprintf("  -ge %08x, %u->%u (%d)\n", psxRegs.pc, psxRegs.cycle,
+               next_interupt, next_interupt - psxRegs.cycle);
+}
+
+