Merge pull request #536 from gameblabla/cdrom_fixes
[pcsx_rearmed.git] / libpcsxcore / lightrec / plugin.c
CommitLineData
6f1edc3c
PC
1#include <lightrec.h>
2#include <stdbool.h>
3#include <stdio.h>
4#include <unistd.h>
5#include <signal.h>
6
7#include "../cdrom.h"
8#include "../gpu.h"
9#include "../gte.h"
10#include "../mdec.h"
11#include "../psxdma.h"
12#include "../psxhw.h"
13#include "../psxmem.h"
14#include "../r3000a.h"
15
16#include "../frontend/main.h"
17
18#define ARRAY_SIZE(x) (sizeof(x) ? sizeof(x) / sizeof((x)[0]) : 0)
19
20#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21# define LE32TOH(x) __builtin_bswap32(x)
22# define HTOLE32(x) __builtin_bswap32(x)
23# define LE16TOH(x) __builtin_bswap16(x)
24# define HTOLE16(x) __builtin_bswap16(x)
25#else
26# define LE32TOH(x) (x)
27# define HTOLE32(x) (x)
28# define LE16TOH(x) (x)
29# define HTOLE16(x) (x)
30#endif
31
32#ifdef __GNUC__
33# define likely(x) __builtin_expect(!!(x),1)
34# define unlikely(x) __builtin_expect(!!(x),0)
35#else
36# define likely(x) (x)
37# define unlikely(x) (x)
38#endif
39
40static struct lightrec_state *lightrec_state;
41
42static char *name = "retroarch.exe";
43
44static bool use_lightrec_interpreter;
6b02f240 45static bool use_pcsx_interpreter;
6f1edc3c
PC
46static bool lightrec_debug;
47static bool lightrec_very_debug;
48static u32 lightrec_begin_cycles;
49
50int stop;
51u32 cycle_multiplier;
52int new_dynarec_hacks;
53
54/* Unused for now */
55u32 event_cycles[PSXINT_COUNT];
56u32 next_interupt;
57
58void new_dyna_before_save() {}
59void new_dyna_after_save() {}
60void new_dyna_freeze(void *f, int i) {}
61
62enum my_cp2_opcodes {
63 OP_CP2_RTPS = 0x01,
64 OP_CP2_NCLIP = 0x06,
65 OP_CP2_OP = 0x0c,
66 OP_CP2_DPCS = 0x10,
67 OP_CP2_INTPL = 0x11,
68 OP_CP2_MVMVA = 0x12,
69 OP_CP2_NCDS = 0x13,
70 OP_CP2_CDP = 0x14,
71 OP_CP2_NCDT = 0x16,
72 OP_CP2_NCCS = 0x1b,
73 OP_CP2_CC = 0x1c,
74 OP_CP2_NCS = 0x1e,
75 OP_CP2_NCT = 0x20,
76 OP_CP2_SQR = 0x28,
77 OP_CP2_DCPL = 0x29,
78 OP_CP2_DPCT = 0x2a,
79 OP_CP2_AVSZ3 = 0x2d,
80 OP_CP2_AVSZ4 = 0x2e,
81 OP_CP2_RTPT = 0x30,
82 OP_CP2_GPF = 0x3d,
83 OP_CP2_GPL = 0x3e,
84 OP_CP2_NCCT = 0x3f,
85};
86
87static void (*cp2_ops[])(struct psxCP2Regs *) = {
88 [OP_CP2_RTPS] = gteRTPS,
89 [OP_CP2_RTPS] = gteRTPS,
90 [OP_CP2_NCLIP] = gteNCLIP,
91 [OP_CP2_OP] = gteOP,
92 [OP_CP2_DPCS] = gteDPCS,
93 [OP_CP2_INTPL] = gteINTPL,
94 [OP_CP2_MVMVA] = gteMVMVA,
95 [OP_CP2_NCDS] = gteNCDS,
96 [OP_CP2_CDP] = gteCDP,
97 [OP_CP2_NCDT] = gteNCDT,
98 [OP_CP2_NCCS] = gteNCCS,
99 [OP_CP2_CC] = gteCC,
100 [OP_CP2_NCS] = gteNCS,
101 [OP_CP2_NCT] = gteNCT,
102 [OP_CP2_SQR] = gteSQR,
103 [OP_CP2_DCPL] = gteDCPL,
104 [OP_CP2_DPCT] = gteDPCT,
105 [OP_CP2_AVSZ3] = gteAVSZ3,
106 [OP_CP2_AVSZ4] = gteAVSZ4,
107 [OP_CP2_RTPT] = gteRTPT,
108 [OP_CP2_GPF] = gteGPF,
109 [OP_CP2_GPL] = gteGPL,
110 [OP_CP2_NCCT] = gteNCCT,
111};
112
113static char cache_buf[64 * 1024];
114
6b02f240 115static u32 cop0_mfc(struct lightrec_state *state, u32 op, u8 reg)
6f1edc3c
PC
116{
117 return psxRegs.CP0.r[reg];
118}
119
120static u32 cop2_mfc_cfc(struct lightrec_state *state, u8 reg, bool cfc)
121{
122 if (cfc)
123 return psxRegs.CP2C.r[reg];
124 else
125 return MFC2(reg);
126}
127
6b02f240 128static u32 cop2_mfc(struct lightrec_state *state, u32 op, u8 reg)
6f1edc3c
PC
129{
130 return cop2_mfc_cfc(state, reg, false);
131}
132
6b02f240 133static u32 cop2_cfc(struct lightrec_state *state, u32 op, u8 reg)
6f1edc3c
PC
134{
135 return cop2_mfc_cfc(state, reg, true);
136}
137
138static void cop0_mtc_ctc(struct lightrec_state *state,
139 u8 reg, u32 value, bool ctc)
140{
141 switch (reg) {
142 case 1:
143 case 4:
144 case 8:
145 case 14:
146 case 15:
147 /* Those registers are read-only */
148 break;
149 case 12: /* Status */
150 if ((psxRegs.CP0.n.Status & ~value) & (1 << 16)) {
151 memcpy(psxM, cache_buf, sizeof(cache_buf));
152 lightrec_invalidate_all(state);
153 } else if ((~psxRegs.CP0.n.Status & value) & (1 << 16)) {
154 memcpy(cache_buf, psxM, sizeof(cache_buf));
155 }
156
157 psxRegs.CP0.n.Status = value;
158 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
159 break;
160 case 13: /* Cause */
161 psxRegs.CP0.n.Cause &= ~0x0300;
162 psxRegs.CP0.n.Cause |= value & 0x0300;
163 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
164 break;
165 default:
166 psxRegs.CP0.r[reg] = value;
167 break;
168 }
169}
170
171static void cop2_mtc_ctc(struct lightrec_state *state,
172 u8 reg, u32 value, bool ctc)
173{
174 if (ctc)
175 CTC2(value, reg);
176 else
177 MTC2(value, reg);
178}
179
6b02f240 180static void cop0_mtc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
6f1edc3c
PC
181{
182 cop0_mtc_ctc(state, reg, value, false);
183}
184
6b02f240 185static void cop0_ctc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
6f1edc3c
PC
186{
187 cop0_mtc_ctc(state, reg, value, true);
188}
189
6b02f240 190static void cop2_mtc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
6f1edc3c
PC
191{
192 cop2_mtc_ctc(state, reg, value, false);
193}
194
6b02f240 195static void cop2_ctc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
6f1edc3c
PC
196{
197 cop2_mtc_ctc(state, reg, value, true);
198}
199
200static void cop0_op(struct lightrec_state *state, u32 func)
201{
202 fprintf(stderr, "Invalid access to COP0\n");
203}
204
205static void cop2_op(struct lightrec_state *state, u32 func)
206{
207 psxRegs.code = func;
208
209 if (unlikely(!cp2_ops[func & 0x3f]))
210 fprintf(stderr, "Invalid CP2 function %u\n", func);
211 else
212 cp2_ops[func & 0x3f](&psxRegs.CP2);
213}
214
6b02f240 215static void hw_write_byte(struct lightrec_state *state,
216 u32 op, void *host, u32 mem, u8 val)
6f1edc3c
PC
217{
218 psxRegs.cycle = lightrec_current_cycle_count(state);
219
220 psxHwWrite8(mem, val);
221 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
222
223 lightrec_reset_cycle_count(state, psxRegs.cycle);
224}
225
6b02f240 226static void hw_write_half(struct lightrec_state *state,
227 u32 op, void *host, u32 mem, u16 val)
6f1edc3c
PC
228{
229 psxRegs.cycle = lightrec_current_cycle_count(state);
230
231 psxHwWrite16(mem, val);
232 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
233
234 lightrec_reset_cycle_count(state, psxRegs.cycle);
235}
236
6b02f240 237static void hw_write_word(struct lightrec_state *state,
238 u32 op, void *host, u32 mem, u32 val)
6f1edc3c
PC
239{
240 psxRegs.cycle = lightrec_current_cycle_count(state);
241
242 psxHwWrite32(mem, val);
243 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
244
245 lightrec_reset_cycle_count(state, psxRegs.cycle);
246}
247
6b02f240 248static u8 hw_read_byte(struct lightrec_state *state, u32 op, void *host, u32 mem)
6f1edc3c
PC
249{
250 u8 val;
251
252 psxRegs.cycle = lightrec_current_cycle_count(state);
253
254 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
255 val = psxHwRead8(mem);
256 lightrec_reset_cycle_count(state, psxRegs.cycle);
257
258 return val;
259}
260
6b02f240 261static u16 hw_read_half(struct lightrec_state *state,
262 u32 op, void *host, u32 mem)
6f1edc3c
PC
263{
264 u16 val;
265
266 psxRegs.cycle = lightrec_current_cycle_count(state);
267
268 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
269 val = psxHwRead16(mem);
270 lightrec_reset_cycle_count(state, psxRegs.cycle);
271
272 return val;
273}
274
6b02f240 275static u32 hw_read_word(struct lightrec_state *state,
276 u32 op, void *host, u32 mem)
6f1edc3c
PC
277{
278 u32 val;
279
280 psxRegs.cycle = lightrec_current_cycle_count(state);
281
282 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
283 val = psxHwRead32(mem);
284 lightrec_reset_cycle_count(state, psxRegs.cycle);
285
286 return val;
287}
288
289static struct lightrec_mem_map_ops hw_regs_ops = {
290 .sb = hw_write_byte,
291 .sh = hw_write_half,
292 .sw = hw_write_word,
293 .lb = hw_read_byte,
294 .lh = hw_read_half,
295 .lw = hw_read_word,
296};
297
298static u32 cache_ctrl;
299
6b02f240 300static void cache_ctrl_write_word(struct lightrec_state *state,
301 u32 op, void *host, u32 mem, u32 val)
6f1edc3c
PC
302{
303 cache_ctrl = val;
304}
305
6b02f240 306static u32 cache_ctrl_read_word(struct lightrec_state *state,
307 u32 op, void *host, u32 mem)
6f1edc3c
PC
308{
309 return cache_ctrl;
310}
311
312static struct lightrec_mem_map_ops cache_ctrl_ops = {
313 .sw = cache_ctrl_write_word,
314 .lw = cache_ctrl_read_word,
315};
316
317static struct lightrec_mem_map lightrec_map[] = {
318 [PSX_MAP_KERNEL_USER_RAM] = {
319 /* Kernel and user memory */
320 .pc = 0x00000000,
321 .length = 0x200000,
322 },
323 [PSX_MAP_BIOS] = {
324 /* BIOS */
325 .pc = 0x1fc00000,
326 .length = 0x80000,
327 },
328 [PSX_MAP_SCRATCH_PAD] = {
329 /* Scratch pad */
330 .pc = 0x1f800000,
331 .length = 0x400,
332 },
333 [PSX_MAP_PARALLEL_PORT] = {
334 /* Parallel port */
335 .pc = 0x1f000000,
336 .length = 0x10000,
337 },
338 [PSX_MAP_HW_REGISTERS] = {
339 /* Hardware registers */
340 .pc = 0x1f801000,
341 .length = 0x2000,
342 .ops = &hw_regs_ops,
343 },
344 [PSX_MAP_CACHE_CONTROL] = {
345 /* Cache control */
346 .pc = 0x5ffe0130,
347 .length = 4,
348 .ops = &cache_ctrl_ops,
349 },
350
351 /* Mirrors of the kernel/user memory */
352 [PSX_MAP_MIRROR1] = {
353 .pc = 0x00200000,
354 .length = 0x200000,
355 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
356 },
357 [PSX_MAP_MIRROR2] = {
358 .pc = 0x00400000,
359 .length = 0x200000,
360 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
361 },
362 [PSX_MAP_MIRROR3] = {
363 .pc = 0x00600000,
364 .length = 0x200000,
365 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
366 },
367};
368
369static const struct lightrec_ops lightrec_ops = {
370 .cop0_ops = {
371 .mfc = cop0_mfc,
372 .cfc = cop0_mfc,
373 .mtc = cop0_mtc,
374 .ctc = cop0_ctc,
375 .op = cop0_op,
376 },
377 .cop2_ops = {
378 .mfc = cop2_mfc,
379 .cfc = cop2_cfc,
380 .mtc = cop2_mtc,
381 .ctc = cop2_ctc,
382 .op = cop2_op,
383 },
384};
385
386static int lightrec_plugin_init(void)
387{
388 lightrec_map[PSX_MAP_KERNEL_USER_RAM].address = psxM;
389 lightrec_map[PSX_MAP_BIOS].address = psxR;
390 lightrec_map[PSX_MAP_SCRATCH_PAD].address = psxH;
391 lightrec_map[PSX_MAP_PARALLEL_PORT].address = psxP;
392
393 lightrec_debug = !!getenv("LIGHTREC_DEBUG");
394 lightrec_very_debug = !!getenv("LIGHTREC_VERY_DEBUG");
395 use_lightrec_interpreter = !!getenv("LIGHTREC_INTERPRETER");
396 if (getenv("LIGHTREC_BEGIN_CYCLES"))
397 lightrec_begin_cycles = (unsigned int) strtol(
398 getenv("LIGHTREC_BEGIN_CYCLES"), NULL, 0);
399
400 lightrec_state = lightrec_init(name,
401 lightrec_map, ARRAY_SIZE(lightrec_map),
402 &lightrec_ops);
403
404 fprintf(stderr, "M=0x%lx, P=0x%lx, R=0x%lx, H=0x%lx\n",
405 (uintptr_t) psxM,
406 (uintptr_t) psxP,
407 (uintptr_t) psxR,
408 (uintptr_t) psxH);
409
410#ifndef _WIN32
411 signal(SIGPIPE, exit);
412#endif
413 return 0;
414}
415
416static u32 hash_calculate_le(const void *buffer, u32 count)
417{
418 unsigned int i;
419 u32 *data = (u32 *) buffer;
420 u32 hash = 0xffffffff;
421
422 count /= 4;
423 for(i = 0; i < count; ++i) {
424 hash += LE32TOH(data[i]);
425 hash += (hash << 10);
426 hash ^= (hash >> 6);
427 }
428
429 hash += (hash << 3);
430 hash ^= (hash >> 11);
431 hash += (hash << 15);
432 return hash;
433}
434
435static u32 hash_calculate(const void *buffer, u32 count)
436{
437 unsigned int i;
438 u32 *data = (u32 *) buffer;
439 u32 hash = 0xffffffff;
440
441 count /= 4;
442 for(i = 0; i < count; ++i) {
443 hash += data[i];
444 hash += (hash << 10);
445 hash ^= (hash >> 6);
446 }
447
448 hash += (hash << 3);
449 hash ^= (hash >> 11);
450 hash += (hash << 15);
451 return hash;
452}
453
454static const char * const mips_regs[] = {
455 "zero",
456 "at",
457 "v0", "v1",
458 "a0", "a1", "a2", "a3",
459 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
460 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
461 "t8", "t9",
462 "k0", "k1",
463 "gp", "sp", "fp", "ra",
464 "lo", "hi",
465};
466
467static void print_for_big_ass_debugger(void)
468{
469 unsigned int i;
470
471 printf("CYCLE 0x%08x PC 0x%08x", psxRegs.cycle, psxRegs.pc);
472
473 if (lightrec_very_debug)
474 printf(" RAM 0x%08x SCRATCH 0x%08x HW 0x%08x",
475 hash_calculate_le(psxM, 0x200000),
476 hash_calculate_le(psxH, 0x400),
477 hash_calculate_le(psxH + 0x1000, 0x2000));
478
479 printf(" CP0 0x%08x CP2D 0x%08x CP2C 0x%08x INT 0x%04x INTCYCLE 0x%08x GPU 0x%08x",
480 hash_calculate(&psxRegs.CP0.r,
481 sizeof(psxRegs.CP0.r)),
482 hash_calculate(&psxRegs.CP2D.r,
483 sizeof(psxRegs.CP2D.r)),
484 hash_calculate(&psxRegs.CP2C.r,
485 sizeof(psxRegs.CP2C.r)),
486 psxRegs.interrupt,
487 hash_calculate(psxRegs.intCycle,
488 sizeof(psxRegs.intCycle)),
489 LE32TOH(HW_GPU_STATUS));
490
491 if (lightrec_very_debug)
492 for (i = 0; i < 34; i++)
493 printf(" %s 0x%08x", mips_regs[i], psxRegs.GPR.r[i]);
494 else
495 printf(" GPR 0x%08x", hash_calculate(&psxRegs.GPR.r,
496 sizeof(psxRegs.GPR.r)));
497 printf("\n");
498}
499
6b02f240 500
501extern void intExecuteBlock();
502
6f1edc3c
PC
503static u32 old_cycle_counter;
504
505static void lightrec_plugin_execute_block(void)
506{
507 u32 old_pc = psxRegs.pc;
508 u32 flags;
509
6b02f240 510 if (use_pcsx_interpreter) {
511 intExecuteBlock();
512 } else {
513 lightrec_reset_cycle_count(lightrec_state, psxRegs.cycle);
514 lightrec_restore_registers(lightrec_state, psxRegs.GPR.r);
6f1edc3c 515
6b02f240 516 if (use_lightrec_interpreter)
517 psxRegs.pc = lightrec_run_interpreter(lightrec_state,
518 psxRegs.pc);
519 else
520 psxRegs.pc = lightrec_execute_one(lightrec_state,
521 psxRegs.pc);
6f1edc3c 522
6b02f240 523 psxRegs.cycle = lightrec_current_cycle_count(lightrec_state);
6f1edc3c 524
6b02f240 525 lightrec_dump_registers(lightrec_state, psxRegs.GPR.r);
526 flags = lightrec_exit_flags(lightrec_state);
6f1edc3c 527
6b02f240 528 if (flags & LIGHTREC_EXIT_SEGFAULT) {
529 fprintf(stderr, "Exiting at cycle 0x%08x\n",
530 psxRegs.cycle);
531 exit(1);
532 }
6f1edc3c 533
6b02f240 534 if (flags & LIGHTREC_EXIT_SYSCALL)
535 psxException(0x20, 0);
536 }
6f1edc3c
PC
537
538 psxBranchTest();
539
540 if (lightrec_debug && psxRegs.cycle >= lightrec_begin_cycles
541 && psxRegs.pc != old_pc)
542 print_for_big_ass_debugger();
543
544 if ((psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x300) &&
545 (psxRegs.CP0.n.Status & 0x1)) {
546 /* Handle software interrupts */
547 psxRegs.CP0.n.Cause &= ~0x7c;
548 psxException(psxRegs.CP0.n.Cause, 0);
549 }
550
551 if ((psxRegs.cycle & ~0xfffffff) != old_cycle_counter) {
6205159e 552 SysDLog("RAM usage: Lightrec %u KiB, IR %u KiB, CODE %u KiB, "
6f1edc3c 553 "MIPS %u KiB, TOTAL %u KiB, avg. IPI %f\n",
6b02f240 554 lightrec_get_mem_usage(MEM_FOR_LIGHTREC) / 1024,
6f1edc3c
PC
555 lightrec_get_mem_usage(MEM_FOR_IR) / 1024,
556 lightrec_get_mem_usage(MEM_FOR_CODE) / 1024,
557 lightrec_get_mem_usage(MEM_FOR_MIPS_CODE) / 1024,
558 lightrec_get_total_mem_usage() / 1024,
559 lightrec_get_average_ipi());
560 old_cycle_counter = psxRegs.cycle & ~0xfffffff;
561 }
562}
563
564static void lightrec_plugin_execute(void)
565{
566 extern int stop;
567
568 while (!stop)
569 lightrec_plugin_execute_block();
570}
571
572static void lightrec_plugin_clear(u32 addr, u32 size)
573{
8c9468f1
ZC
574 if (addr == 0 && size == UINT32_MAX)
575 lightrec_invalidate_all(lightrec_state);
576 else
577 /* size * 4: PCSX uses DMA units */
578 lightrec_invalidate(lightrec_state, addr, size * 4);
6f1edc3c
PC
579}
580
581static void lightrec_plugin_shutdown(void)
582{
583 lightrec_destroy(lightrec_state);
584}
585
586static void lightrec_plugin_reset(void)
587{
37e4b2cc 588 lightrec_plugin_shutdown();
589 lightrec_plugin_init();
6f1edc3c
PC
590}
591
592R3000Acpu psxRec =
593{
594 lightrec_plugin_init,
595 lightrec_plugin_reset,
596 lightrec_plugin_execute,
597 lightrec_plugin_execute_block,
598 lightrec_plugin_clear,
599 lightrec_plugin_shutdown,
600};