Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JIT: completely inline timer reading #975

Merged
merged 1 commit into from
Sep 5, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions Source/Core/Core/CoreTiming.cpp
Expand Up @@ -50,13 +50,13 @@ static Event *eventPool = nullptr;
int slicelength;
static int maxSliceLength = MAX_SLICE_LENGTH;

static s64 globalTimer;
static s64 idledCycles;

static u32 fakeDecStartValue;
static u64 fakeDecStartTicks;
static u64 fakeTBStartValue;
static u64 fakeTBStartTicks;

s64 globalTimer;
u64 fakeTBStartValue;
u64 fakeTBStartTicks;

static int ev_lost;

Expand Down
4 changes: 4 additions & 0 deletions Source/Core/Core/CoreTiming.h
Expand Up @@ -25,6 +25,10 @@ class PointerWrap;
namespace CoreTiming
{

extern s64 globalTimer;
extern u64 fakeTBStartValue;
extern u64 fakeTBStartTicks;

void Init();
void Shutdown();

Expand Down
21 changes: 16 additions & 5 deletions Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp
Expand Up @@ -173,15 +173,25 @@ void Jit64::mfspr(UGeckoInstruction inst)
// typical use of this instruction is to call it three times, e.g. mftbu/mftbl/mftbu/cmpw/bne
// to deal with possible timer wraparound. This makes the second two (out of three) completely
// redundant for the JIT.
u32 registersInUse = CallerSavedRegistersInUse();
u32 offset = js.downcountAmount / SystemTimers::TIMER_RATIO;
ABI_PushRegistersAndAdjustStack(registersInUse, false);
ABI_CallFunction((void *)&SystemTimers::GetFakeTimeBase);
ABI_PopRegistersAndAdjustStack(registersInUse, false);
gpr.FlushLockX(EDX);

// An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the
// cost of calling out to C for this is actually significant.
MOV(64, R(RAX), M(&CoreTiming::globalTimer));
SUB(64, R(RAX), M(&CoreTiming::fakeTBStartTicks));
// a / 12 = (a * 0xAAAAAAAAAAAAAAAB) >> 67
MOV(64, R(RDX), Imm64(0xAAAAAAAAAAAAAAABULL));
MUL(64, R(RDX));
MOV(64, R(RAX), M(&CoreTiming::fakeTBStartValue));
SHR(64, R(RDX), Imm8(3));
// The timer can change within a long block, so add in any difference
if (offset > 0)
ADD(64, R(RAX), Imm32(offset));
LEA(64, RAX, MComplex(RAX, RDX, SCALE_1, offset));
else
ADD(64, R(RAX), R(RDX));
MOV(64, M(&TL), R(RAX));

// Two calls of TU/TL next to each other are extremely common in typical usage, so merge them
// if we can.
u32 nextIndex = (js.next_inst.SPRU << 5) | (js.next_inst.SPRL & 0x1F);
Expand Down Expand Up @@ -225,6 +235,7 @@ void Jit64::mfspr(UGeckoInstruction inst)
break;
}
gpr.UnlockAll();
gpr.UnlockAllX();
}

void Jit64::mtmsr(UGeckoInstruction inst)
Expand Down