yet more random armv5 tweaks
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / emu_if.c
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
27 char invalid_code[0x100000];
28 u32 event_cycles[PSXINT_COUNT];
29
30 static 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
57 typedef void (irq_func)();
58
59 static 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 */
74 static 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
102 void 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
117 extern void MTC0(int reg, u32 val);
118
119 void 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
126 void 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
132 void new_dyna_save(void)
133 {
134         // psxRegs.intCycle is always maintained, no need to convert
135 }
136
137 void 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
144 void *gte_handlers[64];
145
146 void *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 const char *gte_regnames[64] = {
158         NULL  , "RTPS" , NULL   , NULL  , NULL , NULL   , "NCLIP", NULL  , // 00
159         NULL  , NULL   , NULL   , NULL  , "OP" , NULL   , NULL   , NULL  , // 08
160         "DPCS", "INTPL", "MVMVA", "NCDS", "CDP", NULL   , "NCDT" , NULL  , // 10
161         NULL  , NULL   , NULL   , "NCCS", "CC" , NULL   , "NCS"  , NULL  , // 18
162         "NCT" , NULL   , NULL   , NULL  , NULL , NULL   , NULL   , NULL  , // 20
163         "SQR" , "DCPL" , "DPCT" , NULL  , NULL , "AVSZ3", "AVSZ4", NULL  , // 28 
164         "RTPT", NULL   , NULL   , NULL  , NULL , NULL   , NULL   , NULL  , // 30
165         NULL  , NULL   , NULL   , NULL  , NULL , "GPF"  , "GPL"  , "NCCT", // 38
166 };
167
168 /* from gte.txt.. not sure if this is any good. */
169 const char gte_cycletab[64] = {
170         /*   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f */
171          0, 15,  0,  0,  0,  0,  8,  0,  0,  0,  0,  0,  6,  0,  0,  0,
172          8,  8,  8, 19, 13,  0, 44,  0,  0,  0,  0, 17, 11,  0, 14,  0,
173         30,  0,  0,  0,  0,  0,  0,  0,  5,  8, 17,  0,  0,  5,  6,  0,
174         23,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  5,  5, 39,
175 };
176
177 static int ari64_init()
178 {
179         extern void (*psxCP2[64])();
180         extern void psxNULL();
181         size_t i;
182
183         new_dynarec_init();
184         new_dyna_pcsx_mem_init();
185
186         for (i = 0; i < ARRAY_SIZE(gte_handlers); i++)
187                 if (psxCP2[i] != psxNULL)
188                         gte_handlers[i] = psxCP2[i];
189
190 #if !defined(DRC_DBG) && !defined(PCNT)
191 #ifdef __arm__
192         gte_handlers[0x06] = gteNCLIP_arm;
193         gte_handlers_nf[0x01] = gteRTPS_nf_arm;
194         gte_handlers_nf[0x30] = gteRTPT_nf_arm;
195 #endif
196 #ifdef __ARM_NEON__
197         // compiler's _nf version is still a lot slower then neon
198         // _nf_arm RTPS is roughly the same, RTPT slower
199         gte_handlers[0x01] = gte_handlers_nf[0x01] = gteRTPS_neon;
200         gte_handlers[0x30] = gte_handlers_nf[0x30] = gteRTPT_neon;
201         gte_handlers[0x12] = gte_handlers_nf[0x12] = gteMVMVA_neon;
202 #endif
203 #endif
204 #ifdef DRC_DBG
205         memcpy(gte_handlers_nf, gte_handlers, sizeof(gte_handlers_nf));
206 #endif
207         psxH_ptr = psxH;
208
209         return 0;
210 }
211
212 static void ari64_reset()
213 {
214         printf("ari64_reset\n");
215         new_dyna_pcsx_mem_reset();
216         invalidate_all_pages();
217         new_dyna_restore();
218         pending_exception = 1;
219 }
220
221 // execute until predefined leave points
222 // (HLE softcall exit and BIOS fastboot end)
223 static void ari64_execute_until()
224 {
225         schedule_timeslice();
226
227         evprintf("ari64_execute %08x, %u->%u (%d)\n", psxRegs.pc,
228                 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
229
230         new_dyna_start();
231
232         evprintf("ari64_execute end %08x, %u->%u (%d)\n", psxRegs.pc,
233                 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
234 }
235
236 static void ari64_execute()
237 {
238         while (!stop) {
239                 ari64_execute_until();
240                 evprintf("drc left @%08x\n", psxRegs.pc);
241         }
242 }
243
244 static void ari64_clear(u32 addr, u32 size)
245 {
246         u32 start, end, main_ram;
247
248         size *= 4; /* PCSX uses DMA units */
249
250         evprintf("ari64_clear %08x %04x\n", addr, size);
251
252         /* check for RAM mirrors */
253         main_ram = (addr & 0xffe00000) == 0x80000000;
254
255         start = addr >> 12;
256         end = (addr + size) >> 12;
257
258         for (; start <= end; start++)
259                 if (!main_ram || !invalid_code[start])
260                         invalidate_block(start);
261 }
262
263 static void ari64_shutdown()
264 {
265         new_dynarec_cleanup();
266 }
267
268 extern void intExecute();
269 extern void intExecuteT();
270 extern void intExecuteBlock();
271 extern void intExecuteBlockT();
272 #ifndef DRC_DBG
273 #define intExecuteT intExecute
274 #define intExecuteBlockT intExecuteBlock
275 #endif
276
277 R3000Acpu psxRec = {
278         ari64_init,
279         ari64_reset,
280 #if defined(__arm__)
281         ari64_execute,
282         ari64_execute_until,
283 #else
284         intExecuteT,
285         intExecuteBlockT,
286 #endif
287         ari64_clear,
288         ari64_shutdown
289 };
290
291 // TODO: rm
292 #ifndef DRC_DBG
293 void do_insn_trace() {}
294 void do_insn_cmp() {}
295 #endif
296
297 #if defined(__x86_64__) || defined(__i386__)
298 unsigned int address, readmem_word, word;
299 unsigned short hword;
300 unsigned char byte;
301 int pending_exception, stop;
302 unsigned int next_interupt;
303 void *psxH_ptr;
304 void new_dynarec_init() {}
305 void new_dyna_start() {}
306 void new_dynarec_cleanup() {}
307 void new_dynarec_clear_full() {}
308 void invalidate_all_pages() {}
309 void invalidate_block(unsigned int block) {}
310 void new_dyna_pcsx_mem_init(void) {}
311 void new_dyna_pcsx_mem_reset(void) {}
312 #endif
313
314 #ifdef DRC_DBG
315
316 #include <stddef.h>
317 static FILE *f;
318 extern u32 last_io_addr;
319
320 static void dump_mem(const char *fname, void *mem, size_t size)
321 {
322         FILE *f1 = fopen(fname, "wb");
323         if (f1 == NULL)
324                 f1 = fopen(strrchr(fname, '/') + 1, "wb");
325         fwrite(mem, 1, size, f1);
326         fclose(f1);
327 }
328
329 static u32 memcheck_read(u32 a)
330 {
331         if ((a >> 16) == 0x1f80)
332                 // scratchpad/IO
333                 return *(u32 *)(psxH + (a & 0xfffc));
334
335         if ((a >> 16) == 0x1f00)
336                 // parallel
337                 return *(u32 *)(psxP + (a & 0xfffc));
338
339 //      if ((a & ~0xe0600000) < 0x200000)
340         // RAM
341         return *(u32 *)(psxM + (a & 0x1ffffc));
342 }
343
344 void do_insn_trace(void)
345 {
346         static psxRegisters oldregs;
347         static u32 old_io_addr = (u32)-1;
348         static u32 old_io_data = 0xbad0c0de;
349         u32 *allregs_p = (void *)&psxRegs;
350         u32 *allregs_o = (void *)&oldregs;
351         u32 io_data;
352         int i;
353         u8 byte;
354
355 //last_io_addr = 0x5e2c8;
356         if (f == NULL)
357                 f = fopen("tracelog", "wb");
358
359         oldregs.code = psxRegs.code; // don't care
360         for (i = 0; i < offsetof(psxRegisters, intCycle) / 4; i++) {
361                 if (allregs_p[i] != allregs_o[i]) {
362                         fwrite(&i, 1, 1, f);
363                         fwrite(&allregs_p[i], 1, 4, f);
364                         allregs_o[i] = allregs_p[i];
365                 }
366         }
367         if (old_io_addr != last_io_addr) {
368                 byte = 0xfd;
369                 fwrite(&byte, 1, 1, f);
370                 fwrite(&last_io_addr, 1, 4, f);
371                 old_io_addr = last_io_addr;
372         }
373         io_data = memcheck_read(last_io_addr);
374         if (old_io_data != io_data) {
375                 byte = 0xfe;
376                 fwrite(&byte, 1, 1, f);
377                 fwrite(&io_data, 1, 4, f);
378                 old_io_data = io_data;
379         }
380         byte = 0xff;
381         fwrite(&byte, 1, 1, f);
382
383 #if 0
384         if (psxRegs.cycle == 190230) {
385                 dump_mem("/mnt/ntz/dev/pnd/tmp/psxram_i.dump", psxM, 0x200000);
386                 dump_mem("/mnt/ntz/dev/pnd/tmp/psxregs_i.dump", psxH, 0x10000);
387                 printf("dumped\n");
388                 exit(1);
389         }
390 #endif
391 }
392
393 static const char *regnames[offsetof(psxRegisters, intCycle) / 4] = {
394         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
395         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
396         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
397         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
398         "lo",  "hi",
399         "C0_0",  "C0_1",  "C0_2",  "C0_3",  "C0_4",  "C0_5",  "C0_6",  "C0_7",
400         "C0_8",  "C0_9",  "C0_10", "C0_11", "C0_12", "C0_13", "C0_14", "C0_15",
401         "C0_16", "C0_17", "C0_18", "C0_19", "C0_20", "C0_21", "C0_22", "C0_23",
402         "C0_24", "C0_25", "C0_26", "C0_27", "C0_28", "C0_29", "C0_30", "C0_31",
403
404         "C2D0",  "C2D1",  "C2D2",  "C2D3",  "C2D4",  "C2D5",  "C2D6",  "C2D7",
405         "C2D8",  "C2D9",  "C2D10", "C2D11", "C2D12", "C2D13", "C2D14", "C2D15",
406         "C2D16", "C2D17", "C2D18", "C2D19", "C2D20", "C2D21", "C2D22", "C2D23",
407         "C2D24", "C2D25", "C2D26", "C2D27", "C2D28", "C2D29", "C2D30", "C2D31",
408
409         "C2C0",  "C2C1",  "C2C2",  "C2C3",  "C2C4",  "C2C5",  "C2C6",  "C2C7",
410         "C2C8",  "C2C9",  "C2C10", "C2C11", "C2C12", "C2C13", "C2C14", "C2C15",
411         "C2C16", "C2C17", "C2C18", "C2C19", "C2C20", "C2C21", "C2C22", "C2C23",
412         "C2C24", "C2C25", "C2C26", "C2C27", "C2C28", "C2C29", "C2C30", "C2C31",
413
414         "PC", "code", "cycle", "interrupt",
415 };
416
417 static struct {
418         int reg;
419         u32 val, val_expect;
420         u32 pc, cycle;
421 } miss_log[64];
422 static int miss_log_i;
423 #define miss_log_len (sizeof(miss_log)/sizeof(miss_log[0]))
424 #define miss_log_mask (miss_log_len-1)
425
426 static void miss_log_add(int reg, u32 val, u32 val_expect, u32 pc, u32 cycle)
427 {
428         miss_log[miss_log_i].reg = reg;
429         miss_log[miss_log_i].val = val;
430         miss_log[miss_log_i].val_expect = val_expect;
431         miss_log[miss_log_i].pc = pc;
432         miss_log[miss_log_i].cycle = cycle;
433         miss_log_i = (miss_log_i + 1) & miss_log_mask;
434 }
435
436 void breakme() {}
437
438 void do_insn_cmp(void)
439 {
440         static psxRegisters rregs;
441         static u32 mem_addr, mem_val;
442         u32 *allregs_p = (void *)&psxRegs;
443         u32 *allregs_e = (void *)&rregs;
444         static u32 ppc, failcount;
445         int i, ret, bad = 0;
446         u8 code;
447
448         if (f == NULL)
449                 f = fopen("tracelog", "rb");
450
451         while (1) {
452                 if ((ret = fread(&code, 1, 1, f)) <= 0)
453                         break;
454                 if (ret <= 0)
455                         break;
456                 if (code == 0xff)
457                         break;
458                 if (code == 0xfd) {
459                         if ((ret = fread(&mem_addr, 1, 4, f)) <= 0)
460                                 break;
461                         continue;
462                 }
463                 if (code == 0xfe) {
464                         if ((ret = fread(&mem_val, 1, 4, f)) <= 0)
465                                 break;
466                         continue;
467                 }
468                 if ((ret = fread(&allregs_e[code], 1, 4, f)) <= 0)
469                         break;
470         }
471
472         if (ret <= 0) {
473                 printf("EOF?\n");
474                 goto end;
475         }
476
477         psxRegs.code = rregs.code; // don't care
478         psxRegs.cycle = rregs.cycle;
479         psxRegs.CP0.r[9] = rregs.CP0.r[9]; // Count
480
481 //if (psxRegs.cycle == 166172) breakme();
482
483         if (memcmp(&psxRegs, &rregs, offsetof(psxRegisters, intCycle)) == 0 &&
484                         mem_val == memcheck_read(mem_addr)
485            ) {
486                 failcount = 0;
487                 goto ok;
488         }
489
490         for (i = 0; i < offsetof(psxRegisters, intCycle) / 4; i++) {
491                 if (allregs_p[i] != allregs_e[i]) {
492                         miss_log_add(i, allregs_p[i], allregs_e[i], psxRegs.pc, psxRegs.cycle);
493                         bad++;
494                 }
495         }
496
497         if (mem_val != memcheck_read(mem_addr)) {
498                 printf("bad mem @%08x: %08x %08x\n", mem_addr, memcheck_read(mem_addr), mem_val);
499                 goto end;
500         }
501
502         if (psxRegs.pc == rregs.pc && bad < 6 && failcount < 32) {
503                 static int last_mcycle;
504                 if (last_mcycle != psxRegs.cycle >> 20) {
505                         printf("%u\n", psxRegs.cycle);
506                         last_mcycle = psxRegs.cycle >> 20;
507                 }
508                 failcount++;
509                 goto ok;
510         }
511
512 end:
513         for (i = 0; i < miss_log_len; i++, miss_log_i = (miss_log_i + 1) & miss_log_mask)
514                 printf("bad %5s: %08x %08x, pc=%08x, cycle %u\n",
515                         regnames[miss_log[miss_log_i].reg], miss_log[miss_log_i].val,
516                         miss_log[miss_log_i].val_expect, miss_log[miss_log_i].pc, miss_log[miss_log_i].cycle);
517         printf("-- %d\n", bad);
518         for (i = 0; i < 8; i++)
519                 printf("r%d=%08x r%2d=%08x r%2d=%08x r%2d=%08x\n", i, allregs_p[i],
520                         i+8, allregs_p[i+8], i+16, allregs_p[i+16], i+24, allregs_p[i+24]);
521         printf("PC: %08x/%08x, cycle %u\n", psxRegs.pc, ppc, psxRegs.cycle);
522         dump_mem("/mnt/ntz/dev/pnd/tmp/psxram.dump", psxM, 0x200000);
523         dump_mem("/mnt/ntz/dev/pnd/tmp/psxregs.dump", psxH, 0x10000);
524         exit(1);
525 ok:
526         psxRegs.cycle = rregs.cycle + 2; // sync timing
527         ppc = psxRegs.pc;
528 }
529
530 #endif