2a090a0b4ae49196af995b20a5fe1a7c4a2fa6ad
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / backends / psx / 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
20 #include "../../../gte.h"
21
22 #define FLAGLESS
23 #include "../../../gte.h"
24 #undef  FLAGLESS
25
26 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
27
28 //#define evprintf printf
29 #define evprintf(...)
30
31 char invalid_code[0x100000];
32 static u32 scratch_buf[8*8*2] __attribute__((aligned(64)));
33 u32 event_cycles[PSXINT_COUNT];
34
35 static void schedule_timeslice(void)
36 {
37         u32 i, c = psxRegs.cycle;
38         u32 irqs = psxRegs.interrupt;
39         s32 min, dif;
40
41         min = PSXCLK;
42         for (i = 0; irqs != 0; i++, irqs >>= 1) {
43                 if (!(irqs & 1))
44                         continue;
45                 dif = event_cycles[i] - c;
46                 //evprintf("  ev %d\n", dif);
47                 if (0 < dif && dif < min)
48                         min = dif;
49         }
50         next_interupt = c + min;
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         [PSXINT_SPU_UPDATE] = spuUpdate,
68         [PSXINT_RCNT] = psxRcntUpdate,
69 };
70
71 /* local dupe of psxBranchTest, using event_cycles */
72 static void irq_test(void)
73 {
74         u32 irqs = psxRegs.interrupt;
75         u32 cycle = psxRegs.cycle;
76         u32 irq, irq_bits;
77
78         // irq_funcs() may queue more irqs
79         psxRegs.interrupt = 0;
80
81         for (irq = 0, irq_bits = irqs; irq_bits != 0; irq++, irq_bits >>= 1) {
82                 if (!(irq_bits & 1))
83                         continue;
84                 if ((s32)(cycle - event_cycles[irq]) >= 0) {
85                         irqs &= ~(1 << irq);
86                         irq_funcs[irq]();
87                 }
88         }
89         psxRegs.interrupt |= irqs;
90
91         if ((psxHu32(0x1070) & psxHu32(0x1074)) && (Status & 0x401) == 0x401) {
92                 psxException(0x400, 0);
93                 pending_exception = 1;
94         }
95 }
96
97 void gen_interupt()
98 {
99         evprintf("  +ge %08x, %u->%u\n", psxRegs.pc, psxRegs.cycle, next_interupt);
100
101         irq_test();
102         //psxBranchTest();
103         //pending_exception = 1;
104
105         schedule_timeslice();
106
107         evprintf("  -ge %08x, %u->%u (%d)\n", psxRegs.pc, psxRegs.cycle,
108                 next_interupt, next_interupt - psxRegs.cycle);
109 }
110
111 // from interpreter
112 extern void MTC0(int reg, u32 val);
113
114 void pcsx_mtc0(u32 reg, u32 val)
115 {
116         evprintf("MTC0 %d #%x @%08x %u\n", reg, val, psxRegs.pc, psxRegs.cycle);
117         MTC0(reg, val);
118         gen_interupt();
119         if (Cause & Status & 0x0300) // possible sw irq
120                 pending_exception = 1;
121 }
122
123 void pcsx_mtc0_ds(u32 reg, u32 val)
124 {
125         evprintf("MTC0 %d #%x @%08x %u\n", reg, val, psxRegs.pc, psxRegs.cycle);
126         MTC0(reg, val);
127 }
128
129 void new_dyna_before_save(void)
130 {
131         psxRegs.interrupt &= ~(1 << PSXINT_RCNT); // old savestate compat
132
133         // psxRegs.intCycle is always maintained, no need to convert
134 }
135
136 void new_dyna_after_save(void)
137 {
138         psxRegs.interrupt |= 1 << PSXINT_RCNT;
139 }
140
141 static void new_dyna_restore(void)
142 {
143         int i;
144         for (i = 0; i < PSXINT_COUNT; i++)
145                 event_cycles[i] = psxRegs.intCycle[i].sCycle + psxRegs.intCycle[i].cycle;
146
147         event_cycles[PSXINT_RCNT] = psxNextsCounter + psxNextCounter;
148         psxRegs.interrupt |=  1 << PSXINT_RCNT;
149         psxRegs.interrupt &= (1 << PSXINT_COUNT) - 1;
150
151         new_dyna_pcsx_mem_load_state();
152 }
153
154 void new_dyna_freeze(void *f, int mode)
155 {
156         const char header_save[8] = "ariblks";
157         uint32_t addrs[1024 * 4];
158         int32_t size = 0;
159         int bytes;
160         char header[8];
161
162         if (mode != 0) { // save
163                 size = new_dynarec_save_blocks(addrs, sizeof(addrs));
164                 if (size == 0)
165                         return;
166
167                 SaveFuncs.write(f, header_save, sizeof(header_save));
168                 SaveFuncs.write(f, &size, sizeof(size));
169                 SaveFuncs.write(f, addrs, size);
170         }
171         else {
172                 new_dyna_restore();
173
174                 bytes = SaveFuncs.read(f, header, sizeof(header));
175                 if (bytes != sizeof(header) || strcmp(header, header_save)) {
176                         if (bytes > 0)
177                                 SaveFuncs.seek(f, -bytes, SEEK_CUR);
178                         return;
179                 }
180                 SaveFuncs.read(f, &size, sizeof(size));
181                 if (size <= 0)
182                         return;
183                 if (size > sizeof(addrs)) {
184                         bytes = size - sizeof(addrs);
185                         SaveFuncs.seek(f, bytes, SEEK_CUR);
186                         size = sizeof(addrs);
187                 }
188                 bytes = SaveFuncs.read(f, addrs, size);
189                 if (bytes != size)
190                         return;
191
192                 new_dynarec_load_blocks(addrs, size);
193         }
194
195         //printf("drc: %d block info entries %s\n", size/8, mode ? "saved" : "loaded");
196 }
197
198 /* GTE stuff */
199 void *gte_handlers[64];
200
201 void *gte_handlers_nf[64] = {
202         NULL      , gteRTPS_nf , NULL       , NULL      , NULL     , NULL       , gteNCLIP_nf, NULL      , // 00
203         NULL      , NULL       , NULL       , NULL      , gteOP_nf , NULL       , NULL       , NULL      , // 08
204         gteDPCS_nf, gteINTPL_nf, gteMVMVA_nf, gteNCDS_nf, gteCDP_nf, NULL       , gteNCDT_nf , NULL      , // 10
205         NULL      , NULL       , NULL       , gteNCCS_nf, gteCC_nf , NULL       , gteNCS_nf  , NULL      , // 18
206         gteNCT_nf , NULL       , NULL       , NULL      , NULL     , NULL       , NULL       , NULL      , // 20
207         gteSQR_nf , gteDCPL_nf , gteDPCT_nf , NULL      , NULL     , gteAVSZ3_nf, gteAVSZ4_nf, NULL      , // 28 
208         gteRTPT_nf, NULL       , NULL       , NULL      , NULL     , NULL       , NULL       , NULL      , // 30
209         NULL      , NULL       , NULL       , NULL      , NULL     , gteGPF_nf  , gteGPL_nf  , gteNCCT_nf, // 38
210 };
211
212 const char *gte_regnames[64] = {
213         NULL  , "RTPS" , NULL   , NULL  , NULL , NULL   , "NCLIP", NULL  , // 00
214         NULL  , NULL   , NULL   , NULL  , "OP" , NULL   , NULL   , NULL  , // 08
215         "DPCS", "INTPL", "MVMVA", "NCDS", "CDP", NULL   , "NCDT" , NULL  , // 10
216         NULL  , NULL   , NULL   , "NCCS", "CC" , NULL   , "NCS"  , NULL  , // 18
217         "NCT" , NULL   , NULL   , NULL  , NULL , NULL   , NULL   , NULL  , // 20
218         "SQR" , "DCPL" , "DPCT" , NULL  , NULL , "AVSZ3", "AVSZ4", NULL  , // 28 
219         "RTPT", NULL   , NULL   , NULL  , NULL , NULL   , NULL   , NULL  , // 30
220         NULL  , NULL   , NULL   , NULL  , NULL , "GPF"  , "GPL"  , "NCCT", // 38
221 };
222
223 /* from gte.txt.. not sure if this is any good. */
224 const char gte_cycletab[64] = {
225         /*   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f */
226          0, 15,  0,  0,  0,  0,  8,  0,  0,  0,  0,  0,  6,  0,  0,  0,
227          8,  8,  8, 19, 13,  0, 44,  0,  0,  0,  0, 17, 11,  0, 14,  0,
228         30,  0,  0,  0,  0,  0,  0,  0,  5,  8, 17,  0,  0,  5,  6,  0,
229         23,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  5,  5, 39,
230 };
231
232 #define GCBIT(x) \
233         (1ll << (32+x))
234 #define GDBIT(x) \
235         (1ll << (x))
236 #define GCBITS3(b0,b1,b2) \
237         (GCBIT(b0) | GCBIT(b1) | GCBIT(b2))
238 #define GDBITS2(b0,b1) \
239         (GDBIT(b0) | GDBIT(b1))
240 #define GDBITS3(b0,b1,b2) \
241         (GDBITS2(b0,b1) | GDBIT(b2))
242 #define GDBITS4(b0,b1,b2,b3) \
243         (GDBITS3(b0,b1,b2) | GDBIT(b3))
244 #define GDBITS5(b0,b1,b2,b3,b4) \
245         (GDBITS4(b0,b1,b2,b3) | GDBIT(b4))
246 #define GDBITS6(b0,b1,b2,b3,b4,b5) \
247         (GDBITS5(b0,b1,b2,b3,b4) | GDBIT(b5))
248 #define GDBITS7(b0,b1,b2,b3,b4,b5,b6) \
249         (GDBITS6(b0,b1,b2,b3,b4,b5) | GDBIT(b6))
250 #define GDBITS8(b0,b1,b2,b3,b4,b5,b6,b7) \
251         (GDBITS7(b0,b1,b2,b3,b4,b5,b6) | GDBIT(b7))
252 #define GDBITS9(b0,b1,b2,b3,b4,b5,b6,b7,b8) \
253         (GDBITS8(b0,b1,b2,b3,b4,b5,b6,b7) | GDBIT(b8))
254 #define GDBITS10(b0,b1,b2,b3,b4,b5,b6,b7,b8,b9) \
255         (GDBITS9(b0,b1,b2,b3,b4,b5,b6,b7,b8) | GDBIT(b9))
256
257 const uint64_t gte_reg_reads[64] = {
258         [GTE_RTPS]  = 0x1f0000ff00000000ll | GDBITS7(0,1,13,14,17,18,19),
259         [GTE_NCLIP] =                        GDBITS3(12,13,14),
260         [GTE_OP]    = GCBITS3(0,2,4)       | GDBITS3(9,10,11),
261         [GTE_DPCS]  = GCBITS3(21,22,23)    | GDBITS4(6,8,21,22),
262         [GTE_INTPL] = GCBITS3(21,22,23)    | GDBITS7(6,8,9,10,11,21,22),
263         [GTE_MVMVA] = 0x00ffffff00000000ll | GDBITS9(0,1,2,3,4,5,9,10,11), // XXX: maybe decode further?
264         [GTE_NCDS]  = 0x00ffff0000000000ll | GDBITS6(0,1,6,8,21,22),
265         [GTE_CDP]   = 0x00ffe00000000000ll | GDBITS7(6,8,9,10,11,21,22),
266         [GTE_NCDT]  = 0x00ffff0000000000ll | GDBITS8(0,1,2,3,4,5,6,8),
267         [GTE_NCCS]  = 0x001fff0000000000ll | GDBITS5(0,1,6,21,22),
268         [GTE_CC]    = 0x001fe00000000000ll | GDBITS6(6,9,10,11,21,22),
269         [GTE_NCS]   = 0x001fff0000000000ll | GDBITS5(0,1,6,21,22),
270         [GTE_NCT]   = 0x001fff0000000000ll | GDBITS7(0,1,2,3,4,5,6),
271         [GTE_SQR]   =                        GDBITS3(9,10,11),
272         [GTE_DCPL]  = GCBITS3(21,22,23)    | GDBITS7(6,8,9,10,11,21,22),
273         [GTE_DPCT]  = GCBITS3(21,22,23)    | GDBITS4(8,20,21,22),
274         [GTE_AVSZ3] = GCBIT(29)            | GDBITS3(17,18,19),
275         [GTE_AVSZ4] = GCBIT(30)            | GDBITS4(16,17,18,19),
276         [GTE_RTPT]  = 0x1f0000ff00000000ll | GDBITS7(0,1,2,3,4,5,19),
277         [GTE_GPF]   =                        GDBITS7(6,8,9,10,11,21,22),
278         [GTE_GPL]   =                        GDBITS10(6,8,9,10,11,21,22,25,26,27),
279         [GTE_NCCT]  = 0x001fff0000000000ll | GDBITS7(0,1,2,3,4,5,6),
280 };
281
282 // note: this excludes gteFLAG that is always written to
283 const uint64_t gte_reg_writes[64] = {
284         [GTE_RTPS]  = 0x0f0f7f00ll,
285         [GTE_NCLIP] = GDBIT(24),
286         [GTE_OP]    = GDBITS6(9,10,11,25,26,27),
287         [GTE_DPCS]  = GDBITS9(9,10,11,20,21,22,25,26,27),
288         [GTE_INTPL] = GDBITS9(9,10,11,20,21,22,25,26,27),
289         [GTE_MVMVA] = GDBITS6(9,10,11,25,26,27),
290         [GTE_NCDS]  = GDBITS9(9,10,11,20,21,22,25,26,27),
291         [GTE_CDP]   = GDBITS9(9,10,11,20,21,22,25,26,27),
292         [GTE_NCDT]  = GDBITS9(9,10,11,20,21,22,25,26,27),
293         [GTE_NCCS]  = GDBITS9(9,10,11,20,21,22,25,26,27),
294         [GTE_CC]    = GDBITS9(9,10,11,20,21,22,25,26,27),
295         [GTE_NCS]   = GDBITS9(9,10,11,20,21,22,25,26,27),
296         [GTE_NCT]   = GDBITS9(9,10,11,20,21,22,25,26,27),
297         [GTE_SQR]   = GDBITS6(9,10,11,25,26,27),
298         [GTE_DCPL]  = GDBITS9(9,10,11,20,21,22,25,26,27),
299         [GTE_DPCT]  = GDBITS9(9,10,11,20,21,22,25,26,27),
300         [GTE_AVSZ3] = GDBITS2(7,24),
301         [GTE_AVSZ4] = GDBITS2(7,24),
302         [GTE_RTPT]  = 0x0f0f7f00ll,
303         [GTE_GPF]   = GDBITS9(9,10,11,20,21,22,25,26,27),
304         [GTE_GPL]   = GDBITS9(9,10,11,20,21,22,25,26,27),
305         [GTE_NCCT]  = GDBITS9(9,10,11,20,21,22,25,26,27),
306 };
307
308 static int ari64_init()
309 {
310         extern void (*psxCP2[64])();
311         extern void psxNULL();
312         extern unsigned char *out;
313         size_t i;
314
315         new_dynarec_init();
316         new_dyna_pcsx_mem_init();
317
318         for (i = 0; i < ARRAY_SIZE(gte_handlers); i++)
319                 if (psxCP2[i] != psxNULL)
320                         gte_handlers[i] = psxCP2[i];
321
322 #if defined(__arm__) && !defined(DRC_DBG)
323         gte_handlers[0x06] = gteNCLIP_arm;
324 #ifdef HAVE_ARMV5
325         gte_handlers_nf[0x01] = gteRTPS_nf_arm;
326         gte_handlers_nf[0x30] = gteRTPT_nf_arm;
327 #endif
328 #ifdef __ARM_NEON__
329         // compiler's _nf version is still a lot slower than neon
330         // _nf_arm RTPS is roughly the same, RTPT slower
331         gte_handlers[0x01] = gte_handlers_nf[0x01] = gteRTPS_neon;
332         gte_handlers[0x30] = gte_handlers_nf[0x30] = gteRTPT_neon;
333 #endif
334 #endif
335 #ifdef DRC_DBG
336         memcpy(gte_handlers_nf, gte_handlers, sizeof(gte_handlers_nf));
337 #endif
338    
339         psxH_ptr = psxH;
340         zeromem_ptr = zero_mem;
341         scratch_buf_ptr = scratch_buf;
342
343         SysPrintf("Mapped (RAM/scrp/ROM/LUTs/TC):\n");
344         SysPrintf("%08x/%08x/%08x/%08x/%08x\n",
345                 psxM, psxH, psxR, mem_rtab, out);
346
347         return 0;
348 }
349
350 static void ari64_reset()
351 {
352         printf("ari64_reset\n");
353         new_dyna_pcsx_mem_reset();
354         invalidate_all_pages();
355         new_dyna_restore();
356         pending_exception = 1;
357 }
358
359 // execute until predefined leave points
360 // (HLE softcall exit and BIOS fastboot end)
361 static void ari64_execute_until()
362 {
363         schedule_timeslice();
364
365         evprintf("ari64_execute %08x, %u->%u (%d)\n", psxRegs.pc,
366                 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
367
368         new_dyna_start();
369
370         evprintf("ari64_execute end %08x, %u->%u (%d)\n", psxRegs.pc,
371                 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
372 }
373
374 static void ari64_execute()
375 {
376         while (!stop) {
377                 ari64_execute_until();
378                 evprintf("drc left @%08x\n", psxRegs.pc);
379         }
380 }
381
382 static void ari64_clear(u32 addr, u32 size)
383 {
384         u32 start, end, main_ram;
385
386         size *= 4; /* PCSX uses DMA units (words) */
387
388         evprintf("ari64_clear %08x %04x\n", addr, size);
389
390         /* check for RAM mirrors */
391         main_ram = (addr & 0xffe00000) == 0x80000000;
392
393         start = addr >> 12;
394         end = (addr + size) >> 12;
395
396         for (; start <= end; start++)
397                 if (!main_ram || !invalid_code[start])
398                         invalidate_block(start);
399 }
400
401 static void ari64_shutdown()
402 {
403         new_dynarec_cleanup();
404         new_dyna_pcsx_mem_shutdown();
405 }
406
407 extern void intExecute();
408 extern void intExecuteT();
409 extern void intExecuteBlock();
410 extern void intExecuteBlockT();
411 #ifndef DRC_DBG
412 #define intExecuteT intExecute
413 #define intExecuteBlockT intExecuteBlock
414 #endif
415
416 R3000Acpu psxRec = {
417         ari64_init,
418         ari64_reset,
419 #ifndef DRC_DISABLE
420         ari64_execute,
421         ari64_execute_until,
422 #else
423         intExecuteT,
424         intExecuteBlockT,
425 #endif
426         ari64_clear,
427         ari64_shutdown
428 };
429
430 // TODO: rm
431 #ifndef DRC_DBG
432 void do_insn_trace() {}
433 void do_insn_cmp() {}
434 #endif
435
436 #ifdef DRC_DISABLE
437 unsigned int address;
438 int pending_exception, stop;
439 u32 next_interupt;
440 int new_dynarec_did_compile;
441 int cycle_multiplier;
442 int new_dynarec_hacks;
443 void *psxH_ptr;
444 void *zeromem_ptr;
445 u8 zero_mem[0x1000];
446 unsigned char *out;
447 void *mem_rtab;
448 void *scratch_buf_ptr;
449 void new_dynarec_init() { (void)ari64_execute; }
450 void new_dyna_start() {}
451 void new_dynarec_cleanup() {}
452 void new_dynarec_clear_full() {}
453 void invalidate_all_pages() {}
454 void invalidate_block(unsigned int block) {}
455 void new_dyna_pcsx_mem_init(void) {}
456 void new_dyna_pcsx_mem_reset(void) {}
457 void new_dyna_pcsx_mem_load_state(void) {}
458 void new_dyna_pcsx_mem_shutdown(void) {}
459 int  new_dynarec_save_blocks(void *save, int size) { return 0; }
460 void new_dynarec_load_blocks(const void *save, int size) {}
461 #endif
462
463 #ifdef DRC_DBG
464
465 #include <stddef.h>
466 static FILE *f;
467 extern u32 last_io_addr;
468
469 static void dump_mem(const char *fname, void *mem, size_t size)
470 {
471         FILE *f1 = fopen(fname, "wb");
472         if (f1 == NULL)
473                 f1 = fopen(strrchr(fname, '/') + 1, "wb");
474         fwrite(mem, 1, size, f1);
475         fclose(f1);
476 }
477
478 static u32 memcheck_read(u32 a)
479 {
480         if ((a >> 16) == 0x1f80)
481                 // scratchpad/IO
482                 return *(u32 *)(psxH + (a & 0xfffc));
483
484         if ((a >> 16) == 0x1f00)
485                 // parallel
486                 return *(u32 *)(psxP + (a & 0xfffc));
487
488 //      if ((a & ~0xe0600000) < 0x200000)
489         // RAM
490         return *(u32 *)(psxM + (a & 0x1ffffc));
491 }
492
493 void do_insn_trace(void)
494 {
495         static psxRegisters oldregs;
496         static u32 old_io_addr = (u32)-1;
497         static u32 old_io_data = 0xbad0c0de;
498         static u32 event_cycles_o[PSXINT_COUNT];
499         u32 *allregs_p = (void *)&psxRegs;
500         u32 *allregs_o = (void *)&oldregs;
501         u32 io_data;
502         int i;
503         u8 byte;
504
505         //last_io_addr = 0x5e2c8;
506         if (f == NULL)
507                 f = fopen("tracelog", "wb");
508
509         // log reg changes
510         oldregs.code = psxRegs.code; // don't care
511         for (i = 0; i < offsetof(psxRegisters, intCycle) / 4; i++) {
512                 if (allregs_p[i] != allregs_o[i]) {
513                         fwrite(&i, 1, 1, f);
514                         fwrite(&allregs_p[i], 1, 4, f);
515                         allregs_o[i] = allregs_p[i];
516                 }
517         }
518         // log event changes
519         for (i = 0; i < PSXINT_COUNT; i++) {
520                 if (event_cycles[i] != event_cycles_o[i]) {
521                         byte = 0xfc;
522                         fwrite(&byte, 1, 1, f);
523                         fwrite(&i, 1, 1, f);
524                         fwrite(&event_cycles[i], 1, 4, f);
525                         event_cycles_o[i] = event_cycles[i];
526                 }
527         }
528         // log last io
529         if (old_io_addr != last_io_addr) {
530                 byte = 0xfd;
531                 fwrite(&byte, 1, 1, f);
532                 fwrite(&last_io_addr, 1, 4, f);
533                 old_io_addr = last_io_addr;
534         }
535         io_data = memcheck_read(last_io_addr);
536         if (old_io_data != io_data) {
537                 byte = 0xfe;
538                 fwrite(&byte, 1, 1, f);
539                 fwrite(&io_data, 1, 4, f);
540                 old_io_data = io_data;
541         }
542         byte = 0xff;
543         fwrite(&byte, 1, 1, f);
544
545 #if 0
546         if (psxRegs.cycle == 190230) {
547                 dump_mem("/mnt/ntz/dev/pnd/tmp/psxram_i.dump", psxM, 0x200000);
548                 dump_mem("/mnt/ntz/dev/pnd/tmp/psxregs_i.dump", psxH, 0x10000);
549                 printf("dumped\n");
550                 exit(1);
551         }
552 #endif
553 }
554
555 static const char *regnames[offsetof(psxRegisters, intCycle) / 4] = {
556         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
557         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
558         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
559         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
560         "lo",  "hi",
561         "C0_0",  "C0_1",  "C0_2",  "C0_3",  "C0_4",  "C0_5",  "C0_6",  "C0_7",
562         "C0_8",  "C0_9",  "C0_10", "C0_11", "C0_12", "C0_13", "C0_14", "C0_15",
563         "C0_16", "C0_17", "C0_18", "C0_19", "C0_20", "C0_21", "C0_22", "C0_23",
564         "C0_24", "C0_25", "C0_26", "C0_27", "C0_28", "C0_29", "C0_30", "C0_31",
565
566         "C2D0",  "C2D1",  "C2D2",  "C2D3",  "C2D4",  "C2D5",  "C2D6",  "C2D7",
567         "C2D8",  "C2D9",  "C2D10", "C2D11", "C2D12", "C2D13", "C2D14", "C2D15",
568         "C2D16", "C2D17", "C2D18", "C2D19", "C2D20", "C2D21", "C2D22", "C2D23",
569         "C2D24", "C2D25", "C2D26", "C2D27", "C2D28", "C2D29", "C2D30", "C2D31",
570
571         "C2C0",  "C2C1",  "C2C2",  "C2C3",  "C2C4",  "C2C5",  "C2C6",  "C2C7",
572         "C2C8",  "C2C9",  "C2C10", "C2C11", "C2C12", "C2C13", "C2C14", "C2C15",
573         "C2C16", "C2C17", "C2C18", "C2C19", "C2C20", "C2C21", "C2C22", "C2C23",
574         "C2C24", "C2C25", "C2C26", "C2C27", "C2C28", "C2C29", "C2C30", "C2C31",
575
576         "PC", "code", "cycle", "interrupt",
577 };
578
579 static struct {
580         int reg;
581         u32 val, val_expect;
582         u32 pc, cycle;
583 } miss_log[64];
584 static int miss_log_i;
585 #define miss_log_len (sizeof(miss_log)/sizeof(miss_log[0]))
586 #define miss_log_mask (miss_log_len-1)
587
588 static void miss_log_add(int reg, u32 val, u32 val_expect, u32 pc, u32 cycle)
589 {
590         miss_log[miss_log_i].reg = reg;
591         miss_log[miss_log_i].val = val;
592         miss_log[miss_log_i].val_expect = val_expect;
593         miss_log[miss_log_i].pc = pc;
594         miss_log[miss_log_i].cycle = cycle;
595         miss_log_i = (miss_log_i + 1) & miss_log_mask;
596 }
597
598 void breakme() {}
599
600 void do_insn_cmp(void)
601 {
602         static psxRegisters rregs;
603         static u32 mem_addr, mem_val;
604         u32 *allregs_p = (void *)&psxRegs;
605         u32 *allregs_e = (void *)&rregs;
606         static u32 ppc, failcount;
607         int i, ret, bad = 0, which_event = -1;
608         u32 ev_cycles = 0;
609         u8 code;
610
611         if (f == NULL)
612                 f = fopen("tracelog", "rb");
613
614         while (1) {
615                 if ((ret = fread(&code, 1, 1, f)) <= 0)
616                         break;
617                 if (ret <= 0)
618                         break;
619                 if (code == 0xff)
620                         break;
621                 switch (code) {
622                 case 0xfc:
623                         which_event = 0;
624                         fread(&which_event, 1, 1, f);
625                         fread(&ev_cycles, 1, 4, f);
626                         continue;
627                 case 0xfd:
628                         fread(&mem_addr, 1, 4, f);
629                         continue;
630                 case 0xfe:
631                         fread(&mem_val, 1, 4, f);
632                         continue;
633                 }
634                 fread(&allregs_e[code], 1, 4, f);
635         }
636
637         if (ret <= 0) {
638                 printf("EOF?\n");
639                 goto end;
640         }
641
642         psxRegs.code = rregs.code; // don't care
643         psxRegs.cycle = rregs.cycle;
644         psxRegs.CP0.r[9] = rregs.CP0.r[9]; // Count
645
646         //if (psxRegs.cycle == 166172) breakme();
647
648         if (memcmp(&psxRegs, &rregs, offsetof(psxRegisters, intCycle)) == 0 &&
649                         mem_val == memcheck_read(mem_addr)
650            ) {
651                 failcount = 0;
652                 goto ok;
653         }
654
655         for (i = 0; i < offsetof(psxRegisters, intCycle) / 4; i++) {
656                 if (allregs_p[i] != allregs_e[i]) {
657                         miss_log_add(i, allregs_p[i], allregs_e[i], psxRegs.pc, psxRegs.cycle);
658                         bad++;
659                 }
660         }
661
662         if (mem_val != memcheck_read(mem_addr)) {
663                 printf("bad mem @%08x: %08x %08x\n", mem_addr, memcheck_read(mem_addr), mem_val);
664                 goto end;
665         }
666
667         if (which_event >= 0 && event_cycles[which_event] != ev_cycles) {
668                 printf("bad ev_cycles #%d: %08x %08x\n", which_event, event_cycles[which_event], ev_cycles);
669                 goto end;
670         }
671
672         if (psxRegs.pc == rregs.pc && bad < 6 && failcount < 32) {
673                 static int last_mcycle;
674                 if (last_mcycle != psxRegs.cycle >> 20) {
675                         printf("%u\n", psxRegs.cycle);
676                         last_mcycle = psxRegs.cycle >> 20;
677                 }
678                 failcount++;
679                 goto ok;
680         }
681
682 end:
683         for (i = 0; i < miss_log_len; i++, miss_log_i = (miss_log_i + 1) & miss_log_mask)
684                 printf("bad %5s: %08x %08x, pc=%08x, cycle %u\n",
685                         regnames[miss_log[miss_log_i].reg], miss_log[miss_log_i].val,
686                         miss_log[miss_log_i].val_expect, miss_log[miss_log_i].pc, miss_log[miss_log_i].cycle);
687         printf("-- %d\n", bad);
688         for (i = 0; i < 8; i++)
689                 printf("r%d=%08x r%2d=%08x r%2d=%08x r%2d=%08x\n", i, allregs_p[i],
690                         i+8, allregs_p[i+8], i+16, allregs_p[i+16], i+24, allregs_p[i+24]);
691         printf("PC: %08x/%08x, cycle %u\n", psxRegs.pc, ppc, psxRegs.cycle);
692         dump_mem("/mnt/ntz/dev/pnd/tmp/psxram.dump", psxM, 0x200000);
693         dump_mem("/mnt/ntz/dev/pnd/tmp/psxregs.dump", psxH, 0x10000);
694         exit(1);
695 ok:
696         psxRegs.cycle = rregs.cycle + 2; // sync timing
697         ppc = psxRegs.pc;
698 }
699
700 #endif