mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-11 00:29:11 +01:00
JitArm64: Implement timer SPRs
This commit is contained in:
parent
24d5d89056
commit
e3d0de7442
@ -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;
|
||||||
|
@ -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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user