1e2d01f6071a46be4c100610e93b3fb486cef6e9
[pcsx_rearmed.git] / libpcsxcore / psxevents.c
1 #include <stddef.h>
2 #include <stdio.h>
3 #include "r3000a.h"
4 #include "cdrom.h"
5 #include "psxdma.h"
6 #include "mdec.h"
7 #include "psxevents.h"
8
9 //#define evprintf printf
10 #define evprintf(...)
11
12 static psxRegisters *cp0TOpsxRegs(psxCP0Regs *cp0)
13 {
14 #ifndef LIGHTREC
15         return (void *)((char *)cp0 - offsetof(psxRegisters, CP0));
16 #else
17         // lightrec has it's own cp0
18         return &psxRegs;
19 #endif
20 }
21
22 u32 schedule_timeslice(psxRegisters *regs)
23 {
24         u32 i, c = regs->cycle;
25         u32 irqs = regs->interrupt;
26         s32 min, dif;
27
28         min = PSXCLK;
29         for (i = 0; irqs != 0; i++, irqs >>= 1) {
30                 if (!(irqs & 1))
31                         continue;
32                 dif = regs->event_cycles[i] - c;
33                 //evprintf("  ev %d\n", dif);
34                 if (0 < dif && dif < min)
35                         min = dif;
36         }
37         regs->next_interupt = c + min;
38         return regs->next_interupt;
39 }
40
41 static void irqNoOp() {
42 }
43
44 typedef void (irq_func)();
45
46 static irq_func * const irq_funcs[] = {
47         [PSXINT_SIO]    = sioInterrupt,
48         [PSXINT_CDR]    = cdrInterrupt,
49         [PSXINT_CDREAD] = cdrPlayReadInterrupt,
50         [PSXINT_GPUDMA] = gpuInterrupt,
51         [PSXINT_MDECOUTDMA] = mdec1Interrupt,
52         [PSXINT_SPUDMA] = spuInterrupt,
53         [PSXINT_MDECINDMA] = mdec0Interrupt,
54         [PSXINT_GPUOTCDMA] = gpuotcInterrupt,
55         [PSXINT_CDRDMA] = cdrDmaInterrupt,
56         [PSXINT_NEWDRC_CHECK] = irqNoOp,
57         [PSXINT_CDRLID] = cdrLidSeekInterrupt,
58         [PSXINT_IRQ10] = irq10Interrupt,
59         [PSXINT_SPU_UPDATE] = spuUpdate,
60         [PSXINT_SPU_IRQ] = spuDelayedIrq,
61         [PSXINT_RCNT] = psxRcntUpdate,
62 };
63
64 void irq_test(psxCP0Regs *cp0)
65 {
66         psxRegisters *regs = cp0TOpsxRegs(cp0);
67         u32 cycle = regs->cycle;
68         u32 irq, irq_bits;
69
70         for (irq = 0, irq_bits = regs->interrupt; irq_bits != 0; irq++, irq_bits >>= 1) {
71                 if (!(irq_bits & 1))
72                         continue;
73                 if ((s32)(cycle - regs->event_cycles[irq]) >= 0) {
74                         // note: irq_funcs() also modify regs->interrupt
75                         regs->interrupt &= ~(1u << irq);
76                         irq_funcs[irq]();
77                 }
78         }
79
80         cp0->n.Cause &= ~0x400;
81         if (psxHu32(0x1070) & psxHu32(0x1074))
82                 cp0->n.Cause |= 0x400;
83         if (((cp0->n.Cause | 1) & cp0->n.SR & 0x401) == 0x401)
84                 psxException(0, 0, cp0);
85 }
86
87 void gen_interupt(psxCP0Regs *cp0)
88 {
89         psxRegisters *regs = cp0TOpsxRegs(cp0);
90
91         evprintf("  +ge %08x, %u->%u (%d)\n", regs->pc, regs->cycle,
92                 regs->next_interupt, regs->next_interupt - regs->cycle);
93
94         irq_test(cp0);
95         schedule_timeslice(regs);
96
97         evprintf("  -ge %08x, %u->%u (%d)\n", regs->pc, regs->cycle,
98                 regs->next_interupt, regs->next_interupt - regs->cycle);
99 }
100
101 void events_restore(void)
102 {
103         int i;
104         for (i = 0; i < PSXINT_COUNT; i++)
105                 psxRegs.event_cycles[i] = psxRegs.intCycle[i].sCycle + psxRegs.intCycle[i].cycle;
106
107         psxRegs.event_cycles[PSXINT_RCNT] = psxRegs.psxNextsCounter + psxRegs.psxNextCounter;
108         psxRegs.interrupt |=  1 << PSXINT_RCNT;
109         psxRegs.interrupt &= (1 << PSXINT_COUNT) - 1;
110 }