From 0fc3619d1d188b6acc53ffb0479e395142082463 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 3 Sep 2022 13:15:21 -0700 Subject: [PATCH] interp: Handle jumps in branch delay slots better. This matches tests from a PSP-2000. Seems to consistently run the instruction even if likely, which writes rd. If the likely branch is not taken, the jump in the delay slot is taken. However, it should cancel the rd write (not implemented here.) --- Core/MIPS/MIPSInt.cpp | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/Core/MIPS/MIPSInt.cpp b/Core/MIPS/MIPSInt.cpp index 46585b69a9..c9811f5c96 100644 --- a/Core/MIPS/MIPSInt.cpp +++ b/Core/MIPS/MIPSInt.cpp @@ -65,10 +65,15 @@ static inline void DelayBranchTo(u32 where) mipsr4k.inDelaySlot = true; } -static inline void SkipLikely() -{ - PC += 8; - --mipsr4k.downcount; +static inline void SkipLikely() { + MIPSInfo delaySlot = MIPSGetInfo(Memory::Read_Instruction(PC + 4, true)); + // Don't actually skip if it is a jump (seen in Brooktown High.) + if (delaySlot & IS_JUMP) { + PC += 4; + } else { + PC += 8; + --mipsr4k.downcount; + } } int MIPS_SingleStep() @@ -246,17 +251,21 @@ namespace MIPSInt void Int_JumpType(MIPSOpcode op) { if (mipsr4k.inDelaySlot) - _dbg_assert_msg_(false,"Jump in delay slot :("); + ERROR_LOG(CPU, "Jump in delay slot :("); u32 off = ((op & 0x03FFFFFF) << 2); u32 addr = (currentMIPS->pc & 0xF0000000) | off; switch (op>>26) { - case 2: DelayBranchTo(addr); break; //j + case 2: //j + if (!mipsr4k.inDelaySlot) + DelayBranchTo(addr); + break; case 3: //jal - R(31) = PC + 8; - DelayBranchTo(addr); + R(MIPS_REG_RA) = PC + 8; + if (!mipsr4k.inDelaySlot) + DelayBranchTo(addr); break; default: _dbg_assert_msg_(false,"Trying to interpret instruction that can't be interpreted"); @@ -268,11 +277,8 @@ namespace MIPSInt { if (mipsr4k.inDelaySlot) { - // There's one of these in Star Soldier at 0881808c, which seems benign - it should probably be ignored. - if (op == 0x03e00008) - return; + // There's one of these in Star Soldier at 0881808c, which seems benign. ERROR_LOG(CPU, "Jump in delay slot :("); - _dbg_assert_msg_(false,"Jump in delay slot :("); } int rs = _RS; @@ -281,12 +287,15 @@ namespace MIPSInt switch (op & 0x3f) { case 8: //jr - DelayBranchTo(addr); + if (!mipsr4k.inDelaySlot) + DelayBranchTo(addr); break; case 9: //jalr if (rd != 0) R(rd) = PC + 8; - DelayBranchTo(addr); + // Update rd, but otherwise do not take the branch if we're branching. + if (!mipsr4k.inDelaySlot) + DelayBranchTo(addr); break; } }