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