diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h index 160f72fd2f..c8b2c7a1eb 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h @@ -80,9 +80,19 @@ public: // Integer void arith_imm(UGeckoInstruction inst); void boolX(UGeckoInstruction inst); + void extsXx(UGeckoInstruction inst); + void cntlzwx(UGeckoInstruction inst); + void negx(UGeckoInstruction inst); // System Registers void mtmsr(UGeckoInstruction inst); + void mfmsr(UGeckoInstruction inst); + void mcrf(UGeckoInstruction inst); + void mfsr(UGeckoInstruction inst); + void mtsr(UGeckoInstruction inst); + void mfsrin(UGeckoInstruction inst); + void mtsrin(UGeckoInstruction inst); + void twx(UGeckoInstruction inst); // LoadStore void icbi(UGeckoInstruction inst); diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp index 7d8824d75a..ca3db467f0 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Integer.cpp @@ -227,3 +227,64 @@ void JitArm64::boolX(UGeckoInstruction inst) ComputeRC(a); } } + +void JitArm64::extsXx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA, s = inst.RS; + int size = inst.SUBOP10 == 922 ? 16 : 8; + + if (gpr.IsImm(s)) + gpr.SetImmediate(a, (u32)(s32)(size == 16 ? (s16)gpr.GetImm(s) : (s8)gpr.GetImm(s))); + else + SBFM(gpr.R(a), gpr.R(s), 0, size - 1); + + if (inst.Rc) + ComputeRC(a); +} + +void JitArm64::cntlzwx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA; + int s = inst.RS; + + if (gpr.IsImm(s)) + { + u32 mask = 0x80000000; + u32 i = 0; + for (; i < 32; i++, mask >>= 1) + { + if ((u32)gpr.GetImm(s) & mask) + break; + } + gpr.SetImmediate(a, i); + } + else + { + CLZ(gpr.R(a), gpr.R(s)); + } + + if (inst.Rc) + ComputeRC(a); +} + +void JitArm64::negx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + int a = inst.RA; + int d = inst.RD; + + FALLBACK_IF(inst.OE); + + if (gpr.IsImm(a)) + gpr.SetImmediate(d, ~((u32)gpr.GetImm(a)) + 1); + else + SUB(gpr.R(d), WSP, gpr.R(a), ArithOption(gpr.R(a), ST_LSL, 0)); + + if (inst.Rc) + ComputeRC(d); +} diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp index 7c72a0ccac..800c58044a 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp @@ -58,3 +58,136 @@ void JitArm64::mtmsr(UGeckoInstruction inst) WriteExit(js.compilerPC + 4); } + +void JitArm64::mfmsr(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + + LDR(INDEX_UNSIGNED, gpr.R(inst.RD), X29, PPCSTATE_OFF(msr)); +} + +void JitArm64::mcrf(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + + if (inst.CRFS != inst.CRFD) + { + ARM64Reg WA = gpr.GetReg(); + ARM64Reg XA = EncodeRegTo64(WA); + LDR(INDEX_UNSIGNED, XA, X29, PPCSTATE_OFF(cr_val[inst.CRFS])); + STR(INDEX_UNSIGNED, XA, X29, PPCSTATE_OFF(cr_val[inst.CRFD])); + gpr.Unlock(WA); + } +} + +void JitArm64::mfsr(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + + LDR(INDEX_UNSIGNED, gpr.R(inst.RD), X29, PPCSTATE_OFF(sr[inst.SR])); +} + +void JitArm64::mtsr(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + + STR(INDEX_UNSIGNED, gpr.R(inst.RS), X29, PPCSTATE_OFF(sr[inst.SR])); +} + +void JitArm64::mfsrin(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + + ARM64Reg index = gpr.GetReg(); + ARM64Reg index64 = EncodeRegTo64(index); + ARM64Reg RB = gpr.R(inst.RB); + + UBFM(index, RB, 28, 31); + ADD(index64, X29, index64, ArithOption(index64, ST_LSL, 2)); + LDR(INDEX_UNSIGNED, gpr.R(inst.RD), index64, PPCSTATE_OFF(sr[0])); + + gpr.Unlock(index); +} + +void JitArm64::mtsrin(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + + ARM64Reg index = gpr.GetReg(); + ARM64Reg index64 = EncodeRegTo64(index); + ARM64Reg RB = gpr.R(inst.RB); + + UBFM(index, RB, 28, 31); + ADD(index64, X29, index64, ArithOption(index64, ST_LSL, 2)); + STR(INDEX_UNSIGNED, gpr.R(inst.RD), index64, PPCSTATE_OFF(sr[0])); + + gpr.Unlock(index); +} + +void JitArm64::twx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITIntegerOff); + + gpr.Flush(FlushMode::FLUSH_ALL); + fpr.Flush(FlushMode::FLUSH_ALL); + + 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 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); + } + + 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); + + WriteExit(js.compilerPC + 4); +} diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp index f8a246280a..336bf47640 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp @@ -42,7 +42,7 @@ static GekkoOPTemplate primarytable[] = {1, &JitArm64::HLEFunction}, //"HLEFunction", OPTYPE_SYSTEM, FL_ENDBLOCK}}, {2, &JitArm64::FallBackToInterpreter}, //"DynaBlock", OPTYPE_SYSTEM, 0}}, - {3, &JitArm64::Break}, //"twi", OPTYPE_SYSTEM, FL_ENDBLOCK}}, + {3, &JitArm64::twx}, //"twi", OPTYPE_SYSTEM, FL_ENDBLOCK}}, {17, &JitArm64::sc}, //"sc", OPTYPE_SYSTEM, FL_ENDBLOCK, 1}}, {7, &JitArm64::FallBackToInterpreter}, //"mulli", OPTYPE_INTEGER, FL_OUT_D | FL_IN_A | FL_RC_BIT, 2}}, @@ -172,7 +172,7 @@ static GekkoOPTemplate table19[] = {193, &JitArm64::FallBackToInterpreter}, //"crxor", OPTYPE_CR, FL_EVIL}}, {150, &JitArm64::DoNothing}, //"isync", OPTYPE_ICACHE, FL_EVIL}}, - {0, &JitArm64::FallBackToInterpreter}, //"mcrf", OPTYPE_SYSTEM, FL_EVIL}}, + {0, &JitArm64::mcrf}, //"mcrf", OPTYPE_SYSTEM, FL_EVIL}}, {50, &JitArm64::rfi}, //"rfi", OPTYPE_SYSTEM, FL_ENDBLOCK | FL_CHECKEXCEPTIONS, 1}}, {18, &JitArm64::Break}, //"rfid", OPTYPE_SYSTEM, FL_ENDBLOCK | FL_CHECKEXCEPTIONS}} @@ -191,9 +191,9 @@ static GekkoOPTemplate table31[] = {284, &JitArm64::boolX}, //"eqvx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, {0, &JitArm64::FallBackToInterpreter}, //"cmp", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, {32, &JitArm64::FallBackToInterpreter}, //"cmpl", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, - {26, &JitArm64::FallBackToInterpreter}, //"cntlzwx",OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, - {922, &JitArm64::FallBackToInterpreter}, //"extshx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, - {954, &JitArm64::FallBackToInterpreter}, //"extsbx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, + {26, &JitArm64::cntlzwx}, //"cntlzwx",OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, + {922, &JitArm64::extsXx}, //"extshx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, + {954, &JitArm64::extsXx}, //"extsbx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, {536, &JitArm64::FallBackToInterpreter}, //"srwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, {792, &JitArm64::FallBackToInterpreter}, //"srawx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, {824, &JitArm64::FallBackToInterpreter}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, @@ -267,19 +267,19 @@ static GekkoOPTemplate table31[] = {983, &JitArm64::FallBackToInterpreter}, //"stfiwx", OPTYPE_STOREFP, FL_IN_A0 | FL_IN_B}}, {19, &JitArm64::FallBackToInterpreter}, //"mfcr", OPTYPE_SYSTEM, FL_OUT_D}}, - {83, &JitArm64::FallBackToInterpreter}, //"mfmsr", OPTYPE_SYSTEM, FL_OUT_D}}, + {83, &JitArm64::mfmsr}, //"mfmsr", OPTYPE_SYSTEM, FL_OUT_D}}, {144, &JitArm64::FallBackToInterpreter}, //"mtcrf", OPTYPE_SYSTEM, 0}}, {146, &JitArm64::mtmsr}, //"mtmsr", OPTYPE_SYSTEM, FL_ENDBLOCK}}, - {210, &JitArm64::FallBackToInterpreter}, //"mtsr", OPTYPE_SYSTEM, 0}}, - {242, &JitArm64::FallBackToInterpreter}, //"mtsrin", OPTYPE_SYSTEM, 0}}, + {210, &JitArm64::mtsr}, //"mtsr", OPTYPE_SYSTEM, 0}}, + {242, &JitArm64::mtsrin}, //"mtsrin", OPTYPE_SYSTEM, 0}}, {339, &JitArm64::FallBackToInterpreter}, //"mfspr", OPTYPE_SPR, FL_OUT_D}}, {467, &JitArm64::FallBackToInterpreter}, //"mtspr", OPTYPE_SPR, 0, 2}}, {371, &JitArm64::FallBackToInterpreter}, //"mftb", OPTYPE_SYSTEM, FL_OUT_D | FL_TIMER}}, {512, &JitArm64::FallBackToInterpreter}, //"mcrxr", OPTYPE_SYSTEM, 0}}, - {595, &JitArm64::FallBackToInterpreter}, //"mfsr", OPTYPE_SYSTEM, FL_OUT_D, 2}}, - {659, &JitArm64::FallBackToInterpreter}, //"mfsrin", OPTYPE_SYSTEM, FL_OUT_D, 2}}, + {595, &JitArm64::mfsr}, //"mfsr", OPTYPE_SYSTEM, FL_OUT_D, 2}}, + {659, &JitArm64::mfsrin}, //"mfsrin", OPTYPE_SYSTEM, FL_OUT_D, 2}}, - {4, &JitArm64::Break}, //"tw", OPTYPE_SYSTEM, FL_ENDBLOCK, 1}}, + {4, &JitArm64::twx}, //"tw", OPTYPE_SYSTEM, FL_ENDBLOCK, 1}}, {598, &JitArm64::DoNothing}, //"sync", OPTYPE_SYSTEM, 0, 2}}, {982, &JitArm64::icbi}, //"icbi", OPTYPE_SYSTEM, FL_ENDBLOCK, 3}}, @@ -310,7 +310,7 @@ static GekkoOPTemplate table31_2[] = {11, &JitArm64::FallBackToInterpreter}, //"mulhwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, {235, &JitArm64::FallBackToInterpreter}, //"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, {747, &JitArm64::FallBackToInterpreter}, //"mullwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, - {104, &JitArm64::FallBackToInterpreter}, //"negx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, + {104, &JitArm64::negx}, //"negx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, {40, &JitArm64::FallBackToInterpreter}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, {552, &JitArm64::FallBackToInterpreter}, //"subox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, {8, &JitArm64::FallBackToInterpreter}, //"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}},