From da4141aa9f25ebcf9df557c9547817897ee0d862 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sat, 9 Jun 2012 18:16:11 +0200 Subject: [PATCH 1/4] Simulate ARAM DMAState correctly and check for external exceptions after MTMSR is executed. This commits fixes issue 617. WWE Day of Reckoning 1 and 2 are now playable with Dolphin. The changes are not implemented for JitIL yet. --- Source/Core/Core/Src/HW/DSP.cpp | 10 +++------- .../Interpreter/Interpreter_SystemRegisters.cpp | 1 + Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 11 ++++++++--- Source/Core/Core/Src/PowerPC/Jit64/Jit.h | 2 +- .../Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp | 5 ++++- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Source/Core/Core/Src/HW/DSP.cpp b/Source/Core/Core/Src/HW/DSP.cpp index f2509555ed..799fb62f0e 100644 --- a/Source/Core/Core/Src/HW/DSP.cpp +++ b/Source/Core/Core/Src/HW/DSP.cpp @@ -436,10 +436,6 @@ void Write16(const u16 _Value, const u32 _Address) if (tmpControl.ARAM) g_dspState.DSPControl.ARAM = 0; if (tmpControl.DSP) g_dspState.DSPControl.DSP = 0; - // Tracking DMAState fixes Knockout Kings 2003 in DSP HLE mode - if (GetDSPEmulator()->IsLLE()) - g_dspState.DSPControl.DMAState = 0; // keep g_ARAM DMA State zero - // unknown g_dspState.DSPControl.unk3 = tmpControl.unk3; g_dspState.DSPControl.pad = tmpControl.pad; @@ -701,9 +697,9 @@ void Do_ARAM_DMA() // seems like a good estimate CoreTiming::ScheduleEvent_Threadsafe(g_arDMA.Cnt.count >> 1, et_GenerateDSPInterrupt, INT_ARAM | (1<<16)); - // Emulating the DMA wait time fixes Knockout Kings 2003 in DSP HLE mode - if (!GetDSPEmulator()->IsLLE()) - g_dspState.DSPControl.DMAState = 1; + // Set the "DMA in progress" flag. It will be cleared when the interrupt will + // be triggered, after the simulated delay. + g_dspState.DSPControl.DMAState = 1; // Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks if (g_arDMA.Cnt.dir) diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp index bc7e37b533..19fe74b3f2 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp @@ -234,6 +234,7 @@ void Interpreter::mtmsr(UGeckoInstruction _inst) { // Privileged? MSR = m_GPR[_inst.RS]; + PowerPC::CheckExceptions(); m_EndBlock = true; } diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index 357eeb7809..bc0e671f24 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -300,10 +300,15 @@ void Jit64::Cleanup() ABI_CallFunctionCCC((void *)&PowerPC::UpdatePerformanceMonitor, js.downcountAmount, jit->js.numLoadStoreInst, jit->js.numFloatingPointInst); } -void Jit64::WriteExit(u32 destination, int exit_num) +void Jit64::WriteExit(u32 destination, int exit_num, bool force_ee_check) { Cleanup(); - SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount)); + + // External exceptions are checked when the following instruction sets the <= 0 flag. + // If we need to force the check, execute a useless SUB EAX, EAX + SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount)); + if (force_ee_check) + SUB(32, R(EAX), R(EAX)); //If nobody has taken care of this yet (this can be removed when all branches are done) JitBlock *b = js.curBlock; @@ -312,7 +317,7 @@ void Jit64::WriteExit(u32 destination, int exit_num) // Link opportunity! int block = blocks.GetBlockNumberFromStartAddress(destination); - if (block >= 0 && jo.enableBlocklink) + if (!force_ee_check && block >= 0 && jo.enableBlocklink) { // It exists! Joy of joy! JMP(blocks.GetBlock(block)->checkedEntry, true); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h index 1ebd476134..08de7c4609 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h @@ -112,7 +112,7 @@ public: // Utilities for use by opcodes - void WriteExit(u32 destination, int exit_num); + void WriteExit(u32 destination, int exit_num, bool force_ee_check = false); void WriteExitDestInEAX(); void WriteExceptionExit(); void WriteExternalExceptionExit(); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp index 14827129f8..b68f4a926c 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -122,7 +122,10 @@ void Jit64::mtmsr(UGeckoInstruction inst) gpr.UnlockAll(); gpr.Flush(FLUSH_ALL); fpr.Flush(FLUSH_ALL); - WriteExit(js.compilerPC + 4, 0); + + // Force an external exception when going out of mtmsr in order to check + // immediately for interrupts that were delayed because of MSR.EE=0. + WriteExit(js.compilerPC + 4, 0, true); js.firstFPInstructionFound = false; } From e1ddbdd214937e66db48db6f6c2579ffb58bd3d9 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sat, 16 Jun 2012 14:38:48 +0200 Subject: [PATCH 2/4] Use WriteExceptionExit and implement the change for JitIL --- Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 6 ++---- Source/Core/Core/Src/PowerPC/Jit64/Jit.h | 2 +- Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp | 3 ++- Source/Core/Core/Src/PowerPC/Jit64IL/IR.h | 4 ++-- Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp | 3 +++ .../Core/Core/Src/PowerPC/Jit64IL/JitIL_SystemRegisters.cpp | 2 +- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index bc0e671f24..e1692076d1 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -300,15 +300,13 @@ void Jit64::Cleanup() ABI_CallFunctionCCC((void *)&PowerPC::UpdatePerformanceMonitor, js.downcountAmount, jit->js.numLoadStoreInst, jit->js.numFloatingPointInst); } -void Jit64::WriteExit(u32 destination, int exit_num, bool force_ee_check) +void Jit64::WriteExit(u32 destination, int exit_num) { Cleanup(); // External exceptions are checked when the following instruction sets the <= 0 flag. // If we need to force the check, execute a useless SUB EAX, EAX SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount)); - if (force_ee_check) - SUB(32, R(EAX), R(EAX)); //If nobody has taken care of this yet (this can be removed when all branches are done) JitBlock *b = js.curBlock; @@ -317,7 +315,7 @@ void Jit64::WriteExit(u32 destination, int exit_num, bool force_ee_check) // Link opportunity! int block = blocks.GetBlockNumberFromStartAddress(destination); - if (!force_ee_check && block >= 0 && jo.enableBlocklink) + if (block >= 0 && jo.enableBlocklink) { // It exists! Joy of joy! JMP(blocks.GetBlock(block)->checkedEntry, true); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h index 08de7c4609..1ebd476134 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h @@ -112,7 +112,7 @@ public: // Utilities for use by opcodes - void WriteExit(u32 destination, int exit_num, bool force_ee_check = false); + void WriteExit(u32 destination, int exit_num); void WriteExitDestInEAX(); void WriteExceptionExit(); void WriteExternalExceptionExit(); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp index b68f4a926c..5cb7f0e13b 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -125,7 +125,8 @@ void Jit64::mtmsr(UGeckoInstruction inst) // Force an external exception when going out of mtmsr in order to check // immediately for interrupts that were delayed because of MSR.EE=0. - WriteExit(js.compilerPC + 4, 0, true); + MOV(32, M(&PC), Imm32(js.compilerPC + 4)); + WriteExceptionExit(); js.firstFPInstructionFound = false; } diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h index 77f7d6977b..7fabd946f9 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h @@ -276,8 +276,8 @@ public: InstLoc EmitLoadMSR() { return FoldZeroOp(LoadMSR, 0); } - InstLoc EmitStoreMSR(InstLoc val) { - return FoldUOp(StoreMSR, val); + InstLoc EmitStoreMSR(InstLoc val, InstLoc pc) { + return FoldBiOp(StoreMSR, val, pc); } InstLoc EmitStoreFPRF(InstLoc value) { return FoldUOp(StoreFPRF, value); diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp index e91291fa90..448f51d1c6 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp @@ -994,8 +994,11 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak break; } case StoreMSR: { + unsigned InstLoc = ibuild->GetImmValue(getOp2(I)); regStoreInstToConstLoc(RI, 32, getOp1(I), &MSR); regNormalRegClear(RI, I); + Jit->MOV(32, M(&PC), Imm32(InstLoc + 4)); + Jit->WriteExceptionExit(); break; } case StoreGQR: { diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_SystemRegisters.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_SystemRegisters.cpp index f3e25dc2dd..ac914bec94 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_SystemRegisters.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_SystemRegisters.cpp @@ -106,7 +106,7 @@ void JitIL::mfspr(UGeckoInstruction inst) // -------------- void JitIL::mtmsr(UGeckoInstruction inst) { - ibuild.EmitStoreMSR(ibuild.EmitLoadGReg(inst.RS)); + ibuild.EmitStoreMSR(ibuild.EmitLoadGReg(inst.RS), ibuild.EmitIntConst(js.compilerPC)); ibuild.EmitBranchUncond(ibuild.EmitIntConst(js.compilerPC + 4)); } // ============== From bfc797ede1d616c3060a2545529087a0ad2af1b5 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Sat, 16 Jun 2012 14:39:17 +0200 Subject: [PATCH 3/4] Removed an obsolete comment --- Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index e1692076d1..04015afca6 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -304,8 +304,6 @@ void Jit64::WriteExit(u32 destination, int exit_num) { Cleanup(); - // External exceptions are checked when the following instruction sets the <= 0 flag. - // If we need to force the check, execute a useless SUB EAX, EAX SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount)); //If nobody has taken care of this yet (this can be removed when all branches are done) From 76a13604ef49b522281af75675f044d59a74e871 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Tue, 19 Jun 2012 06:35:30 +0200 Subject: [PATCH 4/4] Optimize mtmsr by going to an exception exit only if EE are enabled and some exceptions are pending. --- .../Src/PowerPC/Jit64/Jit_SystemRegisters.cpp | 20 ++++++++++++++++--- .../Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp | 17 +++++++++++++++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp index 5cb7f0e13b..b977e82b28 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -123,10 +123,24 @@ void Jit64::mtmsr(UGeckoInstruction inst) gpr.Flush(FLUSH_ALL); fpr.Flush(FLUSH_ALL); - // Force an external exception when going out of mtmsr in order to check - // immediately for interrupts that were delayed because of MSR.EE=0. + // If some exceptions are pending and EE are now enabled, force checking + // external exceptions when going out of mtmsr in order to execute delayed + // interrupts as soon as possible. + MOV(32, R(EAX), M(&MSR)); + TEST(32, R(EAX), Imm32(0x8000)); + FixupBranch eeDisabled = J_CC(CC_Z); + + MOV(32, R(EAX), M((void*)&PowerPC::ppcState.Exceptions)); + TEST(32, R(EAX), R(EAX)); + FixupBranch noExceptionsPending = J_CC(CC_Z); + MOV(32, M(&PC), Imm32(js.compilerPC + 4)); - WriteExceptionExit(); + WriteExternalExceptionExit(); + + SetJumpTarget(eeDisabled); + SetJumpTarget(noExceptionsPending); + WriteExit(js.compilerPC + 4, 0); + js.firstFPInstructionFound = false; } diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp index 448f51d1c6..d9aa46f6b5 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp @@ -997,8 +997,23 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak unsigned InstLoc = ibuild->GetImmValue(getOp2(I)); regStoreInstToConstLoc(RI, 32, getOp1(I), &MSR); regNormalRegClear(RI, I); + + // If some exceptions are pending and EE are now enabled, force checking + // external exceptions when going out of mtmsr in order to execute delayed + // interrupts as soon as possible. + Jit->MOV(32, R(EAX), M(&MSR)); + Jit->TEST(32, R(EAX), Imm32(0x8000)); + FixupBranch eeDisabled = Jit->J_CC(CC_Z); + + Jit->MOV(32, R(EAX), M((void*)&PowerPC::ppcState.Exceptions)); + Jit->TEST(32, R(EAX), R(EAX)); + FixupBranch noExceptionsPending = Jit->J_CC(CC_Z); + Jit->MOV(32, M(&PC), Imm32(InstLoc + 4)); - Jit->WriteExceptionExit(); + Jit->WriteExceptionExit(); // TODO: Implement WriteExternalExceptionExit for JitIL + + Jit->SetJumpTarget(eeDisabled); + Jit->SetJumpTarget(noExceptionsPending); break; } case StoreGQR: {