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