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