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