#include <stddef.h>
#include <string.h>
-#define GENMASK(h, l) \
- (((uintptr_t)-1 << (l)) & ((uintptr_t)-1 >> (__WORDSIZE - 1 - (h))))
-
static struct block * lightrec_precompile_block(struct lightrec_state *state,
u32 pc);
static bool lightrec_block_is_fully_tagged(const struct block *block);
u32 opcode, void *host, u32 addr, u32 data)
{
unsigned int shift = addr & 0x3;
- unsigned int mask = GENMASK(31, (shift + 1) * 8);
+ unsigned int mask = shift < 3 ? GENMASK(31, (shift + 1) * 8) : 0;
u32 old_data;
/* Align to 32 bits */
u32 opcode, void *host, u32 addr, u32 data)
{
unsigned int shift = addr & 0x3;
- unsigned int mask = GENMASK(31, 32 - shift * 8);
+ unsigned int mask = shift ? GENMASK(31, 32 - shift * 8) : 0;
u32 old_data;
/* Align to 32 bits */
return 0;
}
- if (unlikely(map->ops)) {
- if (flags && !LIGHTREC_FLAGS_GET_IO_MODE(*flags))
- *flags |= LIGHTREC_IO_MODE(LIGHTREC_IO_HW);
- ops = map->ops;
- } else {
+ if (likely(!map->ops)) {
if (flags && !LIGHTREC_FLAGS_GET_IO_MODE(*flags))
*flags |= LIGHTREC_IO_MODE(LIGHTREC_IO_DIRECT);
ops = &lightrec_default_ops;
+ } else if (flags &&
+ LIGHTREC_FLAGS_GET_IO_MODE(*flags) == LIGHTREC_IO_DIRECT_HW) {
+ ops = &lightrec_default_ops;
+ } else {
+ if (flags && !LIGHTREC_FLAGS_GET_IO_MODE(*flags))
+ *flags |= LIGHTREC_IO_MODE(LIGHTREC_IO_HW);
+
+ ops = map->ops;
}
switch (op.i.op) {
if (op.i.op == OP_CP0)
return state->regs.cp0[op.r.rd];
else if (op.r.rs == OP_CP2_BASIC_MFC2)
- return lightrec_mfc2(state, op.r.rd);
+ val = lightrec_mfc2(state, op.r.rd);
+ else {
+ val = state->regs.cp2c[op.r.rd];
+
+ switch (op.r.rd) {
+ case 4:
+ case 12:
+ case 20:
+ case 26:
+ case 27:
+ case 29:
+ case 30:
+ val = (u32)(s16)val;
+ fallthrough;
+ default:
+ break;
+ }
+ }
- val = state->regs.cp2c[op.r.rd];
+ if (state->ops.cop2_notify)
+ (*state->ops.cop2_notify)(state, op.opcode, val);
- switch (op.r.rd) {
- case 4:
- case 12:
- case 20:
- case 26:
- case 27:
- case 29:
- case 30:
- return (u32)(s16)val;
- default:
- return val;
- }
+ return val;
+}
+
+static void lightrec_mfc_cb(struct lightrec_state *state, union code op)
+{
+ u32 rt = lightrec_mfc(state, op);
+
+ if (op.r.rt)
+ state->regs.gpr[op.r.rt] = rt;
}
static void lightrec_mtc0(struct lightrec_state *state, u8 reg, u32 data)
void lightrec_mtc(struct lightrec_state *state, union code op, u32 data)
{
- if (op.i.op == OP_CP0)
+ if (op.i.op == OP_CP0) {
lightrec_mtc0(state, op.r.rd, data);
- else if (op.r.rs == OP_CP2_BASIC_CTC2)
- lightrec_ctc2(state, op.r.rd, data);
- else
- lightrec_mtc2(state, op.r.rd, data);
+ } else {
+ if (op.r.rs == OP_CP2_BASIC_CTC2)
+ lightrec_ctc2(state, op.r.rd, data);
+ else
+ lightrec_mtc2(state, op.r.rd, data);
+
+ if (state->ops.cop2_notify)
+ (*state->ops.cop2_notify)(state, op.opcode, data);
+ }
}
static void lightrec_mtc_cb(struct lightrec_state *state, u32 arg)
pr_debug("Branch at offset 0x%x will be emulated\n",
i << 2);
- lightrec_emit_eob(cstate, block, i, false);
+ lightrec_emit_eob(cstate, block, i);
skip_next = !op_flag_no_ds(elm->flags);
} else {
lightrec_rec_opcode(cstate, block, i);
return NULL;
}
+ if (ops->cop2_notify)
+ pr_debug("Optional cop2_notify callback in lightrec_ops\n");
+ else
+ pr_debug("No optional cop2_notify callback in lightrec_ops\n");
+
if (ENABLE_CODE_BUFFER && nb > PSX_MAP_CODE_BUFFER
&& codebuf_map->address) {
tlsf = tlsf_create_with_pool(codebuf_map->address,
state->c_wrappers[C_WRAPPER_RW] = lightrec_rw_cb;
state->c_wrappers[C_WRAPPER_RW_GENERIC] = lightrec_rw_generic_cb;
+ state->c_wrappers[C_WRAPPER_MFC] = lightrec_mfc_cb;
state->c_wrappers[C_WRAPPER_MTC] = lightrec_mtc_cb;
state->c_wrappers[C_WRAPPER_CP] = lightrec_cp_cb;