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