Merge pull request #578 from gameblabla/counters_lib
[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 #ifdef ICACHE_EMULATION
402 static void ari64_notify(int note, void *data) {
403         /*
404         To change once we have proper icache emulation
405         switch (note)
406         {
407                 case R3000ACPU_NOTIFY_CACHE_UNISOLATED:
408                         ari64_clear(0, 0x200000/4);
409                         break;
410                 case R3000ACPU_NOTIFY_CACHE_ISOLATED:
411                 // Sent from psxDma3().
412                 case R3000ACPU_NOTIFY_DMA3_EXE_LOAD:
413                 default:
414                         break;
415         }*/
416 }
417 #endif
418
419 static void ari64_shutdown()
420 {
421         new_dynarec_cleanup();
422         new_dyna_pcsx_mem_shutdown();
423 }
424
425 extern void intExecute();
426 extern void intExecuteT();
427 extern void intExecuteBlock();
428 extern void intExecuteBlockT();
429 #ifndef DRC_DBG
430 #define intExecuteT intExecute
431 #define intExecuteBlockT intExecuteBlock
432 #endif
433
434 R3000Acpu psxRec = {
435         ari64_init,
436         ari64_reset,
437 #ifndef DRC_DISABLE
438         ari64_execute,
439         ari64_execute_until,
440 #else
441         intExecuteT,
442         intExecuteBlockT,
443 #endif
444         ari64_clear,
445 #ifdef ICACHE_EMULATION
446         ari64_notify,
447 #endif
448         ari64_shutdown
449 };
450
451 // TODO: rm
452 #ifndef DRC_DBG
453 void do_insn_trace() {}
454 void do_insn_cmp() {}
455 #endif
456
457 #ifdef DRC_DISABLE
458 unsigned int address;
459 int pending_exception, stop;
460 u32 next_interupt;
461 int new_dynarec_did_compile;
462 int cycle_multiplier;
463 int new_dynarec_hacks;
464 void *psxH_ptr;
465 void *zeromem_ptr;
466 u8 zero_mem[0x1000];
467 unsigned char *out;
468 void *mem_rtab;
469 void *scratch_buf_ptr;
470 void new_dynarec_init() { (void)ari64_execute; }
471 void new_dyna_start() {}
472 void new_dynarec_cleanup() {}
473 void new_dynarec_clear_full() {}
474 void invalidate_all_pages() {}
475 void invalidate_block(unsigned int block) {}
476 void new_dyna_pcsx_mem_init(void) {}
477 void new_dyna_pcsx_mem_reset(void) {}
478 void new_dyna_pcsx_mem_load_state(void) {}
479 void new_dyna_pcsx_mem_shutdown(void) {}
480 int  new_dynarec_save_blocks(void *save, int size) { return 0; }
481 void new_dynarec_load_blocks(const void *save, int size) {}
482 #endif
483
484 #ifdef DRC_DBG
485
486 #include <stddef.h>
487 static FILE *f;
488 extern u32 last_io_addr;
489
490 static void dump_mem(const char *fname, void *mem, size_t size)
491 {
492         FILE *f1 = fopen(fname, "wb");
493         if (f1 == NULL)
494                 f1 = fopen(strrchr(fname, '/') + 1, "wb");
495         fwrite(mem, 1, size, f1);
496         fclose(f1);
497 }
498
499 static u32 memcheck_read(u32 a)
500 {
501         if ((a >> 16) == 0x1f80)
502                 // scratchpad/IO
503                 return *(u32 *)(psxH + (a & 0xfffc));
504
505         if ((a >> 16) == 0x1f00)
506                 // parallel
507                 return *(u32 *)(psxP + (a & 0xfffc));
508
509 //      if ((a & ~0xe0600000) < 0x200000)
510         // RAM
511         return *(u32 *)(psxM + (a & 0x1ffffc));
512 }
513
514 void do_insn_trace(void)
515 {
516         static psxRegisters oldregs;
517         static u32 old_io_addr = (u32)-1;
518         static u32 old_io_data = 0xbad0c0de;
519         static u32 event_cycles_o[PSXINT_COUNT];
520         u32 *allregs_p = (void *)&psxRegs;
521         u32 *allregs_o = (void *)&oldregs;
522         u32 io_data;
523         int i;
524         u8 byte;
525
526         //last_io_addr = 0x5e2c8;
527         if (f == NULL)
528                 f = fopen("tracelog", "wb");
529
530         // log reg changes
531         oldregs.code = psxRegs.code; // don't care
532         for (i = 0; i < offsetof(psxRegisters, intCycle) / 4; i++) {
533                 if (allregs_p[i] != allregs_o[i]) {
534                         fwrite(&i, 1, 1, f);
535                         fwrite(&allregs_p[i], 1, 4, f);
536                         allregs_o[i] = allregs_p[i];
537                 }
538         }
539         // log event changes
540         for (i = 0; i < PSXINT_COUNT; i++) {
541                 if (event_cycles[i] != event_cycles_o[i]) {
542                         byte = 0xfc;
543                         fwrite(&byte, 1, 1, f);
544                         fwrite(&i, 1, 1, f);
545                         fwrite(&event_cycles[i], 1, 4, f);
546                         event_cycles_o[i] = event_cycles[i];
547                 }
548         }
549         // log last io
550         if (old_io_addr != last_io_addr) {
551                 byte = 0xfd;
552                 fwrite(&byte, 1, 1, f);
553                 fwrite(&last_io_addr, 1, 4, f);
554                 old_io_addr = last_io_addr;
555         }
556         io_data = memcheck_read(last_io_addr);
557         if (old_io_data != io_data) {
558                 byte = 0xfe;
559                 fwrite(&byte, 1, 1, f);
560                 fwrite(&io_data, 1, 4, f);
561                 old_io_data = io_data;
562         }
563         byte = 0xff;
564         fwrite(&byte, 1, 1, f);
565
566 #if 0
567         if (psxRegs.cycle == 190230) {
568                 dump_mem("/mnt/ntz/dev/pnd/tmp/psxram_i.dump", psxM, 0x200000);
569                 dump_mem("/mnt/ntz/dev/pnd/tmp/psxregs_i.dump", psxH, 0x10000);
570                 printf("dumped\n");
571                 exit(1);
572         }
573 #endif
574 }
575
576 static const char *regnames[offsetof(psxRegisters, intCycle) / 4] = {
577         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
578         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
579         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
580         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
581         "lo",  "hi",
582         "C0_0",  "C0_1",  "C0_2",  "C0_3",  "C0_4",  "C0_5",  "C0_6",  "C0_7",
583         "C0_8",  "C0_9",  "C0_10", "C0_11", "C0_12", "C0_13", "C0_14", "C0_15",
584         "C0_16", "C0_17", "C0_18", "C0_19", "C0_20", "C0_21", "C0_22", "C0_23",
585         "C0_24", "C0_25", "C0_26", "C0_27", "C0_28", "C0_29", "C0_30", "C0_31",
586
587         "C2D0",  "C2D1",  "C2D2",  "C2D3",  "C2D4",  "C2D5",  "C2D6",  "C2D7",
588         "C2D8",  "C2D9",  "C2D10", "C2D11", "C2D12", "C2D13", "C2D14", "C2D15",
589         "C2D16", "C2D17", "C2D18", "C2D19", "C2D20", "C2D21", "C2D22", "C2D23",
590         "C2D24", "C2D25", "C2D26", "C2D27", "C2D28", "C2D29", "C2D30", "C2D31",
591
592         "C2C0",  "C2C1",  "C2C2",  "C2C3",  "C2C4",  "C2C5",  "C2C6",  "C2C7",
593         "C2C8",  "C2C9",  "C2C10", "C2C11", "C2C12", "C2C13", "C2C14", "C2C15",
594         "C2C16", "C2C17", "C2C18", "C2C19", "C2C20", "C2C21", "C2C22", "C2C23",
595         "C2C24", "C2C25", "C2C26", "C2C27", "C2C28", "C2C29", "C2C30", "C2C31",
596
597         "PC", "code", "cycle", "interrupt",
598 };
599
600 static struct {
601         int reg;
602         u32 val, val_expect;
603         u32 pc, cycle;
604 } miss_log[64];
605 static int miss_log_i;
606 #define miss_log_len (sizeof(miss_log)/sizeof(miss_log[0]))
607 #define miss_log_mask (miss_log_len-1)
608
609 static void miss_log_add(int reg, u32 val, u32 val_expect, u32 pc, u32 cycle)
610 {
611         miss_log[miss_log_i].reg = reg;
612         miss_log[miss_log_i].val = val;
613         miss_log[miss_log_i].val_expect = val_expect;
614         miss_log[miss_log_i].pc = pc;
615         miss_log[miss_log_i].cycle = cycle;
616         miss_log_i = (miss_log_i + 1) & miss_log_mask;
617 }
618
619 void breakme() {}
620
621 void do_insn_cmp(void)
622 {
623         static psxRegisters rregs;
624         static u32 mem_addr, mem_val;
625         u32 *allregs_p = (void *)&psxRegs;
626         u32 *allregs_e = (void *)&rregs;
627         static u32 ppc, failcount;
628         int i, ret, bad = 0, which_event = -1;
629         u32 ev_cycles = 0;
630         u8 code;
631
632         if (f == NULL)
633                 f = fopen("tracelog", "rb");
634
635         while (1) {
636                 if ((ret = fread(&code, 1, 1, f)) <= 0)
637                         break;
638                 if (ret <= 0)
639                         break;
640                 if (code == 0xff)
641                         break;
642                 switch (code) {
643                 case 0xfc:
644                         which_event = 0;
645                         fread(&which_event, 1, 1, f);
646                         fread(&ev_cycles, 1, 4, f);
647                         continue;
648                 case 0xfd:
649                         fread(&mem_addr, 1, 4, f);
650                         continue;
651                 case 0xfe:
652                         fread(&mem_val, 1, 4, f);
653                         continue;
654                 }
655                 fread(&allregs_e[code], 1, 4, f);
656         }
657
658         if (ret <= 0) {
659                 printf("EOF?\n");
660                 goto end;
661         }
662
663         psxRegs.code = rregs.code; // don't care
664         psxRegs.cycle = rregs.cycle;
665         psxRegs.CP0.r[9] = rregs.CP0.r[9]; // Count
666
667         //if (psxRegs.cycle == 166172) breakme();
668
669         if (memcmp(&psxRegs, &rregs, offsetof(psxRegisters, intCycle)) == 0 &&
670                         mem_val == memcheck_read(mem_addr)
671            ) {
672                 failcount = 0;
673                 goto ok;
674         }
675
676         for (i = 0; i < offsetof(psxRegisters, intCycle) / 4; i++) {
677                 if (allregs_p[i] != allregs_e[i]) {
678                         miss_log_add(i, allregs_p[i], allregs_e[i], psxRegs.pc, psxRegs.cycle);
679                         bad++;
680                 }
681         }
682
683         if (mem_val != memcheck_read(mem_addr)) {
684                 printf("bad mem @%08x: %08x %08x\n", mem_addr, memcheck_read(mem_addr), mem_val);
685                 goto end;
686         }
687
688         if (which_event >= 0 && event_cycles[which_event] != ev_cycles) {
689                 printf("bad ev_cycles #%d: %08x %08x\n", which_event, event_cycles[which_event], ev_cycles);
690                 goto end;
691         }
692
693         if (psxRegs.pc == rregs.pc && bad < 6 && failcount < 32) {
694                 static int last_mcycle;
695                 if (last_mcycle != psxRegs.cycle >> 20) {
696                         printf("%u\n", psxRegs.cycle);
697                         last_mcycle = psxRegs.cycle >> 20;
698                 }
699                 failcount++;
700                 goto ok;
701         }
702
703 end:
704         for (i = 0; i < miss_log_len; i++, miss_log_i = (miss_log_i + 1) & miss_log_mask)
705                 printf("bad %5s: %08x %08x, pc=%08x, cycle %u\n",
706                         regnames[miss_log[miss_log_i].reg], miss_log[miss_log_i].val,
707                         miss_log[miss_log_i].val_expect, miss_log[miss_log_i].pc, miss_log[miss_log_i].cycle);
708         printf("-- %d\n", bad);
709         for (i = 0; i < 8; i++)
710                 printf("r%d=%08x r%2d=%08x r%2d=%08x r%2d=%08x\n", i, allregs_p[i],
711                         i+8, allregs_p[i+8], i+16, allregs_p[i+16], i+24, allregs_p[i+24]);
712         printf("PC: %08x/%08x, cycle %u\n", psxRegs.pc, ppc, psxRegs.cycle);
713         dump_mem("/mnt/ntz/dev/pnd/tmp/psxram.dump", psxM, 0x200000);
714         dump_mem("/mnt/ntz/dev/pnd/tmp/psxregs.dump", psxH, 0x10000);
715         exit(1);
716 ok:
717         psxRegs.cycle = rregs.cycle + 2; // sync timing
718         ppc = psxRegs.pc;
719 }
720
721 #endif