11 #include "../psxdma.h"
13 #include "../psxmem.h"
14 #include "../r3000a.h"
16 #include "../frontend/main.h"
20 #if (defined(__arm__) || defined(__aarch64__)) && !defined(ALLOW_LIGHTREC_ON_ARM)
21 #error "Lightrec should not be used on ARM (please specify DYNAREC=ari64 to make)"
24 #define ARRAY_SIZE(x) (sizeof(x) ? sizeof(x) / sizeof((x)[0]) : 0)
26 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
27 # define LE32TOH(x) __builtin_bswap32(x)
28 # define HTOLE32(x) __builtin_bswap32(x)
29 # define LE16TOH(x) __builtin_bswap16(x)
30 # define HTOLE16(x) __builtin_bswap16(x)
32 # define LE32TOH(x) (x)
33 # define HTOLE32(x) (x)
34 # define LE16TOH(x) (x)
35 # define HTOLE16(x) (x)
39 # define likely(x) __builtin_expect(!!(x),1)
40 # define unlikely(x) __builtin_expect(!!(x),0)
42 # define likely(x) (x)
43 # define unlikely(x) (x)
49 static struct lightrec_state *lightrec_state;
51 static char *name = "retroarch.exe";
53 static bool use_lightrec_interpreter;
54 static bool use_pcsx_interpreter;
55 static bool lightrec_debug;
56 static bool lightrec_very_debug;
58 static u32 lightrec_begin_cycles;
85 static void (*cp2_ops[])(struct psxCP2Regs *) = {
86 [OP_CP2_RTPS] = gteRTPS,
87 [OP_CP2_RTPS] = gteRTPS,
88 [OP_CP2_NCLIP] = gteNCLIP,
90 [OP_CP2_DPCS] = gteDPCS,
91 [OP_CP2_INTPL] = gteINTPL,
92 [OP_CP2_MVMVA] = gteMVMVA,
93 [OP_CP2_NCDS] = gteNCDS,
94 [OP_CP2_CDP] = gteCDP,
95 [OP_CP2_NCDT] = gteNCDT,
96 [OP_CP2_NCCS] = gteNCCS,
98 [OP_CP2_NCS] = gteNCS,
99 [OP_CP2_NCT] = gteNCT,
100 [OP_CP2_SQR] = gteSQR,
101 [OP_CP2_DCPL] = gteDCPL,
102 [OP_CP2_DPCT] = gteDPCT,
103 [OP_CP2_AVSZ3] = gteAVSZ3,
104 [OP_CP2_AVSZ4] = gteAVSZ4,
105 [OP_CP2_RTPT] = gteRTPT,
106 [OP_CP2_GPF] = gteGPF,
107 [OP_CP2_GPL] = gteGPL,
108 [OP_CP2_NCCT] = gteNCCT,
111 static char cache_buf[64 * 1024];
113 static void cop2_op(struct lightrec_state *state, u32 func)
115 struct lightrec_registers *regs = lightrec_get_registers(state);
119 if (unlikely(!cp2_ops[func & 0x3f])) {
120 fprintf(stderr, "Invalid CP2 function %u\n", func);
122 /* This works because regs->cp2c comes right after regs->cp2d,
123 * so it can be cast to a pcsxCP2Regs pointer. */
124 cp2_ops[func & 0x3f]((psxCP2Regs *) regs->cp2d);
128 static bool has_interrupt(void)
130 return ((psxHu32(0x1070) & psxHu32(0x1074)) &&
131 (psxRegs.CP0.n.Status & 0x401) == 0x401) ||
132 (psxRegs.CP0.n.Status & psxRegs.CP0.n.Cause & 0x0300);
135 static void lightrec_restore_state(struct lightrec_state *state)
137 lightrec_reset_cycle_count(state, psxRegs.cycle);
139 if (booting || has_interrupt())
140 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
142 lightrec_set_target_cycle_count(state, next_interupt);
145 static void hw_write_byte(struct lightrec_state *state,
146 u32 op, void *host, u32 mem, u8 val)
148 psxRegs.cycle = lightrec_current_cycle_count(state);
150 psxHwWrite8(mem, val);
152 lightrec_restore_state(state);
155 static void hw_write_half(struct lightrec_state *state,
156 u32 op, void *host, u32 mem, u16 val)
158 psxRegs.cycle = lightrec_current_cycle_count(state);
160 psxHwWrite16(mem, val);
162 lightrec_restore_state(state);
165 static void hw_write_word(struct lightrec_state *state,
166 u32 op, void *host, u32 mem, u32 val)
168 psxRegs.cycle = lightrec_current_cycle_count(state);
170 psxHwWrite32(mem, val);
172 lightrec_restore_state(state);
175 static u8 hw_read_byte(struct lightrec_state *state, u32 op, void *host, u32 mem)
179 psxRegs.cycle = lightrec_current_cycle_count(state);
181 val = psxHwRead8(mem);
183 lightrec_restore_state(state);
188 static u16 hw_read_half(struct lightrec_state *state,
189 u32 op, void *host, u32 mem)
193 psxRegs.cycle = lightrec_current_cycle_count(state);
195 val = psxHwRead16(mem);
197 lightrec_restore_state(state);
202 static u32 hw_read_word(struct lightrec_state *state,
203 u32 op, void *host, u32 mem)
207 psxRegs.cycle = lightrec_current_cycle_count(state);
209 val = psxHwRead32(mem);
211 lightrec_restore_state(state);
216 static struct lightrec_mem_map_ops hw_regs_ops = {
225 static u32 cache_ctrl;
227 static void cache_ctrl_write_word(struct lightrec_state *state,
228 u32 op, void *host, u32 mem, u32 val)
233 static u32 cache_ctrl_read_word(struct lightrec_state *state,
234 u32 op, void *host, u32 mem)
239 static struct lightrec_mem_map_ops cache_ctrl_ops = {
240 .sw = cache_ctrl_write_word,
241 .lw = cache_ctrl_read_word,
244 static struct lightrec_mem_map lightrec_map[] = {
245 [PSX_MAP_KERNEL_USER_RAM] = {
246 /* Kernel and user memory */
255 [PSX_MAP_SCRATCH_PAD] = {
260 [PSX_MAP_PARALLEL_PORT] = {
265 [PSX_MAP_HW_REGISTERS] = {
266 /* Hardware registers */
271 [PSX_MAP_CACHE_CONTROL] = {
275 .ops = &cache_ctrl_ops,
278 /* Mirrors of the kernel/user memory */
279 [PSX_MAP_MIRROR1] = {
282 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
284 [PSX_MAP_MIRROR2] = {
287 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
289 [PSX_MAP_MIRROR3] = {
292 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
294 [PSX_MAP_CODE_BUFFER] = {
295 .length = CODE_BUFFER_SIZE,
299 static void lightrec_enable_ram(struct lightrec_state *state, bool enable)
302 memcpy(psxM, cache_buf, sizeof(cache_buf));
304 memcpy(cache_buf, psxM, sizeof(cache_buf));
307 static const struct lightrec_ops lightrec_ops = {
309 .enable_ram = lightrec_enable_ram,
312 static int lightrec_plugin_init(void)
314 lightrec_map[PSX_MAP_KERNEL_USER_RAM].address = psxM;
315 lightrec_map[PSX_MAP_BIOS].address = psxR;
316 lightrec_map[PSX_MAP_SCRATCH_PAD].address = psxH;
317 lightrec_map[PSX_MAP_PARALLEL_PORT].address = psxP;
319 if (LIGHTREC_CUSTOM_MAP) {
320 lightrec_map[PSX_MAP_MIRROR1].address = psxM + 0x200000;
321 lightrec_map[PSX_MAP_MIRROR2].address = psxM + 0x400000;
322 lightrec_map[PSX_MAP_MIRROR3].address = psxM + 0x600000;
323 lightrec_map[PSX_MAP_CODE_BUFFER].address = code_buffer;
326 lightrec_debug = !!getenv("LIGHTREC_DEBUG");
327 lightrec_very_debug = !!getenv("LIGHTREC_VERY_DEBUG");
328 use_lightrec_interpreter = !!getenv("LIGHTREC_INTERPRETER");
329 if (getenv("LIGHTREC_BEGIN_CYCLES"))
330 lightrec_begin_cycles = (unsigned int) strtol(
331 getenv("LIGHTREC_BEGIN_CYCLES"), NULL, 0);
333 lightrec_state = lightrec_init(name,
334 lightrec_map, ARRAY_SIZE(lightrec_map),
337 // fprintf(stderr, "M=0x%lx, P=0x%lx, R=0x%lx, H=0x%lx\n",
341 // (uintptr_t) psxH);
344 signal(SIGPIPE, exit);
349 static u32 hash_calculate_le(const void *buffer, u32 count)
352 u32 *data = (u32 *) buffer;
353 u32 hash = 0xffffffff;
356 for(i = 0; i < count; ++i) {
357 hash += LE32TOH(data[i]);
358 hash += (hash << 10);
363 hash ^= (hash >> 11);
364 hash += (hash << 15);
368 static u32 hash_calculate(const void *buffer, u32 count)
371 u32 *data = (u32 *) buffer;
372 u32 hash = 0xffffffff;
375 for(i = 0; i < count; ++i) {
377 hash += (hash << 10);
382 hash ^= (hash >> 11);
383 hash += (hash << 15);
387 static const char * const mips_regs[] = {
391 "a0", "a1", "a2", "a3",
392 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
393 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
396 "gp", "sp", "fp", "ra",
400 static void print_for_big_ass_debugger(void)
404 printf("CYCLE 0x%08x PC 0x%08x", psxRegs.cycle, psxRegs.pc);
406 if (lightrec_very_debug)
407 printf(" RAM 0x%08x SCRATCH 0x%08x HW 0x%08x",
408 hash_calculate_le(psxM, 0x200000),
409 hash_calculate_le(psxH, 0x400),
410 hash_calculate_le(psxH + 0x1000, 0x2000));
412 printf(" CP0 0x%08x CP2D 0x%08x CP2C 0x%08x INT 0x%04x INTCYCLE 0x%08x GPU 0x%08x",
413 hash_calculate(&psxRegs.CP0.r,
414 sizeof(psxRegs.CP0.r)),
415 hash_calculate(&psxRegs.CP2D.r,
416 sizeof(psxRegs.CP2D.r)),
417 hash_calculate(&psxRegs.CP2C.r,
418 sizeof(psxRegs.CP2C.r)),
420 hash_calculate(psxRegs.intCycle,
421 sizeof(psxRegs.intCycle)),
422 LE32TOH(HW_GPU_STATUS));
424 if (lightrec_very_debug)
425 for (i = 0; i < 34; i++)
426 printf(" %s 0x%08x", mips_regs[i], psxRegs.GPR.r[i]);
428 printf(" GPR 0x%08x", hash_calculate(&psxRegs.GPR.r,
429 sizeof(psxRegs.GPR.r)));
433 static void lightrec_dump_regs(struct lightrec_state *state)
435 struct lightrec_registers *regs = lightrec_get_registers(state);
437 if (unlikely(booting))
438 memcpy(&psxRegs.GPR, regs->gpr, sizeof(regs->gpr));
439 psxRegs.CP0.n.Status = regs->cp0[12];
440 psxRegs.CP0.n.Cause = regs->cp0[13];
443 static void lightrec_restore_regs(struct lightrec_state *state)
445 struct lightrec_registers *regs = lightrec_get_registers(state);
447 if (unlikely(booting))
448 memcpy(regs->gpr, &psxRegs.GPR, sizeof(regs->gpr));
449 regs->cp0[12] = psxRegs.CP0.n.Status;
450 regs->cp0[13] = psxRegs.CP0.n.Cause;
451 regs->cp0[14] = psxRegs.CP0.n.EPC;
454 extern void intExecuteBlock();
455 extern void gen_interupt();
457 static void lightrec_plugin_execute_block(void)
459 u32 old_pc = psxRegs.pc;
464 if (use_pcsx_interpreter) {
467 lightrec_reset_cycle_count(lightrec_state, psxRegs.cycle);
468 lightrec_restore_regs(lightrec_state);
470 if (unlikely(use_lightrec_interpreter))
471 psxRegs.pc = lightrec_run_interpreter(lightrec_state,
473 // step during early boot so that 0x80030000 fastboot hack works
474 else if (unlikely(booting || lightrec_debug))
475 psxRegs.pc = lightrec_execute_one(lightrec_state,
478 psxRegs.pc = lightrec_execute(lightrec_state,
479 psxRegs.pc, next_interupt);
481 psxRegs.cycle = lightrec_current_cycle_count(lightrec_state);
483 lightrec_dump_regs(lightrec_state);
484 flags = lightrec_exit_flags(lightrec_state);
486 if (flags & LIGHTREC_EXIT_SEGFAULT) {
487 fprintf(stderr, "Exiting at cycle 0x%08x\n",
492 if (flags & LIGHTREC_EXIT_SYSCALL)
493 psxException(0x20, 0);
495 if (booting && (psxRegs.pc & 0xff800000) == 0x80000000)
499 if (lightrec_debug && psxRegs.cycle >= lightrec_begin_cycles
500 && psxRegs.pc != old_pc)
501 print_for_big_ass_debugger();
503 if ((psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x300) &&
504 (psxRegs.CP0.n.Status & 0x1)) {
505 /* Handle software interrupts */
506 psxRegs.CP0.n.Cause &= ~0x7c;
507 psxException(psxRegs.CP0.n.Cause, 0);
511 static void lightrec_plugin_execute(void)
516 lightrec_plugin_execute_block();
519 static void lightrec_plugin_clear(u32 addr, u32 size)
521 if (addr == 0 && size == UINT32_MAX)
522 lightrec_invalidate_all(lightrec_state);
524 /* size * 4: PCSX uses DMA units */
525 lightrec_invalidate(lightrec_state, addr, size * 4);
528 static void lightrec_plugin_notify(int note, void *data)
531 To change once proper icache emulation is emulated
534 case R3000ACPU_NOTIFY_CACHE_UNISOLATED:
535 lightrec_plugin_clear(0, 0x200000/4);
537 case R3000ACPU_NOTIFY_CACHE_ISOLATED:
538 // Sent from psxDma3().
539 case R3000ACPU_NOTIFY_DMA3_EXE_LOAD:
545 static void lightrec_plugin_apply_config()
549 static void lightrec_plugin_shutdown(void)
551 lightrec_destroy(lightrec_state);
554 static void lightrec_plugin_reset(void)
556 struct lightrec_registers *regs;
558 lightrec_plugin_shutdown();
559 lightrec_plugin_init();
561 regs = lightrec_get_registers(lightrec_state);
563 regs->cp0[12] = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1
564 regs->cp0[15] = 0x00000002; // PRevID = Revision ID, same as R3000A
569 void lightrec_plugin_prepare_load_state(void)
571 struct lightrec_registers *regs;
573 regs = lightrec_get_registers(lightrec_state);
574 memcpy(regs->cp2d, &psxRegs.CP2, sizeof(regs->cp2d) + sizeof(regs->cp2c));
575 memcpy(regs->cp0, &psxRegs.CP0, sizeof(regs->cp0));
576 memcpy(regs->gpr, &psxRegs.GPR, sizeof(regs->gpr));
578 lightrec_invalidate_all(lightrec_state);
581 void lightrec_plugin_prepare_save_state(void)
583 struct lightrec_registers *regs;
585 regs = lightrec_get_registers(lightrec_state);
586 memcpy(&psxRegs.CP2, regs->cp2d, sizeof(regs->cp2d) + sizeof(regs->cp2c));
587 memcpy(&psxRegs.CP0, regs->cp0, sizeof(regs->cp0));
588 memcpy(&psxRegs.GPR, regs->gpr, sizeof(regs->gpr));
593 lightrec_plugin_init,
594 lightrec_plugin_reset,
595 lightrec_plugin_execute,
596 lightrec_plugin_execute_block,
597 lightrec_plugin_clear,
598 lightrec_plugin_notify,
599 lightrec_plugin_apply_config,
600 lightrec_plugin_shutdown,