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