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