JitArm64: Implement timer SPRs

This commit is contained in:
MerryMage 2017-03-27 20:06:43 +01:00
parent 24d5d89056
commit e3d0de7442
2 changed files with 51 additions and 34 deletions

View File

@ -28,9 +28,9 @@ namespace CoreTiming
struct Globals struct Globals
{ {
s64 global_timer; s64 global_timer;
int slice_length;
u64 fake_TB_start_value; u64 fake_TB_start_value;
u64 fake_TB_start_ticks; u64 fake_TB_start_ticks;
int slice_length;
float last_OC_factor_inverted; float last_OC_factor_inverted;
}; };
extern Globals g; extern Globals g;

View File

@ -247,41 +247,55 @@ void JitArm64::mfspr(UGeckoInstruction inst)
case SPR_TL: case SPR_TL:
case SPR_TU: case SPR_TU:
{ {
// The inline implementation here is inaccurate and out of date as of PR3601 ARM64Reg Wg = gpr.GetReg();
FALLBACK_IF(true); // Fallback to interpreted version. ARM64Reg Xg = EncodeRegTo64(Wg);
ARM64Reg Wresult = gpr.GetReg();
ARM64Reg Xresult = EncodeRegTo64(Wresult);
/*
ARM64Reg WA = gpr.GetReg(); ARM64Reg WA = gpr.GetReg();
ARM64Reg WB = gpr.GetReg(); ARM64Reg WB = gpr.GetReg();
ARM64Reg XA = EncodeRegTo64(WA); ARM64Reg XA = EncodeRegTo64(WA);
ARM64Reg XB = EncodeRegTo64(WB); ARM64Reg XB = EncodeRegTo64(WB);
ARM64Reg VC = fpr.GetReg();
ARM64Reg VD = fpr.GetReg();
ARM64Reg SC = EncodeRegToSingle(VC);
ARM64Reg SD = EncodeRegToSingle(VD);
// An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the // An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the
// cost of calling out to C for this is actually significant. // cost of calling out to C for this is actually significant.
MOVI2R(XA, (u64)&CoreTiming::g_global_timer);
LDR(INDEX_UNSIGNED, XA, XA, 0); MOVP2R(Xg, &CoreTiming::g);
MOVI2R(XB, (u64)&CoreTiming::g_fake_TB_start_ticks);
LDR(INDEX_UNSIGNED, XB, XB, 0); LDR(INDEX_UNSIGNED, WA, PPC_REG, PPCSTATE_OFF(downcount));
SUB(XA, XA, XB); m_float_emit.SCVTF(SC, WA);
m_float_emit.LDR(32, INDEX_UNSIGNED, SD, Xg,
offsetof(CoreTiming::Globals, last_OC_factor_inverted));
m_float_emit.FMUL(SC, SC, SD);
m_float_emit.FCVTS(Xresult, SC, ROUND_Z);
LDP(INDEX_SIGNED, XA, XB, Xg, offsetof(CoreTiming::Globals, global_timer));
SXTW(XB, WB);
SUB(Xresult, XB, Xresult);
ADD(Xresult, Xresult, XA);
// It might seem convenient to correct the timer for the block position here for even more // It might seem convenient to correct the timer for the block position here for even more
accurate // accurate timing, but as of currently, this can break games. If we end up reading a time
// timing, but as of currently, this can break games. If we end up reading a time *after* the // *after* the time at which an interrupt was supposed to occur, e.g. because we're 100 cycles
time // into a block with only 50 downcount remaining, some games don't function correctly, such as
// at which an interrupt was supposed to occur, e.g. because we're 100 cycles into a block with // Karaoke Party Revolution, which won't get past the loading screen.
only
// 50 downcount remaining, some games don't function correctly, such as Karaoke Party
Revolution,
// which won't get past the loading screen.
// a / 12 = (a * 0xAAAAAAAAAAAAAAAB) >> 67
ORR(XB, SP, 1, 60);
ADD(XB, XB, 1);
UMULH(XA, XA, XB);
MOVI2R(XB, (u64)&CoreTiming::g_fake_TB_start_value); LDP(INDEX_SIGNED, XA, XB, Xg, offsetof(CoreTiming::Globals, fake_TB_start_value));
LDR(INDEX_UNSIGNED, XB, XB, 0); SUB(Xresult, Xresult, XB);
ADD(XA, XB, XA, ArithOption(XA, ST_LSR, 3));
STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(spr[SPR_TL])); // a / 12 = (a * 0xAAAAAAAAAAAAAAAB) >> 67
ORRI2R(XB, ZR, 0xAAAAAAAAAAAAAAAA);
ADD(XB, XB, 1);
UMULH(Xresult, Xresult, XB);
ADD(Xresult, XA, Xresult, ArithOption(Xresult, ST_LSR, 3));
STR(INDEX_UNSIGNED, Xresult, PPC_REG, PPCSTATE_OFF(spr[SPR_TL]));
if (CanMergeNextInstructions(1)) if (CanMergeNextInstructions(1))
{ {
@ -292,32 +306,35 @@ void JitArm64::mfspr(UGeckoInstruction inst)
// Be careful; the actual opcode is for mftb (371), not mfspr (339) // Be careful; the actual opcode is for mftb (371), not mfspr (339)
int n = next.RD; int n = next.RD;
if (next.OPCD == 31 && next.SUBOP10 == 371 && (nextIndex == SPR_TU || nextIndex == SPR_TL) && if (next.OPCD == 31 && next.SUBOP10 == 371 && (nextIndex == SPR_TU || nextIndex == SPR_TL) &&
n != d) n != d)
{ {
js.downcountAmount++; js.downcountAmount++;
js.skipInstructions = 1; js.skipInstructions = 1;
gpr.BindToRegister(d, false); gpr.BindToRegister(d, false);
gpr.BindToRegister(n, false); gpr.BindToRegister(n, false);
if (iIndex == SPR_TL) if (iIndex == SPR_TL)
MOV(gpr.R(d), WA); MOV(gpr.R(d), Wresult);
else else
ORR(EncodeRegTo64(gpr.R(d)), SP, XA, ArithOption(XA, ST_LSR, 32)); ORR(EncodeRegTo64(gpr.R(d)), ZR, Xresult, ArithOption(Xresult, ST_LSR, 32));
if (nextIndex == SPR_TL) if (nextIndex == SPR_TL)
MOV(gpr.R(n), WA); MOV(gpr.R(n), Wresult);
else else
ORR(EncodeRegTo64(gpr.R(n)), SP, XA, ArithOption(XA, ST_LSR, 32)); ORR(EncodeRegTo64(gpr.R(n)), ZR, Xresult, ArithOption(Xresult, ST_LSR, 32));
gpr.Unlock(WA, WB); gpr.Unlock(Wg, Wresult, WA, WB);
fpr.Unlock(VC, VD);
break; break;
} }
} }
gpr.BindToRegister(d, false); gpr.BindToRegister(d, false);
if (iIndex == SPR_TU) if (iIndex == SPR_TU)
ORR(EncodeRegTo64(gpr.R(d)), SP, XA, ArithOption(XA, ST_LSR, 32)); ORR(EncodeRegTo64(gpr.R(d)), ZR, Xresult, ArithOption(Xresult, ST_LSR, 32));
else else
MOV(gpr.R(d), WA); MOV(gpr.R(d), Wresult);
gpr.Unlock(WA, WB);*/
gpr.Unlock(Wg, Wresult, WA, WB);
fpr.Unlock(VC, VD);
} }
break; break;
case SPR_XER: case SPR_XER: