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