frontend/pollux: program MLC2 for TV-out, save/restore regs
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / emu_if.c
... / ...
CommitLineData
1/*
2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2011
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
8#include <stdio.h>
9
10#include "emu_if.h"
11#include "pcsxmem.h"
12#include "../psxhle.h"
13#include "../r3000a.h"
14#include "../cdrom.h"
15#include "../psxdma.h"
16#include "../mdec.h"
17#include "../gte_arm.h"
18#include "../gte_neon.h"
19#define FLAGLESS
20#include "../gte.h"
21
22#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
23
24//#define evprintf printf
25#define evprintf(...)
26
27char invalid_code[0x100000];
28u32 event_cycles[PSXINT_COUNT];
29
30static void schedule_timeslice(void)
31{
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}
56
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,
66 [PSXINT_MDECINDMA] = mdec0Interrupt,
67 [PSXINT_GPUOTCDMA] = gpuotcInterrupt,
68 [PSXINT_CDRDMA] = cdrDmaInterrupt,
69 [PSXINT_CDRLID] = cdrLidSeekInterrupt,
70 [PSXINT_CDRPLAY] = cdrPlayInterrupt,
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
102void gen_interupt()
103{
104 evprintf(" +ge %08x, %u->%u\n", psxRegs.pc, psxRegs.cycle, next_interupt);
105
106 irq_test();
107 //psxBranchTest();
108 //pending_exception = 1;
109
110 schedule_timeslice();
111
112 evprintf(" -ge %08x, %u->%u (%d)\n", psxRegs.pc, psxRegs.cycle,
113 next_interupt, next_interupt - psxRegs.cycle);
114}
115
116// from interpreter
117extern void MTC0(int reg, u32 val);
118
119void pcsx_mtc0(u32 reg, u32 val)
120{
121 evprintf("MTC0 %d #%x @%08x %u\n", reg, val, psxRegs.pc, psxRegs.cycle);
122 MTC0(reg, val);
123 gen_interupt();
124}
125
126void pcsx_mtc0_ds(u32 reg, u32 val)
127{
128 evprintf("MTC0 %d #%x @%08x %u\n", reg, val, psxRegs.pc, psxRegs.cycle);
129 MTC0(reg, val);
130}
131
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;
140 for (i = 0; i < PSXINT_COUNT; i++)
141 event_cycles[i] = psxRegs.intCycle[i].sCycle + psxRegs.intCycle[i].cycle;
142
143 new_dyna_pcsx_mem_load_state();
144}
145
146void *gte_handlers[64];
147
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
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
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};
178
179static int ari64_init()
180{
181 extern void (*psxCP2[64])();
182 extern void psxNULL();
183 size_t i;
184
185 new_dynarec_init();
186 new_dyna_pcsx_mem_init();
187
188 for (i = 0; i < ARRAY_SIZE(gte_handlers); i++)
189 if (psxCP2[i] != psxNULL)
190 gte_handlers[i] = psxCP2[i];
191
192#if !defined(DRC_DBG) && !defined(PCNT)
193#ifdef __arm__
194 gte_handlers[0x06] = gteNCLIP_arm;
195 gte_handlers_nf[0x01] = gteRTPS_nf_arm;
196 gte_handlers_nf[0x30] = gteRTPT_nf_arm;
197#endif
198#ifdef __ARM_NEON__
199 // compiler's _nf version is still a lot slower then neon
200 // _nf_arm RTPS is roughly the same, RTPT slower
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;
204#endif
205#endif
206#ifdef DRC_DBG
207 memcpy(gte_handlers_nf, gte_handlers, sizeof(gte_handlers_nf));
208#endif
209 psxH_ptr = psxH;
210
211 return 0;
212}
213
214static void ari64_reset()
215{
216 printf("ari64_reset\n");
217 new_dyna_pcsx_mem_reset();
218 invalidate_all_pages();
219 new_dyna_restore();
220 pending_exception = 1;
221}
222
223// execute until predefined leave points
224// (HLE softcall exit and BIOS fastboot end)
225static void ari64_execute_until()
226{
227 schedule_timeslice();
228
229 evprintf("ari64_execute %08x, %u->%u (%d)\n", psxRegs.pc,
230 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
231
232 new_dyna_start();
233
234 evprintf("ari64_execute end %08x, %u->%u (%d)\n", psxRegs.pc,
235 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
236}
237
238static void ari64_execute()
239{
240 while (!stop) {
241 ari64_execute_until();
242 evprintf("drc left @%08x\n", psxRegs.pc);
243 }
244}
245
246static void ari64_clear(u32 addr, u32 size)
247{
248 u32 start, end, main_ram;
249
250 size *= 4; /* PCSX uses DMA units */
251
252 evprintf("ari64_clear %08x %04x\n", addr, size);
253
254 /* check for RAM mirrors */
255 main_ram = (addr & 0xffe00000) == 0x80000000;
256
257 start = addr >> 12;
258 end = (addr + size) >> 12;
259
260 for (; start <= end; start++)
261 if (!main_ram || !invalid_code[start])
262 invalidate_block(start);
263}
264
265static void ari64_shutdown()
266{
267 new_dynarec_cleanup();
268}
269
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
279R3000Acpu psxRec = {
280 ari64_init,
281 ari64_reset,
282#if defined(__arm__)
283 ari64_execute,
284 ari64_execute_until,
285#else
286 intExecuteT,
287 intExecuteBlockT,
288#endif
289 ari64_clear,
290 ari64_shutdown
291};
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;
303int pending_exception, stop;
304unsigned int next_interupt;
305int new_dynarec_did_compile;
306int cycle_multiplier;
307void *psxH_ptr;
308void new_dynarec_init() {}
309void new_dyna_start() {}
310void new_dynarec_cleanup() {}
311void new_dynarec_clear_full() {}
312void invalidate_all_pages() {}
313void invalidate_block(unsigned int block) {}
314void new_dyna_pcsx_mem_init(void) {}
315void new_dyna_pcsx_mem_reset(void) {}
316void new_dyna_pcsx_mem_load_state(void) {}
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");
328 if (f1 == NULL)
329 f1 = fopen(strrchr(fname, '/') + 1, "wb");
330 fwrite(mem, 1, size, f1);
331 fclose(f1);
332}
333
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
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;
356 u32 io_data;
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 }
378 io_data = memcheck_read(last_io_addr);
379 if (old_io_data != io_data) {
380 byte = 0xfe;
381 fwrite(&byte, 1, 1, f);
382 fwrite(&io_data, 1, 4, f);
383 old_io_data = io_data;
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
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
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
483 psxRegs.cycle = rregs.cycle;
484 psxRegs.CP0.r[9] = rregs.CP0.r[9]; // Count
485
486//if (psxRegs.cycle == 166172) breakme();
487
488 if (memcmp(&psxRegs, &rregs, offsetof(psxRegisters, intCycle)) == 0 &&
489 mem_val == memcheck_read(mem_addr)
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]) {
497 miss_log_add(i, allregs_p[i], allregs_e[i], psxRegs.pc, psxRegs.cycle);
498 bad++;
499 }
500 }
501
502 if (mem_val != memcheck_read(mem_addr)) {
503 printf("bad mem @%08x: %08x %08x\n", mem_addr, memcheck_read(mem_addr), mem_val);
504 goto end;
505 }
506
507 if (psxRegs.pc == rregs.pc && bad < 6 && failcount < 32) {
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 }
513 failcount++;
514 goto ok;
515 }
516
517end:
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],
525 i+8, allregs_p[i+8], i+16, allregs_p[i+16], i+24, allregs_p[i+24]);
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