X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libpcsxcore%2Flightrec%2Fplugin.c;h=8f12b9797d70baec9957cb9b551d7cd320b49bb8;hb=6ce0b00a79f4fa7c4a1735be9f48bfbc644b080c;hp=64587be62cbf49a80c3c86e102141f7c4122d2b5;hpb=37e4b2cc27ccb08c1063c3db575d92191d141133;p=pcsx_rearmed.git diff --git a/libpcsxcore/lightrec/plugin.c b/libpcsxcore/lightrec/plugin.c index 64587be6..8f12b979 100644 --- a/libpcsxcore/lightrec/plugin.c +++ b/libpcsxcore/lightrec/plugin.c @@ -15,6 +15,13 @@ #include "../frontend/main.h" +#include "mem.h" +#include "plugin.h" + +#if (defined(__arm__) || defined(__aarch64__)) && !defined(ALLOW_LIGHTREC_ON_ARM) +#error "Lightrec should not be used on ARM (please specify DYNAREC=ari64 to make)" +#endif + #define ARRAY_SIZE(x) (sizeof(x) ? sizeof(x) / sizeof((x)[0]) : 0) #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ @@ -37,27 +44,18 @@ # define unlikely(x) (x) #endif +psxRegisters psxRegs; +Rcnt rcnts[4]; + static struct lightrec_state *lightrec_state; static char *name = "retroarch.exe"; static bool use_lightrec_interpreter; -static bool lightrec_debug; -static bool lightrec_very_debug; +static bool use_pcsx_interpreter; +static bool booting; static u32 lightrec_begin_cycles; -int stop; -u32 cycle_multiplier; -int new_dynarec_hacks; - -/* Unused for now */ -u32 event_cycles[PSXINT_COUNT]; -u32 next_interupt; - -void new_dyna_before_save() {} -void new_dyna_after_save() {} -void new_dyna_freeze(void *f, int i) {} - enum my_cp2_opcodes { OP_CP2_RTPS = 0x01, OP_CP2_NCLIP = 0x06, @@ -111,171 +109,107 @@ static void (*cp2_ops[])(struct psxCP2Regs *) = { static char cache_buf[64 * 1024]; -static u32 cop0_mfc(struct lightrec_state *state, u8 reg) -{ - return psxRegs.CP0.r[reg]; -} - -static u32 cop2_mfc_cfc(struct lightrec_state *state, u8 reg, bool cfc) -{ - if (cfc) - return psxRegs.CP2C.r[reg]; - else - return MFC2(reg); -} - -static u32 cop2_mfc(struct lightrec_state *state, u8 reg) +static void cop2_op(struct lightrec_state *state, u32 func) { - return cop2_mfc_cfc(state, reg, false); -} + struct lightrec_registers *regs = lightrec_get_registers(state); -static u32 cop2_cfc(struct lightrec_state *state, u8 reg) -{ - return cop2_mfc_cfc(state, reg, true); -} - -static void cop0_mtc_ctc(struct lightrec_state *state, - u8 reg, u32 value, bool ctc) -{ - switch (reg) { - case 1: - case 4: - case 8: - case 14: - case 15: - /* Those registers are read-only */ - break; - case 12: /* Status */ - if ((psxRegs.CP0.n.Status & ~value) & (1 << 16)) { - memcpy(psxM, cache_buf, sizeof(cache_buf)); - lightrec_invalidate_all(state); - } else if ((~psxRegs.CP0.n.Status & value) & (1 << 16)) { - memcpy(cache_buf, psxM, sizeof(cache_buf)); - } + psxRegs.code = func; - psxRegs.CP0.n.Status = value; - lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT); - break; - case 13: /* Cause */ - psxRegs.CP0.n.Cause &= ~0x0300; - psxRegs.CP0.n.Cause |= value & 0x0300; - lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT); - break; - default: - psxRegs.CP0.r[reg] = value; - break; + if (unlikely(!cp2_ops[func & 0x3f])) { + fprintf(stderr, "Invalid CP2 function %u\n", func); + } else { + /* This works because regs->cp2c comes right after regs->cp2d, + * so it can be cast to a pcsxCP2Regs pointer. */ + cp2_ops[func & 0x3f]((psxCP2Regs *) regs->cp2d); } } -static void cop2_mtc_ctc(struct lightrec_state *state, - u8 reg, u32 value, bool ctc) -{ - if (ctc) - CTC2(value, reg); - else - MTC2(value, reg); -} - -static void cop0_mtc(struct lightrec_state *state, u8 reg, u32 value) -{ - cop0_mtc_ctc(state, reg, value, false); -} - -static void cop0_ctc(struct lightrec_state *state, u8 reg, u32 value) -{ - cop0_mtc_ctc(state, reg, value, true); -} - -static void cop2_mtc(struct lightrec_state *state, u8 reg, u32 value) +static bool has_interrupt(void) { - cop2_mtc_ctc(state, reg, value, false); -} + struct lightrec_registers *regs = lightrec_get_registers(lightrec_state); -static void cop2_ctc(struct lightrec_state *state, u8 reg, u32 value) -{ - cop2_mtc_ctc(state, reg, value, true); -} - -static void cop0_op(struct lightrec_state *state, u32 func) -{ - fprintf(stderr, "Invalid access to COP0\n"); + return ((psxHu32(0x1070) & psxHu32(0x1074)) && + (regs->cp0[12] & 0x401) == 0x401) || + (regs->cp0[12] & regs->cp0[13] & 0x0300); } -static void cop2_op(struct lightrec_state *state, u32 func) +static void lightrec_restore_state(struct lightrec_state *state) { - psxRegs.code = func; + lightrec_reset_cycle_count(state, psxRegs.cycle); - if (unlikely(!cp2_ops[func & 0x3f])) - fprintf(stderr, "Invalid CP2 function %u\n", func); + if (booting || has_interrupt()) + lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT); else - cp2_ops[func & 0x3f](&psxRegs.CP2); + lightrec_set_target_cycle_count(state, next_interupt); } -static void hw_write_byte(struct lightrec_state *state, u32 mem, u8 val) +static void hw_write_byte(struct lightrec_state *state, + u32 op, void *host, u32 mem, u8 val) { psxRegs.cycle = lightrec_current_cycle_count(state); psxHwWrite8(mem, val); - lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT); - lightrec_reset_cycle_count(state, psxRegs.cycle); + lightrec_restore_state(state); } -static void hw_write_half(struct lightrec_state *state, u32 mem, u16 val) +static void hw_write_half(struct lightrec_state *state, + u32 op, void *host, u32 mem, u16 val) { psxRegs.cycle = lightrec_current_cycle_count(state); psxHwWrite16(mem, val); - lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT); - lightrec_reset_cycle_count(state, psxRegs.cycle); + lightrec_restore_state(state); } -static void hw_write_word(struct lightrec_state *state, u32 mem, u32 val) +static void hw_write_word(struct lightrec_state *state, + u32 op, void *host, u32 mem, u32 val) { psxRegs.cycle = lightrec_current_cycle_count(state); psxHwWrite32(mem, val); - lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT); - lightrec_reset_cycle_count(state, psxRegs.cycle); + lightrec_restore_state(state); } -static u8 hw_read_byte(struct lightrec_state *state, u32 mem) +static u8 hw_read_byte(struct lightrec_state *state, u32 op, void *host, u32 mem) { u8 val; psxRegs.cycle = lightrec_current_cycle_count(state); - lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT); val = psxHwRead8(mem); - lightrec_reset_cycle_count(state, psxRegs.cycle); + + lightrec_restore_state(state); return val; } -static u16 hw_read_half(struct lightrec_state *state, u32 mem) +static u16 hw_read_half(struct lightrec_state *state, + u32 op, void *host, u32 mem) { u16 val; psxRegs.cycle = lightrec_current_cycle_count(state); - lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT); val = psxHwRead16(mem); - lightrec_reset_cycle_count(state, psxRegs.cycle); + + lightrec_restore_state(state); return val; } -static u32 hw_read_word(struct lightrec_state *state, u32 mem) +static u32 hw_read_word(struct lightrec_state *state, + u32 op, void *host, u32 mem) { u32 val; psxRegs.cycle = lightrec_current_cycle_count(state); - lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT); val = psxHwRead32(mem); - lightrec_reset_cycle_count(state, psxRegs.cycle); + + lightrec_restore_state(state); return val; } @@ -291,12 +225,14 @@ static struct lightrec_mem_map_ops hw_regs_ops = { static u32 cache_ctrl; -static void cache_ctrl_write_word(struct lightrec_state *state, u32 mem, u32 val) +static void cache_ctrl_write_word(struct lightrec_state *state, + u32 op, void *host, u32 mem, u32 val) { cache_ctrl = val; } -static u32 cache_ctrl_read_word(struct lightrec_state *state, u32 mem) +static u32 cache_ctrl_read_word(struct lightrec_state *state, + u32 op, void *host, u32 mem) { return cache_ctrl; } @@ -356,23 +292,99 @@ static struct lightrec_mem_map lightrec_map[] = { .length = 0x200000, .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM], }, + [PSX_MAP_CODE_BUFFER] = { + .length = CODE_BUFFER_SIZE, + }, }; +static void lightrec_enable_ram(struct lightrec_state *state, bool enable) +{ + if (enable) + memcpy(psxM, cache_buf, sizeof(cache_buf)); + else + memcpy(cache_buf, psxM, sizeof(cache_buf)); +} + +static bool lightrec_can_hw_direct(u32 kaddr, bool is_write, u8 size) +{ + switch (size) { + case 8: + switch (kaddr) { + case 0x1f801040: + case 0x1f801050: + case 0x1f801800: + case 0x1f801801: + case 0x1f801802: + case 0x1f801803: + return false; + default: + return true; + } + case 16: + switch (kaddr) { + case 0x1f801040: + case 0x1f801044: + case 0x1f801048: + case 0x1f80104a: + case 0x1f80104e: + case 0x1f801050: + case 0x1f801054: + case 0x1f80105a: + case 0x1f80105e: + case 0x1f801100: + case 0x1f801104: + case 0x1f801108: + case 0x1f801110: + case 0x1f801114: + case 0x1f801118: + case 0x1f801120: + case 0x1f801124: + case 0x1f801128: + return false; + case 0x1f801070: + case 0x1f801074: + return !is_write; + default: + return is_write || kaddr < 0x1f801c00 || kaddr >= 0x1f801e00; + } + default: + switch (kaddr) { + case 0x1f801040: + case 0x1f801050: + case 0x1f801100: + case 0x1f801104: + case 0x1f801108: + case 0x1f801110: + case 0x1f801114: + case 0x1f801118: + case 0x1f801120: + case 0x1f801124: + case 0x1f801128: + case 0x1f801810: + case 0x1f801814: + case 0x1f801820: + case 0x1f801824: + return false; + case 0x1f801070: + case 0x1f801074: + case 0x1f801088: + case 0x1f801098: + case 0x1f8010a8: + case 0x1f8010b8: + case 0x1f8010c8: + case 0x1f8010e8: + case 0x1f8010f4: + return !is_write; + default: + return !is_write || kaddr < 0x1f801c00 || kaddr >= 0x1f801e00; + } + } +} + static const struct lightrec_ops lightrec_ops = { - .cop0_ops = { - .mfc = cop0_mfc, - .cfc = cop0_mfc, - .mtc = cop0_mtc, - .ctc = cop0_ctc, - .op = cop0_op, - }, - .cop2_ops = { - .mfc = cop2_mfc, - .cfc = cop2_cfc, - .mtc = cop2_mtc, - .ctc = cop2_ctc, - .op = cop2_op, - }, + .cop2_op = cop2_op, + .enable_ram = lightrec_enable_ram, + .hw_direct = lightrec_can_hw_direct, }; static int lightrec_plugin_init(void) @@ -380,10 +392,16 @@ static int lightrec_plugin_init(void) lightrec_map[PSX_MAP_KERNEL_USER_RAM].address = psxM; lightrec_map[PSX_MAP_BIOS].address = psxR; lightrec_map[PSX_MAP_SCRATCH_PAD].address = psxH; + lightrec_map[PSX_MAP_HW_REGISTERS].address = psxH + 0x1000; lightrec_map[PSX_MAP_PARALLEL_PORT].address = psxP; - lightrec_debug = !!getenv("LIGHTREC_DEBUG"); - lightrec_very_debug = !!getenv("LIGHTREC_VERY_DEBUG"); + if (LIGHTREC_CUSTOM_MAP) { + lightrec_map[PSX_MAP_MIRROR1].address = psxM + 0x200000; + lightrec_map[PSX_MAP_MIRROR2].address = psxM + 0x400000; + lightrec_map[PSX_MAP_MIRROR3].address = psxM + 0x600000; + lightrec_map[PSX_MAP_CODE_BUFFER].address = code_buffer; + } + use_lightrec_interpreter = !!getenv("LIGHTREC_INTERPRETER"); if (getenv("LIGHTREC_BEGIN_CYCLES")) lightrec_begin_cycles = (unsigned int) strtol( @@ -393,11 +411,11 @@ static int lightrec_plugin_init(void) lightrec_map, ARRAY_SIZE(lightrec_map), &lightrec_ops); - fprintf(stderr, "M=0x%lx, P=0x%lx, R=0x%lx, H=0x%lx\n", - (uintptr_t) psxM, - (uintptr_t) psxP, - (uintptr_t) psxR, - (uintptr_t) psxH); + // fprintf(stderr, "M=0x%lx, P=0x%lx, R=0x%lx, H=0x%lx\n", + // (uintptr_t) psxM, + // (uintptr_t) psxP, + // (uintptr_t) psxR, + // (uintptr_t) psxH); #ifndef _WIN32 signal(SIGPIPE, exit); @@ -405,124 +423,73 @@ static int lightrec_plugin_init(void) return 0; } -static u32 hash_calculate_le(const void *buffer, u32 count) +static void lightrec_dump_regs(struct lightrec_state *state) { - unsigned int i; - u32 *data = (u32 *) buffer; - u32 hash = 0xffffffff; - - count /= 4; - for(i = 0; i < count; ++i) { - hash += LE32TOH(data[i]); - hash += (hash << 10); - hash ^= (hash >> 6); - } + struct lightrec_registers *regs = lightrec_get_registers(state); - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return hash; + if (unlikely(booting)) + memcpy(&psxRegs.GPR, regs->gpr, sizeof(regs->gpr)); + psxRegs.CP0.n.Status = regs->cp0[12]; + psxRegs.CP0.n.Cause = regs->cp0[13]; } -static u32 hash_calculate(const void *buffer, u32 count) +static void lightrec_restore_regs(struct lightrec_state *state) { - unsigned int i; - u32 *data = (u32 *) buffer; - u32 hash = 0xffffffff; - - count /= 4; - for(i = 0; i < count; ++i) { - hash += data[i]; - hash += (hash << 10); - hash ^= (hash >> 6); - } - - hash += (hash << 3); - hash ^= (hash >> 11); - hash += (hash << 15); - return hash; -} - -static const char * const mips_regs[] = { - "zero", - "at", - "v0", "v1", - "a0", "a1", "a2", "a3", - "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "t8", "t9", - "k0", "k1", - "gp", "sp", "fp", "ra", - "lo", "hi", -}; + struct lightrec_registers *regs = lightrec_get_registers(state); -static void print_for_big_ass_debugger(void) -{ - unsigned int i; - - printf("CYCLE 0x%08x PC 0x%08x", psxRegs.cycle, psxRegs.pc); - - if (lightrec_very_debug) - printf(" RAM 0x%08x SCRATCH 0x%08x HW 0x%08x", - hash_calculate_le(psxM, 0x200000), - hash_calculate_le(psxH, 0x400), - hash_calculate_le(psxH + 0x1000, 0x2000)); - - printf(" CP0 0x%08x CP2D 0x%08x CP2C 0x%08x INT 0x%04x INTCYCLE 0x%08x GPU 0x%08x", - hash_calculate(&psxRegs.CP0.r, - sizeof(psxRegs.CP0.r)), - hash_calculate(&psxRegs.CP2D.r, - sizeof(psxRegs.CP2D.r)), - hash_calculate(&psxRegs.CP2C.r, - sizeof(psxRegs.CP2C.r)), - psxRegs.interrupt, - hash_calculate(psxRegs.intCycle, - sizeof(psxRegs.intCycle)), - LE32TOH(HW_GPU_STATUS)); - - if (lightrec_very_debug) - for (i = 0; i < 34; i++) - printf(" %s 0x%08x", mips_regs[i], psxRegs.GPR.r[i]); - else - printf(" GPR 0x%08x", hash_calculate(&psxRegs.GPR.r, - sizeof(psxRegs.GPR.r))); - printf("\n"); + if (unlikely(booting)) + memcpy(regs->gpr, &psxRegs.GPR, sizeof(regs->gpr)); + regs->cp0[12] = psxRegs.CP0.n.Status; + regs->cp0[13] = psxRegs.CP0.n.Cause; + regs->cp0[14] = psxRegs.CP0.n.EPC; } -static u32 old_cycle_counter; +extern void intExecuteBlock(); +extern void gen_interupt(); static void lightrec_plugin_execute_block(void) { u32 old_pc = psxRegs.pc; u32 flags; - lightrec_reset_cycle_count(lightrec_state, psxRegs.cycle); - lightrec_restore_registers(lightrec_state, psxRegs.GPR.r); - - if (use_lightrec_interpreter) - psxRegs.pc = lightrec_run_interpreter(lightrec_state, psxRegs.pc); - else - psxRegs.pc = lightrec_execute_one(lightrec_state, psxRegs.pc); - - psxRegs.cycle = lightrec_current_cycle_count(lightrec_state); + gen_interupt(); + + // step during early boot so that 0x80030000 fastboot hack works + if (booting) + next_interupt = psxRegs.cycle; + + if (use_pcsx_interpreter) { + intExecuteBlock(); + } else { + lightrec_reset_cycle_count(lightrec_state, psxRegs.cycle); + lightrec_restore_regs(lightrec_state); + + if (unlikely(use_lightrec_interpreter)) { + psxRegs.pc = lightrec_run_interpreter(lightrec_state, + psxRegs.pc, + next_interupt); + } else { + psxRegs.pc = lightrec_execute(lightrec_state, + psxRegs.pc, next_interupt); + } - lightrec_dump_registers(lightrec_state, psxRegs.GPR.r); - flags = lightrec_exit_flags(lightrec_state); + psxRegs.cycle = lightrec_current_cycle_count(lightrec_state); - if (flags & LIGHTREC_EXIT_SEGFAULT) { - fprintf(stderr, "Exiting at cycle 0x%08x\n", - psxRegs.cycle); - exit(1); - } + lightrec_dump_regs(lightrec_state); + flags = lightrec_exit_flags(lightrec_state); - if (flags & LIGHTREC_EXIT_SYSCALL) - psxException(0x20, 0); + if (flags & LIGHTREC_EXIT_SEGFAULT) { + fprintf(stderr, "Exiting at cycle 0x%08x\n", + psxRegs.cycle); + exit(1); + } - psxBranchTest(); + if (flags & LIGHTREC_EXIT_SYSCALL) + psxException(0x20, 0); - if (lightrec_debug && psxRegs.cycle >= lightrec_begin_cycles - && psxRegs.pc != old_pc) - print_for_big_ass_debugger(); + if (booting && (psxRegs.pc & 0xff800000) == 0x80000000) + booting = false; + } if ((psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x300) && (psxRegs.CP0.n.Status & 0x1)) { @@ -530,17 +497,6 @@ static void lightrec_plugin_execute_block(void) psxRegs.CP0.n.Cause &= ~0x7c; psxException(psxRegs.CP0.n.Cause, 0); } - - if ((psxRegs.cycle & ~0xfffffff) != old_cycle_counter) { - printf("RAM usage: IR %u KiB, CODE %u KiB, " - "MIPS %u KiB, TOTAL %u KiB, avg. IPI %f\n", - lightrec_get_mem_usage(MEM_FOR_IR) / 1024, - lightrec_get_mem_usage(MEM_FOR_CODE) / 1024, - lightrec_get_mem_usage(MEM_FOR_MIPS_CODE) / 1024, - lightrec_get_total_mem_usage() / 1024, - lightrec_get_average_ipi()); - old_cycle_counter = psxRegs.cycle & ~0xfffffff; - } } static void lightrec_plugin_execute(void) @@ -553,8 +509,32 @@ static void lightrec_plugin_execute(void) static void lightrec_plugin_clear(u32 addr, u32 size) { - /* size * 4: PCSX uses DMA units */ - lightrec_invalidate(lightrec_state, addr, size * 4); + if (addr == 0 && size == UINT32_MAX) + lightrec_invalidate_all(lightrec_state); + else + /* size * 4: PCSX uses DMA units */ + lightrec_invalidate(lightrec_state, addr, size * 4); +} + +static void lightrec_plugin_notify(int note, void *data) +{ + /* + To change once proper icache emulation is emulated + switch (note) + { + case R3000ACPU_NOTIFY_CACHE_UNISOLATED: + lightrec_plugin_clear(0, 0x200000/4); + break; + case R3000ACPU_NOTIFY_CACHE_ISOLATED: + // Sent from psxDma3(). + case R3000ACPU_NOTIFY_DMA3_EXE_LOAD: + default: + break; + }*/ +} + +static void lightrec_plugin_apply_config() +{ } static void lightrec_plugin_shutdown(void) @@ -564,8 +544,42 @@ static void lightrec_plugin_shutdown(void) static void lightrec_plugin_reset(void) { - lightrec_plugin_shutdown(); - lightrec_plugin_init(); + struct lightrec_registers *regs; + + regs = lightrec_get_registers(lightrec_state); + + /* Invalidate all blocks */ + lightrec_invalidate_all(lightrec_state); + + /* Reset registers */ + memset(regs, 0, sizeof(*regs)); + + regs->cp0[12] = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1 + regs->cp0[15] = 0x00000002; // PRevID = Revision ID, same as R3000A + + booting = true; +} + +void lightrec_plugin_prepare_load_state(void) +{ + struct lightrec_registers *regs; + + regs = lightrec_get_registers(lightrec_state); + memcpy(regs->cp2d, &psxRegs.CP2, sizeof(regs->cp2d) + sizeof(regs->cp2c)); + memcpy(regs->cp0, &psxRegs.CP0, sizeof(regs->cp0)); + memcpy(regs->gpr, &psxRegs.GPR, sizeof(regs->gpr)); + + lightrec_invalidate_all(lightrec_state); +} + +void lightrec_plugin_prepare_save_state(void) +{ + struct lightrec_registers *regs; + + regs = lightrec_get_registers(lightrec_state); + memcpy(&psxRegs.CP2, regs->cp2d, sizeof(regs->cp2d) + sizeof(regs->cp2c)); + memcpy(&psxRegs.CP0, regs->cp0, sizeof(regs->cp0)); + memcpy(&psxRegs.GPR, regs->gpr, sizeof(regs->gpr)); } R3000Acpu psxRec = @@ -575,5 +589,7 @@ R3000Acpu psxRec = lightrec_plugin_execute, lightrec_plugin_execute_block, lightrec_plugin_clear, + lightrec_plugin_notify, + lightrec_plugin_apply_config, lightrec_plugin_shutdown, };