X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=deps%2Flightrec%2Flightrec.c;h=696a5ddd9d954bae9f3271a5d06e78c1fb717a21;hb=5459088bf71ee4da726a70f191d301da2a121910;hp=d5b1de968c57829b43a7abaabf1857fbc0fee90f;hpb=cb72ea130a5ef1b2f47691ed586ad48bb0c39269;p=pcsx_rearmed.git diff --git a/deps/lightrec/lightrec.c b/deps/lightrec/lightrec.c index d5b1de96..696a5ddd 100644 --- a/deps/lightrec/lightrec.c +++ b/deps/lightrec/lightrec.c @@ -40,7 +40,7 @@ static void lightrec_default_sb(struct lightrec_state *state, u32 opcode, { *(u8 *)host = data; - if (!state->invalidate_from_dma_only) + if (!(state->opt_flags & LIGHTREC_OPT_INV_DMA_ONLY)) lightrec_invalidate(state, addr, 1); } @@ -49,7 +49,7 @@ static void lightrec_default_sh(struct lightrec_state *state, u32 opcode, { *(u16 *)host = HTOLE16(data); - if (!state->invalidate_from_dma_only) + if (!(state->opt_flags & LIGHTREC_OPT_INV_DMA_ONLY)) lightrec_invalidate(state, addr, 2); } @@ -58,7 +58,7 @@ static void lightrec_default_sw(struct lightrec_state *state, u32 opcode, { *(u32 *)host = HTOLE32(data); - if (!state->invalidate_from_dma_only) + if (!(state->opt_flags & LIGHTREC_OPT_INV_DMA_ONLY)) lightrec_invalidate(state, addr, 4); } @@ -80,6 +80,27 @@ static u32 lightrec_default_lw(struct lightrec_state *state, return LE32TOH(*(u32 *)host); } +static u32 lightrec_default_lwu(struct lightrec_state *state, + u32 opcode, void *host, u32 addr) +{ + u32 val; + + memcpy(&val, host, 4); + + return LE32TOH(val); +} + +static void lightrec_default_swu(struct lightrec_state *state, u32 opcode, + void *host, u32 addr, u32 data) +{ + data = HTOLE32(data); + + memcpy(host, &data, 4); + + if (!(state->opt_flags & LIGHTREC_OPT_INV_DMA_ONLY)) + lightrec_invalidate(state, addr & ~0x3, 8); +} + static const struct lightrec_mem_map_ops lightrec_default_ops = { .sb = lightrec_default_sb, .sh = lightrec_default_sh, @@ -87,6 +108,8 @@ static const struct lightrec_mem_map_ops lightrec_default_ops = { .lb = lightrec_default_lb, .lh = lightrec_default_lh, .lw = lightrec_default_lw, + .lwu = lightrec_default_lwu, + .swu = lightrec_default_swu, }; static void __segfault_cb(struct lightrec_state *state, u32 addr, @@ -94,9 +117,9 @@ static void __segfault_cb(struct lightrec_state *state, u32 addr, { lightrec_set_exit_flags(state, LIGHTREC_EXIT_SEGFAULT); pr_err("Segmentation fault in recompiled code: invalid " - "load/store at address 0x%08x\n", addr); + "load/store at address "PC_FMT"\n", addr); if (block) - pr_err("Was executing block PC 0x%08x\n", block->pc); + pr_err("Was executing block "PC_FMT"\n", block->pc); } static void lightrec_swl(struct lightrec_state *state, @@ -290,7 +313,7 @@ u32 lightrec_rw(struct lightrec_state *state, union code op, u32 base, old_flags = block_set_flags(block, BLOCK_SHOULD_RECOMPILE); if (!(old_flags & BLOCK_SHOULD_RECOMPILE)) { - pr_debug("Opcode of block at PC 0x%08x has been tagged" + pr_debug("Opcode of block at "PC_FMT" has been tagged" " - flag for recompilation\n", block->pc); lut_write(state, lut_offset(block->pc), NULL); @@ -331,6 +354,11 @@ u32 lightrec_rw(struct lightrec_state *state, union code op, u32 base, return lightrec_lwl(state, ops, opcode, host, addr, data); case OP_LWR: return lightrec_lwr(state, ops, opcode, host, addr, data); + case OP_META_LWU: + return ops->lwu(state, opcode, host, addr); + case OP_META_SWU: + ops->swu(state, opcode, host, addr, data); + return 0; case OP_LW: default: return ops->lw(state, opcode, host, addr); @@ -352,6 +380,7 @@ static void lightrec_rw_helper(struct lightrec_state *state, case OP_LWL: case OP_LWR: case OP_LW: + case OP_META_LWU: if (OPT_HANDLE_LOAD_DELAYS && unlikely(!state->in_delay_slot_n)) { state->temp_reg = ret; state->in_delay_slot_n = 0xff; @@ -376,10 +405,10 @@ static void lightrec_rw_generic_cb(struct lightrec_state *state, u32 arg) u16 offset = (u16)arg; block = lightrec_find_block_from_lut(state->block_cache, - arg >> 16, state->next_pc); + arg >> 16, state->curr_pc); if (unlikely(!block)) { - pr_err("rw_generic: No block found in LUT for PC 0x%x offset 0x%x\n", - state->next_pc, offset); + pr_err("rw_generic: No block found in LUT for "PC_FMT" offset 0x%"PRIx16"\n", + state->curr_pc, offset); lightrec_set_exit_flags(state, LIGHTREC_EXIT_SEGFAULT); return; } @@ -524,7 +553,7 @@ static void lightrec_mtc0(struct lightrec_state *state, u8 reg, u32 data) status = state->regs.cp0[12]; /* Handle software interrupts */ - if (!!(status & cause & 0x300) & status) + if ((!!(status & cause & 0x300)) & status) lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT); /* Handle hardware interrupts */ @@ -665,7 +694,7 @@ static struct block * lightrec_get_block(struct lightrec_state *state, u32 pc) u8 old_flags; if (block && lightrec_block_is_outdated(state, block)) { - pr_debug("Block at PC 0x%08x is outdated!\n", block->pc); + pr_debug("Block at "PC_FMT" is outdated!\n", block->pc); old_flags = block_set_flags(block, BLOCK_IS_DEAD); if (!(old_flags & BLOCK_IS_DEAD)) { @@ -685,7 +714,7 @@ static struct block * lightrec_get_block(struct lightrec_state *state, u32 pc) if (!block) { block = lightrec_precompile_block(state, pc); if (!block) { - pr_err("Unable to recompile block at PC 0x%x\n", pc); + pr_err("Unable to recompile block at "PC_FMT"\n", pc); lightrec_set_exit_flags(state, LIGHTREC_EXIT_SEGFAULT); return NULL; } @@ -724,7 +753,7 @@ static void * get_next_block_func(struct lightrec_state *state, u32 pc) !block_has_flag(block, BLOCK_IS_DEAD); if (unlikely(should_recompile)) { - pr_debug("Block at PC 0x%08x should recompile\n", pc); + pr_debug("Block at "PC_FMT" should recompile\n", pc); if (ENABLE_THREADED_COMPILER) { lightrec_recompiler_add(state->rec, block); @@ -776,7 +805,7 @@ static void * get_next_block_func(struct lightrec_state *state, u32 pc) } while (state->exit_flags == LIGHTREC_EXIT_NORMAL && state->current_cycle < state->target_cycle); - state->next_pc = pc; + state->curr_pc = pc; return func; } @@ -1018,16 +1047,16 @@ static u32 lightrec_memset(struct lightrec_state *state) u32 length = state->regs.gpr[5] * 4; if (!map) { - pr_err("Unable to find memory map for memset target address " - "0x%x\n", kunseg_pc); + pr_err("Unable to find memory map for memset target address "PC_FMT"\n", + kunseg_pc); return 0; } - pr_debug("Calling host memset, PC 0x%x (host address 0x%" PRIxPTR ") for %u bytes\n", + pr_debug("Calling host memset, "PC_FMT" (host address 0x%"PRIxPTR") for %u bytes\n", kunseg_pc, (uintptr_t)host, length); memset(host, 0, length); - if (!state->invalidate_from_dma_only) + if (!(state->opt_flags & LIGHTREC_OPT_INV_DMA_ONLY)) lightrec_invalidate_map(state, map, kunseg_pc, length); /* Rough estimation of the number of cycles consumed */ @@ -1046,7 +1075,7 @@ static u32 lightrec_check_load_delay(struct lightrec_state *state, u32 pc, u8 re } else { block = lightrec_get_block(state, pc); if (unlikely(!block)) { - pr_err("Unable to get block at PC 0x%08x\n", pc); + pr_err("Unable to get block at "PC_FMT"\n", pc); lightrec_set_exit_flags(state, LIGHTREC_EXIT_SEGFAULT); pc = 0; } else { @@ -1077,6 +1106,14 @@ static void update_cycle_counter_after_c(jit_state_t *_jit) jit_subr(LIGHTREC_REG_CYCLE, JIT_R2, JIT_R1); } +static void sync_next_pc(jit_state_t *_jit) +{ + if (lightrec_store_next_pc()) { + jit_ldxi_ui(JIT_V0, LIGHTREC_REG_STATE, + offsetof(struct lightrec_state, next_pc)); + } +} + static struct block * generate_dispatcher(struct lightrec_state *state) { struct block *block; @@ -1140,6 +1177,7 @@ static struct block * generate_dispatcher(struct lightrec_state *state) * in JIT_V0 and the address of the block in JIT_V1. */ addr4 = jit_indirect(); + sync_next_pc(_jit); update_cycle_counter_before_c(_jit); jit_prepare(); @@ -1167,6 +1205,7 @@ static struct block * generate_dispatcher(struct lightrec_state *state) * in question; and if it does, handle it accordingly. */ addr5 = jit_indirect(); + sync_next_pc(_jit); update_cycle_counter_before_c(_jit); jit_prepare(); @@ -1178,22 +1217,24 @@ static struct block * generate_dispatcher(struct lightrec_state *state) jit_retval(JIT_V0); update_cycle_counter_after_c(_jit); - - if (OPT_DETECT_IMPOSSIBLE_BRANCHES) - jit_patch(jmp2); } + /* The block will jump here, with the number of cycles remaining in + * LIGHTREC_REG_CYCLE */ + addr2 = jit_indirect(); + + sync_next_pc(_jit); + + if (OPT_HANDLE_LOAD_DELAYS && OPT_DETECT_IMPOSSIBLE_BRANCHES) + jit_patch(jmp2); + if (OPT_REPLACE_MEMSET && (OPT_DETECT_IMPOSSIBLE_BRANCHES || OPT_HANDLE_LOAD_DELAYS)) { jit_patch(jmp); } - /* The block will jump here, with the number of cycles remaining in - * LIGHTREC_REG_CYCLE */ - addr2 = jit_indirect(); - - /* Store back the next_pc to the lightrec_state structure */ - offset = offsetof(struct lightrec_state, next_pc); + /* Store back the next PC to the lightrec_state structure */ + offset = offsetof(struct lightrec_state, curr_pc); jit_stxi_i(offset, LIGHTREC_REG_STATE, JIT_V0); /* Jump to end if state->target_cycle < state->current_cycle */ @@ -1254,7 +1295,7 @@ static struct block * generate_dispatcher(struct lightrec_state *state) /* Reset JIT_V0 to the next PC */ jit_ldxi_ui(JIT_V0, LIGHTREC_REG_STATE, - offsetof(struct lightrec_state, next_pc)); + offsetof(struct lightrec_state, curr_pc)); /* If we get non-NULL, loop */ jit_patch_at(jit_bnei(JIT_V1, 0), loop); @@ -1311,9 +1352,10 @@ union code lightrec_read_opcode(struct lightrec_state *state, u32 pc) return (union code) LE32TOH(*code); } -__cnst unsigned int lightrec_cycles_of_opcode(union code code) +unsigned int lightrec_cycles_of_opcode(const struct lightrec_state *state, + union code code) { - return 2; + return state->cycles_per_op; } void lightrec_free_opcode_list(struct lightrec_state *state, struct opcode *ops) @@ -1469,6 +1511,8 @@ static bool lightrec_block_is_fully_tagged(const struct block *block) case OP_SWR: case OP_LWC2: case OP_SWC2: + case OP_META_LWU: + case OP_META_SWU: if (!LIGHTREC_FLAGS_GET_IO_MODE(op->flags)) return false; fallthrough; @@ -1484,7 +1528,7 @@ static void lightrec_reap_block(struct lightrec_state *state, void *data) { struct block *block = data; - pr_debug("Reap dead block at PC 0x%08x\n", block->pc); + pr_debug("Reap dead block at "PC_FMT"\n", block->pc); lightrec_unregister_block(state->block_cache, block); lightrec_free_block(state, block); } @@ -1543,7 +1587,9 @@ int lightrec_compile_block(struct lightrec_cstate *cstate, block->_jit = _jit; lightrec_regcache_reset(cstate->reg_cache); - lightrec_preload_pc(cstate->reg_cache); + + if (OPT_PRELOAD_PC && (block->flags & BLOCK_PRELOAD_PC)) + lightrec_preload_pc(cstate->reg_cache, _jit); cstate->cycles = 0; cstate->nb_local_branches = 0; @@ -1581,7 +1627,7 @@ int lightrec_compile_block(struct lightrec_cstate *cstate, #endif } - cstate->cycles += lightrec_cycles_of_opcode(elm->c); + cstate->cycles += lightrec_cycles_of_opcode(state, elm->c); } for (i = 0; i < cstate->nb_local_branches; i++) { @@ -1702,7 +1748,7 @@ int lightrec_compile_block(struct lightrec_cstate *cstate, old_flags = block_set_flags(block, BLOCK_NO_OPCODE_LIST); if (fully_tagged && !(old_flags & BLOCK_NO_OPCODE_LIST)) { - pr_debug("Block PC 0x%08x is fully tagged" + pr_debug("Block "PC_FMT" is fully tagged" " - free opcode list\n", block->pc); if (ENABLE_THREADED_COMPILER) { @@ -1763,13 +1809,13 @@ u32 lightrec_execute(struct lightrec_state *state, u32 pc, u32 target_cycle) target_cycle = UINT_MAX; state->target_cycle = target_cycle; - state->next_pc = pc; + state->curr_pc = pc; block_trace = get_next_block_func(state, pc); if (block_trace) { cycles_delta = state->target_cycle - state->current_cycle; - cycles_delta = (*func)(state, state->next_pc, + cycles_delta = (*func)(state, state->curr_pc, block_trace, cycles_delta); state->current_cycle = state->target_cycle - cycles_delta; @@ -1781,7 +1827,7 @@ u32 lightrec_execute(struct lightrec_state *state, u32 pc, u32 target_cycle) if (LOG_LEVEL >= INFO_L) lightrec_print_info(state); - return state->next_pc; + return state->curr_pc; } u32 lightrec_run_interpreter(struct lightrec_state *state, u32 pc, @@ -1906,6 +1952,7 @@ struct lightrec_state * lightrec_init(char *argv0, state->tlsf = tlsf; state->with_32bit_lut = with_32bit_lut; state->in_delay_slot_n = 0xff; + state->cycles_per_op = 2; state->block_cache = lightrec_blockcache_init(state); if (!state->block_cache) @@ -2052,12 +2099,12 @@ void lightrec_invalidate_all(struct lightrec_state *state) memset(state->code_lut, 0, lut_elm_size(state) * CODE_LUT_SIZE); } -void lightrec_set_invalidate_mode(struct lightrec_state *state, bool dma_only) +void lightrec_set_unsafe_opt_flags(struct lightrec_state *state, u32 flags) { - if (state->invalidate_from_dma_only != dma_only) + if ((flags ^ state->opt_flags) & LIGHTREC_OPT_INV_DMA_ONLY) lightrec_invalidate_all(state); - state->invalidate_from_dma_only = dma_only; + state->opt_flags = flags; } void lightrec_set_exit_flags(struct lightrec_state *state, u32 flags) @@ -2100,3 +2147,8 @@ struct lightrec_registers * lightrec_get_registers(struct lightrec_state *state) { return &state->regs; } + +void lightrec_set_cycles_per_opcode(struct lightrec_state *state, u32 cycles) +{ + state->cycles_per_op = cycles; +}