b44feb394076172fc24396311e7cf6c59df3cef1
[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         [PSXINT_CDRDMA] = cdrDmaInterrupt,
65         [PSXINT_CDRLID] = cdrLidSeekInterrupt,
66         [PSXINT_CDRPLAY] = cdrPlayInterrupt,
67 };
68
69 /* local dupe of psxBranchTest, using event_cycles */
70 static void irq_test(void)
71 {
72         u32 irqs = psxRegs.interrupt;
73         u32 cycle = psxRegs.cycle;
74         u32 irq, irq_bits;
75
76         if ((psxRegs.cycle - psxNextsCounter) >= psxNextCounter)
77                 psxRcntUpdate();
78
79         // irq_funcs() may queue more irqs
80         psxRegs.interrupt = 0;
81
82         for (irq = 0, irq_bits = irqs; irq_bits != 0; irq++, irq_bits >>= 1) {
83                 if (!(irq_bits & 1))
84                         continue;
85                 if ((s32)(cycle - event_cycles[irq]) >= 0) {
86                         irqs &= ~(1 << irq);
87                         irq_funcs[irq]();
88                 }
89         }
90         psxRegs.interrupt |= irqs;
91
92         if ((psxHu32(0x1070) & psxHu32(0x1074)) && (Status & 0x401) == 0x401) {
93                 psxException(0x400, 0);
94                 pending_exception = 1;
95         }
96 }
97
98 void gen_interupt()
99 {
100         evprintf("  +ge %08x, %u->%u\n", psxRegs.pc, psxRegs.cycle, next_interupt);
101 #ifdef DRC_DBG
102         psxRegs.cycle += 2;
103 #endif
104
105         irq_test();
106         //psxBranchTest();
107         //pending_exception = 1;
108
109         schedule_timeslice();
110
111         evprintf("  -ge %08x, %u->%u (%d)\n", psxRegs.pc, psxRegs.cycle,
112                 next_interupt, next_interupt - psxRegs.cycle);
113 }
114
115 // from interpreter
116 extern void MTC0(int reg, u32 val);
117
118 void pcsx_mtc0(u32 reg)
119 {
120         evprintf("MTC0 %d #%x @%08x %u\n", reg, readmem_word, psxRegs.pc, psxRegs.cycle);
121         MTC0(reg, readmem_word);
122         gen_interupt();
123 }
124
125 void pcsx_mtc0_ds(u32 reg)
126 {
127         evprintf("MTC0 %d #%x @%08x %u\n", reg, readmem_word, psxRegs.pc, psxRegs.cycle);
128         MTC0(reg, readmem_word);
129 }
130
131 void new_dyna_save(void)
132 {
133         // psxRegs.intCycle is always maintained, no need to convert
134 }
135
136 void new_dyna_restore(void)
137 {
138         int i;
139         for (i = 0; i < PSXINT_COUNT; i++)
140                 event_cycles[i] = psxRegs.intCycle[i].sCycle + psxRegs.intCycle[i].cycle;
141 }
142
143 void *gte_handlers[64];
144
145 /* from gte.txt.. not sure if this is any good. */
146 const char gte_cycletab[64] = {
147         /*   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f */
148          0, 15,  0,  0,  0,  0,  8,  0,  0,  0,  0,  0,  6,  0,  0,  0,
149          8,  8,  8, 19, 13,  0, 44,  0,  0,  0,  0, 17, 11,  0, 14,  0,
150         30,  0,  0,  0,  0,  0,  0,  0,  5,  8, 17,  0,  0,  5,  6,  0,
151         23,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  5,  5, 39,
152 };
153
154 static int ari64_init()
155 {
156         extern void (*psxCP2[64])();
157         extern void psxNULL();
158         size_t i;
159
160         new_dynarec_init();
161         new_dyna_pcsx_mem_init();
162
163         for (i = 0; i < ARRAY_SIZE(gte_handlers); i++)
164                 if (psxCP2[i] != psxNULL)
165                         gte_handlers[i] = psxCP2[i];
166
167         psxH_ptr = psxH;
168
169         return 0;
170 }
171
172 static void ari64_reset()
173 {
174         printf("ari64_reset\n");
175         new_dyna_pcsx_mem_reset();
176         invalidate_all_pages();
177         new_dyna_restore();
178         pending_exception = 1;
179 }
180
181 // execute until predefined leave points
182 // (HLE softcall exit and BIOS fastboot end)
183 static void ari64_execute_until()
184 {
185         schedule_timeslice();
186
187         evprintf("ari64_execute %08x, %u->%u (%d)\n", psxRegs.pc,
188                 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
189
190         new_dyna_start();
191
192         evprintf("ari64_execute end %08x, %u->%u (%d)\n", psxRegs.pc,
193                 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
194 }
195
196 static void ari64_execute()
197 {
198         while (!stop) {
199                 ari64_execute_until();
200                 evprintf("drc left @%08x\n", psxRegs.pc);
201         }
202 }
203
204 static void ari64_clear(u32 addr, u32 size)
205 {
206         u32 start, end, main_ram;
207
208         size *= 4; /* PCSX uses DMA units */
209
210         evprintf("ari64_clear %08x %04x\n", addr, size);
211
212         /* check for RAM mirrors */
213         main_ram = (addr & 0xffe00000) == 0x80000000;
214
215         start = addr >> 12;
216         end = (addr + size) >> 12;
217
218         for (; start <= end; start++)
219                 if (!main_ram || !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