drc: improved interrupt code for emu_if
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / emu_if.c
1 /*
2  * (C) GraÅžvydas "notaz" Ignotas, 2010
3  *
4  * This work is licensed under the terms of GNU GPL version 2 or later.
5  * See the COPYING file in the top-level directory.
6  */
7
8 #include <stdio.h>
9
10 #include "emu_if.h"
11 #include "pcsxmem.h"
12 #include "../psxhle.h"
13 #include "../r3000a.h"
14 #include "../cdrom.h"
15 #include "../psxdma.h"
16 #include "../mdec.h"
17
18 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
19
20 //#define evprintf printf
21 #define evprintf(...)
22
23 char invalid_code[0x100000];
24 u32 event_cycles[PSXINT_COUNT];
25
26 static void schedule_timeslice(void)
27 {
28         u32 i, c = psxRegs.cycle;
29         s32 min, dif;
30
31         min = psxNextsCounter + psxNextCounter - c;
32         for (i = 0; i < ARRAY_SIZE(event_cycles); i++) {
33                 dif = event_cycles[i] - c;
34                 //evprintf("  ev %d\n", dif);
35                 if (0 < dif && dif < min)
36                         min = dif;
37         }
38         next_interupt = c + min;
39
40 #if 0
41         static u32 cnt, last_cycle;
42         static u64 sum;
43         if (last_cycle) {
44                 cnt++;
45                 sum += psxRegs.cycle - last_cycle;
46                 if ((cnt & 0xff) == 0)
47                         printf("%u\n", (u32)(sum / cnt));
48         }
49         last_cycle = psxRegs.cycle;
50 #endif
51 }
52
53 typedef void (irq_func)();
54
55 static irq_func * const irq_funcs[] = {
56         [PSXINT_SIO]    = sioInterrupt,
57         [PSXINT_CDR]    = cdrInterrupt,
58         [PSXINT_CDREAD] = cdrReadInterrupt,
59         [PSXINT_GPUDMA] = gpuInterrupt,
60         [PSXINT_MDECOUTDMA] = mdec1Interrupt,
61         [PSXINT_SPUDMA] = spuInterrupt,
62 };
63
64 /* local dupe of psxBranchTest, using event_cycles */
65 static void irq_test(void)
66 {
67         u32 irqs = psxRegs.interrupt;
68         u32 cycle = psxRegs.cycle;
69         u32 irq, irq_bits;
70
71         if ((psxRegs.cycle - psxNextsCounter) >= psxNextCounter)
72                 psxRcntUpdate();
73
74         // irq_funcs() may queue more irqs
75         psxRegs.interrupt = 0;
76
77         for (irq = 0, irq_bits = irqs; irq_bits != 0; irq++, irq_bits >>= 1) {
78                 if (!(irq_bits & 1))
79                         continue;
80                 if ((s32)(cycle - event_cycles[irq]) >= 0) {
81                         irqs &= ~(1 << irq);
82                         irq_funcs[irq]();
83                 }
84         }
85         psxRegs.interrupt |= irqs;
86
87         if ((psxHu32(0x1070) & psxHu32(0x1074)) && (Status & 0x401) == 0x401) {
88                 psxException(0x400, 0);
89                 pending_exception = 1;
90         }
91 }
92
93 void gen_interupt()
94 {
95         evprintf("  +ge %08x, %u->%u\n", psxRegs.pc, psxRegs.cycle, next_interupt);
96 #ifdef DRC_DBG
97         psxRegs.cycle += 2;
98 #endif
99
100         irq_test();
101         //psxBranchTest();
102         //pending_exception = 1;
103
104         schedule_timeslice();
105
106         evprintf("  -ge %08x, %u->%u (%d)\n", psxRegs.pc, psxRegs.cycle,
107                 next_interupt, next_interupt - psxRegs.cycle);
108 }
109
110 void MTC0_()
111 {
112         extern void psxMTC0();
113
114         evprintf("ari64 MTC0 %08x %08x %u\n", psxRegs.code, psxRegs.pc, psxRegs.cycle);
115         psxMTC0();
116         gen_interupt(); /* FIXME: checking pending irqs should be enough */
117 }
118
119 void check_interupt()
120 {
121         /* FIXME (also asm) */
122         printf("ari64_check_interupt\n");
123 }
124
125 void new_dyna_save(void)
126 {
127         // psxRegs.intCycle is always maintained, no need to convert
128 }
129
130 void new_dyna_restore(void)
131 {
132         int i;
133         for (i = 0; i < PSXINT_NEWDRC_CHECK; i++)
134                 event_cycles[i] = psxRegs.intCycle[i].sCycle + psxRegs.intCycle[i].cycle;
135 }
136
137 void *gte_handlers[64];
138
139 /* from gte.txt.. not sure if this is any good. */
140 const char gte_cycletab[64] = {
141         /*   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f */
142          0, 15,  0,  0,  0,  0,  8,  0,  0,  0,  0,  0,  6,  0,  0,  0,
143          8,  8,  8, 19, 13,  0, 44,  0,  0,  0,  0, 17, 11,  0, 14,  0,
144         30,  0,  0,  0,  0,  0,  0,  0,  5,  8, 17,  0,  0,  5,  6,  0,
145         23,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  5,  5, 39,
146 };
147
148 static int ari64_init()
149 {
150         extern void (*psxCP2[64])();
151         extern void psxNULL();
152         extern void *psxH_ptr;
153         size_t i;
154
155         new_dynarec_init();
156         new_dyna_pcsx_mem_init();
157
158         for (i = 0; i < ARRAY_SIZE(gte_handlers); i++)
159                 if (psxCP2[i] != psxNULL)
160                         gte_handlers[i] = psxCP2[i];
161
162         psxH_ptr = psxH;
163
164         return 0;
165 }
166
167 static void ari64_reset()
168 {
169         printf("ari64_reset\n");
170         new_dyna_pcsx_mem_reset();
171         invalidate_all_pages();
172         pending_exception = 1;
173 }
174
175 static void ari64_execute()
176 {
177         schedule_timeslice();
178
179         evprintf("ari64_execute %08x, %u->%u (%d)\n", psxRegs.pc,
180                 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
181
182         new_dyna_start();
183
184         evprintf("ari64_execute end %08x, %u->%u (%d)\n", psxRegs.pc,
185                 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
186 }
187
188 static void ari64_clear(u32 addr, u32 size)
189 {
190         u32 start, end;
191
192         evprintf("ari64_clear %08x %04x\n", addr, size);
193
194         /* check for RAM mirrors */
195         if ((addr & ~0xe0600000) < 0x200000) {
196                 addr &= ~0xe0600000;
197                 addr |=  0x80000000;
198         }
199
200         start = addr >> 12;
201         end = (addr + size) >> 12;
202
203         for (; start <= end; start++)
204                 if (!invalid_code[start])
205                         invalidate_block(start);
206 }
207
208 static void ari64_shutdown()
209 {
210         new_dynarec_cleanup();
211 }
212
213 extern void intExecute();
214 extern void intExecuteT();
215 extern void intExecuteBlock();
216 extern void intExecuteBlockT();
217 #ifndef DRC_DBG
218 #define intExecuteT intExecute
219 #define intExecuteBlockT intExecuteBlock
220 #endif
221
222 R3000Acpu psxRec = {
223         ari64_init,
224         ari64_reset,
225 #if 1
226         ari64_execute,
227         ari64_execute,
228 #else
229         intExecuteT,
230         intExecuteBlockT,
231 #endif
232         ari64_clear,
233         ari64_shutdown
234 };
235
236 // TODO: rm
237 #ifndef DRC_DBG
238 void do_insn_trace() {}
239 void do_insn_cmp() {}
240 #endif
241
242 #if defined(__x86_64__) || defined(__i386__)
243 unsigned int address, readmem_word, word;
244 unsigned short hword;
245 unsigned char byte;
246 int pending_exception, stop;
247 unsigned int next_interupt;
248 void *psxH_ptr;
249 void new_dynarec_init() {}
250 void new_dyna_start() {}
251 void new_dynarec_cleanup() {}
252 void invalidate_all_pages() {}
253 void invalidate_block(unsigned int block) {}
254 void new_dyna_pcsx_mem_init(void) {}
255 void new_dyna_pcsx_mem_reset(void) {}
256 #endif
257
258 #ifdef DRC_DBG
259
260 #include <stddef.h>
261 static FILE *f;
262 extern u32 last_io_addr;
263
264 static void dump_mem(const char *fname, void *mem, size_t size)
265 {
266         FILE *f1 = fopen(fname, "wb");
267         if (f1 == NULL)
268                 f1 = fopen(strrchr(fname, '/') + 1, "wb");
269         fwrite(mem, 1, size, f1);
270         fclose(f1);
271 }
272
273 void do_insn_trace(void)
274 {
275         static psxRegisters oldregs;
276         static u32 old_io_addr = (u32)-1;
277         static u32 old_io_data = 0xbad0c0de;
278         u32 *allregs_p = (void *)&psxRegs;
279         u32 *allregs_o = (void *)&oldregs;
280         u32 *io_data;
281         int i;
282         u8 byte;
283
284 //last_io_addr = 0x5e2c8;
285         if (f == NULL)
286                 f = fopen("tracelog", "wb");
287
288         oldregs.code = psxRegs.code; // don't care
289         for (i = 0; i < offsetof(psxRegisters, intCycle) / 4; i++) {
290                 if (allregs_p[i] != allregs_o[i]) {
291                         fwrite(&i, 1, 1, f);
292                         fwrite(&allregs_p[i], 1, 4, f);
293                         allregs_o[i] = allregs_p[i];
294                 }
295         }
296         if (old_io_addr != last_io_addr) {
297                 byte = 0xfd;
298                 fwrite(&byte, 1, 1, f);
299                 fwrite(&last_io_addr, 1, 4, f);
300                 old_io_addr = last_io_addr;
301         }
302         io_data = (void *)(psxM + (last_io_addr&0x1ffffc));
303         if (old_io_data != *io_data) {
304                 byte = 0xfe;
305                 fwrite(&byte, 1, 1, f);
306                 fwrite(io_data, 1, 4, f);
307                 old_io_data = *io_data;
308         }
309         byte = 0xff;
310         fwrite(&byte, 1, 1, f);
311
312 #if 0
313         if (psxRegs.cycle == 190230) {
314                 dump_mem("/mnt/ntz/dev/pnd/tmp/psxram_i.dump", psxM, 0x200000);
315                 dump_mem("/mnt/ntz/dev/pnd/tmp/psxregs_i.dump", psxH, 0x10000);
316                 printf("dumped\n");
317                 exit(1);
318         }
319 #endif
320 }
321
322 static const char *regnames[offsetof(psxRegisters, intCycle) / 4] = {
323         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
324         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
325         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
326         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
327         "lo",  "hi",
328         "C0_0",  "C0_1",  "C0_2",  "C0_3",  "C0_4",  "C0_5",  "C0_6",  "C0_7",
329         "C0_8",  "C0_9",  "C0_10", "C0_11", "C0_12", "C0_13", "C0_14", "C0_15",
330         "C0_16", "C0_17", "C0_18", "C0_19", "C0_20", "C0_21", "C0_22", "C0_23",
331         "C0_24", "C0_25", "C0_26", "C0_27", "C0_28", "C0_29", "C0_30", "C0_31",
332
333         "C2D0",  "C2D1",  "C2D2",  "C2D3",  "C2D4",  "C2D5",  "C2D6",  "C2D7",
334         "C2D8",  "C2D9",  "C2D10", "C2D11", "C2D12", "C2D13", "C2D14", "C2D15",
335         "C2D16", "C2D17", "C2D18", "C2D19", "C2D20", "C2D21", "C2D22", "C2D23",
336         "C2D24", "C2D25", "C2D26", "C2D27", "C2D28", "C2D29", "C2D30", "C2D31",
337
338         "C2C0",  "C2C1",  "C2C2",  "C2C3",  "C2C4",  "C2C5",  "C2C6",  "C2C7",
339         "C2C8",  "C2C9",  "C2C10", "C2C11", "C2C12", "C2C13", "C2C14", "C2C15",
340         "C2C16", "C2C17", "C2C18", "C2C19", "C2C20", "C2C21", "C2C22", "C2C23",
341         "C2C24", "C2C25", "C2C26", "C2C27", "C2C28", "C2C29", "C2C30", "C2C31",
342
343         "PC", "code", "cycle", "interrupt",
344 };
345
346 static struct {
347         int reg;
348         u32 val, val_expect;
349         u32 pc, cycle;
350 } miss_log[64];
351 static int miss_log_i;
352 #define miss_log_len (sizeof(miss_log)/sizeof(miss_log[0]))
353 #define miss_log_mask (miss_log_len-1)
354
355 static void miss_log_add(int reg, u32 val, u32 val_expect, u32 pc, u32 cycle)
356 {
357         miss_log[miss_log_i].reg = reg;
358         miss_log[miss_log_i].val = val;
359         miss_log[miss_log_i].val_expect = val_expect;
360         miss_log[miss_log_i].pc = pc;
361         miss_log[miss_log_i].cycle = cycle;
362         miss_log_i = (miss_log_i + 1) & miss_log_mask;
363 }
364
365 void breakme() {}
366
367 void do_insn_cmp(void)
368 {
369         static psxRegisters rregs;
370         static u32 mem_addr, mem_val;
371         u32 *allregs_p = (void *)&psxRegs;
372         u32 *allregs_e = (void *)&rregs;
373         static u32 ppc, failcount;
374         int i, ret, bad = 0;
375         u8 code;
376
377         if (f == NULL)
378                 f = fopen("tracelog", "rb");
379
380         while (1) {
381                 if ((ret = fread(&code, 1, 1, f)) <= 0)
382                         break;
383                 if (ret <= 0)
384                         break;
385                 if (code == 0xff)
386                         break;
387                 if (code == 0xfd) {
388                         if ((ret = fread(&mem_addr, 1, 4, f)) <= 0)
389                                 break;
390                         continue;
391                 }
392                 if (code == 0xfe) {
393                         if ((ret = fread(&mem_val, 1, 4, f)) <= 0)
394                                 break;
395                         continue;
396                 }
397                 if ((ret = fread(&allregs_e[code], 1, 4, f)) <= 0)
398                         break;
399         }
400
401         if (ret <= 0) {
402                 printf("EOF?\n");
403                 goto end;
404         }
405
406         psxRegs.code = rregs.code; // don't care
407 psxRegs.cycle = rregs.cycle;
408 psxRegs.CP0.r[9] = rregs.CP0.r[9]; // Count
409
410 //if (psxRegs.cycle == 166172) breakme();
411 //if (psxRegs.cycle > 11296376) printf("pc=%08x %u  %08x\n", psxRegs.pc, psxRegs.cycle, psxRegs.interrupt);
412
413         mem_addr &= 0x1ffffc;
414
415         if (memcmp(&psxRegs, &rregs, offsetof(psxRegisters, intCycle)) == 0 &&
416                         mem_val == *(u32 *)(psxM + mem_addr)
417            ) {
418                 failcount = 0;
419                 goto ok;
420         }
421
422         for (i = 0; i < offsetof(psxRegisters, intCycle) / 4; i++) {
423                 if (allregs_p[i] != allregs_e[i]) {
424                         miss_log_add(i, allregs_p[i], allregs_e[i], psxRegs.pc, psxRegs.cycle);
425                         bad++;
426                 }
427         }
428
429         if (mem_val != *(u32 *)(psxM + mem_addr)) {
430                 printf("bad mem @%08x: %08x %08x\n", mem_addr, *(u32 *)(psxM + mem_addr), mem_val);
431                 goto end;
432         }
433
434         if (psxRegs.pc == rregs.pc && bad < 6 && failcount < 32) {
435                 static int last_mcycle;
436                 if (last_mcycle != psxRegs.cycle >> 20) {
437                         printf("%u\n", psxRegs.cycle);
438                         last_mcycle = psxRegs.cycle >> 20;
439                 }
440                 failcount++;
441                 goto ok;
442         }
443
444 end:
445         for (i = 0; i < miss_log_len; i++, miss_log_i = (miss_log_i + 1) & miss_log_mask)
446                 printf("bad %5s: %08x %08x, pc=%08x, cycle %u\n",
447                         regnames[miss_log[miss_log_i].reg], miss_log[miss_log_i].val,
448                         miss_log[miss_log_i].val_expect, miss_log[miss_log_i].pc, miss_log[miss_log_i].cycle);
449         printf("-- %d\n", bad);
450         for (i = 0; i < 8; i++)
451                 printf("r%d=%08x r%2d=%08x r%2d=%08x r%2d=%08x\n", i, allregs_p[i],
452                         i+8, allregs_p[i+8], i+16, allregs_p[i+16], i+24, allregs_p[i+24]);
453         printf("PC: %08x/%08x, cycle %u\n", psxRegs.pc, ppc, psxRegs.cycle);
454         dump_mem("/mnt/ntz/dev/pnd/tmp/psxram.dump", psxM, 0x200000);
455         dump_mem("/mnt/ntz/dev/pnd/tmp/psxregs.dump", psxH, 0x10000);
456         exit(1);
457 ok:
458         psxRegs.cycle = rregs.cycle + 2; // sync timing
459         ppc = psxRegs.pc;
460 }
461
462 #endif