void JitArm::lwz(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(LoadStore) ARMReg rA = gpr.GetReg(); ARMReg rB = gpr.GetReg(); ARMReg RD = gpr.R(inst.RD); LDR(rA, R9, PPCSTATE_OFF(Exceptions)); CMP(rA, EXCEPTION_DSI); FixupBranch DoNotLoad = B_CC(CC_EQ); { if (inst.RA) { MOVI2R(rB, inst.SIMM_16); ARMReg RA = gpr.R(inst.RA); ADD(rB, rB, RA); } else MOVI2R(rB, (u32)inst.SIMM_16); MOVI2R(rA, (u32)&Memory::Read_U32); PUSH(4, R0, R1, R2, R3); MOV(R0, rB); BL(rA); MOV(rA, R0); POP(4, R0, R1, R2, R3); MOV(RD, rA); gpr.Unlock(rA, rB); } SetJumpTarget(DoNotLoad); if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle && (inst.hex & 0xFFFF0000) == 0x800D0000 && (Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x28000000 || (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x2C000000)) && Memory::ReadUnchecked_U32(js.compilerPC + 8) == 0x4182fff8) { gpr.Flush(); fpr.Flush(); // if it's still 0, we can wait until the next event TST(RD, RD); FixupBranch noIdle = B_CC(CC_NEQ); rA = gpr.GetReg(); MOVI2R(rA, (u32)&PowerPC::OnIdle); MOVI2R(R0, PowerPC::ppcState.gpr[inst.RA] + (s32)(s16)inst.SIMM_16); BL(rA); gpr.Unlock(rA); WriteExceptionExit(); SetJumpTarget(noIdle); //js.compilerPC += 8; return; } }
void JitArm64::mtmsr(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITSystemRegistersOff); gpr.BindToRegister(inst.RS, true); STR(INDEX_UNSIGNED, gpr.R(inst.RS), PPC_REG, PPCSTATE_OFF(msr)); gpr.Flush(FlushMode::FLUSH_ALL); fpr.Flush(FlushMode::FLUSH_ALL); WriteExceptionExit(js.compilerPC + 4, true); }
void JitArm64::twx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITSystemRegistersOff); s32 a = inst.RA; ARM64Reg WA = gpr.GetReg(); if (inst.OPCD == 3) // twi { if (inst.SIMM_16 >= 0 && inst.SIMM_16 < 4096) { // Can fit in immediate in to the instruction encoding CMP(gpr.R(a), inst.SIMM_16); } else { MOVI2R(WA, (s32)(s16)inst.SIMM_16); CMP(gpr.R(a), WA); } } else // tw { CMP(gpr.R(a), gpr.R(inst.RB)); } std::vector<FixupBranch> fixups; CCFlags conditions[] = { CC_LT, CC_GT, CC_EQ, CC_VC, CC_VS }; for (int i = 0; i < 5; i++) { if (inst.TO & (1 << i)) { FixupBranch f = B(conditions[i]); fixups.push_back(f); } } FixupBranch dont_trap = B(); for (const FixupBranch& fixup : fixups) { SetJumpTarget(fixup); } gpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE); fpr.Flush(FlushMode::FLUSH_MAINTAIN_STATE); LDR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(Exceptions)); ORR(WA, WA, 24, 0); // Same as WA | EXCEPTION_PROGRAM STR(INDEX_UNSIGNED, WA, X29, PPCSTATE_OFF(Exceptions)); MOVI2R(WA, js.compilerPC); // WA is unlocked in this function WriteExceptionExit(WA); SetJumpTarget(dont_trap); if (!analyzer.HasOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE)) { gpr.Flush(FlushMode::FLUSH_ALL); fpr.Flush(FlushMode::FLUSH_ALL); WriteExit(js.compilerPC + 4); } }
void JitArm::lXX(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITLoadStoreOff); u32 a = inst.RA, b = inst.RB, d = inst.RD; s32 offset = inst.SIMM_16; u32 accessSize = 0; s32 offsetReg = -1; bool update = false; bool signExtend = false; bool reverse = false; bool fastmem = false; switch (inst.OPCD) { case 31: switch (inst.SUBOP10) { case 55: // lwzux update = true; case 23: // lwzx fastmem = true; accessSize = 32; offsetReg = b; break; case 119: //lbzux update = true; case 87: // lbzx fastmem = true; accessSize = 8; offsetReg = b; break; case 311: // lhzux update = true; case 279: // lhzx fastmem = true; accessSize = 16; offsetReg = b; break; case 375: // lhaux update = true; case 343: // lhax accessSize = 16; signExtend = true; offsetReg = b; break; case 534: // lwbrx accessSize = 32; reverse = true; break; case 790: // lhbrx accessSize = 16; reverse = true; break; } break; case 33: // lwzu update = true; case 32: // lwz fastmem = true; accessSize = 32; break; case 35: // lbzu update = true; case 34: // lbz fastmem = true; accessSize = 8; break; case 41: // lhzu update = true; case 40: // lhz fastmem = true; accessSize = 16; break; case 43: // lhau update = true; case 42: // lha signExtend = true; accessSize = 16; break; } // Check for exception before loading ARMReg rA = gpr.GetReg(false); LDR(rA, R9, PPCSTATE_OFF(Exceptions)); TST(rA, EXCEPTION_DSI); FixupBranch DoNotLoad = B_CC(CC_NEQ); SafeLoadToReg(fastmem, d, update ? a : (a ? a : -1), offsetReg, accessSize, offset, signExtend, reverse); if (update) { ARMReg RA = gpr.R(a); if (offsetReg == -1) { rA = gpr.GetReg(false); MOVI2R(rA, offset); ADD(RA, RA, rA); } else { ADD(RA, RA, gpr.R(offsetReg)); } } SetJumpTarget(DoNotLoad); // LWZ idle skipping if (SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle && inst.OPCD == 32 && (inst.hex & 0xFFFF0000) == 0x800D0000 && (Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x28000000 || (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii && Memory::ReadUnchecked_U32(js.compilerPC + 4) == 0x2C000000)) && Memory::ReadUnchecked_U32(js.compilerPC + 8) == 0x4182fff8) { ARMReg RD = gpr.R(d); // if it's still 0, we can wait until the next event TST(RD, RD); FixupBranch noIdle = B_CC(CC_NEQ); gpr.Flush(FLUSH_MAINTAIN_STATE); fpr.Flush(FLUSH_MAINTAIN_STATE); rA = gpr.GetReg(); MOVI2R(rA, (u32)&PowerPC::OnIdle); MOVI2R(R0, PowerPC::ppcState.gpr[a] + (s32)(s16)inst.SIMM_16); BL(rA); gpr.Unlock(rA); WriteExceptionExit(); SetJumpTarget(noIdle); //js.compilerPC += 8; return; } }