11 #include "../psxdma.h"
13 #include "../psxmem.h"
14 #include "../r3000a.h"
16 #include "../frontend/main.h"
18 #if (defined(__arm__) || defined(__aarch64__)) && !defined(ALLOW_LIGHTREC_ON_ARM)
19 #error "Lightrec should not be used on ARM (please specify DYNAREC=ari64 to make)"
22 #define ARRAY_SIZE(x) (sizeof(x) ? sizeof(x) / sizeof((x)[0]) : 0)
24 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
25 # define LE32TOH(x) __builtin_bswap32(x)
26 # define HTOLE32(x) __builtin_bswap32(x)
27 # define LE16TOH(x) __builtin_bswap16(x)
28 # define HTOLE16(x) __builtin_bswap16(x)
30 # define LE32TOH(x) (x)
31 # define HTOLE32(x) (x)
32 # define LE16TOH(x) (x)
33 # define HTOLE16(x) (x)
37 # define likely(x) __builtin_expect(!!(x),1)
38 # define unlikely(x) __builtin_expect(!!(x),0)
40 # define likely(x) (x)
41 # define unlikely(x) (x)
47 static struct lightrec_state *lightrec_state;
49 static char *name = "retroarch.exe";
51 static bool use_lightrec_interpreter;
52 static bool use_pcsx_interpreter;
53 static bool lightrec_debug;
54 static bool lightrec_very_debug;
56 static u32 lightrec_begin_cycles;
83 static void (*cp2_ops[])(struct psxCP2Regs *) = {
84 [OP_CP2_RTPS] = gteRTPS,
85 [OP_CP2_RTPS] = gteRTPS,
86 [OP_CP2_NCLIP] = gteNCLIP,
88 [OP_CP2_DPCS] = gteDPCS,
89 [OP_CP2_INTPL] = gteINTPL,
90 [OP_CP2_MVMVA] = gteMVMVA,
91 [OP_CP2_NCDS] = gteNCDS,
92 [OP_CP2_CDP] = gteCDP,
93 [OP_CP2_NCDT] = gteNCDT,
94 [OP_CP2_NCCS] = gteNCCS,
96 [OP_CP2_NCS] = gteNCS,
97 [OP_CP2_NCT] = gteNCT,
98 [OP_CP2_SQR] = gteSQR,
99 [OP_CP2_DCPL] = gteDCPL,
100 [OP_CP2_DPCT] = gteDPCT,
101 [OP_CP2_AVSZ3] = gteAVSZ3,
102 [OP_CP2_AVSZ4] = gteAVSZ4,
103 [OP_CP2_RTPT] = gteRTPT,
104 [OP_CP2_GPF] = gteGPF,
105 [OP_CP2_GPL] = gteGPL,
106 [OP_CP2_NCCT] = gteNCCT,
109 static char cache_buf[64 * 1024];
111 static void cop2_op(struct lightrec_state *state, u32 func)
113 struct lightrec_registers *regs = lightrec_get_registers(state);
117 if (unlikely(!cp2_ops[func & 0x3f])) {
118 fprintf(stderr, "Invalid CP2 function %u\n", func);
120 /* This works because regs->cp2c comes right after regs->cp2d,
121 * so it can be cast to a pcsxCP2Regs pointer. */
122 cp2_ops[func & 0x3f]((psxCP2Regs *) regs->cp2d);
126 static bool has_interrupt(void)
128 return ((psxHu32(0x1070) & psxHu32(0x1074)) &&
129 (psxRegs.CP0.n.Status & 0x401) == 0x401) ||
130 (psxRegs.CP0.n.Status & psxRegs.CP0.n.Cause & 0x0300);
133 static void lightrec_restore_state(struct lightrec_state *state)
135 lightrec_reset_cycle_count(state, psxRegs.cycle);
137 if (booting || has_interrupt())
138 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
140 lightrec_set_target_cycle_count(state, next_interupt);
143 static void hw_write_byte(struct lightrec_state *state,
144 u32 op, void *host, u32 mem, u8 val)
146 psxRegs.cycle = lightrec_current_cycle_count(state);
148 psxHwWrite8(mem, val);
150 lightrec_restore_state(state);
153 static void hw_write_half(struct lightrec_state *state,
154 u32 op, void *host, u32 mem, u16 val)
156 psxRegs.cycle = lightrec_current_cycle_count(state);
158 psxHwWrite16(mem, val);
160 lightrec_restore_state(state);
163 static void hw_write_word(struct lightrec_state *state,
164 u32 op, void *host, u32 mem, u32 val)
166 psxRegs.cycle = lightrec_current_cycle_count(state);
168 psxHwWrite32(mem, val);
170 lightrec_restore_state(state);
173 static u8 hw_read_byte(struct lightrec_state *state, u32 op, void *host, u32 mem)
177 psxRegs.cycle = lightrec_current_cycle_count(state);
179 val = psxHwRead8(mem);
181 lightrec_restore_state(state);
186 static u16 hw_read_half(struct lightrec_state *state,
187 u32 op, void *host, u32 mem)
191 psxRegs.cycle = lightrec_current_cycle_count(state);
193 val = psxHwRead16(mem);
195 lightrec_restore_state(state);
200 static u32 hw_read_word(struct lightrec_state *state,
201 u32 op, void *host, u32 mem)
205 psxRegs.cycle = lightrec_current_cycle_count(state);
207 val = psxHwRead32(mem);
209 lightrec_restore_state(state);
214 static struct lightrec_mem_map_ops hw_regs_ops = {
223 static u32 cache_ctrl;
225 static void cache_ctrl_write_word(struct lightrec_state *state,
226 u32 op, void *host, u32 mem, u32 val)
231 static u32 cache_ctrl_read_word(struct lightrec_state *state,
232 u32 op, void *host, u32 mem)
237 static struct lightrec_mem_map_ops cache_ctrl_ops = {
238 .sw = cache_ctrl_write_word,
239 .lw = cache_ctrl_read_word,
242 static struct lightrec_mem_map lightrec_map[] = {
243 [PSX_MAP_KERNEL_USER_RAM] = {
244 /* Kernel and user memory */
253 [PSX_MAP_SCRATCH_PAD] = {
258 [PSX_MAP_PARALLEL_PORT] = {
263 [PSX_MAP_HW_REGISTERS] = {
264 /* Hardware registers */
269 [PSX_MAP_CACHE_CONTROL] = {
273 .ops = &cache_ctrl_ops,
276 /* Mirrors of the kernel/user memory */
277 [PSX_MAP_MIRROR1] = {
280 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
282 [PSX_MAP_MIRROR2] = {
285 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
287 [PSX_MAP_MIRROR3] = {
290 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
294 static void lightrec_enable_ram(struct lightrec_state *state, bool enable)
297 memcpy(psxM, cache_buf, sizeof(cache_buf));
299 memcpy(cache_buf, psxM, sizeof(cache_buf));
302 static const struct lightrec_ops lightrec_ops = {
304 .enable_ram = lightrec_enable_ram,
307 static int lightrec_plugin_init(void)
309 lightrec_map[PSX_MAP_KERNEL_USER_RAM].address = psxM;
310 lightrec_map[PSX_MAP_BIOS].address = psxR;
311 lightrec_map[PSX_MAP_SCRATCH_PAD].address = psxH;
312 lightrec_map[PSX_MAP_PARALLEL_PORT].address = psxP;
314 if (LIGHTREC_CUSTOM_MAP) {
315 lightrec_map[PSX_MAP_MIRROR1].address = psxM + 0x200000;
316 lightrec_map[PSX_MAP_MIRROR2].address = psxM + 0x400000;
317 lightrec_map[PSX_MAP_MIRROR3].address = psxM + 0x600000;
320 lightrec_debug = !!getenv("LIGHTREC_DEBUG");
321 lightrec_very_debug = !!getenv("LIGHTREC_VERY_DEBUG");
322 use_lightrec_interpreter = !!getenv("LIGHTREC_INTERPRETER");
323 if (getenv("LIGHTREC_BEGIN_CYCLES"))
324 lightrec_begin_cycles = (unsigned int) strtol(
325 getenv("LIGHTREC_BEGIN_CYCLES"), NULL, 0);
327 lightrec_state = lightrec_init(name,
328 lightrec_map, ARRAY_SIZE(lightrec_map),
331 // fprintf(stderr, "M=0x%lx, P=0x%lx, R=0x%lx, H=0x%lx\n",
335 // (uintptr_t) psxH);
338 signal(SIGPIPE, exit);
343 static u32 hash_calculate_le(const void *buffer, u32 count)
346 u32 *data = (u32 *) buffer;
347 u32 hash = 0xffffffff;
350 for(i = 0; i < count; ++i) {
351 hash += LE32TOH(data[i]);
352 hash += (hash << 10);
357 hash ^= (hash >> 11);
358 hash += (hash << 15);
362 static u32 hash_calculate(const void *buffer, u32 count)
365 u32 *data = (u32 *) buffer;
366 u32 hash = 0xffffffff;
369 for(i = 0; i < count; ++i) {
371 hash += (hash << 10);
376 hash ^= (hash >> 11);
377 hash += (hash << 15);
381 static const char * const mips_regs[] = {
385 "a0", "a1", "a2", "a3",
386 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
387 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
390 "gp", "sp", "fp", "ra",
394 static void print_for_big_ass_debugger(void)
398 printf("CYCLE 0x%08x PC 0x%08x", psxRegs.cycle, psxRegs.pc);
400 if (lightrec_very_debug)
401 printf(" RAM 0x%08x SCRATCH 0x%08x HW 0x%08x",
402 hash_calculate_le(psxM, 0x200000),
403 hash_calculate_le(psxH, 0x400),
404 hash_calculate_le(psxH + 0x1000, 0x2000));
406 printf(" CP0 0x%08x CP2D 0x%08x CP2C 0x%08x INT 0x%04x INTCYCLE 0x%08x GPU 0x%08x",
407 hash_calculate(&psxRegs.CP0.r,
408 sizeof(psxRegs.CP0.r)),
409 hash_calculate(&psxRegs.CP2D.r,
410 sizeof(psxRegs.CP2D.r)),
411 hash_calculate(&psxRegs.CP2C.r,
412 sizeof(psxRegs.CP2C.r)),
414 hash_calculate(psxRegs.intCycle,
415 sizeof(psxRegs.intCycle)),
416 LE32TOH(HW_GPU_STATUS));
418 if (lightrec_very_debug)
419 for (i = 0; i < 34; i++)
420 printf(" %s 0x%08x", mips_regs[i], psxRegs.GPR.r[i]);
422 printf(" GPR 0x%08x", hash_calculate(&psxRegs.GPR.r,
423 sizeof(psxRegs.GPR.r)));
427 static void lightrec_dump_regs(struct lightrec_state *state)
429 struct lightrec_registers *regs = lightrec_get_registers(state);
431 if (unlikely(booting))
432 memcpy(&psxRegs.GPR, regs->gpr, sizeof(regs->gpr));
433 psxRegs.CP0.n.Status = regs->cp0[12];
434 psxRegs.CP0.n.Cause = regs->cp0[13];
437 static void lightrec_restore_regs(struct lightrec_state *state)
439 struct lightrec_registers *regs = lightrec_get_registers(state);
441 if (unlikely(booting))
442 memcpy(regs->gpr, &psxRegs.GPR, sizeof(regs->gpr));
443 regs->cp0[12] = psxRegs.CP0.n.Status;
444 regs->cp0[13] = psxRegs.CP0.n.Cause;
445 regs->cp0[14] = psxRegs.CP0.n.EPC;
448 extern void intExecuteBlock();
449 extern void gen_interupt();
451 static void lightrec_plugin_execute_block(void)
453 u32 old_pc = psxRegs.pc;
458 if (use_pcsx_interpreter) {
461 lightrec_reset_cycle_count(lightrec_state, psxRegs.cycle);
462 lightrec_restore_regs(lightrec_state);
464 if (unlikely(use_lightrec_interpreter))
465 psxRegs.pc = lightrec_run_interpreter(lightrec_state,
467 // step during early boot so that 0x80030000 fastboot hack works
468 else if (unlikely(booting || lightrec_debug))
469 psxRegs.pc = lightrec_execute_one(lightrec_state,
472 psxRegs.pc = lightrec_execute(lightrec_state,
473 psxRegs.pc, next_interupt);
475 psxRegs.cycle = lightrec_current_cycle_count(lightrec_state);
477 lightrec_dump_regs(lightrec_state);
478 flags = lightrec_exit_flags(lightrec_state);
480 if (flags & LIGHTREC_EXIT_SEGFAULT) {
481 fprintf(stderr, "Exiting at cycle 0x%08x\n",
486 if (flags & LIGHTREC_EXIT_SYSCALL)
487 psxException(0x20, 0);
489 if (booting && (psxRegs.pc & 0xff800000) == 0x80000000)
493 if (lightrec_debug && psxRegs.cycle >= lightrec_begin_cycles
494 && psxRegs.pc != old_pc)
495 print_for_big_ass_debugger();
497 if ((psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x300) &&
498 (psxRegs.CP0.n.Status & 0x1)) {
499 /* Handle software interrupts */
500 psxRegs.CP0.n.Cause &= ~0x7c;
501 psxException(psxRegs.CP0.n.Cause, 0);
505 static void lightrec_plugin_execute(void)
510 lightrec_plugin_execute_block();
513 static void lightrec_plugin_clear(u32 addr, u32 size)
515 if (addr == 0 && size == UINT32_MAX)
516 lightrec_invalidate_all(lightrec_state);
518 /* size * 4: PCSX uses DMA units */
519 lightrec_invalidate(lightrec_state, addr, size * 4);
522 static void lightrec_plugin_notify(int note, void *data)
525 To change once proper icache emulation is emulated
528 case R3000ACPU_NOTIFY_CACHE_UNISOLATED:
529 lightrec_plugin_clear(0, 0x200000/4);
531 case R3000ACPU_NOTIFY_CACHE_ISOLATED:
532 // Sent from psxDma3().
533 case R3000ACPU_NOTIFY_DMA3_EXE_LOAD:
539 static void lightrec_plugin_apply_config()
543 static void lightrec_plugin_shutdown(void)
545 lightrec_destroy(lightrec_state);
548 static void lightrec_plugin_reset(void)
550 struct lightrec_registers *regs;
552 lightrec_plugin_shutdown();
553 lightrec_plugin_init();
555 regs = lightrec_get_registers(lightrec_state);
557 regs->cp0[12] = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1
558 regs->cp0[15] = 0x00000002; // PRevID = Revision ID, same as R3000A
563 void lightrec_plugin_prepare_load_state(void)
565 struct lightrec_registers *regs;
567 regs = lightrec_get_registers(lightrec_state);
568 memcpy(regs->cp2d, &psxRegs.CP2, sizeof(regs->cp2d) + sizeof(regs->cp2c));
569 memcpy(regs->cp0, &psxRegs.CP0, sizeof(regs->cp0));
570 memcpy(regs->gpr, &psxRegs.GPR, sizeof(regs->gpr));
572 lightrec_invalidate_all(lightrec_state);
575 void lightrec_plugin_prepare_save_state(void)
577 struct lightrec_registers *regs;
579 regs = lightrec_get_registers(lightrec_state);
580 memcpy(&psxRegs.CP2, regs->cp2d, sizeof(regs->cp2d) + sizeof(regs->cp2c));
581 memcpy(&psxRegs.CP0, regs->cp0, sizeof(regs->cp0));
582 memcpy(&psxRegs.GPR, regs->gpr, sizeof(regs->gpr));
587 lightrec_plugin_init,
588 lightrec_plugin_reset,
589 lightrec_plugin_execute,
590 lightrec_plugin_execute_block,
591 lightrec_plugin_clear,
592 lightrec_plugin_notify,
593 lightrec_plugin_apply_config,
594 lightrec_plugin_shutdown,