CoreTiming: Cleanup naming conventions

This commit is contained in:
EmptyChaos
2016-08-26 02:47:34 +00:00
parent da82389347
commit b88b188819
5 changed files with 128 additions and 131 deletions

View File

@ -2,6 +2,7 @@
// Licensed under GPLv2+ // Licensed under GPLv2+
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <algorithm>
#include <cinttypes> #include <cinttypes>
#include <mutex> #include <mutex>
#include <string> #include <string>
@ -20,8 +21,6 @@
#include "VideoCommon/Fifo.h" #include "VideoCommon/Fifo.h"
#include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoBackendBase.h"
#define MAX_SLICE_LENGTH 20000
namespace CoreTiming namespace CoreTiming
{ {
struct EventType struct EventType
@ -30,7 +29,7 @@ struct EventType
std::string name; std::string name;
}; };
static std::vector<EventType> event_types; static std::vector<EventType> s_event_types;
struct BaseEvent struct BaseEvent
{ {
@ -42,45 +41,45 @@ struct BaseEvent
typedef LinkedListItem<BaseEvent> Event; typedef LinkedListItem<BaseEvent> Event;
// STATE_TO_SAVE // STATE_TO_SAVE
static Event* first; static Event* s_first_event;
static std::mutex tsWriteLock; static std::mutex s_ts_write_lock;
static Common::FifoQueue<BaseEvent, false> tsQueue; static Common::FifoQueue<BaseEvent, false> s_ts_queue;
// event pools // event pools
static Event* eventPool = nullptr; static Event* s_event_pool = nullptr;
static float s_lastOCFactor; static float s_last_OC_factor;
float g_lastOCFactor_inverted; float g_last_OC_factor_inverted;
int g_slicelength; int g_slice_length;
static int maxslicelength = MAX_SLICE_LENGTH; static constexpr int MAX_SLICE_LENGTH = 20000;
static s64 idledCycles; static s64 s_idled_cycles;
static u32 fakeDecStartValue; static u32 s_fake_dec_start_value;
static u64 fakeDecStartTicks; static u64 s_fake_dec_start_ticks;
// Are we in a function that has been called from Advance() // Are we in a function that has been called from Advance()
static bool globalTimerIsSane; static bool s_is_global_timer_sane;
s64 g_globalTimer; s64 g_global_timer;
u64 g_fakeTBStartValue; u64 g_fake_TB_start_value;
u64 g_fakeTBStartTicks; u64 g_fake_TB_start_ticks;
static int ev_lost; static int s_ev_lost;
static Event* GetNewEvent() static Event* GetNewEvent()
{ {
if (!eventPool) if (!s_event_pool)
return new Event; return new Event;
Event* ev = eventPool; Event* ev = s_event_pool;
eventPool = ev->next; s_event_pool = ev->next;
return ev; return ev;
} }
static void FreeEvent(Event* ev) static void FreeEvent(Event* ev)
{ {
ev->next = eventPool; ev->next = s_event_pool;
eventPool = ev; s_event_pool = ev;
} }
static void EmptyTimedCallback(u64 userdata, s64 cyclesLate) static void EmptyTimedCallback(u64 userdata, s64 cyclesLate)
@ -96,12 +95,12 @@ static void EmptyTimedCallback(u64 userdata, s64 cyclesLate)
// but the effect is largely the same. // but the effect is largely the same.
static int DowncountToCycles(int downcount) static int DowncountToCycles(int downcount)
{ {
return (int)(downcount * g_lastOCFactor_inverted); return static_cast<int>(downcount * g_last_OC_factor_inverted);
} }
static int CyclesToDowncount(int cycles) static int CyclesToDowncount(int cycles)
{ {
return (int)(cycles * s_lastOCFactor); return static_cast<int>(cycles * s_last_OC_factor);
} }
int RegisterEvent(const std::string& name, TimedCallback callback) int RegisterEvent(const std::string& name, TimedCallback callback)
@ -112,7 +111,7 @@ int RegisterEvent(const std::string& name, TimedCallback callback)
// check for existing type with same name. // check for existing type with same name.
// we want event type names to remain unique so that we can use them for serialization. // we want event type names to remain unique so that we can use them for serialization.
for (auto& event_type : event_types) for (auto& event_type : s_event_types)
{ {
if (name == event_type.name) if (name == event_type.name)
{ {
@ -127,41 +126,41 @@ int RegisterEvent(const std::string& name, TimedCallback callback)
} }
} }
event_types.push_back(type); s_event_types.push_back(type);
return (int)event_types.size() - 1; return static_cast<int>(s_event_types.size() - 1);
} }
void UnregisterAllEvents() void UnregisterAllEvents()
{ {
if (first) if (s_first_event)
PanicAlert("Cannot unregister events with events pending"); PanicAlert("Cannot unregister events with events pending");
event_types.clear(); s_event_types.clear();
} }
void Init() void Init()
{ {
s_lastOCFactor = SConfig::GetInstance().m_OCEnable ? SConfig::GetInstance().m_OCFactor : 1.0f; s_last_OC_factor = SConfig::GetInstance().m_OCEnable ? SConfig::GetInstance().m_OCFactor : 1.0f;
g_lastOCFactor_inverted = 1.0f / s_lastOCFactor; g_last_OC_factor_inverted = 1.0f / s_last_OC_factor;
PowerPC::ppcState.downcount = CyclesToDowncount(maxslicelength); PowerPC::ppcState.downcount = CyclesToDowncount(MAX_SLICE_LENGTH);
g_slicelength = maxslicelength; g_slice_length = MAX_SLICE_LENGTH;
g_globalTimer = 0; g_global_timer = 0;
idledCycles = 0; s_idled_cycles = 0;
globalTimerIsSane = true; s_is_global_timer_sane = true;
ev_lost = RegisterEvent("_lost_event", &EmptyTimedCallback); s_ev_lost = RegisterEvent("_lost_event", &EmptyTimedCallback);
} }
void Shutdown() void Shutdown()
{ {
std::lock_guard<std::mutex> lk(tsWriteLock); std::lock_guard<std::mutex> lk(s_ts_write_lock);
MoveEvents(); MoveEvents();
ClearPendingEvents(); ClearPendingEvents();
UnregisterAllEvents(); UnregisterAllEvents();
while (eventPool) while (s_event_pool)
{ {
Event* ev = eventPool; Event* ev = s_event_pool;
eventPool = ev->next; s_event_pool = ev->next;
delete ev; delete ev;
} }
} }
@ -178,15 +177,15 @@ static void EventDoState(PointerWrap& p, BaseEvent* ev)
// so, we savestate the event's type's name, and derive ev->type from that when loading. // so, we savestate the event's type's name, and derive ev->type from that when loading.
std::string name; std::string name;
if (p.GetMode() != PointerWrap::MODE_READ) if (p.GetMode() != PointerWrap::MODE_READ)
name = event_types[ev->type].name; name = s_event_types[ev->type].name;
p.Do(name); p.Do(name);
if (p.GetMode() == PointerWrap::MODE_READ) if (p.GetMode() == PointerWrap::MODE_READ)
{ {
bool foundMatch = false; bool foundMatch = false;
for (unsigned int i = 0; i < event_types.size(); ++i) for (unsigned int i = 0; i < s_event_types.size(); ++i)
{ {
if (name == event_types[i].name) if (name == s_event_types[i].name)
{ {
ev->type = i; ev->type = i;
foundMatch = true; foundMatch = true;
@ -198,30 +197,29 @@ static void EventDoState(PointerWrap& p, BaseEvent* ev)
WARN_LOG(POWERPC, WARN_LOG(POWERPC,
"Lost event from savestate because its type, \"%s\", has not been registered.", "Lost event from savestate because its type, \"%s\", has not been registered.",
name.c_str()); name.c_str());
ev->type = ev_lost; ev->type = s_ev_lost;
} }
} }
} }
void DoState(PointerWrap& p) void DoState(PointerWrap& p)
{ {
std::lock_guard<std::mutex> lk(tsWriteLock); std::lock_guard<std::mutex> lk(s_ts_write_lock);
p.Do(g_slicelength); p.Do(g_slice_length);
p.Do(g_globalTimer); p.Do(g_global_timer);
p.Do(idledCycles); p.Do(s_idled_cycles);
p.Do(fakeDecStartValue); p.Do(s_fake_dec_start_value);
p.Do(fakeDecStartTicks); p.Do(s_fake_dec_start_ticks);
p.Do(g_fakeTBStartValue); p.Do(g_fake_TB_start_value);
p.Do(g_fakeTBStartTicks); p.Do(g_fake_TB_start_ticks);
p.Do(s_lastOCFactor); p.Do(s_last_OC_factor);
if (p.GetMode() == PointerWrap::MODE_READ) g_last_OC_factor_inverted = 1.0f / s_last_OC_factor;
g_lastOCFactor_inverted = 1.0f / s_lastOCFactor;
p.DoMarker("CoreTimingData"); p.DoMarker("CoreTimingData");
MoveEvents(); MoveEvents();
p.DoLinkedList<BaseEvent, GetNewEvent, FreeEvent, EventDoState>(first); p.DoLinkedList<BaseEvent, GetNewEvent, FreeEvent, EventDoState>(s_first_event);
p.DoMarker("CoreTimingEvents"); p.DoMarker("CoreTimingEvents");
} }
@ -229,34 +227,34 @@ void DoState(PointerWrap& p)
// it from any other thread, you are doing something evil // it from any other thread, you are doing something evil
u64 GetTicks() u64 GetTicks()
{ {
u64 ticks = (u64)g_globalTimer; u64 ticks = static_cast<u64>(g_global_timer);
if (!globalTimerIsSane) if (!s_is_global_timer_sane)
{ {
int downcount = DowncountToCycles(PowerPC::ppcState.downcount); int downcount = DowncountToCycles(PowerPC::ppcState.downcount);
ticks += g_slicelength - downcount; ticks += g_slice_length - downcount;
} }
return ticks; return ticks;
} }
u64 GetIdleTicks() u64 GetIdleTicks()
{ {
return (u64)idledCycles; return static_cast<u64>(s_idled_cycles);
} }
void ClearPendingEvents() void ClearPendingEvents()
{ {
while (first) while (s_first_event)
{ {
Event* e = first->next; Event* e = s_first_event->next;
FreeEvent(first); FreeEvent(s_first_event);
first = e; s_first_event = e;
} }
} }
static void AddEventToQueue(Event* ne) static void AddEventToQueue(Event* ne)
{ {
Event* prev = nullptr; Event* prev = nullptr;
Event** pNext = &first; Event** pNext = &s_first_event;
for (;;) for (;;)
{ {
Event*& next = *pNext; Event*& next = *pNext;
@ -293,7 +291,7 @@ void ScheduleEvent(s64 cycles_into_future, int event_type, u64 userdata, FromThr
ne->type = event_type; ne->type = event_type;
// If this event needs to be scheduled before the next advance(), force one early // If this event needs to be scheduled before the next advance(), force one early
if (!globalTimerIsSane) if (!s_is_global_timer_sane)
ForceExceptionCheck(cycles_into_future); ForceExceptionCheck(cycles_into_future);
AddEventToQueue(ne); AddEventToQueue(ne);
@ -304,31 +302,31 @@ void ScheduleEvent(s64 cycles_into_future, int event_type, u64 userdata, FromThr
{ {
ERROR_LOG(POWERPC, "Someone scheduled an off-thread \"%s\" event while netplay or " ERROR_LOG(POWERPC, "Someone scheduled an off-thread \"%s\" event while netplay or "
"movie play/record was active. This is likely to cause a desync.", "movie play/record was active. This is likely to cause a desync.",
event_types[event_type].name.c_str()); s_event_types[event_type].name.c_str());
} }
std::lock_guard<std::mutex> lk(tsWriteLock); std::lock_guard<std::mutex> lk(s_ts_write_lock);
Event ne; Event ne;
ne.time = g_globalTimer + cycles_into_future; ne.time = g_global_timer + cycles_into_future;
ne.type = event_type; ne.type = event_type;
ne.userdata = userdata; ne.userdata = userdata;
tsQueue.Push(ne); s_ts_queue.Push(ne);
} }
} }
void RemoveEvent(int event_type) void RemoveEvent(int event_type)
{ {
while (first && first->type == event_type) while (s_first_event && s_first_event->type == event_type)
{ {
Event* next = first->next; Event* next = s_first_event->next;
FreeEvent(first); FreeEvent(s_first_event);
first = next; s_first_event = next;
} }
if (!first) if (!s_first_event)
return; return;
Event* prev = first; Event* prev = s_first_event;
Event* ptr = prev->next; Event* ptr = prev->next;
while (ptr) while (ptr)
{ {
@ -354,20 +352,19 @@ void RemoveAllEvents(int event_type)
void ForceExceptionCheck(s64 cycles) void ForceExceptionCheck(s64 cycles)
{ {
if (s64(DowncountToCycles(PowerPC::ppcState.downcount)) > cycles) if (DowncountToCycles(PowerPC::ppcState.downcount) > cycles)
{ {
// downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int here. // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int here.
g_slicelength -= // Account for cycles already executed by adjusting the g_slice_length
(DowncountToCycles(PowerPC::ppcState.downcount) - g_slice_length -= (DowncountToCycles(PowerPC::ppcState.downcount) - static_cast<int>(cycles));
(int)cycles); // Account for cycles already executed by adjusting the g_slicelength PowerPC::ppcState.downcount = CyclesToDowncount(static_cast<int>(cycles));
PowerPC::ppcState.downcount = CyclesToDowncount((int)cycles);
} }
} }
void MoveEvents() void MoveEvents()
{ {
BaseEvent sevt; BaseEvent sevt;
while (tsQueue.Pop(sevt)) while (s_ts_queue.Pop(sevt))
{ {
Event* evt = GetNewEvent(); Event* evt = GetNewEvent();
evt->time = sevt.time; evt->time = sevt.time;
@ -381,35 +378,35 @@ void Advance()
{ {
MoveEvents(); MoveEvents();
int cyclesExecuted = g_slicelength - DowncountToCycles(PowerPC::ppcState.downcount); int cyclesExecuted = g_slice_length - DowncountToCycles(PowerPC::ppcState.downcount);
g_globalTimer += cyclesExecuted; g_global_timer += cyclesExecuted;
s_lastOCFactor = SConfig::GetInstance().m_OCEnable ? SConfig::GetInstance().m_OCFactor : 1.0f; s_last_OC_factor = SConfig::GetInstance().m_OCEnable ? SConfig::GetInstance().m_OCFactor : 1.0f;
g_lastOCFactor_inverted = 1.0f / s_lastOCFactor; g_last_OC_factor_inverted = 1.0f / s_last_OC_factor;
g_slicelength = maxslicelength; g_slice_length = MAX_SLICE_LENGTH;
globalTimerIsSane = true; s_is_global_timer_sane = true;
while (first && first->time <= g_globalTimer) while (s_first_event && s_first_event->time <= g_global_timer)
{ {
// LOG(POWERPC, "[Scheduler] %s (%lld, %lld) ", // LOG(POWERPC, "[Scheduler] %s (%lld, %lld) ",
// event_types[first->type].name ? event_types[first->type].name : "?", // s_event_types[s_first_event->type].name ? s_event_types[s_first_event->type].name
// (u64)g_globalTimer, (u64)first->time); // : "?",
Event* evt = first; // (u64)g_global_timer, (u64)s_first_event->time);
first = first->next; Event* evt = s_first_event;
event_types[evt->type].callback(evt->userdata, (int)(g_globalTimer - evt->time)); s_first_event = s_first_event->next;
s_event_types[evt->type].callback(evt->userdata, g_global_timer - evt->time);
FreeEvent(evt); FreeEvent(evt);
} }
globalTimerIsSane = false; s_is_global_timer_sane = false;
if (first) if (s_first_event)
{ {
g_slicelength = (int)(first->time - g_globalTimer); g_slice_length =
if (g_slicelength > maxslicelength) static_cast<int>(std::min<s64>(s_first_event->time - g_global_timer, MAX_SLICE_LENGTH));
g_slicelength = maxslicelength;
} }
PowerPC::ppcState.downcount = CyclesToDowncount(g_slicelength); PowerPC::ppcState.downcount = CyclesToDowncount(g_slice_length);
// Check for any external exceptions. // Check for any external exceptions.
// It's important to do this after processing events otherwise any exceptions will be delayed // It's important to do this after processing events otherwise any exceptions will be delayed
@ -420,10 +417,10 @@ void Advance()
void LogPendingEvents() void LogPendingEvents()
{ {
Event* ptr = first; Event* ptr = s_first_event;
while (ptr) while (ptr)
{ {
INFO_LOG(POWERPC, "PENDING: Now: %" PRId64 " Pending: %" PRId64 " Type: %d", g_globalTimer, INFO_LOG(POWERPC, "PENDING: Now: %" PRId64 " Pending: %" PRId64 " Type: %d", g_global_timer,
ptr->time, ptr->type); ptr->time, ptr->type);
ptr = ptr->next; ptr = ptr->next;
} }
@ -439,22 +436,22 @@ void Idle()
Fifo::FlushGpu(); Fifo::FlushGpu();
} }
idledCycles += DowncountToCycles(PowerPC::ppcState.downcount); s_idled_cycles += DowncountToCycles(PowerPC::ppcState.downcount);
PowerPC::ppcState.downcount = 0; PowerPC::ppcState.downcount = 0;
} }
std::string GetScheduledEventsSummary() std::string GetScheduledEventsSummary()
{ {
Event* ptr = first; Event* ptr = s_first_event;
std::string text = "Scheduled events\n"; std::string text = "Scheduled events\n";
text.reserve(1000); text.reserve(1000);
while (ptr) while (ptr)
{ {
unsigned int t = ptr->type; unsigned int t = ptr->type;
if (t >= event_types.size()) if (t >= s_event_types.size())
PanicAlertT("Invalid event type %i", t); PanicAlertT("Invalid event type %i", t);
const std::string& name = event_types[ptr->type].name; const std::string& name = s_event_types[ptr->type].name;
text += StringFromFormat("%s : %" PRIi64 " %016" PRIx64 "\n", name.c_str(), ptr->time, text += StringFromFormat("%s : %" PRIi64 " %016" PRIx64 "\n", name.c_str(), ptr->time,
ptr->userdata); ptr->userdata);
@ -465,42 +462,42 @@ std::string GetScheduledEventsSummary()
u32 GetFakeDecStartValue() u32 GetFakeDecStartValue()
{ {
return fakeDecStartValue; return s_fake_dec_start_value;
} }
void SetFakeDecStartValue(u32 val) void SetFakeDecStartValue(u32 val)
{ {
fakeDecStartValue = val; s_fake_dec_start_value = val;
} }
u64 GetFakeDecStartTicks() u64 GetFakeDecStartTicks()
{ {
return fakeDecStartTicks; return s_fake_dec_start_ticks;
} }
void SetFakeDecStartTicks(u64 val) void SetFakeDecStartTicks(u64 val)
{ {
fakeDecStartTicks = val; s_fake_dec_start_ticks = val;
} }
u64 GetFakeTBStartValue() u64 GetFakeTBStartValue()
{ {
return g_fakeTBStartValue; return g_fake_TB_start_value;
} }
void SetFakeTBStartValue(u64 val) void SetFakeTBStartValue(u64 val)
{ {
g_fakeTBStartValue = val; g_fake_TB_start_value = val;
} }
u64 GetFakeTBStartTicks() u64 GetFakeTBStartTicks()
{ {
return g_fakeTBStartTicks; return g_fake_TB_start_ticks;
} }
void SetFakeTBStartTicks(u64 val) void SetFakeTBStartTicks(u64 val)
{ {
g_fakeTBStartTicks = val; g_fake_TB_start_ticks = val;
} }
} // namespace } // namespace

View File

@ -25,11 +25,11 @@ class PointerWrap;
namespace CoreTiming namespace CoreTiming
{ {
// These really shouldn't be global, but jit64 accesses them directly // These really shouldn't be global, but jit64 accesses them directly
extern s64 g_globalTimer; extern s64 g_global_timer;
extern u64 g_fakeTBStartValue; extern u64 g_fake_TB_start_value;
extern u64 g_fakeTBStartTicks; extern u64 g_fake_TB_start_ticks;
extern int g_slicelength; extern int g_slice_length;
extern float g_lastOCFactor_inverted; extern float g_last_OC_factor_inverted;
void Init(); void Init();
void Shutdown(); void Shutdown();

View File

@ -198,7 +198,7 @@ void Interpreter::SingleStep()
{ {
SingleStepInner(); SingleStepInner();
CoreTiming::g_slicelength = 1; CoreTiming::g_slice_length = 1;
PowerPC::ppcState.downcount = 0; PowerPC::ppcState.downcount = 0;
CoreTiming::Advance(); CoreTiming::Advance();

View File

@ -286,13 +286,13 @@ void Jit64::mfspr(UGeckoInstruction inst)
// cost of calling out to C for this is actually significant. // cost of calling out to C for this is actually significant.
// Scale downcount by the CPU overclocking factor. // Scale downcount by the CPU overclocking factor.
CVTSI2SS(XMM0, PPCSTATE(downcount)); CVTSI2SS(XMM0, PPCSTATE(downcount));
MULSS(XMM0, M(&CoreTiming::g_lastOCFactor_inverted)); MULSS(XMM0, M(&CoreTiming::g_last_OC_factor_inverted));
CVTSS2SI(RDX, R(XMM0)); // RDX is downcount scaled by the overclocking factor CVTSS2SI(RDX, R(XMM0)); // RDX is downcount scaled by the overclocking factor
MOV(32, R(RAX), M(&CoreTiming::g_slicelength)); MOV(32, R(RAX), M(&CoreTiming::g_slice_length));
SUB(64, R(RAX), R(RDX)); // cycles since the last CoreTiming::Advance() event is (slicelength - SUB(64, R(RAX), R(RDX)); // cycles since the last CoreTiming::Advance() event is (slicelength -
// Scaled_downcount) // Scaled_downcount)
ADD(64, R(RAX), M(&CoreTiming::g_globalTimer)); ADD(64, R(RAX), M(&CoreTiming::g_global_timer));
SUB(64, R(RAX), M(&CoreTiming::g_fakeTBStartTicks)); SUB(64, R(RAX), M(&CoreTiming::g_fake_TB_start_ticks));
// 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 *after* the // timing, but as of currently, this can break games. If we end up reading a time *after* the
@ -308,7 +308,7 @@ void Jit64::mfspr(UGeckoInstruction inst)
// a / 12 = (a * 0xAAAAAAAAAAAAAAAB) >> 67 // a / 12 = (a * 0xAAAAAAAAAAAAAAAB) >> 67
MOV(64, R(RDX), Imm64(0xAAAAAAAAAAAAAAABULL)); MOV(64, R(RDX), Imm64(0xAAAAAAAAAAAAAAABULL));
MUL(64, R(RDX)); MUL(64, R(RDX));
MOV(64, R(RAX), M(&CoreTiming::g_fakeTBStartValue)); MOV(64, R(RAX), M(&CoreTiming::g_fake_TB_start_value));
SHR(64, R(RDX), Imm8(3)); SHR(64, R(RDX), Imm8(3));
ADD(64, R(RAX), R(RDX)); ADD(64, R(RAX), R(RDX));
MOV(64, PPCSTATE(spr[SPR_TL]), R(RAX)); MOV(64, PPCSTATE(spr[SPR_TL]), R(RAX));

View File

@ -234,9 +234,9 @@ void JitArm64::mfspr(UGeckoInstruction inst)
// 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_globalTimer); MOVI2R(XA, (u64)&CoreTiming::g_global_timer);
LDR(INDEX_UNSIGNED, XA, XA, 0); LDR(INDEX_UNSIGNED, XA, XA, 0);
MOVI2R(XB, (u64)&CoreTiming::g_fakeTBStartTicks); MOVI2R(XB, (u64)&CoreTiming::g_fake_TB_start_ticks);
LDR(INDEX_UNSIGNED, XB, XB, 0); LDR(INDEX_UNSIGNED, XB, XB, 0);
SUB(XA, XA, XB); SUB(XA, XA, XB);
@ -254,7 +254,7 @@ void JitArm64::mfspr(UGeckoInstruction inst)
ADD(XB, XB, 1); ADD(XB, XB, 1);
UMULH(XA, XA, XB); UMULH(XA, XA, XB);
MOVI2R(XB, (u64)&CoreTiming::g_fakeTBStartValue); MOVI2R(XB, (u64)&CoreTiming::g_fake_TB_start_value);
LDR(INDEX_UNSIGNED, XB, XB, 0); LDR(INDEX_UNSIGNED, XB, XB, 0);
ADD(XA, XB, XA, ArithOption(XA, ST_LSR, 3)); ADD(XA, XB, XA, ArithOption(XA, ST_LSR, 3));
STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(spr[SPR_TL])); STR(INDEX_UNSIGNED, XA, PPC_REG, PPCSTATE_OFF(spr[SPR_TL]));