diff --git a/Source/Core/Core/HW/SystemTimers.cpp b/Source/Core/Core/HW/SystemTimers.cpp index b82ec4c4ee..53452a8d65 100644 --- a/Source/Core/Core/HW/SystemTimers.cpp +++ b/Source/Core/Core/HW/SystemTimers.cpp @@ -70,31 +70,6 @@ namespace SystemTimers static u32 CPU_CORE_CLOCK = 486000000u; // 486 mhz (its not 485, stop bugging me!) -/* -GameCube MHz -flipper <-> ARAM bus: 81 (DSP) -gekko <-> flipper bus: 162 -flipper <-> 1T-SRAM bus: 324 -gekko: 486 - -These contain some guesses: -Wii MHz -hollywood <-> GDDR3 RAM bus: ??? no idea really -broadway <-> hollywood bus: 243 -hollywood <-> 1T-SRAM bus: 486 -broadway: 729 -*/ -// Ratio of TB and Decrementer to clock cycles. -// TB clk is 1/4 of BUS clk. And it seems BUS clk is really 1/3 of CPU clk. -// So, ratio is 1 / (1/4 * 1/3 = 1/12) = 12. -// note: ZWW is ok and faster with TIMER_RATIO=8 though. -// !!! POSSIBLE STABLE PERF BOOST HACK THERE !!! - -enum -{ - TIMER_RATIO = 12 -}; - static int et_Dec; static int et_VI; static int et_SI; diff --git a/Source/Core/Core/HW/SystemTimers.h b/Source/Core/Core/HW/SystemTimers.h index e0f6d3447f..a98d8085bf 100644 --- a/Source/Core/Core/HW/SystemTimers.h +++ b/Source/Core/Core/HW/SystemTimers.h @@ -9,6 +9,31 @@ namespace SystemTimers { +/* +GameCube MHz +flipper <-> ARAM bus: 81 (DSP) +gekko <-> flipper bus: 162 +flipper <-> 1T-SRAM bus: 324 +gekko: 486 + +These contain some guesses: +Wii MHz +hollywood <-> GDDR3 RAM bus: ??? no idea really +broadway <-> hollywood bus: 243 +hollywood <-> 1T-SRAM bus: 486 +broadway: 729 +*/ +// Ratio of TB and Decrementer to clock cycles. +// TB clk is 1/4 of BUS clk. And it seems BUS clk is really 1/3 of CPU clk. +// So, ratio is 1 / (1/4 * 1/3 = 1/12) = 12. +// note: ZWW is ok and faster with TIMER_RATIO=8 though. +// !!! POSSIBLE STABLE PERF BOOST HACK THERE !!! + +enum +{ + TIMER_RATIO = 12 +}; + u32 GetTicksPerSecond(); void PreInit(); void Init(); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp index 703341ba8a..af2fe33bb8 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -166,10 +166,53 @@ void Jit64::mfspr(UGeckoInstruction inst) int d = inst.RD; switch (iIndex) { - case SPR_WPAR: - case SPR_DEC: case SPR_TL: case SPR_TU: + { + // TODO: we really only need to call GetFakeTimeBase once per JIT block; this matters because + // 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); + // The timer can change within a long block, so add in any difference + if (offset > 0) + ADD(64, R(RAX), Imm32(offset)); + 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); + // Be careful; the actual opcode is for mftb (371), not mfspr (339) + if (js.next_inst.OPCD == 31 && js.next_inst.SUBOP10 == 371 && (nextIndex == SPR_TU || nextIndex == SPR_TL)) + { + int n = js.next_inst.RD; + js.downcountAmount++; + js.skipnext = true; + gpr.Lock(d, n); + if (iIndex == SPR_TL) + MOV(32, gpr.R(d), R(EAX)); + if (nextIndex == SPR_TL) + MOV(32, gpr.R(n), R(EAX)); + SHR(64, R(RAX), Imm8(32)); + if (iIndex == SPR_TU) + MOV(32, gpr.R(d), R(EAX)); + if (nextIndex == SPR_TU) + MOV(32, gpr.R(n), R(EAX)); + } + else + { + gpr.Lock(d); + if (iIndex == SPR_TU) + SHR(64, R(RAX), Imm8(32)); + MOV(32, gpr.R(d), R(EAX)); + } + break; + } + case SPR_WPAR: + case SPR_DEC: case SPR_PMC1: case SPR_PMC2: case SPR_PMC3: @@ -179,9 +222,9 @@ void Jit64::mfspr(UGeckoInstruction inst) gpr.Lock(d); gpr.BindToRegister(d, false); MOV(32, gpr.R(d), M(&PowerPC::ppcState.spr[iIndex])); - gpr.UnlockAll(); break; } + gpr.UnlockAll(); } void Jit64::mtmsr(UGeckoInstruction inst)