drc: handle MTC0 in delay slot
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / emu_if.c
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
23 char invalid_code[0x100000];
24 u32 event_cycles[PSXINT_COUNT];
25
26 static 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
53 typedef void (irq_func)();
54
55 static 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 */
67 static 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
95 void 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
113 extern void MTC0(int reg, u32 val);
114
115 void 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
122 void 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
128 void new_dyna_save(void)
129 {
130         // psxRegs.intCycle is always maintained, no need to convert
131 }
132
133 void 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
140 void *gte_handlers[64];
141
142 /* from gte.txt.. not sure if this is any good. */
143 const 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
151 static 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
170 static 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
178 static 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
191 static 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
211 static void ari64_shutdown()
212 {
213         new_dynarec_cleanup();
214 }
215
216 extern void intExecute();
217 extern void intExecuteT();
218 extern void intExecuteBlock();
219 extern void intExecuteBlockT();
220 #ifndef DRC_DBG
221 #define intExecuteT intExecute
222 #define intExecuteBlockT intExecuteBlock
223 #endif
224
225 R3000Acpu 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
241 void do_insn_trace() {}
242 void do_insn_cmp() {}
243 #endif
244
245 #if defined(__x86_64__) || defined(__i386__)
246 unsigned int address, readmem_word, word;
247 unsigned short hword;
248 unsigned char byte;
249 int pending_exception, stop;
250 unsigned int next_interupt;
251 void *psxH_ptr;
252 void new_dynarec_init() {}
253 void new_dyna_start() {}
254 void new_dynarec_cleanup() {}
255 void invalidate_all_pages() {}
256 void invalidate_block(unsigned int block) {}
257 void new_dyna_pcsx_mem_init(void) {}
258 void new_dyna_pcsx_mem_reset(void) {}
259 #endif
260
261 #ifdef DRC_DBG
262
263 #include <stddef.h>
264 static FILE *f;
265 extern u32 last_io_addr;
266
267 static 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
276 static 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
291 void 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
340 static 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
364 static struct {
365         int reg;
366         u32 val, val_expect;
367         u32 pc, cycle;
368 } miss_log[64];
369 static 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
373 static 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
383 void breakme() {}
384
385 void 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
459 end:
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);
472 ok:
473         psxRegs.cycle = rregs.cycle + 2; // sync timing
474         ppc = psxRegs.pc;
475 }
476
477 #endif