diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index 31031ef70c..a8795bb4ed 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -6,6 +6,7 @@ #include "Common/Arm64Emitter.h" #include "Common/CommonTypes.h" +#include "Common/MathUtil.h" #include "Common/PerformanceCounter.h" #include "Common/StringUtil.h" #include "Common/Logging/Log.h" @@ -364,15 +365,9 @@ void JitArm64::Jit(u32) { ClearCache(); } - int block_num = blocks.AllocateBlock(PowerPC::ppcState.pc); - JitBlock *b = blocks.GetBlock(block_num); - const u8* BlockPtr = DoJit(PowerPC::ppcState.pc, &code_buffer, b); - blocks.FinalizeBlock(block_num, jo.enableBlocklink, BlockPtr); -} -const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b) -{ - int blockSize = code_buf->GetSize(); + int blockSize = code_buffer.GetSize(); + u32 em_address = PowerPC::ppcState.pc; if (SConfig::GetInstance().bEnableDebugging) { @@ -380,6 +375,28 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB blockSize = 1; } + // Analyze the block, collect all instructions it is made of (including inlining, + // if that is enabled), reorder instructions for optimal performance, and join joinable instructions. + u32 nextPC = analyzer.Analyze(em_address, &code_block, &code_buffer, blockSize); + + if (code_block.m_memory_exception) + { + // Address of instruction could not be translated + NPC = nextPC; + PowerPC::ppcState.Exceptions |= EXCEPTION_ISI; + PowerPC::CheckExceptions(); + WARN_LOG(POWERPC, "ISI exception at 0x%08x", nextPC); + return; + } + + int block_num = blocks.AllocateBlock(em_address); + JitBlock *b = blocks.GetBlock(block_num); + const u8* BlockPtr = DoJit(em_address, &code_buffer, b, nextPC); + blocks.FinalizeBlock(block_num, jo.enableBlocklink, BlockPtr); +} + +const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b, u32 nextPC) +{ if (em_address == 0) { Core::SetState(Core::CORE_PAUSE); @@ -395,11 +412,6 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB js.skipInstructions = 0; js.curBlock = b; - u32 nextPC = em_address; - // Analyze the block, collect all instructions it is made of (including inlining, - // if that is enabled), reorder instructions for optimal performance, and join joinable instructions. - nextPC = analyzer.Analyze(em_address, &code_block, code_buf, blockSize); - PPCAnalyst::CodeOp *ops = code_buf->codebuffer; const u8 *start = GetCodePtr(); @@ -467,6 +479,7 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB js.compilerPC = ops[i].address; js.op = &ops[i]; js.instructionNumber = i; + js.instructionsLeft = (code_block.m_num_instructions - 1) - i; const GekkoOPInfo *opinfo = ops[i].opinfo; js.downcountAmount += opinfo->numCycles; @@ -578,12 +591,6 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB js.firstFPInstructionFound = true; } - if (jo.memcheck && (opinfo->flags & FL_USE_FPU)) - { - // Don't do this yet - BRK(0x7777); - } - JitArm64Tables::CompileInstruction(ops[i]); // If we have a register that will never be used again, flush it. @@ -592,8 +599,22 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB if (jo.memcheck && (opinfo->flags & FL_LOADSTORE)) { - // Don't do this yet - BRK(0x666); + ARM64Reg WA = gpr.GetReg(); + LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); + FixupBranch noException = TBZ(WA, IntLog2(EXCEPTION_DSI)); + + FixupBranch handleException = B(); + SwitchToFarCode(); + SetJumpTarget(handleException); + + gpr.Flush(FLUSH_MAINTAIN_STATE); + fpr.Flush(FLUSH_MAINTAIN_STATE); + + WriteExceptionExit(js.compilerPC); + + SwitchToNearCode(); + SetJumpTarget(noException); + gpr.Unlock(WA); } } @@ -601,12 +622,10 @@ const u8* JitArm64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitB js.skipInstructions = 0; } - if (code_block.m_memory_exception) - BRK(0x500); - if (code_block.m_broken) { - printf("Broken Block going to 0x%08x\n", nextPC); + gpr.Flush(FLUSH_ALL); + fpr.Flush(FLUSH_ALL); WriteExit(nextPC); } diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h index a791b279e4..6bf30e351a 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h @@ -221,7 +221,7 @@ private: void SafeLoadToReg(u32 dest, s32 addr, s32 offsetReg, u32 flags, s32 offset, bool update); void SafeStoreFromReg(s32 dest, u32 value, s32 regOffset, u32 flags, s32 offset); - const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b); + const u8* DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlock *b, u32 nextPC); void DoDownCount(); void Cleanup(); diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp index b5ba689d21..c4053ff779 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp @@ -375,6 +375,7 @@ void JitArm64::lXX(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); u32 a = inst.RA, b = inst.RB, d = inst.RD; s32 offset = inst.SIMM_16; @@ -446,11 +447,11 @@ void JitArm64::lXX(UGeckoInstruction inst) // LWZ idle skipping if (SConfig::GetInstance().bSkipIdle && - inst.OPCD == 32 && - (inst.hex & 0xFFFF0000) == 0x800D0000 && - (PowerPC::HostRead_U32(js.compilerPC + 4) == 0x28000000 || - (SConfig::GetInstance().bWii && PowerPC::HostRead_U32(js.compilerPC + 4) == 0x2C000000)) && - PowerPC::HostRead_U32(js.compilerPC + 8) == 0x4182fff8) + inst.OPCD == 32 && MergeAllowedNextInstructions(2) && + (inst.hex & 0xFFFF0000) == 0x800D0000 && // lwz r0, XXXX(r13) + (js.op[1].inst.hex == 0x28000000 || + (SConfig::GetInstance().bWii && js.op[1].inst.hex == 0x2C000000)) && // cmpXwi r0,0 + js.op[2].inst.hex == 0x4182fff8) // beq -8 { // if it's still 0, we can wait until the next event FixupBranch noIdle = CBNZ(gpr.R(d)); @@ -480,6 +481,7 @@ void JitArm64::stX(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); u32 a = inst.RA, b = inst.RB, s = inst.RS; s32 offset = inst.SIMM_16; @@ -557,7 +559,7 @@ void JitArm64::lmw(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(!jo.fastmem); + FALLBACK_IF(!jo.fastmem || jo.memcheck); u32 a = inst.RA; @@ -643,7 +645,7 @@ void JitArm64::stmw(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreOff); - FALLBACK_IF(!jo.fastmem); + FALLBACK_IF(!jo.fastmem || jo.memcheck); u32 a = inst.RA; @@ -803,6 +805,7 @@ void JitArm64::dcbz(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreOff); + FALLBACK_IF(jo.memcheck); int a = inst.RA, b = inst.RB; diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStoreFloating.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStoreFloating.cpp index f27367f297..69ed5811d3 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStoreFloating.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStoreFloating.cpp @@ -23,6 +23,7 @@ void JitArm64::lfXX(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreFloatingOff); + FALLBACK_IF(jo.memcheck); u32 a = inst.RA, b = inst.RB; @@ -210,6 +211,7 @@ void JitArm64::stfXX(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreFloatingOff); + FALLBACK_IF(jo.memcheck); u32 a = inst.RA, b = inst.RB; diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp index 3bcb89a10a..49a869fa13 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp @@ -57,7 +57,7 @@ void JitArm64::mtmsr(UGeckoInstruction inst) gpr.Flush(FlushMode::FLUSH_ALL); fpr.Flush(FlushMode::FLUSH_ALL); - WriteExit(js.compilerPC + 4); + WriteExceptionExit(js.compilerPC + 4, true); } void JitArm64::mfmsr(UGeckoInstruction inst) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp b/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp index 02cf15f1a0..11cfe363fd 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp @@ -5,6 +5,7 @@ #include "Common/Arm64Emitter.h" #include "Common/CommonTypes.h" #include "Common/JitRegister.h" +#include "Common/MathUtil.h" #include "Core/CoreTiming.h" #include "Core/HW/Memmap.h" #include "Core/PowerPC/PowerPC.h" @@ -46,12 +47,36 @@ void JitArm64::GenerateAsm() dispatcherNoCheck = GetCodePtr(); - // This block of code gets the address of the compiled block of code - // It runs though to the compiling portion if it isn't found - BFM(DISPATCHER_PC, WSP, 3, 2); // Wipe the top 3 bits. Same as PC & JIT_ICACHE_MASK + FixupBranch exram, vmem, not_exram, not_vmem; + ARM64Reg pc_masked = W25; + ARM64Reg cache_base = X27; - MOVI2R(X27, (u64)jit->GetBlockCache()->iCache.data()); - LDR(W27, X27, EncodeRegTo64(DISPATCHER_PC)); + // VMEM + not_vmem = TBZ(DISPATCHER_PC, IntLog2(JIT_ICACHE_VMEM_BIT)); + ANDI2R(pc_masked, DISPATCHER_PC, JIT_ICACHE_MASK); + MOVI2R(cache_base, (u64)jit->GetBlockCache()->iCacheVMEM.data()); + vmem = B(); + SetJumpTarget(not_vmem); + + if (SConfig::GetInstance().bWii) + { + // Wii EX-RAM + not_exram = TBZ(DISPATCHER_PC, IntLog2(JIT_ICACHE_EXRAM_BIT)); + ANDI2R(pc_masked, DISPATCHER_PC, JIT_ICACHEEX_MASK); + MOVI2R(cache_base, (u64)jit->GetBlockCache()->iCacheEx.data()); + exram = B(); + SetJumpTarget(not_exram); + } + + // Common memory + ANDI2R(pc_masked, DISPATCHER_PC, JIT_ICACHE_MASK); + MOVI2R(cache_base, (u64)jit->GetBlockCache()->iCache.data()); + + SetJumpTarget(vmem); + if (SConfig::GetInstance().bWii) + SetJumpTarget(exram); + + LDR(W27, cache_base, EncodeRegTo64(pc_masked)); FixupBranch JitBlock = TBNZ(W27, 7); // Test the 7th bit // Success, it is our Jitblock. @@ -64,10 +89,11 @@ void JitArm64::GenerateAsm() SetJumpTarget(JitBlock); STR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); - MOVI2R(X30, (u64)&::Jit); BLR(X30); + LDR(INDEX_UNSIGNED, DISPATCHER_PC, PPC_REG, PPCSTATE_OFF(pc)); + B(dispatcherNoCheck); SetJumpTarget(bail);