diff --git a/Source/Core/Core/Src/CoreTiming.cpp b/Source/Core/Core/Src/CoreTiming.cpp index 73ee67100a..459df3935b 100644 --- a/Source/Core/Core/Src/CoreTiming.cpp +++ b/Source/Core/Core/Src/CoreTiming.cpp @@ -66,7 +66,7 @@ s64 idledCycles; Common::CriticalSection externalEventSection; -void (*advanceCallback)(int cyclesExecuted); +void (*advanceCallback)(int cyclesExecuted) = NULL; Event* GetNewEvent() { diff --git a/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp b/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp index 44f79f0043..6ac1edca71 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp +++ b/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp @@ -271,13 +271,10 @@ void CEXIIPL::TransferByte(u8& _uByte) if (m_uPosition == 3) { // Get the time ... - // Subtract Wii bias - u32 GCTime = CEXIIPL::GetGCTime() - cWiiBias; - u8* pGCTime = (u8*)&GCTime; - for (int i=0; i<4; i++) - { - m_RTC[i] = pGCTime[i^3]; - } + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) + *((u32 *)&m_RTC) = Common::swap32(CEXIIPL::GetGCTime() - cWiiBias); // Subtract Wii bias + else + *((u32 *)&m_RTC) = Common::swap32(CEXIIPL::GetGCTime()); #if MAX_LOGLEVEL >= INFO_LEVEL diff --git a/Source/Core/Core/Src/HW/SystemTimers.cpp b/Source/Core/Core/Src/HW/SystemTimers.cpp index 1b39eeaea1..69491cad8f 100644 --- a/Source/Core/Core/Src/HW/SystemTimers.cpp +++ b/Source/Core/Core/Src/HW/SystemTimers.cpp @@ -81,8 +81,10 @@ namespace SystemTimers u32 CPU_CORE_CLOCK = 486000000u; // 486 mhz (its not 485, stop bugging me!) -s64 fakeDec; -u64 startTimeBaseTicks; +u32 fakeDecStartValue; +u64 fakeDecStartTicks; +u64 fakeTBStartValue; +u64 fakeTBStartTicks; /* Gamecube MHz @@ -189,9 +191,6 @@ void SICallback(u64 userdata, int cyclesLate) void DecrementerCallback(u64 userdata, int cyclesLate) { - // Why is fakeDec too big here? - // A: Because it's 64bit (0xffffffffffffffff)...? - fakeDec = -1; PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF; Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_DECREMENTER); } @@ -199,23 +198,32 @@ void DecrementerCallback(u64 userdata, int cyclesLate) void DecrementerSet() { u32 decValue = PowerPC::ppcState.spr[SPR_DEC]; - fakeDec = decValue * TIMER_RATIO; + CoreTiming::RemoveEvent(et_Dec); - CoreTiming::ScheduleEvent(decValue * TIMER_RATIO, et_Dec); + if ((decValue & 0x80000000) == 0) + { + fakeDecStartTicks = CoreTiming::GetTicks(); + fakeDecStartValue = decValue; + + CoreTiming::ScheduleEvent(decValue * TIMER_RATIO, et_Dec); + } } -void AdvanceCallback(int cyclesExecuted) +u32 GetFakeDecrementer() { - if (PowerPC::GetState() != PowerPC::CPU_RUNNING) - return; - - fakeDec -= cyclesExecuted; - u64 timebase_ticks = CoreTiming::GetTicks() / TIMER_RATIO; - *(u64*)&TL = timebase_ticks + startTimeBaseTicks; //works since we are little endian and TL comes first :) - if (fakeDec >= 0) - PowerPC::ppcState.spr[SPR_DEC] = (u32)fakeDec / TIMER_RATIO; + return (fakeDecStartValue - (u32)((CoreTiming::GetTicks() - fakeDecStartTicks) / TIMER_RATIO)); } +void TimeBaseSet() +{ + fakeTBStartTicks = CoreTiming::GetTicks(); + fakeTBStartValue = *((u64 *)&TL); +} + +u64 GetFakeTimeBase() +{ + return fakeTBStartValue + ((CoreTiming::GetTicks() - fakeTBStartTicks) / TIMER_RATIO); +} // For DC watchdog hack void FakeGPWatchdogCallback(u64 userdata, int cyclesLate) @@ -273,7 +281,11 @@ void Init() Common::Timer::IncreaseResolution(); // store and convert localtime at boot to timebase ticks - startTimeBaseTicks = (u64)(CPU_CORE_CLOCK / TIMER_RATIO) * (u64)CEXIIPL::GetGCTime(); + fakeTBStartValue = (u64)(CPU_CORE_CLOCK / TIMER_RATIO) * (u64)CEXIIPL::GetGCTime(); + fakeTBStartTicks = CoreTiming::GetTicks(); + + fakeDecStartValue = 0xFFFFFFFF; + u64 fakeDecStartTicks = CoreTiming::GetTicks(); et_Dec = CoreTiming::RegisterEvent("DecCallback", DecrementerCallback); et_AI = CoreTiming::RegisterEvent("AICallback", AICallback); @@ -300,8 +312,6 @@ void Init() if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) CoreTiming::ScheduleEvent(IPC_HLE_PERIOD, et_IPC_HLE); - - CoreTiming::RegisterAdvanceCallback(&AdvanceCallback); } void Shutdown() diff --git a/Source/Core/Core/Src/HW/SystemTimers.h b/Source/Core/Core/Src/HW/SystemTimers.h index 6bb36d884a..ec8e425907 100644 --- a/Source/Core/Core/Src/HW/SystemTimers.h +++ b/Source/Core/Core/Src/HW/SystemTimers.h @@ -29,6 +29,10 @@ void Shutdown(); // Notify timing system that somebody wrote to the decrementer void DecrementerSet(); +u32 GetFakeDecrementer(); + +void TimeBaseSet(); +u64 GetFakeTimeBase(); } diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp index 22f923fbbf..caec9f5866 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp @@ -263,9 +263,8 @@ void Interpreter::mtsrin(UGeckoInstruction _inst) void Interpreter::mftb(UGeckoInstruction _inst) { int iIndex = (_inst.TBR >> 5) | ((_inst.TBR & 0x1F) << 5); - if (iIndex == SPR_TL) m_GPR[_inst.RD] = TL; - else if (iIndex == SPR_TU) m_GPR[_inst.RD] = TU; - else _dbg_assert_(POWERPC, 0); + _dbg_assert_msg_(POWERPC, (iIndex == SPR_TL) || (iIndex == SPR_TU), "Invalid mftb"); + mfspr(_inst); } @@ -279,9 +278,18 @@ void Interpreter::mfspr(UGeckoInstruction _inst) switch (iIndex) { - //case SPR_DEC: - // MessageBox(NULL, "Read from DEC", "????", MB_OK); - // break; + case SPR_DEC: + if ((rSPR(iIndex) & 0x80000000) == 0) // We are still decrementing + { + rSPR(iIndex) = SystemTimers::GetFakeDecrementer(); + } + break; + + case SPR_TL: + case SPR_TU: + *((u64 *)&TL) = SystemTimers::GetFakeTimeBase(); //works since we are little endian and TL comes first :) + break; + case SPR_WPAR: { // If wpar_empty ever is false, Paper Mario hangs. Strange. @@ -318,10 +326,12 @@ void Interpreter::mtspr(UGeckoInstruction _inst) case SPR_TL_W: TL = m_GPR[_inst.RD]; + SystemTimers::TimeBaseSet(); break; case SPR_TU_W: TU = m_GPR[_inst.RD]; + SystemTimers::TimeBaseSet(); break; case SPR_HID0: // HID0 @@ -416,10 +426,7 @@ void Interpreter::mtspr(UGeckoInstruction _inst) PanicAlert("Interesting - Software triggered Decrementer exception"); Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_DECREMENTER); } - else - { - SystemTimers::DecrementerSet(); - } + SystemTimers::DecrementerSet(); break; // Page table base etc diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp index b2c5487997..52d3ad6453 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -90,15 +90,11 @@ void Jit64::mfspr(UGeckoInstruction inst) switch (iIndex) { case SPR_WPAR: - Default(inst); - return; - // case SPR_DEC: - //MessageBox(NULL, "Read from DEC", "????", MB_OK); - //break; + case SPR_DEC: case SPR_TL: case SPR_TU: - //CALL((void Jit64::*)&CoreTiming::Advance); - // fall through + Default(inst); + return; default: gpr.Lock(d); gpr.BindToRegister(d, false); diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.cpp b/Source/Core/Core/Src/PowerPC/PowerPC.cpp index 9632ea6b4d..3729b020e2 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/Src/PowerPC/PowerPC.cpp @@ -26,6 +26,7 @@ #include "../HW/CPU.h" #include "../Core.h" #include "../CoreTiming.h" +#include "../HW/SystemTimers.h" #include "Interpreter/Interpreter.h" #include "JitCommon/JitBase.h" @@ -73,7 +74,13 @@ void ExpandCR() void DoState(PointerWrap &p) { + rSPR(SPR_DEC) = SystemTimers::GetFakeDecrementer(); + *((u64 *)&TL) = SystemTimers::GetFakeTimeBase(); //works since we are little endian and TL comes first :) + p.Do(ppcState); + + SystemTimers::DecrementerSet(); + SystemTimers::TimeBaseSet(); } void ResetRegisters() @@ -110,10 +117,12 @@ void ResetRegisters() TL = 0; TU = 0; + SystemTimers::TimeBaseSet(); // MSR should be 0x40, but we don't emulate BS1, so it would never be turned off :} ppcState.msr = 0; rDEC = 0xFFFFFFFF; + SystemTimers::DecrementerSet(); } void Init(int cpu_core)