drc: don't leave until we really need to
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / emu_if.c
... / ...
CommitLineData
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
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
18#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
19
20//#define evprintf printf
21#define evprintf(...)
22
23char invalid_code[0x100000];
24u32 event_cycles[PSXINT_COUNT];
25
26static void schedule_timeslice(void)
27{
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}
52
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,
62 [PSXINT_MDECINDMA] = mdec0Interrupt,
63 [PSXINT_GPUOTCDMA] = gpuotcInterrupt,
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
95void gen_interupt()
96{
97 evprintf(" +ge %08x, %u->%u\n", psxRegs.pc, psxRegs.cycle, next_interupt);
98#ifdef DRC_DBG
99 psxRegs.cycle += 2;
100#endif
101
102 irq_test();
103 //psxBranchTest();
104 //pending_exception = 1;
105
106 schedule_timeslice();
107
108 evprintf(" -ge %08x, %u->%u (%d)\n", psxRegs.pc, psxRegs.cycle,
109 next_interupt, next_interupt - psxRegs.cycle);
110}
111
112// from interpreter
113extern void MTC0(int reg, u32 val);
114
115void pcsx_mtc0(u32 reg)
116{
117 evprintf("MTC0 %d #%x @%08x %u\n", reg, readmem_word, psxRegs.pc, psxRegs.cycle);
118 MTC0(reg, readmem_word);
119 gen_interupt();
120}
121
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);
126}
127
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
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};
150
151static int ari64_init()
152{
153 extern void (*psxCP2[64])();
154 extern void psxNULL();
155 extern void *psxH_ptr;
156 size_t i;
157
158 new_dynarec_init();
159 new_dyna_pcsx_mem_init();
160
161 for (i = 0; i < ARRAY_SIZE(gte_handlers); i++)
162 if (psxCP2[i] != psxNULL)
163 gte_handlers[i] = psxCP2[i];
164
165 psxH_ptr = psxH;
166
167 return 0;
168}
169
170static void ari64_reset()
171{
172 printf("ari64_reset\n");
173 new_dyna_pcsx_mem_reset();
174 invalidate_all_pages();
175 pending_exception = 1;
176}
177
178// execute until predefined leave points
179// (HLE softcall exit and BIOS fastboot end)
180static void ari64_execute_until()
181{
182 schedule_timeslice();
183
184 evprintf("ari64_execute %08x, %u->%u (%d)\n", psxRegs.pc,
185 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
186
187 new_dyna_start();
188
189 evprintf("ari64_execute end %08x, %u->%u (%d)\n", psxRegs.pc,
190 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
191}
192
193static void ari64_execute()
194{
195 while (!stop) {
196 ari64_execute_until();
197 evprintf("drc left @%08x\n", psxRegs.pc);
198 }
199}
200
201static void ari64_clear(u32 addr, u32 size)
202{
203 u32 start, end;
204
205 size *= 4; /* PCSX uses DMA units */
206
207 evprintf("ari64_clear %08x %04x\n", addr, size);
208
209 /* check for RAM mirrors */
210 if ((addr & ~0xe0600000) < 0x200000) {
211 addr &= ~0xe0600000;
212 addr |= 0x80000000;
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);
221}
222
223static void ari64_shutdown()
224{
225 new_dynarec_cleanup();
226}
227
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
237R3000Acpu psxRec = {
238 ari64_init,
239 ari64_reset,
240#if defined(__arm__)
241 ari64_execute,
242 ari64_execute_until,
243#else
244 intExecuteT,
245 intExecuteBlockT,
246#endif
247 ari64_clear,
248 ari64_shutdown
249};
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;
261int pending_exception, stop;
262unsigned int next_interupt;
263void *psxH_ptr;
264void new_dynarec_init() {}
265void new_dyna_start() {}
266void new_dynarec_cleanup() {}
267void invalidate_all_pages() {}
268void invalidate_block(unsigned int block) {}
269void new_dyna_pcsx_mem_init(void) {}
270void new_dyna_pcsx_mem_reset(void) {}
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");
282 if (f1 == NULL)
283 f1 = fopen(strrchr(fname, '/') + 1, "wb");
284 fwrite(mem, 1, size, f1);
285 fclose(f1);
286}
287
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
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;
310 u32 io_data;
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 }
332 io_data = memcheck_read(last_io_addr);
333 if (old_io_data != io_data) {
334 byte = 0xfe;
335 fwrite(&byte, 1, 1, f);
336 fwrite(&io_data, 1, 4, f);
337 old_io_data = io_data;
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
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
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
437 psxRegs.cycle = rregs.cycle;
438 psxRegs.CP0.r[9] = rregs.CP0.r[9]; // Count
439
440//if (psxRegs.cycle == 166172) breakme();
441
442 if (memcmp(&psxRegs, &rregs, offsetof(psxRegisters, intCycle)) == 0 &&
443 mem_val == memcheck_read(mem_addr)
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]) {
451 miss_log_add(i, allregs_p[i], allregs_e[i], psxRegs.pc, psxRegs.cycle);
452 bad++;
453 }
454 }
455
456 if (mem_val != memcheck_read(mem_addr)) {
457 printf("bad mem @%08x: %08x %08x\n", mem_addr, memcheck_read(mem_addr), mem_val);
458 goto end;
459 }
460
461 if (psxRegs.pc == rregs.pc && bad < 6 && failcount < 32) {
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 }
467 failcount++;
468 goto ok;
469 }
470
471end:
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],
479 i+8, allregs_p[i+8], i+16, allregs_p[i+16], i+24, allregs_p[i+24]);
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