gte_arm: implement RTPS, RTPT
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / emu_if.c
CommitLineData
7e605697 1/*
009faf24 2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2011
7e605697 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"
59774ed0 17#include "../gte_arm.h"
009faf24 18#include "../gte_neon.h"
59774ed0 19#define FLAGLESS
20#include "../gte.h"
7139f3c8 21
ae602c19 22#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
23
7139f3c8 24//#define evprintf printf
25#define evprintf(...)
26
f95a77f7 27char invalid_code[0x100000];
d28b54b1 28u32 event_cycles[PSXINT_COUNT];
f95a77f7 29
654e8cfb 30static void schedule_timeslice(void)
f95a77f7 31{
654e8cfb 32 u32 i, c = psxRegs.cycle;
33 s32 min, dif;
34
35 min = psxNextsCounter + psxNextCounter - c;
36 for (i = 0; i < ARRAY_SIZE(event_cycles); i++) {
37 dif = event_cycles[i] - c;
38 //evprintf(" ev %d\n", dif);
39 if (0 < dif && dif < min)
40 min = dif;
41 }
42 next_interupt = c + min;
43
44#if 0
45 static u32 cnt, last_cycle;
46 static u64 sum;
47 if (last_cycle) {
48 cnt++;
49 sum += psxRegs.cycle - last_cycle;
50 if ((cnt & 0xff) == 0)
51 printf("%u\n", (u32)(sum / cnt));
52 }
53 last_cycle = psxRegs.cycle;
54#endif
55}
ae602c19 56
52082bc1 57typedef void (irq_func)();
58
59static irq_func * const irq_funcs[] = {
60 [PSXINT_SIO] = sioInterrupt,
61 [PSXINT_CDR] = cdrInterrupt,
62 [PSXINT_CDREAD] = cdrReadInterrupt,
63 [PSXINT_GPUDMA] = gpuInterrupt,
64 [PSXINT_MDECOUTDMA] = mdec1Interrupt,
65 [PSXINT_SPUDMA] = spuInterrupt,
528ad661 66 [PSXINT_MDECINDMA] = mdec0Interrupt,
57a757ce 67 [PSXINT_GPUOTCDMA] = gpuotcInterrupt,
9f8b032d 68 [PSXINT_CDRDMA] = cdrDmaInterrupt,
69 [PSXINT_CDRLID] = cdrLidSeekInterrupt,
7f457614 70 [PSXINT_CDRPLAY] = cdrPlayInterrupt,
52082bc1 71};
72
73/* local dupe of psxBranchTest, using event_cycles */
74static void irq_test(void)
75{
76 u32 irqs = psxRegs.interrupt;
77 u32 cycle = psxRegs.cycle;
78 u32 irq, irq_bits;
79
80 if ((psxRegs.cycle - psxNextsCounter) >= psxNextCounter)
81 psxRcntUpdate();
82
83 // irq_funcs() may queue more irqs
84 psxRegs.interrupt = 0;
85
86 for (irq = 0, irq_bits = irqs; irq_bits != 0; irq++, irq_bits >>= 1) {
87 if (!(irq_bits & 1))
88 continue;
89 if ((s32)(cycle - event_cycles[irq]) >= 0) {
90 irqs &= ~(1 << irq);
91 irq_funcs[irq]();
92 }
93 }
94 psxRegs.interrupt |= irqs;
95
96 if ((psxHu32(0x1070) & psxHu32(0x1074)) && (Status & 0x401) == 0x401) {
97 psxException(0x400, 0);
98 pending_exception = 1;
99 }
100}
101
654e8cfb 102void gen_interupt()
103{
654e8cfb 104 evprintf(" +ge %08x, %u->%u\n", psxRegs.pc, psxRegs.cycle, next_interupt);
7139f3c8 105
52082bc1 106 irq_test();
107 //psxBranchTest();
108 //pending_exception = 1;
7139f3c8 109
654e8cfb 110 schedule_timeslice();
ae602c19 111
654e8cfb 112 evprintf(" -ge %08x, %u->%u (%d)\n", psxRegs.pc, psxRegs.cycle,
113 next_interupt, next_interupt - psxRegs.cycle);
f95a77f7 114}
115
fca1aef2 116// from interpreter
117extern void MTC0(int reg, u32 val);
118
119void pcsx_mtc0(u32 reg)
28bc5688 120{
fca1aef2 121 evprintf("MTC0 %d #%x @%08x %u\n", reg, readmem_word, psxRegs.pc, psxRegs.cycle);
122 MTC0(reg, readmem_word);
123 gen_interupt();
124}
28bc5688 125
fca1aef2 126void pcsx_mtc0_ds(u32 reg)
127{
128 evprintf("MTC0 %d #%x @%08x %u\n", reg, readmem_word, psxRegs.pc, psxRegs.cycle);
129 MTC0(reg, readmem_word);
28bc5688 130}
131
52082bc1 132void new_dyna_save(void)
133{
134 // psxRegs.intCycle is always maintained, no need to convert
135}
136
137void new_dyna_restore(void)
138{
139 int i;
9f8b032d 140 for (i = 0; i < PSXINT_COUNT; i++)
52082bc1 141 event_cycles[i] = psxRegs.intCycle[i].sCycle + psxRegs.intCycle[i].cycle;
142}
143
b9b61529 144void *gte_handlers[64];
145
59774ed0 146void *gte_handlers_nf[64] = {
147 NULL , gteRTPS_nf , NULL , NULL , NULL , NULL , gteNCLIP_nf, NULL , // 00
148 NULL , NULL , NULL , NULL , gteOP_nf , NULL , NULL , NULL , // 08
149 gteDPCS_nf, gteINTPL_nf, gteMVMVA_nf, gteNCDS_nf, gteCDP_nf, NULL , gteNCDT_nf , NULL , // 10
150 NULL , NULL , NULL , gteNCCS_nf, gteCC_nf , NULL , gteNCS_nf , NULL , // 18
151 gteNCT_nf , NULL , NULL , NULL , NULL , NULL , NULL , NULL , // 20
152 gteSQR_nf , gteDCPL_nf , gteDPCT_nf , NULL , NULL , gteAVSZ3_nf, gteAVSZ4_nf, NULL , // 28
153 gteRTPT_nf, NULL , NULL , NULL , NULL , NULL , NULL , NULL , // 30
154 NULL , NULL , NULL , NULL , NULL , gteGPF_nf , gteGPL_nf , gteNCCT_nf, // 38
155};
156
bedfea38 157const char *gte_regnames[64] = {
158 NULL , "RTPS" , NULL , NULL , NULL , NULL , "NCLIP", NULL , // 00
159 NULL , NULL , NULL , NULL , "OP" , NULL , NULL , NULL , // 08
160 "DPCS", "INTPL", "MVMVA", "NCDS", "CDP", NULL , "NCDT" , NULL , // 10
161 NULL , NULL , NULL , "NCCS", "CC" , NULL , "NCS" , NULL , // 18
162 "NCT" , NULL , NULL , NULL , NULL , NULL , NULL , NULL , // 20
163 "SQR" , "DCPL" , "DPCT" , NULL , NULL , "AVSZ3", "AVSZ4", NULL , // 28
164 "RTPT", NULL , NULL , NULL , NULL , NULL , NULL , NULL , // 30
165 NULL , NULL , NULL , NULL , NULL , "GPF" , "GPL" , "NCCT", // 38
166};
167
b9b61529 168/* from gte.txt.. not sure if this is any good. */
169const char gte_cycletab[64] = {
170 /* 1 2 3 4 5 6 7 8 9 a b c d e f */
171 0, 15, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 6, 0, 0, 0,
172 8, 8, 8, 19, 13, 0, 44, 0, 0, 0, 0, 17, 11, 0, 14, 0,
173 30, 0, 0, 0, 0, 0, 0, 0, 5, 8, 17, 0, 0, 5, 6, 0,
174 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 39,
175};
f95a77f7 176
177static int ari64_init()
178{
b9b61529 179 extern void (*psxCP2[64])();
180 extern void psxNULL();
f95a77f7 181 size_t i;
b9b61529 182
f95a77f7 183 new_dynarec_init();
7e605697 184 new_dyna_pcsx_mem_init();
7139f3c8 185
ae602c19 186 for (i = 0; i < ARRAY_SIZE(gte_handlers); i++)
b9b61529 187 if (psxCP2[i] != psxNULL)
188 gte_handlers[i] = psxCP2[i];
59774ed0 189
190#if !defined(DRC_DBG) && !defined(PCNT)
191#ifdef __arm__
192 gte_handlers[0x06] = gteNCLIP_arm;
0c2ca3ba 193 gte_handlers_nf[0x01] = gteRTPS_nf_arm;
194 gte_handlers_nf[0x30] = gteRTPT_nf_arm;
59774ed0 195#endif
a80ae4a0 196#ifdef __ARM_NEON__
59774ed0 197 // compiler's _nf version is still a lot slower then neon
0c2ca3ba 198 // _nf_arm RTPS is roughly the same, RTPT slower
59774ed0 199 gte_handlers[0x01] = gte_handlers_nf[0x01] = gteRTPS_neon;
200 gte_handlers[0x30] = gte_handlers_nf[0x30] = gteRTPT_neon;
201 gte_handlers[0x12] = gte_handlers_nf[0x12] = gteMVMVA_neon;
a80ae4a0 202#endif
009faf24 203#endif
7e605697 204 psxH_ptr = psxH;
205
b9b61529 206 return 0;
f95a77f7 207}
208
209static void ari64_reset()
210{
f95a77f7 211 printf("ari64_reset\n");
7e605697 212 new_dyna_pcsx_mem_reset();
4b421010 213 invalidate_all_pages();
7f457614 214 new_dyna_restore();
4b421010 215 pending_exception = 1;
f95a77f7 216}
217
e4eb18c1 218// execute until predefined leave points
219// (HLE softcall exit and BIOS fastboot end)
220static void ari64_execute_until()
f95a77f7 221{
654e8cfb 222 schedule_timeslice();
223
224 evprintf("ari64_execute %08x, %u->%u (%d)\n", psxRegs.pc,
225 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
7139f3c8 226
b9b61529 227 new_dyna_start();
654e8cfb 228
229 evprintf("ari64_execute end %08x, %u->%u (%d)\n", psxRegs.pc,
230 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
f95a77f7 231}
232
e4eb18c1 233static void ari64_execute()
234{
235 while (!stop) {
236 ari64_execute_until();
237 evprintf("drc left @%08x\n", psxRegs.pc);
238 }
239}
240
4b421010 241static void ari64_clear(u32 addr, u32 size)
f95a77f7 242{
0ce47d46 243 u32 start, end, main_ram;
4b421010 244
76739a08 245 size *= 4; /* PCSX uses DMA units */
246
4b421010 247 evprintf("ari64_clear %08x %04x\n", addr, size);
248
249 /* check for RAM mirrors */
0ce47d46 250 main_ram = (addr & 0xffe00000) == 0x80000000;
4b421010 251
252 start = addr >> 12;
253 end = (addr + size) >> 12;
254
255 for (; start <= end; start++)
0ce47d46 256 if (!main_ram || !invalid_code[start])
4b421010 257 invalidate_block(start);
f95a77f7 258}
259
260static void ari64_shutdown()
261{
262 new_dynarec_cleanup();
263}
264
7139f3c8 265extern void intExecute();
266extern void intExecuteT();
267extern void intExecuteBlock();
268extern void intExecuteBlockT();
269#ifndef DRC_DBG
270#define intExecuteT intExecute
271#define intExecuteBlockT intExecuteBlock
272#endif
273
f95a77f7 274R3000Acpu psxRec = {
275 ari64_init,
276 ari64_reset,
2185e39b 277#if defined(__arm__)
f95a77f7 278 ari64_execute,
e4eb18c1 279 ari64_execute_until,
7139f3c8 280#else
281 intExecuteT,
282 intExecuteBlockT,
283#endif
f95a77f7 284 ari64_clear,
285 ari64_shutdown
286};
7139f3c8 287
288// TODO: rm
289#ifndef DRC_DBG
290void do_insn_trace() {}
291void do_insn_cmp() {}
292#endif
293
294#if defined(__x86_64__) || defined(__i386__)
295unsigned int address, readmem_word, word;
296unsigned short hword;
297unsigned char byte;
ccf51908 298int pending_exception, stop;
7139f3c8 299unsigned int next_interupt;
7e605697 300void *psxH_ptr;
7139f3c8 301void new_dynarec_init() {}
3eb78778 302void new_dyna_start() {}
7139f3c8 303void new_dynarec_cleanup() {}
2c886904 304void new_dynarec_clear_full() {}
ccf51908 305void invalidate_all_pages() {}
306void invalidate_block(unsigned int block) {}
7e605697 307void new_dyna_pcsx_mem_init(void) {}
308void new_dyna_pcsx_mem_reset(void) {}
7139f3c8 309#endif
310
311#ifdef DRC_DBG
312
313#include <stddef.h>
314static FILE *f;
315extern u32 last_io_addr;
316
317static void dump_mem(const char *fname, void *mem, size_t size)
318{
319 FILE *f1 = fopen(fname, "wb");
3eb78778 320 if (f1 == NULL)
321 f1 = fopen(strrchr(fname, '/') + 1, "wb");
7139f3c8 322 fwrite(mem, 1, size, f1);
323 fclose(f1);
324}
325
2185e39b 326static u32 memcheck_read(u32 a)
327{
328 if ((a >> 16) == 0x1f80)
329 // scratchpad/IO
330 return *(u32 *)(psxH + (a & 0xfffc));
331
332 if ((a >> 16) == 0x1f00)
333 // parallel
334 return *(u32 *)(psxP + (a & 0xfffc));
335
336// if ((a & ~0xe0600000) < 0x200000)
337 // RAM
338 return *(u32 *)(psxM + (a & 0x1ffffc));
339}
340
7139f3c8 341void do_insn_trace(void)
342{
343 static psxRegisters oldregs;
344 static u32 old_io_addr = (u32)-1;
345 static u32 old_io_data = 0xbad0c0de;
346 u32 *allregs_p = (void *)&psxRegs;
347 u32 *allregs_o = (void *)&oldregs;
2185e39b 348 u32 io_data;
7139f3c8 349 int i;
350 u8 byte;
351
352//last_io_addr = 0x5e2c8;
353 if (f == NULL)
354 f = fopen("tracelog", "wb");
355
356 oldregs.code = psxRegs.code; // don't care
357 for (i = 0; i < offsetof(psxRegisters, intCycle) / 4; i++) {
358 if (allregs_p[i] != allregs_o[i]) {
359 fwrite(&i, 1, 1, f);
360 fwrite(&allregs_p[i], 1, 4, f);
361 allregs_o[i] = allregs_p[i];
362 }
363 }
364 if (old_io_addr != last_io_addr) {
365 byte = 0xfd;
366 fwrite(&byte, 1, 1, f);
367 fwrite(&last_io_addr, 1, 4, f);
368 old_io_addr = last_io_addr;
369 }
2185e39b 370 io_data = memcheck_read(last_io_addr);
371 if (old_io_data != io_data) {
7139f3c8 372 byte = 0xfe;
373 fwrite(&byte, 1, 1, f);
2185e39b 374 fwrite(&io_data, 1, 4, f);
375 old_io_data = io_data;
7139f3c8 376 }
377 byte = 0xff;
378 fwrite(&byte, 1, 1, f);
379
380#if 0
381 if (psxRegs.cycle == 190230) {
382 dump_mem("/mnt/ntz/dev/pnd/tmp/psxram_i.dump", psxM, 0x200000);
383 dump_mem("/mnt/ntz/dev/pnd/tmp/psxregs_i.dump", psxH, 0x10000);
384 printf("dumped\n");
385 exit(1);
386 }
387#endif
388}
389
390static const char *regnames[offsetof(psxRegisters, intCycle) / 4] = {
391 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
392 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
393 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
394 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
395 "lo", "hi",
396 "C0_0", "C0_1", "C0_2", "C0_3", "C0_4", "C0_5", "C0_6", "C0_7",
397 "C0_8", "C0_9", "C0_10", "C0_11", "C0_12", "C0_13", "C0_14", "C0_15",
398 "C0_16", "C0_17", "C0_18", "C0_19", "C0_20", "C0_21", "C0_22", "C0_23",
399 "C0_24", "C0_25", "C0_26", "C0_27", "C0_28", "C0_29", "C0_30", "C0_31",
400
401 "C2D0", "C2D1", "C2D2", "C2D3", "C2D4", "C2D5", "C2D6", "C2D7",
402 "C2D8", "C2D9", "C2D10", "C2D11", "C2D12", "C2D13", "C2D14", "C2D15",
403 "C2D16", "C2D17", "C2D18", "C2D19", "C2D20", "C2D21", "C2D22", "C2D23",
404 "C2D24", "C2D25", "C2D26", "C2D27", "C2D28", "C2D29", "C2D30", "C2D31",
405
406 "C2C0", "C2C1", "C2C2", "C2C3", "C2C4", "C2C5", "C2C6", "C2C7",
407 "C2C8", "C2C9", "C2C10", "C2C11", "C2C12", "C2C13", "C2C14", "C2C15",
408 "C2C16", "C2C17", "C2C18", "C2C19", "C2C20", "C2C21", "C2C22", "C2C23",
409 "C2C24", "C2C25", "C2C26", "C2C27", "C2C28", "C2C29", "C2C30", "C2C31",
410
411 "PC", "code", "cycle", "interrupt",
412};
413
3eb78778 414static struct {
415 int reg;
416 u32 val, val_expect;
417 u32 pc, cycle;
418} miss_log[64];
419static int miss_log_i;
420#define miss_log_len (sizeof(miss_log)/sizeof(miss_log[0]))
421#define miss_log_mask (miss_log_len-1)
422
423static void miss_log_add(int reg, u32 val, u32 val_expect, u32 pc, u32 cycle)
424{
425 miss_log[miss_log_i].reg = reg;
426 miss_log[miss_log_i].val = val;
427 miss_log[miss_log_i].val_expect = val_expect;
428 miss_log[miss_log_i].pc = pc;
429 miss_log[miss_log_i].cycle = cycle;
430 miss_log_i = (miss_log_i + 1) & miss_log_mask;
431}
432
7139f3c8 433void breakme() {}
434
435void do_insn_cmp(void)
436{
437 static psxRegisters rregs;
438 static u32 mem_addr, mem_val;
439 u32 *allregs_p = (void *)&psxRegs;
440 u32 *allregs_e = (void *)&rregs;
441 static u32 ppc, failcount;
442 int i, ret, bad = 0;
443 u8 code;
444
445 if (f == NULL)
446 f = fopen("tracelog", "rb");
447
448 while (1) {
449 if ((ret = fread(&code, 1, 1, f)) <= 0)
450 break;
451 if (ret <= 0)
452 break;
453 if (code == 0xff)
454 break;
455 if (code == 0xfd) {
456 if ((ret = fread(&mem_addr, 1, 4, f)) <= 0)
457 break;
458 continue;
459 }
460 if (code == 0xfe) {
461 if ((ret = fread(&mem_val, 1, 4, f)) <= 0)
462 break;
463 continue;
464 }
465 if ((ret = fread(&allregs_e[code], 1, 4, f)) <= 0)
466 break;
467 }
468
469 if (ret <= 0) {
470 printf("EOF?\n");
471 goto end;
472 }
473
474 psxRegs.code = rregs.code; // don't care
2185e39b 475 psxRegs.cycle = rregs.cycle;
476 psxRegs.CP0.r[9] = rregs.CP0.r[9]; // Count
7139f3c8 477
478//if (psxRegs.cycle == 166172) breakme();
7139f3c8 479
480 if (memcmp(&psxRegs, &rregs, offsetof(psxRegisters, intCycle)) == 0 &&
2185e39b 481 mem_val == memcheck_read(mem_addr)
7139f3c8 482 ) {
483 failcount = 0;
484 goto ok;
485 }
486
487 for (i = 0; i < offsetof(psxRegisters, intCycle) / 4; i++) {
488 if (allregs_p[i] != allregs_e[i]) {
3eb78778 489 miss_log_add(i, allregs_p[i], allregs_e[i], psxRegs.pc, psxRegs.cycle);
7139f3c8 490 bad++;
491 }
492 }
493
2185e39b 494 if (mem_val != memcheck_read(mem_addr)) {
495 printf("bad mem @%08x: %08x %08x\n", mem_addr, memcheck_read(mem_addr), mem_val);
7139f3c8 496 goto end;
497 }
498
499 if (psxRegs.pc == rregs.pc && bad < 6 && failcount < 32) {
3eb78778 500 static int last_mcycle;
501 if (last_mcycle != psxRegs.cycle >> 20) {
502 printf("%u\n", psxRegs.cycle);
503 last_mcycle = psxRegs.cycle >> 20;
504 }
7139f3c8 505 failcount++;
506 goto ok;
507 }
508
509end:
3eb78778 510 for (i = 0; i < miss_log_len; i++, miss_log_i = (miss_log_i + 1) & miss_log_mask)
511 printf("bad %5s: %08x %08x, pc=%08x, cycle %u\n",
512 regnames[miss_log[miss_log_i].reg], miss_log[miss_log_i].val,
513 miss_log[miss_log_i].val_expect, miss_log[miss_log_i].pc, miss_log[miss_log_i].cycle);
514 printf("-- %d\n", bad);
515 for (i = 0; i < 8; i++)
516 printf("r%d=%08x r%2d=%08x r%2d=%08x r%2d=%08x\n", i, allregs_p[i],
87c06e51 517 i+8, allregs_p[i+8], i+16, allregs_p[i+16], i+24, allregs_p[i+24]);
7139f3c8 518 printf("PC: %08x/%08x, cycle %u\n", psxRegs.pc, ppc, psxRegs.cycle);
519 dump_mem("/mnt/ntz/dev/pnd/tmp/psxram.dump", psxM, 0x200000);
520 dump_mem("/mnt/ntz/dev/pnd/tmp/psxregs.dump", psxH, 0x10000);
521 exit(1);
522ok:
523 psxRegs.cycle = rregs.cycle + 2; // sync timing
524 ppc = psxRegs.pc;
525}
526
527#endif