X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=deps%2Flightrec%2Finterpreter.c;h=ff609a4524203678be795c0fc0ff6cafbd3e6160;hb=f533290e855dcdb9d266f147716b10e9a6268058;hp=acc41eaf78549c158c72d0a1fcc75f5746fb0524;hpb=28d1bea2e828cd079593abc8c97ea6ff4fd7d4f4;p=pcsx_rearmed.git diff --git a/deps/lightrec/interpreter.c b/deps/lightrec/interpreter.c index acc41eaf..ff609a45 100644 --- a/deps/lightrec/interpreter.c +++ b/deps/lightrec/interpreter.c @@ -150,8 +150,8 @@ static u32 int_delay_slot(struct interpreter *inter, u32 pc, bool branch) * but on branch boundaries, we need to adjust the return * address so that the GTE opcode is effectively executed. */ - cause = (*state->ops.cop0_ops.cfc)(state, 13); - epc = (*state->ops.cop0_ops.cfc)(state, 14); + cause = (*state->ops.cop0_ops.cfc)(state, op->c.opcode, 13); + epc = (*state->ops.cop0_ops.cfc)(state, op->c.opcode, 14); if (!(cause & 0x7c) && epc == pc - 4) pc -= 4; @@ -218,6 +218,8 @@ static u32 int_delay_slot(struct interpreter *inter, u32 pc, bool branch) branch_taken = is_branch_taken(reg_cache, op_next); pr_debug("Target of impossible branch is a branch, " "%staken.\n", branch_taken ? "" : "not "); + inter->cycles += lightrec_cycles_of_opcode(op_next); + old_rs = reg_cache[op_next.r.rs]; } else { new_op.c = op_next; new_op.flags = 0; @@ -248,16 +250,24 @@ static u32 int_delay_slot(struct interpreter *inter, u32 pc, bool branch) new_rt = reg_cache[op->r.rt]; /* Execute delay slot opcode */ - if (branch_at_addr) - ds_next_pc = int_branch(&inter2, pc, op_next, branch_taken); - else - ds_next_pc = (*int_standard[inter2.op->i.op])(&inter2); + ds_next_pc = (*int_standard[inter2.op->i.op])(&inter2); + + if (branch_at_addr) { + if (op_next.i.op == OP_SPECIAL) + /* TODO: Handle JALR setting $ra */ + ds_next_pc = old_rs; + else if (op_next.i.op == OP_J || op_next.i.op == OP_JAL) + /* TODO: Handle JAL setting $ra */ + ds_next_pc = (pc & 0xf0000000) | (op_next.j.imm << 2); + else + ds_next_pc = pc + 4 + ((s16)op_next.i.imm << 2); + } if (branch_at_addr && !branch_taken) { /* If the branch at the target of the branch opcode is not * taken, we jump to its delay slot */ next_pc = pc + sizeof(u32); - } else if (!branch && branch_in_ds) { + } else if (branch_at_addr || (!branch && branch_in_ds)) { next_pc = ds_next_pc; } @@ -475,7 +485,8 @@ static u32 int_ctc(struct interpreter *inter) /* If we have a MTC0 or CTC0 to CP0 register 12 (Status) or 13 (Cause), * return early so that the emulator will be able to check software * interrupt status. */ - if (op->i.op == OP_CP0 && (op->r.rd == 12 || op->r.rd == 13)) + if (!(inter->op->flags & LIGHTREC_NO_DS) && + op->i.op == OP_CP0 && (op->r.rd == 12 || op->r.rd == 13)) return inter->block->pc + (op->offset + 1) * sizeof(u32); else return jump_next(inter); @@ -487,13 +498,13 @@ static u32 int_cp0_RFE(struct interpreter *inter) u32 status; /* Read CP0 Status register (r12) */ - status = state->ops.cop0_ops.mfc(state, 12); + status = state->ops.cop0_ops.mfc(state, inter->op->c.opcode, 12); /* Switch the bits */ status = ((status & 0x3c) >> 2) | (status & ~0xf); /* Write it back */ - state->ops.cop0_ops.ctc(state, 12, status); + state->ops.cop0_ops.ctc(state, inter->op->c.opcode, 12, status); return jump_next(inter); } @@ -790,6 +801,9 @@ static u32 int_special_DIV(struct interpreter *inter) if (rt == 0) { hi = rs; lo = (rs < 0) * 2 - 1; + } else if ((rs == 0x80000000) && (rt == 0xFFFFFFFF)) { + lo = rs; + hi = 0; } else { lo = rs / rt; hi = rs % rt;