struct opcode *op;
u32 cycles;
bool delay_slot;
+ bool load_delay;
u16 offset;
};
.state = state,
.cycles = inter->cycles,
.delay_slot = true,
- .block = NULL,
+ .load_delay = true,
};
bool run_first_op = false, dummy_ld = false, save_rs = false,
load_in_ds, branch_in_ds = false, branch_at_addr = false,
branch_taken;
u32 new_rt, old_rs = 0, new_rs = 0;
- u32 next_pc, ds_next_pc;
- u32 cause, epc;
+ u32 next_pc, ds_next_pc, epc;
if (op->i.op == OP_CP0 && op->r.rs == OP_CP0_RFE) {
/* When an IRQ happens, the PSX exception handlers (when done)
* but on branch boundaries, we need to adjust the return
* address so that the GTE opcode is effectively executed.
*/
- cause = state->regs.cp0[13];
epc = state->regs.cp0[14];
- if (!(cause & 0x7c) && epc == pc - 4)
- pc -= 4;
+ if (epc == pc - 4) {
+ op_next = lightrec_read_opcode(state, epc);
+ if (op_next.i.op == OP_CP2)
+ pc -= 4;
+ }
}
if (inter->delay_slot) {
u32 *reg_cache = inter->state->regs.gpr;
u32 val, *flags = NULL;
- if (inter->block)
+ if (!inter->load_delay && inter->block)
flags = &inter->op->flags;
val = lightrec_rw(inter->state, inter->op->c,
static u32 lightrec_emulate_block_list(struct lightrec_state *state,
struct block *block, u32 offset)
{
- struct interpreter inter;
+ struct interpreter inter = {
+ .block = block,
+ .state = state,
+ .offset = offset,
+ .op = &block->opcode_list[offset],
+ };
u32 pc;
- inter.block = block;
- inter.state = state;
- inter.offset = offset;
- inter.op = &block->opcode_list[offset];
- inter.cycles = 0;
- inter.delay_slot = false;
-
pc = lightrec_int_op(&inter);
/* Add the cycles of the last branch */
struct interpreter inter = {
.block = block,
.state = state,
- .offset = 0,
.op = op,
- .cycles = 0,
+ .load_delay = true,
};
bool branch_taken;
u32 reg_mask, next_pc;