- Fixed TimeBase and Decrementer registers so that they are updated only when needed

- Fixed RTC for GC homebrews

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6158 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
dok.slade 2010-09-01 23:44:03 +00:00
parent 8d6f98439e
commit 9e17007c90
7 changed files with 67 additions and 44 deletions

View File

@ -66,7 +66,7 @@ s64 idledCycles;
Common::CriticalSection externalEventSection; Common::CriticalSection externalEventSection;
void (*advanceCallback)(int cyclesExecuted); void (*advanceCallback)(int cyclesExecuted) = NULL;
Event* GetNewEvent() Event* GetNewEvent()
{ {

View File

@ -271,13 +271,10 @@ void CEXIIPL::TransferByte(u8& _uByte)
if (m_uPosition == 3) if (m_uPosition == 3)
{ {
// Get the time ... // Get the time ...
// Subtract Wii bias if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
u32 GCTime = CEXIIPL::GetGCTime() - cWiiBias; *((u32 *)&m_RTC) = Common::swap32(CEXIIPL::GetGCTime() - cWiiBias); // Subtract Wii bias
u8* pGCTime = (u8*)&GCTime; else
for (int i=0; i<4; i++) *((u32 *)&m_RTC) = Common::swap32(CEXIIPL::GetGCTime());
{
m_RTC[i] = pGCTime[i^3];
}
#if MAX_LOGLEVEL >= INFO_LEVEL #if MAX_LOGLEVEL >= INFO_LEVEL

View File

@ -81,8 +81,10 @@ namespace SystemTimers
u32 CPU_CORE_CLOCK = 486000000u; // 486 mhz (its not 485, stop bugging me!) u32 CPU_CORE_CLOCK = 486000000u; // 486 mhz (its not 485, stop bugging me!)
s64 fakeDec; u32 fakeDecStartValue;
u64 startTimeBaseTicks; u64 fakeDecStartTicks;
u64 fakeTBStartValue;
u64 fakeTBStartTicks;
/* /*
Gamecube MHz Gamecube MHz
@ -189,9 +191,6 @@ void SICallback(u64 userdata, int cyclesLate)
void DecrementerCallback(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; PowerPC::ppcState.spr[SPR_DEC] = 0xFFFFFFFF;
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_DECREMENTER); Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_DECREMENTER);
} }
@ -199,23 +198,32 @@ void DecrementerCallback(u64 userdata, int cyclesLate)
void DecrementerSet() void DecrementerSet()
{ {
u32 decValue = PowerPC::ppcState.spr[SPR_DEC]; u32 decValue = PowerPC::ppcState.spr[SPR_DEC];
fakeDec = decValue * TIMER_RATIO;
CoreTiming::RemoveEvent(et_Dec); CoreTiming::RemoveEvent(et_Dec);
if ((decValue & 0x80000000) == 0)
{
fakeDecStartTicks = CoreTiming::GetTicks();
fakeDecStartValue = decValue;
CoreTiming::ScheduleEvent(decValue * TIMER_RATIO, et_Dec); CoreTiming::ScheduleEvent(decValue * TIMER_RATIO, et_Dec);
} }
void AdvanceCallback(int cyclesExecuted)
{
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;
} }
u32 GetFakeDecrementer()
{
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 // For DC watchdog hack
void FakeGPWatchdogCallback(u64 userdata, int cyclesLate) void FakeGPWatchdogCallback(u64 userdata, int cyclesLate)
@ -273,7 +281,11 @@ void Init()
Common::Timer::IncreaseResolution(); Common::Timer::IncreaseResolution();
// store and convert localtime at boot to timebase ticks // 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_Dec = CoreTiming::RegisterEvent("DecCallback", DecrementerCallback);
et_AI = CoreTiming::RegisterEvent("AICallback", AICallback); et_AI = CoreTiming::RegisterEvent("AICallback", AICallback);
@ -300,8 +312,6 @@ void Init()
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
CoreTiming::ScheduleEvent(IPC_HLE_PERIOD, et_IPC_HLE); CoreTiming::ScheduleEvent(IPC_HLE_PERIOD, et_IPC_HLE);
CoreTiming::RegisterAdvanceCallback(&AdvanceCallback);
} }
void Shutdown() void Shutdown()

View File

@ -29,6 +29,10 @@ void Shutdown();
// Notify timing system that somebody wrote to the decrementer // Notify timing system that somebody wrote to the decrementer
void DecrementerSet(); void DecrementerSet();
u32 GetFakeDecrementer();
void TimeBaseSet();
u64 GetFakeTimeBase();
} }

View File

@ -263,9 +263,8 @@ void Interpreter::mtsrin(UGeckoInstruction _inst)
void Interpreter::mftb(UGeckoInstruction _inst) void Interpreter::mftb(UGeckoInstruction _inst)
{ {
int iIndex = (_inst.TBR >> 5) | ((_inst.TBR & 0x1F) << 5); int iIndex = (_inst.TBR >> 5) | ((_inst.TBR & 0x1F) << 5);
if (iIndex == SPR_TL) m_GPR[_inst.RD] = TL; _dbg_assert_msg_(POWERPC, (iIndex == SPR_TL) || (iIndex == SPR_TU), "Invalid mftb");
else if (iIndex == SPR_TU) m_GPR[_inst.RD] = TU; mfspr(_inst);
else _dbg_assert_(POWERPC, 0);
} }
@ -279,9 +278,18 @@ void Interpreter::mfspr(UGeckoInstruction _inst)
switch (iIndex) switch (iIndex)
{ {
//case SPR_DEC: case SPR_DEC:
// MessageBox(NULL, "Read from DEC", "????", MB_OK); if ((rSPR(iIndex) & 0x80000000) == 0) // We are still decrementing
// break; {
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: case SPR_WPAR:
{ {
// If wpar_empty ever is false, Paper Mario hangs. Strange. // If wpar_empty ever is false, Paper Mario hangs. Strange.
@ -318,10 +326,12 @@ void Interpreter::mtspr(UGeckoInstruction _inst)
case SPR_TL_W: case SPR_TL_W:
TL = m_GPR[_inst.RD]; TL = m_GPR[_inst.RD];
SystemTimers::TimeBaseSet();
break; break;
case SPR_TU_W: case SPR_TU_W:
TU = m_GPR[_inst.RD]; TU = m_GPR[_inst.RD];
SystemTimers::TimeBaseSet();
break; break;
case SPR_HID0: // HID0 case SPR_HID0: // HID0
@ -416,10 +426,7 @@ void Interpreter::mtspr(UGeckoInstruction _inst)
PanicAlert("Interesting - Software triggered Decrementer exception"); PanicAlert("Interesting - Software triggered Decrementer exception");
Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_DECREMENTER); Common::AtomicOr(PowerPC::ppcState.Exceptions, EXCEPTION_DECREMENTER);
} }
else
{
SystemTimers::DecrementerSet(); SystemTimers::DecrementerSet();
}
break; break;
// Page table base etc // Page table base etc

View File

@ -90,15 +90,11 @@ void Jit64::mfspr(UGeckoInstruction inst)
switch (iIndex) switch (iIndex)
{ {
case SPR_WPAR: case SPR_WPAR:
Default(inst); case SPR_DEC:
return;
// case SPR_DEC:
//MessageBox(NULL, "Read from DEC", "????", MB_OK);
//break;
case SPR_TL: case SPR_TL:
case SPR_TU: case SPR_TU:
//CALL((void Jit64::*)&CoreTiming::Advance); Default(inst);
// fall through return;
default: default:
gpr.Lock(d); gpr.Lock(d);
gpr.BindToRegister(d, false); gpr.BindToRegister(d, false);

View File

@ -26,6 +26,7 @@
#include "../HW/CPU.h" #include "../HW/CPU.h"
#include "../Core.h" #include "../Core.h"
#include "../CoreTiming.h" #include "../CoreTiming.h"
#include "../HW/SystemTimers.h"
#include "Interpreter/Interpreter.h" #include "Interpreter/Interpreter.h"
#include "JitCommon/JitBase.h" #include "JitCommon/JitBase.h"
@ -73,7 +74,13 @@ void ExpandCR()
void DoState(PointerWrap &p) 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); p.Do(ppcState);
SystemTimers::DecrementerSet();
SystemTimers::TimeBaseSet();
} }
void ResetRegisters() void ResetRegisters()
@ -110,10 +117,12 @@ void ResetRegisters()
TL = 0; TL = 0;
TU = 0; TU = 0;
SystemTimers::TimeBaseSet();
// MSR should be 0x40, but we don't emulate BS1, so it would never be turned off :} // MSR should be 0x40, but we don't emulate BS1, so it would never be turned off :}
ppcState.msr = 0; ppcState.msr = 0;
rDEC = 0xFFFFFFFF; rDEC = 0xFFFFFFFF;
SystemTimers::DecrementerSet();
} }
void Init(int cpu_core) void Init(int cpu_core)