void JitArm::mtmsr(UGeckoInstruction inst) { INSTRUCTION_START // Don't interpret this, if we do we get thrown out //JITDISABLE(SystemRegisters) ARMReg rA = gpr.GetReg(); MOVI2R(rA, (u32)&MSR); STR(rA, gpr.R(inst.RS)); gpr.Unlock(rA); WriteExit(js.compilerPC + 4, 0); }
void JitArm64::mtmsr(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITSystemRegistersOff); gpr.BindToRegister(inst.RS, true); STR(INDEX_UNSIGNED, gpr.R(inst.RS), X29, PPCSTATE_OFF(msr)); gpr.Flush(FlushMode::FLUSH_ALL); fpr.Flush(FlushMode::FLUSH_ALL); WriteExit(js.compilerPC + 4); }
void JitArm::mtmsr(UGeckoInstruction inst) { INSTRUCTION_START // Don't interpret this, if we do we get thrown out //JITDISABLE(SystemRegisters) STR(gpr.R(inst.RS), R9, PPCSTATE_OFF(msr)); gpr.Flush(); fpr.Flush(); WriteExit(js.compilerPC + 4, 0); }
const u8 *MipsJit::DoJit(u32 em_address, JitBlock *b) { js.cancel = false; js.blockStart = js.compilerPC = mips_->pc; js.lastContinuedPC = 0; js.initialBlockSize = 0; js.nextExit = 0; js.downcountAmount = 0; js.curBlock = b; js.compiling = true; js.inDelaySlot = false; js.PrefixStart(); b->normalEntry = GetCodePtr(); js.numInstructions = 0; while (js.compiling) { MIPSOpcode inst = Memory::Read_Opcode_JIT(js.compilerPC); js.downcountAmount += MIPSGetInstructionCycleEstimate(inst); MIPSCompileOp(inst); js.compilerPC += 4; js.numInstructions++; // Safety check, in case we get a bunch of really large jit ops without a lot of branching. if (GetSpaceLeft() < 0x800 || js.numInstructions >= JitBlockCache::MAX_BLOCK_INSTRUCTIONS) { FlushAll(); WriteExit(js.compilerPC, js.nextExit++); js.compiling = false; } } b->codeSize = GetCodePtr() - b->normalEntry; // Don't forget to zap the newly written instructions in the instruction cache! FlushIcache(); if (js.lastContinuedPC == 0) b->originalSize = js.numInstructions; else { // We continued at least once. Add the last proxy and set the originalSize correctly. blocks.ProxyBlock(js.blockStart, js.lastContinuedPC, (js.compilerPC - js.lastContinuedPC) / sizeof(u32), GetCodePtr()); b->originalSize = js.initialBlockSize; } return b->normalEntry; }
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); } }
const u8 *Jit::DoJit(u32 em_address, JitBlock *b) { js.cancel = false; js.blockStart = js.compilerPC = mips_->pc; js.nextExit = 0; js.downcountAmount = 0; js.curBlock = b; js.compiling = true; js.inDelaySlot = false; js.afterOp = JitState::AFTER_NONE; js.PrefixStart(); // We add a check before the block, used when entering from a linked block. b->checkedEntry = GetCodePtr(); // Downcount flag check. The last block decremented downcounter, and the flag should still be available. FixupBranch skip = J_CC(CC_NBE); MOV(32, M(&mips_->pc), Imm32(js.blockStart)); JMP(asm_.outerLoop, true); // downcount hit zero - go advance. SetJumpTarget(skip); b->normalEntry = GetCodePtr(); MIPSAnalyst::AnalysisResults analysis = MIPSAnalyst::Analyze(em_address); gpr.Start(mips_, analysis); fpr.Start(mips_, analysis); js.numInstructions = 0; while (js.compiling) { // Jit breakpoints are quite fast, so let's do them in release too. CheckJitBreakpoint(js.compilerPC, 0); MIPSOpcode inst = Memory::Read_Opcode_JIT(js.compilerPC); js.downcountAmount += MIPSGetInstructionCycleEstimate(inst); MIPSCompileOp(inst); if (js.afterOp & JitState::AFTER_CORE_STATE) { // TODO: Save/restore? FlushAll(); // If we're rewinding, CORE_NEXTFRAME should not cause a rewind. // It doesn't really matter either way if we're not rewinding. // CORE_RUNNING is <= CORE_NEXTFRAME. CMP(32, M(&coreState), Imm32(CORE_NEXTFRAME)); FixupBranch skipCheck = J_CC(CC_LE); if (js.afterOp & JitState::AFTER_REWIND_PC_BAD_STATE) MOV(32, M(&mips_->pc), Imm32(js.compilerPC)); else MOV(32, M(&mips_->pc), Imm32(js.compilerPC + 4)); WriteSyscallExit(); SetJumpTarget(skipCheck); js.afterOp = JitState::AFTER_NONE; } if (js.afterOp & JitState::AFTER_MEMCHECK_CLEANUP) { js.afterOp &= ~JitState::AFTER_MEMCHECK_CLEANUP; } js.compilerPC += 4; js.numInstructions++; // Safety check, in case we get a bunch of really large jit ops without a lot of branching. if (GetSpaceLeft() < 0x800) { FlushAll(); WriteExit(js.compilerPC, js.nextExit++); js.compiling = false; } } b->codeSize = (u32)(GetCodePtr() - b->normalEntry); NOP(); AlignCode4(); b->originalSize = js.numInstructions; return b->normalEntry; }
void JitArm::icbi(UGeckoInstruction inst) { FallBackToInterpreter(inst); WriteExit(js.compilerPC + 4); }