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