From 9e398fd418027e4932a1539f7d382b70e8acc408 Mon Sep 17 00:00:00 2001 From: skidau Date: Fri, 2 Mar 2012 18:53:41 +1100 Subject: [PATCH 01/16] Added an external exception check when the CPU writes to the FIFO. This allows the CPU time to service FIFO overflows. Fixes random hangs caused by FIFO overflows and desyncs like in "The Last Story" and "Battalion Wars 2". Thanks to marcosvitali for the research. Fixes issue 5209. Fixes issue 5150. Fixes issue 5055. Fixes issue 4889. Fixes issue 4061. Fixes issue 4010. Fixes issue 3902. --- Source/Core/Core/Src/HW/GPFifo.cpp | 14 ++++++++++-- .../Interpreter/Interpreter_LoadStore.cpp | 4 ++-- Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 19 ++++++++++++++++ Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp | 6 ++--- Source/Core/Core/Src/PowerPC/Jit64IL/IR.h | 7 ++++-- .../Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp | 17 ++++++++++++++ .../Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp | 5 +++++ .../Core/Core/Src/PowerPC/JitCommon/JitBase.h | 4 ++++ .../Core/Src/PowerPC/JitCommon/JitCache.cpp | 11 +++++----- .../Core/Src/PowerPC/JitCommon/JitCache.h | 2 +- Source/Core/Core/Src/PowerPC/PPCCache.cpp | 2 +- .../Core/VideoCommon/Src/CommandProcessor.cpp | 22 ------------------- .../Core/VideoCommon/Src/CommandProcessor.h | 1 - Source/Core/VideoCommon/Src/Fifo.cpp | 3 +-- 14 files changed, 75 insertions(+), 42 deletions(-) diff --git a/Source/Core/Core/Src/HW/GPFifo.cpp b/Source/Core/Core/Src/HW/GPFifo.cpp index 4d72317e0d..35d678a411 100644 --- a/Source/Core/Core/Src/HW/GPFifo.cpp +++ b/Source/Core/Core/Src/HW/GPFifo.cpp @@ -19,9 +19,9 @@ #include "ChunkFile.h" #include "ProcessorInterface.h" #include "Memmap.h" -#include "../PowerPC/PowerPC.h" - #include "VideoBackendBase.h" +#include "../PowerPC/JitCommon/JitBase.h" +#include "../PowerPC/PowerPC.h" #include "GPFifo.h" @@ -96,6 +96,16 @@ void STACKALIGN CheckGatherPipe() // move back the spill bytes memmove(m_gatherPipe, m_gatherPipe + cnt, m_gatherPipeCount); + + // Profile where the FIFO writes are occurring. + const u32 addr = PC - 4; + if (jit && (jit->js.fifoWriteAddresses.find(addr)) == (jit->js.fifoWriteAddresses.end())) + { + jit->js.fifoWriteAddresses.insert(addr); + + // Invalidate the JIT block so that it gets recompiled with the external exception check included. + jit->GetBlockCache()->InvalidateICache(addr, 8); + } } } diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp index a7955c0982..cad4761e55 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp @@ -367,7 +367,7 @@ void Interpreter::dcbf(UGeckoInstruction _inst) if (jit) { u32 address = Helper_Get_EA_X(_inst); - jit->GetBlockCache()->InvalidateICache(address & ~0x1f); + jit->GetBlockCache()->InvalidateICache(address & ~0x1f, 32); } } @@ -378,7 +378,7 @@ void Interpreter::dcbi(UGeckoInstruction _inst) if (jit) { u32 address = Helper_Get_EA_X(_inst); - jit->GetBlockCache()->InvalidateICache(address & ~0x1f); + jit->GetBlockCache()->InvalidateICache(address & ~0x1f, 32); } } diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index 0d31893b53..a98df95fc3 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -41,6 +41,7 @@ #include "JitAsm.h" #include "JitRegCache.h" #include "Jit64_Tables.h" +#include "HW/ProcessorInterface.h" using namespace Gen; using namespace PowerPC; @@ -569,6 +570,24 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc SetJumpTarget(b1); } + // Add an external exception check if the instruction writes to the FIFO. + if (jit->js.fifoWriteAddresses.find(js.compilerPC) != jit->js.fifoWriteAddresses.end()) + { + gpr.Flush(FLUSH_ALL); + fpr.Flush(FLUSH_ALL); + + TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT)); + FixupBranch noExtException = J_CC(CC_Z); + TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); + FixupBranch noCPInt = J_CC(CC_Z); + + MOV(32, M(&PC), Imm32(js.compilerPC)); + WriteExceptionExit(); + + SetJumpTarget(noCPInt); + SetJumpTarget(noExtException); + } + Jit64Tables::CompileInstruction(ops[i]); if (js.memcheck && (opinfo->flags & FL_LOADSTORE)) diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp index 3a60a0ae11..afab21b30e 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp @@ -1260,8 +1260,8 @@ static const std::string opcodeNames[] = { "FResult_End", "StorePaired", "StoreSingle", "StoreDouble", "StoreFReg", "FDCmpCR", "CInt16", "CInt32", "SystemCall", "RFIExit", "InterpreterBranch", "IdleBranch", "ShortIdleLoop", - "FPExceptionCheckStart", "FPExceptionCheckEnd", "ISIException", "Tramp", - "BlockStart", "BlockEnd", "Int3", + "FPExceptionCheckStart", "FPExceptionCheckEnd", "ISIException", "ExtExceptionCheck", + "Tramp", "BlockStart", "BlockEnd", "Int3", }; static const unsigned alwaysUsedList[] = { InterpreterFallback, StoreGReg, StoreCR, StoreLink, StoreCTR, StoreMSR, @@ -1269,7 +1269,7 @@ static const unsigned alwaysUsedList[] = { Store16, Store32, StoreSingle, StoreDouble, StorePaired, StoreFReg, FDCmpCR, BlockStart, BlockEnd, IdleBranch, BranchCond, BranchUncond, ShortIdleLoop, SystemCall, InterpreterBranch, RFIExit, FPExceptionCheckStart, - FPExceptionCheckEnd, ISIException, Int3, Tramp, Nop + FPExceptionCheckEnd, ISIException, ExtExceptionCheck, Int3, Tramp, Nop }; static const unsigned extra8RegList[] = { LoadGReg, LoadCR, LoadGQR, LoadFReg, LoadFRegDENToZero, diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h index aca3dd0e37..284cbe6538 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h @@ -165,10 +165,10 @@ enum Opcode { ShortIdleLoop, // Idle loop seen in homebrew like wii mahjong, // just a branch - // used for MMU, at least until someone + // used for exception checking, at least until someone // has a better idea of integrating it FPExceptionCheckStart, FPExceptionCheckEnd, - ISIException, + ISIException,ExtExceptionCheck, // "Opcode" representing a register too far away to // reference directly; this is a size optimization Tramp, @@ -411,6 +411,9 @@ public: InstLoc EmitISIException(InstLoc dest) { return EmitUOp(ISIException, dest); } + InstLoc EmitExtExceptionCheck(InstLoc pc) { + return EmitUOp(ExtExceptionCheck, pc); + } InstLoc EmitRFIExit() { return FoldZeroOp(RFIExit, 0); } diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp index e1807cfbb4..6648189809 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp @@ -50,6 +50,7 @@ The register allocation is linear scan allocation. #include "../../../../Common/Src/CPUDetect.h" #include "MathUtil.h" #include "../../Core.h" +#include "HW/ProcessorInterface.h" static ThunkManager thunks; @@ -761,6 +762,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak case FPExceptionCheckStart: case FPExceptionCheckEnd: case ISIException: + case ExtExceptionCheck: case Int3: case Tramp: // No liveness effects @@ -1920,6 +1922,21 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak Jit->WriteExceptionExit(); break; } + case ExtExceptionCheck: { + unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); + + Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT)); + FixupBranch noExtException = Jit->J_CC(CC_Z); + Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); + FixupBranch noCPInt = Jit->J_CC(CC_Z); + + Jit->MOV(32, M(&PC), Imm32(InstLoc)); + Jit->WriteExceptionExit(); + + Jit->SetJumpTarget(noCPInt); + Jit->SetJumpTarget(noExtException); + break; + } case Int3: { Jit->INT3(); break; diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp index 75755de5cb..96afff1613 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp @@ -648,6 +648,11 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc { ibuild.EmitFPExceptionCheckStart(ibuild.EmitIntConst(ops[i].address)); } + + if (jit->js.fifoWriteAddresses.find(js.compilerPC) != jit->js.fifoWriteAddresses.end()) + { + ibuild.EmitExtExceptionCheck(ibuild.EmitIntConst(ops[i].address)); + } JitILTables::CompileInstruction(ops[i]); diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h index b832e96e1f..be80754bdc 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h @@ -31,6 +31,8 @@ #include "PowerPCDisasm.h" #include "disasm.h" +#include + #define JIT_OPCODE 0 class JitBase : public CPUCoreBase, public EmuCodeBlock @@ -75,6 +77,8 @@ protected: u8* rewriteStart; JitBlock *curBlock; + + std::set fifoWriteAddresses; }; public: diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp index 422369d307..8f5ff5d820 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp @@ -390,13 +390,12 @@ bool JitBlock::ContainsAddress(u32 em_address) } - void JitBlockCache::InvalidateICache(u32 address) + void JitBlockCache::InvalidateICache(u32 address, const u32 length) { - address &= ~0x1f; // destroy JIT blocks // !! this works correctly under assumption that any two overlapping blocks end at the same address std::map, u32>::iterator it1 = block_map.lower_bound(std::make_pair(address, 0)), it2 = it1, it; - while (it2 != block_map.end() && it2->first.second < address + 0x20) + while (it2 != block_map.end() && it2->first.second < address + length) { DestroyBlock(it2->second, true); it2++; @@ -418,17 +417,17 @@ bool JitBlock::ContainsAddress(u32 em_address) if (address & JIT_ICACHE_VMEM_BIT) { u32 cacheaddr = address & JIT_ICACHE_MASK; - memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32); + memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, length); } else if (address & JIT_ICACHE_EXRAM_BIT) { u32 cacheaddr = address & JIT_ICACHEEX_MASK; - memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32); + memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, length); } else { u32 cacheaddr = address & JIT_ICACHE_MASK; - memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32); + memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, length); } #endif } diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h index 91d47a3d0e..7c19310e02 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h @@ -129,7 +129,7 @@ public: CompiledCode GetCompiledCodeFromBlock(int block_num); // DOES NOT WORK CORRECTLY WITH INLINING - void InvalidateICache(u32 em_address); + void InvalidateICache(u32 address, const u32 length); void DestroyBlock(int block_num, bool invalidate); // Not currently used diff --git a/Source/Core/Core/Src/PowerPC/PPCCache.cpp b/Source/Core/Core/Src/PowerPC/PPCCache.cpp index 704caa4a2c..6956e9db1c 100644 --- a/Source/Core/Core/Src/PowerPC/PPCCache.cpp +++ b/Source/Core/Core/Src/PowerPC/PPCCache.cpp @@ -110,7 +110,7 @@ namespace PowerPC #endif valid[set] = 0; if (jit) - jit->GetBlockCache()->InvalidateICache(addr); + jit->GetBlockCache()->InvalidateICache(addr & ~0x1f, 32); } u32 InstructionCache::ReadInstruction(u32 addr) diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index fc85b8e39d..dbe09aaa0e 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -60,7 +60,6 @@ volatile bool interruptSet= false; volatile bool interruptWaiting= false; volatile bool interruptTokenWaiting = false; volatile bool interruptFinishWaiting = false; -volatile bool OnOverflow = false; bool IsOnThread() { @@ -92,7 +91,6 @@ void DoState(PointerWrap &p) p.Do(interruptWaiting); p.Do(interruptTokenWaiting); p.Do(interruptFinishWaiting); - p.Do(OnOverflow); } inline void WriteLow (volatile u32& _reg, u16 lowbits) {Common::AtomicStore(_reg,(_reg & 0xFFFF0000) | lowbits);} @@ -135,7 +133,6 @@ void Init() bProcessFifoToLoWatermark = false; bProcessFifoAllDistance = false; isPossibleWaitingSetDrawDone = false; - OnOverflow = false; et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper); } @@ -449,26 +446,7 @@ void STACKALIGN GatherPipeBursted() Common::AtomicAdd(fifo.CPReadWriteDistance, GATHER_PIPE_SIZE); if (!IsOnThread()) - { RunGpu(); - } - else - { - if(fifo.CPReadWriteDistance == fifo.CPEnd - fifo.CPBase - 32) - { - if(!OnOverflow) - NOTICE_LOG(COMMANDPROCESSOR,"FIFO is almost in overflown, BreakPoint: %i", fifo.bFF_Breakpoint); - OnOverflow = true; - while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && - fifo.CPReadWriteDistance > fifo.CPEnd - fifo.CPBase - 64) - Common::YieldCPU(); - } - else - { - OnOverflow = false; - } - } - _assert_msg_(COMMANDPROCESSOR, fifo.CPReadWriteDistance <= fifo.CPEnd - fifo.CPBase, "FIFO is overflown by GatherPipe !\nCPU thread is too fast!"); diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.h b/Source/Core/VideoCommon/Src/CommandProcessor.h index db6772d66d..bb969fcb95 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.h +++ b/Source/Core/VideoCommon/Src/CommandProcessor.h @@ -35,7 +35,6 @@ extern volatile bool interruptSet; extern volatile bool interruptWaiting; extern volatile bool interruptTokenWaiting; extern volatile bool interruptFinishWaiting; -extern volatile bool OnOverflow; // internal hardware addresses enum diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index 842ff49e78..5cb3252816 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -137,8 +137,7 @@ void RunGpuLoop() CommandProcessor::SetCpStatus(); // check if we are able to run this buffer - while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && - fifo.CPReadWriteDistance && (!AtBreakpoint() || CommandProcessor::OnOverflow)) + while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint()) { if (!GpuRunningState) break; From 9e649ce79850f6c39fa16ea5a207659bb2e5b052 Mon Sep 17 00:00:00 2001 From: skidau Date: Sat, 3 Mar 2012 14:26:39 +1100 Subject: [PATCH 02/16] Added additional checks to ensure that only a FIFO breakpoint exception is handled. This fixes the hangs in games like de Blob, Xenoblade and Super Mario Galaxy introduced by r9e398fd41802. --- Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index a98df95fc3..07eb36d263 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -571,7 +571,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc } // Add an external exception check if the instruction writes to the FIFO. - if (jit->js.fifoWriteAddresses.find(js.compilerPC) != jit->js.fifoWriteAddresses.end()) + if (jit->js.fifoWriteAddresses.find(ops[i].address) != jit->js.fifoWriteAddresses.end()) { gpr.Flush(FLUSH_ALL); fpr.Flush(FLUSH_ALL); @@ -580,10 +580,16 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc FixupBranch noExtException = J_CC(CC_Z); TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); FixupBranch noCPInt = J_CC(CC_Z); + TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), + Imm32(ProcessorInterface::INT_CAUSE_PE_TOKEN | + ProcessorInterface::INT_CAUSE_PE_FINISH | + ProcessorInterface::INT_CAUSE_DSP)); + FixupBranch ClearInt = J_CC(CC_NZ); - MOV(32, M(&PC), Imm32(js.compilerPC)); + MOV(32, M(&PC), Imm32(ops[i].address)); WriteExceptionExit(); + SetJumpTarget(ClearInt); SetJumpTarget(noCPInt); SetJumpTarget(noExtException); } From 874e17e504c6c6b19f5a1eb9ef16c82bde179032 Mon Sep 17 00:00:00 2001 From: skidau Date: Sat, 3 Mar 2012 15:41:55 +1100 Subject: [PATCH 03/16] Added the corresponding change from r9e649ce79850 to JITIL. --- Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 9 +++------ Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp | 3 +++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index 07eb36d263..44ce9325b6 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -580,16 +580,13 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc FixupBranch noExtException = J_CC(CC_Z); TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); FixupBranch noCPInt = J_CC(CC_Z); - TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), - Imm32(ProcessorInterface::INT_CAUSE_PE_TOKEN | - ProcessorInterface::INT_CAUSE_PE_FINISH | - ProcessorInterface::INT_CAUSE_DSP)); - FixupBranch ClearInt = J_CC(CC_NZ); + TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_DSP)); + FixupBranch clearInt = J_CC(CC_NZ); MOV(32, M(&PC), Imm32(ops[i].address)); WriteExceptionExit(); - SetJumpTarget(ClearInt); + SetJumpTarget(clearInt); SetJumpTarget(noCPInt); SetJumpTarget(noExtException); } diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp index 6648189809..0152d0d96e 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp @@ -1929,10 +1929,13 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak FixupBranch noExtException = Jit->J_CC(CC_Z); Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); FixupBranch noCPInt = Jit->J_CC(CC_Z); + Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_DSP)); + FixupBranch clearInt = Jit->J_CC(CC_NZ); Jit->MOV(32, M(&PC), Imm32(InstLoc)); Jit->WriteExceptionExit(); + Jit->SetJumpTarget(clearInt); Jit->SetJumpTarget(noCPInt); Jit->SetJumpTarget(noExtException); break; From 5de8366db2ec084e95420b0853abb4d11a431ac0 Mon Sep 17 00:00:00 2001 From: skidau Date: Sun, 4 Mar 2012 08:10:46 +1100 Subject: [PATCH 04/16] Made the invalidation of the FIFO write JIT blocks more selective (efficient). Fixes the slowdown in the House of the Dead: Overkill cutscenes. --- Source/Core/Core/Src/HW/GPFifo.cpp | 7 +++---- Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 2 +- Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/Src/HW/GPFifo.cpp b/Source/Core/Core/Src/HW/GPFifo.cpp index 35d678a411..725db3011c 100644 --- a/Source/Core/Core/Src/HW/GPFifo.cpp +++ b/Source/Core/Core/Src/HW/GPFifo.cpp @@ -98,13 +98,12 @@ void STACKALIGN CheckGatherPipe() memmove(m_gatherPipe, m_gatherPipe + cnt, m_gatherPipeCount); // Profile where the FIFO writes are occurring. - const u32 addr = PC - 4; - if (jit && (jit->js.fifoWriteAddresses.find(addr)) == (jit->js.fifoWriteAddresses.end())) + if (jit && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end())) { - jit->js.fifoWriteAddresses.insert(addr); + jit->js.fifoWriteAddresses.insert(PC); // Invalidate the JIT block so that it gets recompiled with the external exception check included. - jit->GetBlockCache()->InvalidateICache(addr, 8); + jit->GetBlockCache()->InvalidateICache(PC, 4); } } } diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index 44ce9325b6..71718c6085 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -580,7 +580,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc FixupBranch noExtException = J_CC(CC_Z); TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); FixupBranch noCPInt = J_CC(CC_Z); - TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_DSP)); + TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_VI | ProcessorInterface::INT_CAUSE_PE_TOKEN | ProcessorInterface::INT_CAUSE_PE_FINISH)); FixupBranch clearInt = J_CC(CC_NZ); MOV(32, M(&PC), Imm32(ops[i].address)); diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp index 0152d0d96e..cffc3b5feb 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp @@ -1929,7 +1929,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak FixupBranch noExtException = Jit->J_CC(CC_Z); Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); FixupBranch noCPInt = Jit->J_CC(CC_Z); - Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_DSP)); + Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_VI | ProcessorInterface::INT_CAUSE_PE_TOKEN | ProcessorInterface::INT_CAUSE_PE_FINISH)); FixupBranch clearInt = Jit->J_CC(CC_NZ); Jit->MOV(32, M(&PC), Imm32(InstLoc)); From a53916ff5d7d2840ef8612bc16511554d259e848 Mon Sep 17 00:00:00 2001 From: skidau Date: Sun, 4 Mar 2012 23:42:33 +1100 Subject: [PATCH 05/16] Changed the detection of FIFO write addresses to writes at the gather pipe boundary. This speeds up games which frequently write to the gather pipe like the pre-rendered movies in The Last Story. Added some code to unlink invalidated blocks so that the recompiled block can be linked (speed-up). --- Source/Core/Core/Src/HW/GPFifo.cpp | 2 +- .../Core/Src/PowerPC/JitCommon/JitCache.cpp | 22 ++++++++++++++++++- .../Core/Src/PowerPC/JitCommon/JitCache.h | 1 + 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/Src/HW/GPFifo.cpp b/Source/Core/Core/Src/HW/GPFifo.cpp index 725db3011c..fd81f099e9 100644 --- a/Source/Core/Core/Src/HW/GPFifo.cpp +++ b/Source/Core/Core/Src/HW/GPFifo.cpp @@ -98,7 +98,7 @@ void STACKALIGN CheckGatherPipe() memmove(m_gatherPipe, m_gatherPipe + cnt, m_gatherPipeCount); // Profile where the FIFO writes are occurring. - if (jit && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end())) + if (m_gatherPipeCount == 0 && jit && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end())) { jit->js.fifoWriteAddresses.insert(PC); diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp index 8f5ff5d820..bccb218fd9 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp @@ -353,6 +353,24 @@ bool JitBlock::ContainsAddress(u32 em_address) } } + void JitBlockCache::UnlinkBlock(int i) + { + JitBlock &b = blocks[i]; + std::map::iterator iter; + pair::iterator, multimap::iterator> ppp; + ppp = links_to.equal_range(b.originalAddress); + if (ppp.first == ppp.second) + return; + for (multimap::iterator iter2 = ppp.first; iter2 != ppp.second; ++iter2) { + JitBlock &sourceBlock = blocks[iter2->second]; + for (int e = 0; e < 2; e++) + { + if (sourceBlock.exitAddress[e] == b.originalAddress) + sourceBlock.linkStatus[e] = false; + } + } + } + void JitBlockCache::DestroyBlock(int block_num, bool invalidate) { if (block_num < 0 || block_num >= num_blocks) @@ -375,7 +393,9 @@ bool JitBlock::ContainsAddress(u32 em_address) Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress); #endif - // We don't unlink blocks, we just send anyone who tries to run them back to the dispatcher. + UnlinkBlock(block_num); + + // Send anyone who tries to run this block back to the dispatcher. // Not entirely ideal, but .. pretty good. // Spurious entrances from previously linked blocks can only come through checkedEntry XEmitter emit((u8 *)b.checkedEntry); diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h index 7c19310e02..16f16d6d14 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h @@ -87,6 +87,7 @@ class JitBlockCache bool RangeIntersect(int s1, int e1, int s2, int e2) const; void LinkBlockExits(int i); void LinkBlock(int i); + void UnlinkBlock(int i); public: JitBlockCache() : From b0f75f17ae19484735675fea348f7e95740f597f Mon Sep 17 00:00:00 2001 From: marcosvitali Date: Mon, 5 Mar 2012 02:40:10 -0300 Subject: [PATCH 06/16] This release still fixed the hangs produced by fifo overflow without sacrifice performance. For example you can test Tutorial moves at the beginning of The last history now is fluid 30/60. Shuffle2: I've delete the hacky line, I think is not necessary anymore. Additional some clean in CommandProcessor. Please test The Last Story and others games affected in the previous commits and give me a feedback. --- Source/Core/Common/Src/VideoBackendBase.h | 2 + Source/Core/Core/Src/HW/GPFifo.cpp | 5 ++- Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 3 -- .../Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp | 4 +- .../Core/VideoCommon/Src/CommandProcessor.cpp | 39 +++++++++++-------- .../Core/VideoCommon/Src/CommandProcessor.h | 1 + Source/Core/VideoCommon/Src/MainBase.cpp | 5 +++ Source/Core/VideoCommon/Src/PixelEngine.cpp | 2 - .../Plugin_VideoSoftware/Src/SWmain.cpp | 6 +++ .../Plugin_VideoSoftware/Src/VideoBackend.h | 2 +- 10 files changed, 41 insertions(+), 28 deletions(-) diff --git a/Source/Core/Common/Src/VideoBackendBase.h b/Source/Core/Common/Src/VideoBackendBase.h index 28c8f23246..96f639832b 100644 --- a/Source/Core/Common/Src/VideoBackendBase.h +++ b/Source/Core/Common/Src/VideoBackendBase.h @@ -119,6 +119,7 @@ public: virtual void Video_GatherPipeBursted() = 0; virtual bool Video_IsPossibleWaitingSetDrawDone() = 0; + virtual bool Video_IsHiWatermarkActive() = 0; virtual void Video_AbortFrame() = 0; virtual readFn16 Video_CPRead16() = 0; @@ -159,6 +160,7 @@ class VideoBackendHardware : public VideoBackend void Video_GatherPipeBursted(); bool Video_IsPossibleWaitingSetDrawDone(); + bool Video_IsHiWatermarkActive(); void Video_AbortFrame(); readFn16 Video_CPRead16(); diff --git a/Source/Core/Core/Src/HW/GPFifo.cpp b/Source/Core/Core/Src/HW/GPFifo.cpp index fd81f099e9..9bae7bb621 100644 --- a/Source/Core/Core/Src/HW/GPFifo.cpp +++ b/Source/Core/Core/Src/HW/GPFifo.cpp @@ -96,9 +96,10 @@ void STACKALIGN CheckGatherPipe() // move back the spill bytes memmove(m_gatherPipe, m_gatherPipe + cnt, m_gatherPipeCount); - + // Profile where the FIFO writes are occurring. - if (m_gatherPipeCount == 0 && jit && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end())) + + if (g_video_backend->Video_IsHiWatermarkActive() && jit && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end())) { jit->js.fifoWriteAddresses.insert(PC); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index 71718c6085..417d1159da 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -580,13 +580,10 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc FixupBranch noExtException = J_CC(CC_Z); TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); FixupBranch noCPInt = J_CC(CC_Z); - TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_VI | ProcessorInterface::INT_CAUSE_PE_TOKEN | ProcessorInterface::INT_CAUSE_PE_FINISH)); - FixupBranch clearInt = J_CC(CC_NZ); MOV(32, M(&PC), Imm32(ops[i].address)); WriteExceptionExit(); - SetJumpTarget(clearInt); SetJumpTarget(noCPInt); SetJumpTarget(noExtException); } diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp index cffc3b5feb..811440d098 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp @@ -1929,13 +1929,11 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak FixupBranch noExtException = Jit->J_CC(CC_Z); Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); FixupBranch noCPInt = Jit->J_CC(CC_Z); - Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_VI | ProcessorInterface::INT_CAUSE_PE_TOKEN | ProcessorInterface::INT_CAUSE_PE_FINISH)); - FixupBranch clearInt = Jit->J_CC(CC_NZ); Jit->MOV(32, M(&PC), Imm32(InstLoc)); Jit->WriteExceptionExit(); - Jit->SetJumpTarget(clearInt); + Jit->SetJumpTarget(noCPInt); Jit->SetJumpTarget(noExtException); break; diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index dbe09aaa0e..38b342b76c 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -56,6 +56,7 @@ static bool bProcessFifoToLoWatermark = false; static bool bProcessFifoAllDistance = false; volatile bool isPossibleWaitingSetDrawDone = false; +volatile bool isHiWatermarkActive = false; volatile bool interruptSet= false; volatile bool interruptWaiting= false; volatile bool interruptTokenWaiting = false; @@ -85,7 +86,7 @@ void DoState(PointerWrap &p) p.Do(bProcessFifoToLoWatermark); p.Do(bProcessFifoAllDistance); - + p.Do(isHiWatermarkActive); p.Do(isPossibleWaitingSetDrawDone); p.Do(interruptSet); p.Do(interruptWaiting); @@ -133,6 +134,7 @@ void Init() bProcessFifoToLoWatermark = false; bProcessFifoAllDistance = false; isPossibleWaitingSetDrawDone = false; + isHiWatermarkActive = false; et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper); } @@ -141,7 +143,6 @@ void Read16(u16& _rReturnValue, const u32 _Address) { INFO_LOG(COMMANDPROCESSOR, "(r): 0x%08x", _Address); - ProcessFifoEvents(); switch (_Address & 0xFFF) { case STATUS_REGISTER: @@ -409,7 +410,6 @@ void Write16(const u16 _Value, const u32 _Address) if (!IsOnThread()) RunGpu(); - ProcessFifoEvents(); } void Read32(u32& _rReturnValue, const u32 _Address) @@ -425,7 +425,6 @@ void Write32(const u32 _Data, const u32 _Address) void STACKALIGN GatherPipeBursted() { - ProcessFifoEvents(); // if we aren't linked, we don't care about gather pipe data if (!m_CPCtrlReg.GPLinkEnable) { @@ -487,17 +486,18 @@ void AbortFrame() void SetOverflowStatusFromGatherPipe() { - if (!fifo.bFF_HiWatermarkInt) return; + fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark); - fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark); + isHiWatermarkActive = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt && m_CPCtrlReg.GPReadEnable; - bool interrupt = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt && - m_CPCtrlReg.GPLinkEnable && m_CPCtrlReg.GPReadEnable; - - if (interrupt != interruptSet && interrupt) - CommandProcessor::UpdateInterrupts(true); - + if (isHiWatermarkActive) + { + interruptSet = true; + INFO_LOG(COMMANDPROCESSOR,"Interrupt set"); + ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true); + } + } void SetCpStatus() @@ -505,7 +505,7 @@ void SetCpStatus() // overflow & underflow check fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark); fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark); - + // breakpoint if (fifo.bFF_BPEnable) @@ -540,13 +540,18 @@ void SetCpStatus() bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable; + isHiWatermarkActive = ovfInt && m_CPCtrlReg.GPReadEnable; + if (interrupt != interruptSet && !interruptWaiting) { u64 userdata = interrupt?1:0; if (IsOnThread()) { - interruptWaiting = true; - CommandProcessor::UpdateInterruptsFromVideoBackend(userdata); + if(!interrupt || bpInt || undfInt) + { + interruptWaiting = true; + CommandProcessor::UpdateInterruptsFromVideoBackend(userdata); + } } else CommandProcessor::UpdateInterrupts(userdata); @@ -631,8 +636,8 @@ void SetCpControlRegister() ProcessorInterface::Fifo_CPUEnd = fifo.CPEnd; } // If overflown happens process the fifo to LoWatemark - if (bProcessFifoToLoWatermark) - ProcessFifoToLoWatermark(); + //if (bProcessFifoToLoWatermark) + // ProcessFifoToLoWatermark(); if(fifo.bFF_GPReadEnable && !m_CPCtrlReg.GPReadEnable) { diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.h b/Source/Core/VideoCommon/Src/CommandProcessor.h index bb969fcb95..2bf965a3ba 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.h +++ b/Source/Core/VideoCommon/Src/CommandProcessor.h @@ -31,6 +31,7 @@ namespace CommandProcessor extern SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread. extern volatile bool isPossibleWaitingSetDrawDone; //This one is used for sync gfx thread and emulator thread. +extern volatile bool isHiWatermarkActive; extern volatile bool interruptSet; extern volatile bool interruptWaiting; extern volatile bool interruptTokenWaiting; diff --git a/Source/Core/VideoCommon/Src/MainBase.cpp b/Source/Core/VideoCommon/Src/MainBase.cpp index af21ebbb94..0b1258a662 100644 --- a/Source/Core/VideoCommon/Src/MainBase.cpp +++ b/Source/Core/VideoCommon/Src/MainBase.cpp @@ -250,6 +250,11 @@ bool VideoBackendHardware::Video_IsPossibleWaitingSetDrawDone() return CommandProcessor::isPossibleWaitingSetDrawDone; } +bool VideoBackendHardware::Video_IsHiWatermarkActive() +{ + return CommandProcessor::isHiWatermarkActive; +} + void VideoBackendHardware::Video_AbortFrame() { CommandProcessor::AbortFrame(); diff --git a/Source/Core/VideoCommon/Src/PixelEngine.cpp b/Source/Core/VideoCommon/Src/PixelEngine.cpp index 456e0fb535..ec0683742f 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.cpp +++ b/Source/Core/VideoCommon/Src/PixelEngine.cpp @@ -180,7 +180,6 @@ void Init() void Read16(u16& _uReturnValue, const u32 _iAddress) { DEBUG_LOG(PIXELENGINE, "(r16) 0x%08x", _iAddress); - CommandProcessor::ProcessFifoEvents(); switch (_iAddress & 0xFFF) { // CPU Direct Access EFB Raster State Config @@ -334,7 +333,6 @@ void Write16(const u16 _iValue, const u32 _iAddress) break; } - CommandProcessor::ProcessFifoEvents(); } void Write32(const u32 _iValue, const u32 _iAddress) diff --git a/Source/Plugins/Plugin_VideoSoftware/Src/SWmain.cpp b/Source/Plugins/Plugin_VideoSoftware/Src/SWmain.cpp index abfd9155f5..c591bd0957 100644 --- a/Source/Plugins/Plugin_VideoSoftware/Src/SWmain.cpp +++ b/Source/Plugins/Plugin_VideoSoftware/Src/SWmain.cpp @@ -215,6 +215,12 @@ bool VideoSoftware::Video_IsPossibleWaitingSetDrawDone(void) return false; } +bool VideoSoftware::Video_IsHiWatermarkActive(void) +{ + return false; +} + + void VideoSoftware::Video_AbortFrame(void) { } diff --git a/Source/Plugins/Plugin_VideoSoftware/Src/VideoBackend.h b/Source/Plugins/Plugin_VideoSoftware/Src/VideoBackend.h index 08b4c155ad..7c52e34291 100644 --- a/Source/Plugins/Plugin_VideoSoftware/Src/VideoBackend.h +++ b/Source/Plugins/Plugin_VideoSoftware/Src/VideoBackend.h @@ -36,7 +36,7 @@ class VideoSoftware : public VideoBackend void Video_SetRendering(bool bEnabled); void Video_GatherPipeBursted(); - + bool Video_IsHiWatermarkActive(); bool Video_IsPossibleWaitingSetDrawDone(); void Video_AbortFrame(); From c2e6fdf09f33f7765526fac680d13af9ba744125 Mon Sep 17 00:00:00 2001 From: marcosvitali Date: Thu, 8 Mar 2012 02:47:55 -0300 Subject: [PATCH 07/16] - I've fixed possibles random hangs in DC mode. - I've fixed hangs in DC mode in (Simpsons, Monkey Island, Pokemon XD, etc) - I've implemented accurate manage of Pixel Engine Interrupts, now the GPU loop is stopped when a PE Interrupt needs to be managed and resume when Pixel Engine finish, I think now, the Fifo in DC mode is more accurate than SC mode. :) Time to close the big fifo Issue 3694 (snif), please if you have a possible fifo issue report this like a game issue. I was working with Skid_AU together, especially thanks for him. Test a lot all games, and compare the performance with the master maybe this accuracy has a cost (not a lot). I think now the fifo is very stable, overflow fixed, random hang fixed, if you have a game with a hang with this rev and not in master please report this. --- Source/Core/VideoCommon/Src/CommandProcessor.cpp | 5 +++-- Source/Core/VideoCommon/Src/Fifo.cpp | 3 ++- Source/Core/VideoCommon/Src/PixelEngine.cpp | 5 +++++ Source/Core/VideoCommon/Src/PixelEngine.h | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index 38b342b76c..4fd7e88f5e 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -596,8 +596,8 @@ void SetCpStatusRegister() // Here always there is one fifo attached to the GPU m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint; - m_CPStatusReg.ReadIdle = (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint); - m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance; + m_CPStatusReg.ReadIdle = (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint) ; + m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance || (IsOnThread() && PixelEngine::WaitingForPEInterrupt()); m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark; m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark; @@ -620,6 +620,7 @@ void SetCpControlRegister() if (!fifo.bFF_GPReadEnable && m_CPCtrlReg.GPReadEnable && !m_CPCtrlReg.BPEnable) { + ProcessFifoEvents(); PixelEngine::ResetSetFinish(); } diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index 5cb3252816..2e60055c97 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -22,6 +22,7 @@ #include "Atomic.h" #include "OpcodeDecoding.h" #include "CommandProcessor.h" +#include "PixelEngine.h" #include "ChunkFile.h" #include "Fifo.h" #include "HW/Memmap.h" @@ -137,7 +138,7 @@ void RunGpuLoop() CommandProcessor::SetCpStatus(); // check if we are able to run this buffer - while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint()) + while (GpuRunningState && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() && !PixelEngine::WaitingForPEInterrupt()) { if (!GpuRunningState) break; diff --git a/Source/Core/VideoCommon/Src/PixelEngine.cpp b/Source/Core/VideoCommon/Src/PixelEngine.cpp index ec0683742f..09cb9b8a5c 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.cpp +++ b/Source/Core/VideoCommon/Src/PixelEngine.cpp @@ -468,4 +468,9 @@ void ResetSetToken() } CommandProcessor::interruptTokenWaiting = false; } + +bool WaitingForPEInterrupt() +{ + return CommandProcessor::interruptFinishWaiting || CommandProcessor::interruptTokenWaiting || interruptSetFinish || interruptSetToken; +} } // end of namespace PixelEngine diff --git a/Source/Core/VideoCommon/Src/PixelEngine.h b/Source/Core/VideoCommon/Src/PixelEngine.h index dd0304fbe1..5e64300ef3 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.h +++ b/Source/Core/VideoCommon/Src/PixelEngine.h @@ -80,7 +80,7 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge); void SetFinish(void); void ResetSetFinish(void); void ResetSetToken(void); -bool AllowIdleSkipping(); +bool WaitingForPEInterrupt(); // Bounding box functionality. Paper Mario (both) are a couple of the few games that use it. extern u16 bbox[4]; From 41652d6b1f391fdcd0f599463f689c0299cdc007 Mon Sep 17 00:00:00 2001 From: marcosvitali Date: Fri, 9 Mar 2012 01:33:29 -0300 Subject: [PATCH 08/16] I've fixed Metroid Prime 3 and 2 desync. And other games with desync because of FIFO Reset. That happens because FIFO_RW_DISTANCE_HI must be written first, for checking fifo.CPReadWriteDistance == 0, so some fifo resets was not managed in the right way. I didn't test Metroid 2 desync reported in Issue 4336 but I think is the same. About the flickering in MP2, I don't know for my is not related or yes, but you can test anyway. Fixed Issue 3902 Well now the FIFO is 99.99% finished :) --- Source/Core/VideoCommon/Src/CommandProcessor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index 4fd7e88f5e..a6e68f6298 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -388,10 +388,6 @@ void Write16(const u16 _Value, const u32 _Address) case FIFO_RW_DISTANCE_HI: WriteHigh((u32 &)fifo.CPReadWriteDistance, _Value); - DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_HI : %04x", _Value); - break; - case FIFO_RW_DISTANCE_LO: - WriteLow((u32 &)fifo.CPReadWriteDistance, _Value & 0xFFE0); if (fifo.CPReadWriteDistance == 0) { GPFifo::ResetGatherPipe(); @@ -401,6 +397,10 @@ void Write16(const u16 _Value, const u32 _Address) ResetVideoBuffer(); } IncrementCheckContextId(); + DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_HI : %04x", _Value); + break; + case FIFO_RW_DISTANCE_LO: + WriteLow((u32 &)fifo.CPReadWriteDistance, _Value & 0xFFE0); DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_LO : %04x", _Value); break; From 104603467be6cc15e63dfb5cadec8044edd1da46 Mon Sep 17 00:00:00 2001 From: marcosvitali Date: Fri, 9 Mar 2012 18:58:23 -0300 Subject: [PATCH 09/16] This commit fix games hanging because of my prior Revision c2e6fdf09f33 The external exceptions in dolphin are checking frequently but is different to real HW, so sometime the game is in a loop checking GPU STATUS, the exceptions doesn't checked, and the game hang.\ For solve this I need a trick: still waiting for the exception handler be linked but if CommandProcecsor is reading the GPStatus, resume this. This fixed "TimeSplitters: Future Perfect" broken in the Revision c2e6fdf09f33 and surely others games. --- Source/Core/VideoCommon/Src/CommandProcessor.cpp | 10 +++++++--- Source/Core/VideoCommon/Src/PixelEngine.cpp | 14 ++++++++------ Source/Core/VideoCommon/Src/PixelEngine.h | 1 + 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index a6e68f6298..77c02d1692 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -574,7 +574,7 @@ void ProcessFifoAllDistance() if (IsOnThread()) { while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && - fifo.CPReadWriteDistance && !AtBreakpoint()) + fifo.CPReadWriteDistance && !AtBreakpoint() && !PixelEngine::WaitingForPEInterrupt()) Common::YieldCPU(); } bProcessFifoAllDistance = false; @@ -597,10 +597,12 @@ void SetCpStatusRegister() m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint; m_CPStatusReg.ReadIdle = (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint) ; - m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance || (IsOnThread() && PixelEngine::WaitingForPEInterrupt()); + m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance; m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark; m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark; - + + PixelEngine::ResumeWaitingForPEInterrupt(); + INFO_LOG(COMMANDPROCESSOR,"\t Read from STATUS_REGISTER : %04x", m_CPStatusReg.Hex); DEBUG_LOG(COMMANDPROCESSOR, "(r) status: iBP %s | fReadIdle %s | fCmdIdle %s | iOvF %s | iUndF %s" , m_CPStatusReg.Breakpoint ? "ON" : "OFF" @@ -609,6 +611,8 @@ void SetCpStatusRegister() , m_CPStatusReg.OverflowHiWatermark ? "ON" : "OFF" , m_CPStatusReg.UnderflowLoWatermark ? "ON" : "OFF" ); + + } void SetCpControlRegister() diff --git a/Source/Core/VideoCommon/Src/PixelEngine.cpp b/Source/Core/VideoCommon/Src/PixelEngine.cpp index 09cb9b8a5c..750e8fbb40 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.cpp +++ b/Source/Core/VideoCommon/Src/PixelEngine.cpp @@ -356,22 +356,16 @@ void UpdateInterrupts() void UpdateTokenInterrupt(bool active) { - if(interruptSetToken != active) - { ProcessorInterface::SetInterrupt(INT_CAUSE_PE_TOKEN, active); interruptSetToken = active; - } } void UpdateFinishInterrupt(bool active) { - if(interruptSetFinish != active) - { ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH, active); interruptSetFinish = active; if (active) State::ProcessRequestedStates(0); - } } // TODO(mb2): Refactor SetTokenINT_OnMainThread(u64 userdata, int cyclesLate). @@ -473,4 +467,12 @@ bool WaitingForPEInterrupt() { return CommandProcessor::interruptFinishWaiting || CommandProcessor::interruptTokenWaiting || interruptSetFinish || interruptSetToken; } + +void ResumeWaitingForPEInterrupt() +{ + interruptSetFinish = false; + interruptSetToken = false; + CommandProcessor::interruptFinishWaiting = false; + CommandProcessor::interruptTokenWaiting = false; +} } // end of namespace PixelEngine diff --git a/Source/Core/VideoCommon/Src/PixelEngine.h b/Source/Core/VideoCommon/Src/PixelEngine.h index 5e64300ef3..64f959009f 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.h +++ b/Source/Core/VideoCommon/Src/PixelEngine.h @@ -81,6 +81,7 @@ void SetFinish(void); void ResetSetFinish(void); void ResetSetToken(void); bool WaitingForPEInterrupt(); +void ResumeWaitingForPEInterrupt(); // Bounding box functionality. Paper Mario (both) are a couple of the few games that use it. extern u16 bbox[4]; From fedf6055ce2d1ac9862eac8c2c112160b8d7fbe8 Mon Sep 17 00:00:00 2001 From: marcosvitali Date: Sun, 11 Mar 2012 12:40:39 -0300 Subject: [PATCH 10/16] I've fixed Super Monkey Ball in some cases when the game write the WriteReadDistance need to be safe like the SafeCPRead. This fix is not related with the previous commits, but the previous commits help me to see that because in the new scenery SMB was hanging. May be in the past also doesn't boot some times because of that. Please Test FZero boot also. Thanks. --- .../Core/VideoCommon/Src/CommandProcessor.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index 77c02d1692..dbf4907160 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -171,11 +171,23 @@ void Read16(u16& _rReturnValue, const u32 _Address) case FIFO_LO_WATERMARK_HI: _rReturnValue = ReadHigh(fifo.CPLoWatermark); return; case FIFO_RW_DISTANCE_LO: + if (IsOnThread()) + if(fifo.CPWritePointer >= fifo.SafeCPReadPointer) + _rReturnValue = ReadLow (fifo.CPWritePointer - fifo.SafeCPReadPointer); + else + _rReturnValue = ReadLow (fifo.CPEnd - fifo.CPWritePointer + fifo.SafeCPReadPointer); + else _rReturnValue = ReadLow (fifo.CPReadWriteDistance); DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_RW_DISTANCE_LO : %04x", _rReturnValue); return; case FIFO_RW_DISTANCE_HI: - _rReturnValue = ReadHigh(fifo.CPReadWriteDistance); + if (IsOnThread()) + if(fifo.CPWritePointer >= fifo.SafeCPReadPointer) + _rReturnValue = ReadHigh (fifo.CPWritePointer - fifo.SafeCPReadPointer); + else + _rReturnValue = ReadHigh (fifo.CPEnd - fifo.CPWritePointer + fifo.SafeCPReadPointer); + else + _rReturnValue = ReadHigh(fifo.CPReadWriteDistance); DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_RW_DISTANCE_HI : %04x", _rReturnValue); return; case FIFO_WRITE_POINTER_LO: @@ -356,6 +368,7 @@ void Write16(const u16 _Value, const u32 _Address) break; case FIFO_READ_POINTER_HI: WriteHigh((u32 &)fifo.CPReadPointer, _Value); + fifo.SafeCPReadPointer = fifo.CPReadPointer; DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_READ_POINTER_HI : %04x", _Value); break; @@ -596,7 +609,7 @@ void SetCpStatusRegister() // Here always there is one fifo attached to the GPU m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint; - m_CPStatusReg.ReadIdle = (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint) ; + m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint) ; m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance; m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark; m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark; From 352ab2ba4394180739d7315c0c505aab83ffe211 Mon Sep 17 00:00:00 2001 From: marcosvitali Date: Tue, 13 Mar 2012 01:44:10 -0300 Subject: [PATCH 11/16] Improved the CheckException for the GatherPipe writes in JIT, now only the External Exceptions are processed. We Didn't Check 0x0008000 in PowerPC::ppcState.msr this was killing the performance, this also fix a hang when this check is performed. SMG for example. Deleted the HiWatermark condition from GPFifo. Please test games affected in this Revision 9e649ce79850, and games affected in this Revision b0f75f17ae19. I do not want to excite the game players of 'The Las Story', but Could test again the random hangs with this rev? Thanks --- Source/Core/Core/Src/HW/GPFifo.cpp | 2 +- Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Source/Core/Core/Src/HW/GPFifo.cpp b/Source/Core/Core/Src/HW/GPFifo.cpp index 9bae7bb621..77fdbf5933 100644 --- a/Source/Core/Core/Src/HW/GPFifo.cpp +++ b/Source/Core/Core/Src/HW/GPFifo.cpp @@ -99,7 +99,7 @@ void STACKALIGN CheckGatherPipe() // Profile where the FIFO writes are occurring. - if (g_video_backend->Video_IsHiWatermarkActive() && jit && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end())) + if (jit && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end())) { jit->js.fifoWriteAddresses.insert(PC); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index 417d1159da..b23964b071 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -576,14 +576,21 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc gpr.Flush(FLUSH_ALL); fpr.Flush(FLUSH_ALL); + + TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT | EXCEPTION_DECREMENTER)); + FixupBranch clearInt = J_CC(CC_NZ); TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT)); FixupBranch noExtException = J_CC(CC_Z); - TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); + TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000)); FixupBranch noCPInt = J_CC(CC_Z); - + TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); + FixupBranch noCPInt2 = J_CC(CC_Z); + MOV(32, M(&PC), Imm32(ops[i].address)); WriteExceptionExit(); + SetJumpTarget(clearInt); + SetJumpTarget(noCPInt2); SetJumpTarget(noCPInt); SetJumpTarget(noExtException); } From dc79d68e72f04f60366484f60bff1e39d7e6babe Mon Sep 17 00:00:00 2001 From: skidau Date: Tue, 13 Mar 2012 22:35:11 +1100 Subject: [PATCH 12/16] Added the corresponding change from r352ab2ba4394 into JITIL. Tidied some code. --- Source/Core/Core/Src/HW/GPFifo.cpp | 1 - Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 16 +++++---- .../Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp | 7 +++- .../Core/Src/PowerPC/JitCommon/JitBase.cpp | 2 ++ .../Core/Core/Src/PowerPC/JitCommon/JitBase.h | 3 -- .../Core/VideoCommon/Src/CommandProcessor.cpp | 34 ++++++------------- .../Core/VideoCommon/Src/CommandProcessor.h | 1 - Source/Core/VideoCommon/Src/PixelEngine.cpp | 3 -- 8 files changed, 28 insertions(+), 39 deletions(-) diff --git a/Source/Core/Core/Src/HW/GPFifo.cpp b/Source/Core/Core/Src/HW/GPFifo.cpp index 77fdbf5933..3af387792f 100644 --- a/Source/Core/Core/Src/HW/GPFifo.cpp +++ b/Source/Core/Core/Src/HW/GPFifo.cpp @@ -98,7 +98,6 @@ void STACKALIGN CheckGatherPipe() memmove(m_gatherPipe, m_gatherPipe + cnt, m_gatherPipeCount); // Profile where the FIFO writes are occurring. - if (jit && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end())) { jit->js.fifoWriteAddresses.insert(PC); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index b23964b071..1506170b2b 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -42,6 +42,9 @@ #include "JitRegCache.h" #include "Jit64_Tables.h" #include "HW/ProcessorInterface.h" +#if defined(_DEBUG) || defined(DEBUGFAST) +#include "PowerPCDisasm.h" +#endif using namespace Gen; using namespace PowerPC; @@ -576,23 +579,22 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc gpr.Flush(FLUSH_ALL); fpr.Flush(FLUSH_ALL); - TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT | EXCEPTION_DECREMENTER)); FixupBranch clearInt = J_CC(CC_NZ); TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT)); FixupBranch noExtException = J_CC(CC_Z); TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000)); - FixupBranch noCPInt = J_CC(CC_Z); + FixupBranch noExtIntEnable = J_CC(CC_Z); TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); - FixupBranch noCPInt2 = J_CC(CC_Z); - + FixupBranch noCPInt = J_CC(CC_Z); + MOV(32, M(&PC), Imm32(ops[i].address)); WriteExceptionExit(); - SetJumpTarget(clearInt); - SetJumpTarget(noCPInt2); SetJumpTarget(noCPInt); + SetJumpTarget(noExtIntEnable); SetJumpTarget(noExtException); + SetJumpTarget(clearInt); } Jit64Tables::CompileInstruction(ops[i]); @@ -619,7 +621,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc { char ppcInst[256]; DisassembleGekko(ops[i].inst.hex, em_address, ppcInst, 256); - NOTICE_LOG(DYNA_REC, "Unflushed reg: %s", ppcInst); + DEBUG_LOG(DYNA_REC, "Unflushed reg: %s", ppcInst); } #endif diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp index 811440d098..f82e34b5b1 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp @@ -1925,17 +1925,22 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak case ExtExceptionCheck: { unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); + Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT | EXCEPTION_DECREMENTER)); + FixupBranch clearInt = Jit->J_CC(CC_NZ); Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT)); FixupBranch noExtException = Jit->J_CC(CC_Z); + Jit->TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000)); + FixupBranch noExtIntEnable = Jit->J_CC(CC_Z); Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); FixupBranch noCPInt = Jit->J_CC(CC_Z); Jit->MOV(32, M(&PC), Imm32(InstLoc)); Jit->WriteExceptionExit(); - Jit->SetJumpTarget(noCPInt); + Jit->SetJumpTarget(noExtIntEnable); Jit->SetJumpTarget(noExtException); + Jit->SetJumpTarget(clearInt); break; } case Int3: { diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.cpp index 7f6cac8dd3..6203a81e15 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.cpp +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.cpp @@ -13,6 +13,8 @@ // If not, see http://www.gnu.org/licenses/ #include "JitBase.h" +#include "PowerPCDisasm.h" +#include "disasm.h" JitBase *jit; diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h index be80754bdc..c2febde722 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h @@ -28,9 +28,6 @@ #include "JitBackpatch.h" // for EmuCodeBlock #include "JitAsmCommon.h" -#include "PowerPCDisasm.h" -#include "disasm.h" - #include #define JIT_OPCODE 0 diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index dbf4907160..3744acd200 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -141,7 +141,6 @@ void Init() void Read16(u16& _rReturnValue, const u32 _Address) { - INFO_LOG(COMMANDPROCESSOR, "(r): 0x%08x", _Address); switch (_Address & 0xFFF) { @@ -177,7 +176,7 @@ void Read16(u16& _rReturnValue, const u32 _Address) else _rReturnValue = ReadLow (fifo.CPEnd - fifo.CPWritePointer + fifo.SafeCPReadPointer); else - _rReturnValue = ReadLow (fifo.CPReadWriteDistance); + _rReturnValue = ReadLow (fifo.CPReadWriteDistance); DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_RW_DISTANCE_LO : %04x", _rReturnValue); return; case FIFO_RW_DISTANCE_HI: @@ -187,7 +186,7 @@ void Read16(u16& _rReturnValue, const u32 _Address) else _rReturnValue = ReadHigh (fifo.CPEnd - fifo.CPWritePointer + fifo.SafeCPReadPointer); else - _rReturnValue = ReadHigh(fifo.CPReadWriteDistance); + _rReturnValue = ReadHigh(fifo.CPReadWriteDistance); DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_RW_DISTANCE_HI : %04x", _rReturnValue); return; case FIFO_WRITE_POINTER_LO: @@ -499,18 +498,15 @@ void AbortFrame() void SetOverflowStatusFromGatherPipe() { - - fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark); isHiWatermarkActive = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt && m_CPCtrlReg.GPReadEnable; - + if (isHiWatermarkActive) { interruptSet = true; INFO_LOG(COMMANDPROCESSOR,"Interrupt set"); - ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true); + ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true); } - } void SetCpStatus() @@ -520,12 +516,10 @@ void SetCpStatus() fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark); // breakpoint - if (fifo.bFF_BPEnable) { if (fifo.CPBreakpoint == fifo.CPReadPointer) - { - + { if (!fifo.bFF_Breakpoint) { INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %i", fifo.CPReadPointer); @@ -607,15 +601,16 @@ void Shutdown() void SetCpStatusRegister() { // Here always there is one fifo attached to the GPU - m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint; m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint) ; m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance; m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark; m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark; - - PixelEngine::ResumeWaitingForPEInterrupt(); - + + // HACK to compensate for slow response to PE interrupts in Time Splitters: Future Perfect + if (IsOnThread()) + PixelEngine::ResumeWaitingForPEInterrupt(); + INFO_LOG(COMMANDPROCESSOR,"\t Read from STATUS_REGISTER : %04x", m_CPStatusReg.Hex); DEBUG_LOG(COMMANDPROCESSOR, "(r) status: iBP %s | fReadIdle %s | fCmdIdle %s | iOvF %s | iUndF %s" , m_CPStatusReg.Breakpoint ? "ON" : "OFF" @@ -624,13 +619,10 @@ void SetCpStatusRegister() , m_CPStatusReg.OverflowHiWatermark ? "ON" : "OFF" , m_CPStatusReg.UnderflowLoWatermark ? "ON" : "OFF" ); - - } void SetCpControlRegister() { - // If the new fifo is being attached We make sure there wont be SetFinish event pending. // This protection fix eternal darkness booting, because the second SetFinish event when it is booting // seems invalid or has a bug and hang the game. @@ -638,7 +630,7 @@ void SetCpControlRegister() if (!fifo.bFF_GPReadEnable && m_CPCtrlReg.GPReadEnable && !m_CPCtrlReg.BPEnable) { ProcessFifoEvents(); - PixelEngine::ResetSetFinish(); + PixelEngine::ResetSetFinish(); } fifo.bFF_BPInt = m_CPCtrlReg.BPInt; @@ -653,9 +645,6 @@ void SetCpControlRegister() ProcessorInterface::Fifo_CPUBase = fifo.CPBase; ProcessorInterface::Fifo_CPUEnd = fifo.CPEnd; } - // If overflown happens process the fifo to LoWatemark - //if (bProcessFifoToLoWatermark) - // ProcessFifoToLoWatermark(); if(fifo.bFF_GPReadEnable && !m_CPCtrlReg.GPReadEnable) { @@ -667,7 +656,6 @@ void SetCpControlRegister() fifo.bFF_GPReadEnable = m_CPCtrlReg.GPReadEnable; } - DEBUG_LOG(COMMANDPROCESSOR, "\t GPREAD %s | BP %s | Int %s | OvF %s | UndF %s | LINK %s" , fifo.bFF_GPReadEnable ? "ON" : "OFF" , fifo.bFF_BPEnable ? "ON" : "OFF" diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.h b/Source/Core/VideoCommon/Src/CommandProcessor.h index 2bf965a3ba..440c900dc3 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.h +++ b/Source/Core/VideoCommon/Src/CommandProcessor.h @@ -25,7 +25,6 @@ class PointerWrap; extern bool MT; - namespace CommandProcessor { diff --git a/Source/Core/VideoCommon/Src/PixelEngine.cpp b/Source/Core/VideoCommon/Src/PixelEngine.cpp index 750e8fbb40..38c85cc10c 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.cpp +++ b/Source/Core/VideoCommon/Src/PixelEngine.cpp @@ -322,7 +322,6 @@ void Write16(const u16 _iValue, const u32 _iAddress) break; case PE_TOKEN_REG: - //LOG(PIXELENGINE,"WEIRD: program wrote token: %i",_iValue); PanicAlert("(w16) WTF? PowerPC program wrote token: %i", _iValue); //only the gx pipeline is supposed to be able to write here //g_token = _iValue; @@ -384,8 +383,6 @@ void SetToken_OnMainThread(u64 userdata, int cyclesLate) CommandProcessor::interruptTokenWaiting = false; IncrementCheckContextId(); //} - //else - // LOGV(PIXELENGINE, 1, "VIDEO Backend wrote token: %i", CommandProcessor::fifo.PEToken); } void SetFinish_OnMainThread(u64 userdata, int cyclesLate) From 8ed6ea3b076a3d1aec2a170d0c71dc1a12122371 Mon Sep 17 00:00:00 2001 From: skidau Date: Thu, 15 Mar 2012 21:48:19 +1100 Subject: [PATCH 13/16] Sped up the Dolphin debugger in JIT mode by splitting a block only while stepping or when it contains a breakpoint. The block is invalidated when a breakpoint is set or cleared. Fixed a bug in the JitCache where the JIT icache was not being invalidated when a block containing the instruction was destroyed. --- Source/Core/Common/Src/BreakPoints.cpp | 23 +++++++++++++++++-- Source/Core/Common/Src/BreakPoints.h | 2 +- Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 19 ++++++++++++--- Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp | 3 ++- Source/Core/Core/Src/PowerPC/Jit64IL/IR.h | 5 +++- .../Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp | 12 ++++++++++ .../Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp | 9 ++++++-- .../Core/Src/PowerPC/JitCommon/JitCache.cpp | 18 +++++++++++++++ 8 files changed, 81 insertions(+), 10 deletions(-) diff --git a/Source/Core/Common/Src/BreakPoints.cpp b/Source/Core/Common/Src/BreakPoints.cpp index 45a0b52daf..9164312f82 100644 --- a/Source/Core/Common/Src/BreakPoints.cpp +++ b/Source/Core/Common/Src/BreakPoints.cpp @@ -19,6 +19,7 @@ #include "DebugInterface.h" #include "BreakPoints.h" #include +#include "..\..\Core\Src\PowerPC\JitCommon\JitBase.h" bool BreakPoints::IsAddressBreakPoint(u32 _iAddress) { @@ -70,7 +71,11 @@ void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) void BreakPoints::Add(const TBreakPoint& bp) { if (!IsAddressBreakPoint(bp.iAddress)) + { m_BreakPoints.push_back(bp); + if (jit) + jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4); + } } void BreakPoints::Add(u32 em_address, bool temp) @@ -83,21 +88,35 @@ void BreakPoints::Add(u32 em_address, bool temp) pt.iAddress = em_address; m_BreakPoints.push_back(pt); + + if (jit) + jit->GetBlockCache()->InvalidateICache(em_address, 4); } } -void BreakPoints::Remove(u32 _iAddress) +void BreakPoints::Remove(u32 em_address) { for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) { - if (i->iAddress == _iAddress) + if (i->iAddress == em_address) { m_BreakPoints.erase(i); + if (jit) + jit->GetBlockCache()->InvalidateICache(em_address, 4); return; } } } +void BreakPoints::Clear() +{ + for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) + { + if (jit) + jit->GetBlockCache()->InvalidateICache(i->iAddress, 4); + m_BreakPoints.erase(i); + } +} MemChecks::TMemChecksStr MemChecks::GetStrings() const { diff --git a/Source/Core/Common/Src/BreakPoints.h b/Source/Core/Common/Src/BreakPoints.h index a97452cde6..c742f812a7 100644 --- a/Source/Core/Common/Src/BreakPoints.h +++ b/Source/Core/Common/Src/BreakPoints.h @@ -78,7 +78,7 @@ public: // Remove Breakpoint void Remove(u32 _iAddress); - void Clear() { m_BreakPoints.clear(); }; + void Clear(); void DeleteByAddress(u32 _Address); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index 1506170b2b..cb9f66b7d4 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -415,9 +415,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc if (Core::g_CoreStartupParameter.bEnableDebugging) { - // Comment out the following to disable breakpoints (speed-up) - blockSize = 1; - broken_block = true; + if (GetState() == CPU_STEPPING) + blockSize = 1; Trace(); } @@ -597,6 +596,20 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc SetJumpTarget(clearInt); } + if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING) + { + MOV(32, M(&PC), Imm32(ops[i].address)); + ABI_CallFunction(reinterpret_cast(&PowerPC::CheckBreakPoints)); + TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF)); + + FixupBranch noBreakpoint = J_CC(CC_Z); + gpr.Flush(FLUSH_ALL); + fpr.Flush(FLUSH_ALL); + + WriteExit(ops[i].address, 0); + SetJumpTarget(noBreakpoint); + } + Jit64Tables::CompileInstruction(ops[i]); if (js.memcheck && (opinfo->flags & FL_LOADSTORE)) diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp index afab21b30e..7c3e7f0810 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp @@ -1269,7 +1269,8 @@ static const unsigned alwaysUsedList[] = { Store16, Store32, StoreSingle, StoreDouble, StorePaired, StoreFReg, FDCmpCR, BlockStart, BlockEnd, IdleBranch, BranchCond, BranchUncond, ShortIdleLoop, SystemCall, InterpreterBranch, RFIExit, FPExceptionCheckStart, - FPExceptionCheckEnd, ISIException, ExtExceptionCheck, Int3, Tramp, Nop + FPExceptionCheckEnd, ISIException, ExtExceptionCheck, BreakPointCheck, + Int3, Tramp, Nop }; static const unsigned extra8RegList[] = { LoadGReg, LoadCR, LoadGQR, LoadFReg, LoadFRegDENToZero, diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h index 284cbe6538..f41742b01c 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h @@ -168,7 +168,7 @@ enum Opcode { // used for exception checking, at least until someone // has a better idea of integrating it FPExceptionCheckStart, FPExceptionCheckEnd, - ISIException,ExtExceptionCheck, + ISIException, ExtExceptionCheck, BreakPointCheck, // "Opcode" representing a register too far away to // reference directly; this is a size optimization Tramp, @@ -414,6 +414,9 @@ public: InstLoc EmitExtExceptionCheck(InstLoc pc) { return EmitUOp(ExtExceptionCheck, pc); } + InstLoc EmitBreakPointCheck(InstLoc pc) { + return EmitUOp(BreakPointCheck, pc); + } InstLoc EmitRFIExit() { return FoldZeroOp(RFIExit, 0); } diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp index f82e34b5b1..743eaf2030 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp @@ -763,6 +763,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak case FPExceptionCheckEnd: case ISIException: case ExtExceptionCheck: + case BreakPointCheck: case Int3: case Tramp: // No liveness effects @@ -1943,6 +1944,17 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak Jit->SetJumpTarget(clearInt); break; } + case BreakPointCheck: { + unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); + + Jit->MOV(32, M(&PC), Imm32(InstLoc)); + Jit->ABI_CallFunction(reinterpret_cast(&PowerPC::CheckBreakPoints)); + Jit->TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF)); + FixupBranch noBreakpoint = Jit->J_CC(CC_Z); + Jit->WriteExit(InstLoc, 0); + Jit->SetJumpTarget(noBreakpoint); + break; + } case Int3: { Jit->INT3(); break; diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp index 96afff1613..7694722bb5 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp @@ -523,8 +523,8 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc if (Core::g_CoreStartupParameter.bEnableDebugging) { - // Comment out the following to disable breakpoints (speed-up) - blockSize = 1; + if (GetState() == CPU_STEPPING) + blockSize = 1; Trace(); } @@ -653,6 +653,11 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc { ibuild.EmitExtExceptionCheck(ibuild.EmitIntConst(ops[i].address)); } + + if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING) + { + ibuild.EmitBreakPointCheck(ibuild.EmitIntConst(ops[i].address)); + } JitILTables::CompileInstruction(ops[i]); diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp index bccb218fd9..46096450e7 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp @@ -417,6 +417,24 @@ bool JitBlock::ContainsAddress(u32 em_address) std::map, u32>::iterator it1 = block_map.lower_bound(std::make_pair(address, 0)), it2 = it1, it; while (it2 != block_map.end() && it2->first.second < address + length) { +#ifdef JIT_UNLIMITED_ICACHE + JitBlock &b = blocks[it2->second]; + if (b.originalAddress & JIT_ICACHE_VMEM_BIT) + { + u32 cacheaddr = b.originalAddress & JIT_ICACHE_MASK; + memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, length); + } + else if (b.originalAddress & JIT_ICACHE_EXRAM_BIT) + { + u32 cacheaddr = b.originalAddress & JIT_ICACHEEX_MASK; + memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, length); + } + else + { + u32 cacheaddr = b.originalAddress & JIT_ICACHE_MASK; + memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, length); + } +#endif DestroyBlock(it2->second, true); it2++; } From 05692b1e7e88d19d6045cc42464cc8ef11760c62 Mon Sep 17 00:00:00 2001 From: skidau Date: Fri, 16 Mar 2012 20:08:05 +1100 Subject: [PATCH 14/16] Sped up to the Dolphin debugger by not checking for breakpoints when stepping. Fixed the JIT cache, invalidating one instruction length at a time. Fixed a bug where the JIT cache did not get invalidated when stepping. Disabled fused instructions in the debugger. --- Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 2 +- Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp | 3 +++ Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp | 2 +- Source/Core/Core/Src/PowerPC/Jit64IL/JitILAsm.cpp | 3 +++ Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp | 6 +++--- Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp | 2 ++ 6 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index cb9f66b7d4..8140a075a2 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -601,8 +601,8 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc MOV(32, M(&PC), Imm32(ops[i].address)); ABI_CallFunction(reinterpret_cast(&PowerPC::CheckBreakPoints)); TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF)); - FixupBranch noBreakpoint = J_CC(CC_Z); + gpr.Flush(FLUSH_ALL); fpr.Flush(FLUSH_ALL); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp index b9aaa2df6a..04462872e6 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp @@ -81,12 +81,15 @@ void Jit64AsmRoutineManager::Generate() if (Core::g_CoreStartupParameter.bEnableDebugging) { + TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(PowerPC::CPU_STEPPING)); + FixupBranch notStepping = J_CC(CC_Z); ABI_CallFunction(reinterpret_cast(&PowerPC::CheckBreakPoints)); TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF)); FixupBranch noBreakpoint = J_CC(CC_Z); ABI_PopAllCalleeSavedRegsAndAdjustStack(); RET(); SetJumpTarget(noBreakpoint); + SetJumpTarget(notStepping); } SetJumpTarget(skipToRealDispatch); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp index 4980b4d7a4..5aaf4b99f1 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp @@ -266,7 +266,7 @@ void Jit64::reg_imm(UGeckoInstruction inst) case 15: if (a == 0) { // lis // Merge with next instruction if loading a 32-bits immediate value (lis + addi, lis + ori) - if (!js.isLastInstruction) { + if (!js.isLastInstruction && !Core::g_CoreStartupParameter.bEnableDebugging) { if ((js.next_inst.OPCD == 14) && (js.next_inst.RD == d) && (js.next_inst.RA == d)) { // addi gpr.SetImmediate32(d, ((u32)inst.SIMM_16 << 16) + (u32)(s32)js.next_inst.SIMM_16); js.downcountAmount++; diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitILAsm.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitILAsm.cpp index da94c881e3..ac533dd473 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitILAsm.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitILAsm.cpp @@ -83,12 +83,15 @@ void JitILAsmRoutineManager::Generate() if (Core::g_CoreStartupParameter.bEnableDebugging) { + TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(PowerPC::CPU_STEPPING)); + FixupBranch notStepping = J_CC(CC_Z); ABI_CallFunction(reinterpret_cast(&PowerPC::CheckBreakPoints)); TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF)); FixupBranch noBreakpoint = J_CC(CC_Z); ABI_PopAllCalleeSavedRegsAndAdjustStack(); RET(); SetJumpTarget(noBreakpoint); + SetJumpTarget(notStepping); } SetJumpTarget(skipToRealDispatch); diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp index 46096450e7..8cc85e3284 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp @@ -422,17 +422,17 @@ bool JitBlock::ContainsAddress(u32 em_address) if (b.originalAddress & JIT_ICACHE_VMEM_BIT) { u32 cacheaddr = b.originalAddress & JIT_ICACHE_MASK; - memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, length); + memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, 4); } else if (b.originalAddress & JIT_ICACHE_EXRAM_BIT) { u32 cacheaddr = b.originalAddress & JIT_ICACHEEX_MASK; - memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, length); + memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, 4); } else { u32 cacheaddr = b.originalAddress & JIT_ICACHE_MASK; - memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, length); + memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, 4); } #endif DestroyBlock(it2->second, true); diff --git a/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp b/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp index 37ff81772a..0b6b366c88 100644 --- a/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp +++ b/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp @@ -263,6 +263,8 @@ void CCodeWindow::SingleStep() { if (CCPU::IsStepping()) { + if (jit) + jit->GetBlockCache()->InvalidateICache(PC, 4); CCPU::StepOpcode(&sync_event); wxThread::Sleep(20); // need a short wait here From cfbcaa2cc6d2c990b907747298ad012aa1c6c2fd Mon Sep 17 00:00:00 2001 From: skidau Date: Sun, 18 Mar 2012 23:37:38 +1100 Subject: [PATCH 15/16] Linux build fix --- Source/Core/Common/Src/BreakPoints.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Common/Src/BreakPoints.cpp b/Source/Core/Common/Src/BreakPoints.cpp index 9164312f82..1700276d85 100644 --- a/Source/Core/Common/Src/BreakPoints.cpp +++ b/Source/Core/Common/Src/BreakPoints.cpp @@ -18,8 +18,8 @@ #include "Common.h" #include "DebugInterface.h" #include "BreakPoints.h" +#include "../../Core/Src/PowerPC/JitCommon/JitBase.h" #include -#include "..\..\Core\Src\PowerPC\JitCommon\JitBase.h" bool BreakPoints::IsAddressBreakPoint(u32 _iAddress) { From 20eca1bf7e2e02dd18229dc2b6b83935ce0d4047 Mon Sep 17 00:00:00 2001 From: marcosvitali Date: Sun, 18 Mar 2012 22:54:58 -0300 Subject: [PATCH 16/16] Ive fixed definitely Pokemon XD in dual core mode. This game is doing something not allowed. It attach to CPU the same fifo attached to the GPU in multibuffer mode. I added a check to prevent overwrite the GPU FIFO with the CPU FIFO. If the game do that on breakpoint the solution can fail. Fixed ReadWriteDistance calc when CPRead > CPWrite. Added Token and Finish cause to GP Jit checking. --- Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 2 +- .../Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp | 2 +- .../Core/VideoCommon/Src/CommandProcessor.cpp | 19 +++++++++++++++++-- .../Core/VideoCommon/Src/CommandProcessor.h | 3 ++- Source/Core/VideoCommon/Src/PixelEngine.cpp | 2 +- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index 8140a075a2..fe090d1b50 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -584,7 +584,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc FixupBranch noExtException = J_CC(CC_Z); TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000)); FixupBranch noExtIntEnable = J_CC(CC_Z); - TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); + TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN | ProcessorInterface::INT_CAUSE_PE_FINISH)); FixupBranch noCPInt = J_CC(CC_Z); MOV(32, M(&PC), Imm32(ops[i].address)); diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp index 743eaf2030..7579c69a03 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp @@ -1932,7 +1932,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak FixupBranch noExtException = Jit->J_CC(CC_Z); Jit->TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000)); FixupBranch noExtIntEnable = Jit->J_CC(CC_Z); - Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP)); + Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP || ProcessorInterface::INT_CAUSE_PE_TOKEN || ProcessorInterface::INT_CAUSE_PE_FINISH)); FixupBranch noCPInt = Jit->J_CC(CC_Z); Jit->MOV(32, M(&PC), Imm32(InstLoc)); diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index 3744acd200..a4dddf537f 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -61,6 +61,7 @@ volatile bool interruptSet= false; volatile bool interruptWaiting= false; volatile bool interruptTokenWaiting = false; volatile bool interruptFinishWaiting = false; +volatile bool waitingForPEInterruptDisable = false; bool IsOnThread() { @@ -174,7 +175,7 @@ void Read16(u16& _rReturnValue, const u32 _Address) if(fifo.CPWritePointer >= fifo.SafeCPReadPointer) _rReturnValue = ReadLow (fifo.CPWritePointer - fifo.SafeCPReadPointer); else - _rReturnValue = ReadLow (fifo.CPEnd - fifo.CPWritePointer + fifo.SafeCPReadPointer); + _rReturnValue = ReadLow (fifo.CPEnd - fifo.SafeCPReadPointer + fifo.CPWritePointer - fifo.CPBase + 32); else _rReturnValue = ReadLow (fifo.CPReadWriteDistance); DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_RW_DISTANCE_LO : %04x", _rReturnValue); @@ -184,7 +185,7 @@ void Read16(u16& _rReturnValue, const u32 _Address) if(fifo.CPWritePointer >= fifo.SafeCPReadPointer) _rReturnValue = ReadHigh (fifo.CPWritePointer - fifo.SafeCPReadPointer); else - _rReturnValue = ReadHigh (fifo.CPEnd - fifo.CPWritePointer + fifo.SafeCPReadPointer); + _rReturnValue = ReadHigh (fifo.CPEnd - fifo.SafeCPReadPointer + fifo.CPWritePointer - fifo.CPBase + 32); else _rReturnValue = ReadHigh(fifo.CPReadWriteDistance); DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_RW_DISTANCE_HI : %04x", _rReturnValue); @@ -437,11 +438,25 @@ void Write32(const u32 _Data, const u32 _Address) void STACKALIGN GatherPipeBursted() { + ProcessFifoEvents(); // if we aren't linked, we don't care about gather pipe data if (!m_CPCtrlReg.GPLinkEnable) { if (!IsOnThread()) RunGpu(); + else + { + // In multibuffer mode is not allowed write in the same fifo attached to the GPU. + // Fix Pokemon XD in DC mode. + if((ProcessorInterface::Fifo_CPUEnd == fifo.CPEnd) && (ProcessorInterface::Fifo_CPUBase == fifo.CPBase) + && fifo.CPReadWriteDistance > 0) + { + waitingForPEInterruptDisable = true; + ProcessFifoAllDistance(); + waitingForPEInterruptDisable = false; + } + + } return; } diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.h b/Source/Core/VideoCommon/Src/CommandProcessor.h index 440c900dc3..5d31453537 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.h +++ b/Source/Core/VideoCommon/Src/CommandProcessor.h @@ -35,7 +35,8 @@ extern volatile bool interruptSet; extern volatile bool interruptWaiting; extern volatile bool interruptTokenWaiting; extern volatile bool interruptFinishWaiting; - +extern volatile bool waitingForPEInterruptDisable; + // internal hardware addresses enum { diff --git a/Source/Core/VideoCommon/Src/PixelEngine.cpp b/Source/Core/VideoCommon/Src/PixelEngine.cpp index 38c85cc10c..e6dbdb8c26 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.cpp +++ b/Source/Core/VideoCommon/Src/PixelEngine.cpp @@ -462,7 +462,7 @@ void ResetSetToken() bool WaitingForPEInterrupt() { - return CommandProcessor::interruptFinishWaiting || CommandProcessor::interruptTokenWaiting || interruptSetFinish || interruptSetToken; + return !CommandProcessor::waitingForPEInterruptDisable && (CommandProcessor::interruptFinishWaiting || CommandProcessor::interruptTokenWaiting || interruptSetFinish || interruptSetToken); } void ResumeWaitingForPEInterrupt()