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