- 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;
void (*advanceCallback)(int cyclesExecuted);
void (*advanceCallback)(int cyclesExecuted) = NULL;
Event* GetNewEvent()
{

View File

@ -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

View File

@ -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()

View File

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

View File

@ -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

View File

@ -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);

View File

@ -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)