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