gte: split arm code for pollux, generate flagless handlers
[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
b9b61529 157/* from gte.txt.. not sure if this is any good. */
158const char gte_cycletab[64] = {
159 /* 1 2 3 4 5 6 7 8 9 a b c d e f */
160 0, 15, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 6, 0, 0, 0,
161 8, 8, 8, 19, 13, 0, 44, 0, 0, 0, 0, 17, 11, 0, 14, 0,
162 30, 0, 0, 0, 0, 0, 0, 0, 5, 8, 17, 0, 0, 5, 6, 0,
163 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 39,
164};
f95a77f7 165
166static int ari64_init()
167{
b9b61529 168 extern void (*psxCP2[64])();
169 extern void psxNULL();
f95a77f7 170 size_t i;
b9b61529 171
f95a77f7 172 new_dynarec_init();
7e605697 173 new_dyna_pcsx_mem_init();
7139f3c8 174
ae602c19 175 for (i = 0; i < ARRAY_SIZE(gte_handlers); i++)
b9b61529 176 if (psxCP2[i] != psxNULL)
177 gte_handlers[i] = psxCP2[i];
59774ed0 178
179#if !defined(DRC_DBG) && !defined(PCNT)
180#ifdef __arm__
181 gte_handlers[0x06] = gteNCLIP_arm;
182#endif
a80ae4a0 183#ifdef __ARM_NEON__
59774ed0 184 // compiler's _nf version is still a lot slower then neon
185 gte_handlers[0x01] = gte_handlers_nf[0x01] = gteRTPS_neon;
186 gte_handlers[0x30] = gte_handlers_nf[0x30] = gteRTPT_neon;
187 gte_handlers[0x12] = gte_handlers_nf[0x12] = gteMVMVA_neon;
a80ae4a0 188#endif
009faf24 189#endif
7e605697 190 psxH_ptr = psxH;
191
b9b61529 192 return 0;
f95a77f7 193}
194
195static void ari64_reset()
196{
f95a77f7 197 printf("ari64_reset\n");
7e605697 198 new_dyna_pcsx_mem_reset();
4b421010 199 invalidate_all_pages();
7f457614 200 new_dyna_restore();
4b421010 201 pending_exception = 1;
f95a77f7 202}
203
e4eb18c1 204// execute until predefined leave points
205// (HLE softcall exit and BIOS fastboot end)
206static void ari64_execute_until()
f95a77f7 207{
654e8cfb 208 schedule_timeslice();
209
210 evprintf("ari64_execute %08x, %u->%u (%d)\n", psxRegs.pc,
211 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
7139f3c8 212
b9b61529 213 new_dyna_start();
654e8cfb 214
215 evprintf("ari64_execute end %08x, %u->%u (%d)\n", psxRegs.pc,
216 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
f95a77f7 217}
218
e4eb18c1 219static void ari64_execute()
220{
221 while (!stop) {
222 ari64_execute_until();
223 evprintf("drc left @%08x\n", psxRegs.pc);
224 }
225}
226
4b421010 227static void ari64_clear(u32 addr, u32 size)
f95a77f7 228{
0ce47d46 229 u32 start, end, main_ram;
4b421010 230
76739a08 231 size *= 4; /* PCSX uses DMA units */
232
4b421010 233 evprintf("ari64_clear %08x %04x\n", addr, size);
234
235 /* check for RAM mirrors */
0ce47d46 236 main_ram = (addr & 0xffe00000) == 0x80000000;
4b421010 237
238 start = addr >> 12;
239 end = (addr + size) >> 12;
240
241 for (; start <= end; start++)
0ce47d46 242 if (!main_ram || !invalid_code[start])
4b421010 243 invalidate_block(start);
f95a77f7 244}
245
246static void ari64_shutdown()
247{
248 new_dynarec_cleanup();
249}
250
7139f3c8 251extern void intExecute();
252extern void intExecuteT();
253extern void intExecuteBlock();
254extern void intExecuteBlockT();
255#ifndef DRC_DBG
256#define intExecuteT intExecute
257#define intExecuteBlockT intExecuteBlock
258#endif
259
f95a77f7 260R3000Acpu psxRec = {
261 ari64_init,
262 ari64_reset,
2185e39b 263#if defined(__arm__)
f95a77f7 264 ari64_execute,
e4eb18c1 265 ari64_execute_until,
7139f3c8 266#else
267 intExecuteT,
268 intExecuteBlockT,
269#endif
f95a77f7 270 ari64_clear,
271 ari64_shutdown
272};
7139f3c8 273
274// TODO: rm
275#ifndef DRC_DBG
276void do_insn_trace() {}
277void do_insn_cmp() {}
278#endif
279
280#if defined(__x86_64__) || defined(__i386__)
281unsigned int address, readmem_word, word;
282unsigned short hword;
283unsigned char byte;
ccf51908 284int pending_exception, stop;
7139f3c8 285unsigned int next_interupt;
7e605697 286void *psxH_ptr;
7139f3c8 287void new_dynarec_init() {}
3eb78778 288void new_dyna_start() {}
7139f3c8 289void new_dynarec_cleanup() {}
2c886904 290void new_dynarec_clear_full() {}
ccf51908 291void invalidate_all_pages() {}
292void invalidate_block(unsigned int block) {}
7e605697 293void new_dyna_pcsx_mem_init(void) {}
294void new_dyna_pcsx_mem_reset(void) {}
7139f3c8 295#endif
296
297#ifdef DRC_DBG
298
299#include <stddef.h>
300static FILE *f;
301extern u32 last_io_addr;
302
303static void dump_mem(const char *fname, void *mem, size_t size)
304{
305 FILE *f1 = fopen(fname, "wb");
3eb78778 306 if (f1 == NULL)
307 f1 = fopen(strrchr(fname, '/') + 1, "wb");
7139f3c8 308 fwrite(mem, 1, size, f1);
309 fclose(f1);
310}
311
2185e39b 312static u32 memcheck_read(u32 a)
313{
314 if ((a >> 16) == 0x1f80)
315 // scratchpad/IO
316 return *(u32 *)(psxH + (a & 0xfffc));
317
318 if ((a >> 16) == 0x1f00)
319 // parallel
320 return *(u32 *)(psxP + (a & 0xfffc));
321
322// if ((a & ~0xe0600000) < 0x200000)
323 // RAM
324 return *(u32 *)(psxM + (a & 0x1ffffc));
325}
326
7139f3c8 327void do_insn_trace(void)
328{
329 static psxRegisters oldregs;
330 static u32 old_io_addr = (u32)-1;
331 static u32 old_io_data = 0xbad0c0de;
332 u32 *allregs_p = (void *)&psxRegs;
333 u32 *allregs_o = (void *)&oldregs;
2185e39b 334 u32 io_data;
7139f3c8 335 int i;
336 u8 byte;
337
338//last_io_addr = 0x5e2c8;
339 if (f == NULL)
340 f = fopen("tracelog", "wb");
341
342 oldregs.code = psxRegs.code; // don't care
343 for (i = 0; i < offsetof(psxRegisters, intCycle) / 4; i++) {
344 if (allregs_p[i] != allregs_o[i]) {
345 fwrite(&i, 1, 1, f);
346 fwrite(&allregs_p[i], 1, 4, f);
347 allregs_o[i] = allregs_p[i];
348 }
349 }
350 if (old_io_addr != last_io_addr) {
351 byte = 0xfd;
352 fwrite(&byte, 1, 1, f);
353 fwrite(&last_io_addr, 1, 4, f);
354 old_io_addr = last_io_addr;
355 }
2185e39b 356 io_data = memcheck_read(last_io_addr);
357 if (old_io_data != io_data) {
7139f3c8 358 byte = 0xfe;
359 fwrite(&byte, 1, 1, f);
2185e39b 360 fwrite(&io_data, 1, 4, f);
361 old_io_data = io_data;
7139f3c8 362 }
363 byte = 0xff;
364 fwrite(&byte, 1, 1, f);
365
366#if 0
367 if (psxRegs.cycle == 190230) {
368 dump_mem("/mnt/ntz/dev/pnd/tmp/psxram_i.dump", psxM, 0x200000);
369 dump_mem("/mnt/ntz/dev/pnd/tmp/psxregs_i.dump", psxH, 0x10000);
370 printf("dumped\n");
371 exit(1);
372 }
373#endif
374}
375
376static const char *regnames[offsetof(psxRegisters, intCycle) / 4] = {
377 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
378 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
379 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
380 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
381 "lo", "hi",
382 "C0_0", "C0_1", "C0_2", "C0_3", "C0_4", "C0_5", "C0_6", "C0_7",
383 "C0_8", "C0_9", "C0_10", "C0_11", "C0_12", "C0_13", "C0_14", "C0_15",
384 "C0_16", "C0_17", "C0_18", "C0_19", "C0_20", "C0_21", "C0_22", "C0_23",
385 "C0_24", "C0_25", "C0_26", "C0_27", "C0_28", "C0_29", "C0_30", "C0_31",
386
387 "C2D0", "C2D1", "C2D2", "C2D3", "C2D4", "C2D5", "C2D6", "C2D7",
388 "C2D8", "C2D9", "C2D10", "C2D11", "C2D12", "C2D13", "C2D14", "C2D15",
389 "C2D16", "C2D17", "C2D18", "C2D19", "C2D20", "C2D21", "C2D22", "C2D23",
390 "C2D24", "C2D25", "C2D26", "C2D27", "C2D28", "C2D29", "C2D30", "C2D31",
391
392 "C2C0", "C2C1", "C2C2", "C2C3", "C2C4", "C2C5", "C2C6", "C2C7",
393 "C2C8", "C2C9", "C2C10", "C2C11", "C2C12", "C2C13", "C2C14", "C2C15",
394 "C2C16", "C2C17", "C2C18", "C2C19", "C2C20", "C2C21", "C2C22", "C2C23",
395 "C2C24", "C2C25", "C2C26", "C2C27", "C2C28", "C2C29", "C2C30", "C2C31",
396
397 "PC", "code", "cycle", "interrupt",
398};
399
3eb78778 400static struct {
401 int reg;
402 u32 val, val_expect;
403 u32 pc, cycle;
404} miss_log[64];
405static int miss_log_i;
406#define miss_log_len (sizeof(miss_log)/sizeof(miss_log[0]))
407#define miss_log_mask (miss_log_len-1)
408
409static void miss_log_add(int reg, u32 val, u32 val_expect, u32 pc, u32 cycle)
410{
411 miss_log[miss_log_i].reg = reg;
412 miss_log[miss_log_i].val = val;
413 miss_log[miss_log_i].val_expect = val_expect;
414 miss_log[miss_log_i].pc = pc;
415 miss_log[miss_log_i].cycle = cycle;
416 miss_log_i = (miss_log_i + 1) & miss_log_mask;
417}
418
7139f3c8 419void breakme() {}
420
421void do_insn_cmp(void)
422{
423 static psxRegisters rregs;
424 static u32 mem_addr, mem_val;
425 u32 *allregs_p = (void *)&psxRegs;
426 u32 *allregs_e = (void *)&rregs;
427 static u32 ppc, failcount;
428 int i, ret, bad = 0;
429 u8 code;
430
431 if (f == NULL)
432 f = fopen("tracelog", "rb");
433
434 while (1) {
435 if ((ret = fread(&code, 1, 1, f)) <= 0)
436 break;
437 if (ret <= 0)
438 break;
439 if (code == 0xff)
440 break;
441 if (code == 0xfd) {
442 if ((ret = fread(&mem_addr, 1, 4, f)) <= 0)
443 break;
444 continue;
445 }
446 if (code == 0xfe) {
447 if ((ret = fread(&mem_val, 1, 4, f)) <= 0)
448 break;
449 continue;
450 }
451 if ((ret = fread(&allregs_e[code], 1, 4, f)) <= 0)
452 break;
453 }
454
455 if (ret <= 0) {
456 printf("EOF?\n");
457 goto end;
458 }
459
460 psxRegs.code = rregs.code; // don't care
2185e39b 461 psxRegs.cycle = rregs.cycle;
462 psxRegs.CP0.r[9] = rregs.CP0.r[9]; // Count
7139f3c8 463
464//if (psxRegs.cycle == 166172) breakme();
7139f3c8 465
466 if (memcmp(&psxRegs, &rregs, offsetof(psxRegisters, intCycle)) == 0 &&
2185e39b 467 mem_val == memcheck_read(mem_addr)
7139f3c8 468 ) {
469 failcount = 0;
470 goto ok;
471 }
472
473 for (i = 0; i < offsetof(psxRegisters, intCycle) / 4; i++) {
474 if (allregs_p[i] != allregs_e[i]) {
3eb78778 475 miss_log_add(i, allregs_p[i], allregs_e[i], psxRegs.pc, psxRegs.cycle);
7139f3c8 476 bad++;
477 }
478 }
479
2185e39b 480 if (mem_val != memcheck_read(mem_addr)) {
481 printf("bad mem @%08x: %08x %08x\n", mem_addr, memcheck_read(mem_addr), mem_val);
7139f3c8 482 goto end;
483 }
484
485 if (psxRegs.pc == rregs.pc && bad < 6 && failcount < 32) {
3eb78778 486 static int last_mcycle;
487 if (last_mcycle != psxRegs.cycle >> 20) {
488 printf("%u\n", psxRegs.cycle);
489 last_mcycle = psxRegs.cycle >> 20;
490 }
7139f3c8 491 failcount++;
492 goto ok;
493 }
494
495end:
3eb78778 496 for (i = 0; i < miss_log_len; i++, miss_log_i = (miss_log_i + 1) & miss_log_mask)
497 printf("bad %5s: %08x %08x, pc=%08x, cycle %u\n",
498 regnames[miss_log[miss_log_i].reg], miss_log[miss_log_i].val,
499 miss_log[miss_log_i].val_expect, miss_log[miss_log_i].pc, miss_log[miss_log_i].cycle);
500 printf("-- %d\n", bad);
501 for (i = 0; i < 8; i++)
502 printf("r%d=%08x r%2d=%08x r%2d=%08x r%2d=%08x\n", i, allregs_p[i],
87c06e51 503 i+8, allregs_p[i+8], i+16, allregs_p[i+16], i+24, allregs_p[i+24]);
7139f3c8 504 printf("PC: %08x/%08x, cycle %u\n", psxRegs.pc, ppc, psxRegs.cycle);
505 dump_mem("/mnt/ntz/dev/pnd/tmp/psxram.dump", psxM, 0x200000);
506 dump_mem("/mnt/ntz/dev/pnd/tmp/psxregs.dump", psxH, 0x10000);
507 exit(1);
508ok:
509 psxRegs.cycle = rregs.cycle + 2; // sync timing
510 ppc = psxRegs.pc;
511}
512
513#endif