drc: improved interrupt code for emu_if
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / emu_if.c
CommitLineData
7e605697 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
f95a77f7 8#include <stdio.h>
9
10#include "emu_if.h"
7e605697 11#include "pcsxmem.h"
7139f3c8 12#include "../psxhle.h"
d28b54b1 13#include "../r3000a.h"
52082bc1 14#include "../cdrom.h"
15#include "../psxdma.h"
16#include "../mdec.h"
7139f3c8 17
ae602c19 18#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
19
7139f3c8 20//#define evprintf printf
21#define evprintf(...)
22
f95a77f7 23char invalid_code[0x100000];
d28b54b1 24u32 event_cycles[PSXINT_COUNT];
f95a77f7 25
654e8cfb 26static void schedule_timeslice(void)
f95a77f7 27{
654e8cfb 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}
ae602c19 52
52082bc1 53typedef void (irq_func)();
54
55static 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 */
65static 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
654e8cfb 93void gen_interupt()
94{
654e8cfb 95 evprintf(" +ge %08x, %u->%u\n", psxRegs.pc, psxRegs.cycle, next_interupt);
7139f3c8 96#ifdef DRC_DBG
97 psxRegs.cycle += 2;
7139f3c8 98#endif
99
52082bc1 100 irq_test();
101 //psxBranchTest();
102 //pending_exception = 1;
7139f3c8 103
654e8cfb 104 schedule_timeslice();
ae602c19 105
654e8cfb 106 evprintf(" -ge %08x, %u->%u (%d)\n", psxRegs.pc, psxRegs.cycle,
107 next_interupt, next_interupt - psxRegs.cycle);
f95a77f7 108}
109
28bc5688 110void 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
f95a77f7 119void check_interupt()
120{
52082bc1 121 /* FIXME (also asm) */
7139f3c8 122 printf("ari64_check_interupt\n");
f95a77f7 123}
124
52082bc1 125void new_dyna_save(void)
126{
127 // psxRegs.intCycle is always maintained, no need to convert
128}
129
130void 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
b9b61529 137void *gte_handlers[64];
138
139/* from gte.txt.. not sure if this is any good. */
140const 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};
f95a77f7 147
148static int ari64_init()
149{
b9b61529 150 extern void (*psxCP2[64])();
151 extern void psxNULL();
7e605697 152 extern void *psxH_ptr;
f95a77f7 153 size_t i;
b9b61529 154
f95a77f7 155 new_dynarec_init();
7e605697 156 new_dyna_pcsx_mem_init();
7139f3c8 157
ae602c19 158 for (i = 0; i < ARRAY_SIZE(gte_handlers); i++)
b9b61529 159 if (psxCP2[i] != psxNULL)
160 gte_handlers[i] = psxCP2[i];
161
7e605697 162 psxH_ptr = psxH;
163
b9b61529 164 return 0;
f95a77f7 165}
166
167static void ari64_reset()
168{
f95a77f7 169 printf("ari64_reset\n");
7e605697 170 new_dyna_pcsx_mem_reset();
4b421010 171 invalidate_all_pages();
172 pending_exception = 1;
f95a77f7 173}
174
175static void ari64_execute()
176{
654e8cfb 177 schedule_timeslice();
178
179 evprintf("ari64_execute %08x, %u->%u (%d)\n", psxRegs.pc,
180 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
7139f3c8 181
b9b61529 182 new_dyna_start();
654e8cfb 183
184 evprintf("ari64_execute end %08x, %u->%u (%d)\n", psxRegs.pc,
185 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
f95a77f7 186}
187
4b421010 188static void ari64_clear(u32 addr, u32 size)
f95a77f7 189{
4b421010 190 u32 start, end;
191
192 evprintf("ari64_clear %08x %04x\n", addr, size);
193
194 /* check for RAM mirrors */
4cb76aa4 195 if ((addr & ~0xe0600000) < 0x200000) {
196 addr &= ~0xe0600000;
f76eeef9 197 addr |= 0x80000000;
4b421010 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);
f95a77f7 206}
207
208static void ari64_shutdown()
209{
210 new_dynarec_cleanup();
211}
212
7139f3c8 213extern void intExecute();
214extern void intExecuteT();
215extern void intExecuteBlock();
216extern void intExecuteBlockT();
217#ifndef DRC_DBG
218#define intExecuteT intExecute
219#define intExecuteBlockT intExecuteBlock
220#endif
221
f95a77f7 222R3000Acpu psxRec = {
223 ari64_init,
224 ari64_reset,
7139f3c8 225#if 1
f95a77f7 226 ari64_execute,
7139f3c8 227 ari64_execute,
228#else
229 intExecuteT,
230 intExecuteBlockT,
231#endif
f95a77f7 232 ari64_clear,
233 ari64_shutdown
234};
7139f3c8 235
236// TODO: rm
237#ifndef DRC_DBG
238void do_insn_trace() {}
239void do_insn_cmp() {}
240#endif
241
242#if defined(__x86_64__) || defined(__i386__)
243unsigned int address, readmem_word, word;
244unsigned short hword;
245unsigned char byte;
ccf51908 246int pending_exception, stop;
7139f3c8 247unsigned int next_interupt;
7e605697 248void *psxH_ptr;
7139f3c8 249void new_dynarec_init() {}
3eb78778 250void new_dyna_start() {}
7139f3c8 251void new_dynarec_cleanup() {}
ccf51908 252void invalidate_all_pages() {}
253void invalidate_block(unsigned int block) {}
7e605697 254void new_dyna_pcsx_mem_init(void) {}
255void new_dyna_pcsx_mem_reset(void) {}
7139f3c8 256#endif
257
258#ifdef DRC_DBG
259
260#include <stddef.h>
261static FILE *f;
262extern u32 last_io_addr;
263
264static void dump_mem(const char *fname, void *mem, size_t size)
265{
266 FILE *f1 = fopen(fname, "wb");
3eb78778 267 if (f1 == NULL)
268 f1 = fopen(strrchr(fname, '/') + 1, "wb");
7139f3c8 269 fwrite(mem, 1, size, f1);
270 fclose(f1);
271}
272
273void 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
322static 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
3eb78778 346static struct {
347 int reg;
348 u32 val, val_expect;
349 u32 pc, cycle;
350} miss_log[64];
351static 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
355static 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
7139f3c8 365void breakme() {}
366
367void 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
407psxRegs.cycle = rregs.cycle;
408psxRegs.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]) {
3eb78778 424 miss_log_add(i, allregs_p[i], allregs_e[i], psxRegs.pc, psxRegs.cycle);
7139f3c8 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) {
3eb78778 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 }
7139f3c8 440 failcount++;
441 goto ok;
442 }
443
444end:
3eb78778 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],
87c06e51 452 i+8, allregs_p[i+8], i+16, allregs_p[i+16], i+24, allregs_p[i+24]);
7139f3c8 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);
457ok:
458 psxRegs.cycle = rregs.cycle + 2; // sync timing
459 ppc = psxRegs.pc;
460}
461
462#endif