[subrepo]
remote = https://github.com/pcercuei/lightrec.git
branch = master
- commit = 962ba057937b7fcb809f16682b4e24d27f08cdb1
- parent = 5b2da975316f1d88d02a14f8f2c876b2213ff1f3
+ commit = 75374fa374a367c85f5cac6c1b9fc2c583298d42
+ parent = 22a3b99d24fada1c7a5e7ab4458c132a0c387d50
method = merge
cmdver = 0.4.3
rec_break_syscall(state, block, offset, LIGHTREC_EXIT_BREAK);
}
+static void rec_mfc(struct lightrec_cstate *state, const struct block *block, u16 offset)
+{
+ struct regcache *reg_cache = state->reg_cache;
+ union code c = block->opcode_list[offset].c;
+ jit_state_t *_jit = block->_jit;
+
+ jit_note(__FILE__, __LINE__);
+ lightrec_clean_reg_if_loaded(reg_cache, _jit, c.i.rt, true);
+
+ call_to_c_wrapper(state, block, c.opcode, C_WRAPPER_MFC);
+}
+
static void rec_mtc(struct lightrec_cstate *state, const struct block *block, u16 offset)
{
struct regcache *reg_cache = state->reg_cache;
_jit_name(block->_jit, __func__);
+ if (state->state->ops.cop2_notify) {
+ /* We must call cop2_notify, handle that in C. */
+ rec_mfc(state, block, offset);
+ return;
+ }
+
flags = (zext_regs & BIT(reg)) ? REG_ZEXT : REG_EXT;
rt = lightrec_alloc_reg_out(reg_cache, _jit, c.r.rt, flags);
_jit_name(block->_jit, __func__);
+ if (state->state->ops.cop2_notify) {
+ /* We must call cop2_notify, handle that in C. */
+ rec_mfc(state, block, offset);
+ return;
+ }
+
switch (c.r.rd) {
case 4:
case 12:
_jit_name(block->_jit, __func__);
+ if (state->state->ops.cop2_notify) {
+ /* We must call cop2_notify, handle that in C. */
+ rec_mtc(state, block, offset);
+ return;
+ }
+
if (c.r.rd == 31)
return;
_jit_name(block->_jit, __func__);
+ if (state->state->ops.cop2_notify) {
+ /* We must call cop2_notify, handle that in C. */
+ rec_mtc(state, block, offset);
+ return;
+ }
+
rt = lightrec_alloc_reg_in(reg_cache, _jit, c.r.rt, 0);
switch (c.r.rd) {
enum c_wrappers {
C_WRAPPER_RW,
C_WRAPPER_RW_GENERIC,
+ C_WRAPPER_MFC,
C_WRAPPER_MTC,
C_WRAPPER_CP,
C_WRAPPERS_COUNT,
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)
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;
};
struct lightrec_ops {
+ void (*cop2_notify)(struct lightrec_state *state, u32 op, u32 data);
void (*cop2_op)(struct lightrec_state *state, u32 op);
void (*enable_ram)(struct lightrec_state *state, _Bool enable);
_Bool (*hw_direct)(u32 kaddr, _Bool is_write, u8 size);
case OP_LBU:
case OP_LHU:
case OP_LWR:
+ case OP_META_EXTC:
+ case OP_META_EXTS:
return BIT(op.i.rt);
case OP_JAL:
return BIT(31);
known &= ~BIT(c.r.rd);
}
break;
+ case OP_META_EXTC:
+ if (known & BIT(c.i.rs)) {
+ known |= BIT(c.i.rt);
+ v[c.i.rt] = (s32)(s8)v[c.i.rs];
+ } else {
+ known &= ~BIT(c.i.rt);
+ }
+ break;
+ case OP_META_EXTS:
+ if (known & BIT(c.i.rs)) {
+ known |= BIT(c.i.rt);
+ v[c.i.rt] = (s32)(s16)v[c.i.rs];
+ } else {
+ known &= ~BIT(c.i.rt);
+ }
+ break;
default:
break;
}