daedalus/Source/OSHLE/patch_timer_hle.inl
2021-10-23 21:48:59 +11:00

193 lines
5.8 KiB
C++

#define TEST_DISABLE_TIMER_FUNCS DAEDALUS_PROFILE(__FUNCTION__);
//*****************************************************************************
//
//*****************************************************************************
u32 Patch___osSetTimerIntr()
{
TEST_DISABLE_TIMER_FUNCS
s64 TimeLo = (s64)gGPR[REG_a1]._s32_0;
//s64 qwTimeHi = (s64)(s32)gGPR[REG_a0];
s64 count = (s64)gCPUState.CPUControl[C0_COUNT]._s32;
Write32Bits(VAR_ADDRESS(osSystemLastCount), (u32)count);
s64 sum = (s64)(s32)((s32)count + (s32)TimeLo);
CPU_SetCompare((u32)sum);
return PATCH_RET_JR_RA;
}
//*****************************************************************************
//
//*****************************************************************************
u32 Patch___osInsertTimer()
{
TEST_DISABLE_TIMER_FUNCS
u32 NewTimer = gGPR[REG_a0]._u32_0;
u32 TopTimer = Read32Bits(VAR_ADDRESS(osTopTimer));
u32 InsertTimer = Read32Bits(TopTimer + 0x00); // Read next
u8 * pNewTimerBase = (u8 *)ReadAddress(NewTimer);
u8 * pInsertTimerBase = (u8 *)ReadAddress(InsertTimer);
u64 NewValue = QuickRead64Bits(pNewTimerBase, 0x10); // Check ordering is correct?!
u64 InsertValue = QuickRead64Bits(pInsertTimerBase, 0x10);
#ifdef DAEDALUS_ENABLE_ASSERTS
DAEDALUS_ASSERT( InsertTimer, "osInsertTimer with NULL insert timer" );
#endif
/*
if ( InsertTimer == 0 )
{
// What gives?
DBGConsole_Msg( 0, "[W__osInsertTimer with NULL insert timer" );
// We can quit, because we've not written anything
return PATCH_RET_NOT_PROCESSED0(__osInsertTimer);
}
*/
while (InsertValue < NewValue)
{
// Decrease by the pause for this timer
NewValue -= InsertValue;
InsertTimer = QuickRead32Bits(pInsertTimerBase, 0x0); // Read next timer
pInsertTimerBase = (u8*)ReadAddress(InsertTimer); // keep InsertTimer base pointer updated
InsertValue = QuickRead64Bits(pInsertTimerBase, 0x10);
if (InsertTimer == TopTimer) // At the end of the list?
break;
}
/// Save the modified time value
QuickWrite64Bits(pNewTimerBase, 0x10, NewValue);
// Inserting before InsertTimer
// Modify InsertTimer's values if this is not the sentinel node
if (InsertTimer != TopTimer)
{
InsertValue -= NewValue;
QuickWrite64Bits(pInsertTimerBase, 0x10, InsertValue);
}
// pNewTimer->next = pInsertTimer
QuickWrite32Bits(pNewTimerBase, 0x00, InsertTimer);
// pNewTimer->prev = pInsertTimer->prev
u32 InsertTimerPrev = QuickRead32Bits(pInsertTimerBase, 0x04);
QuickWrite32Bits(pNewTimerBase, 0x04, InsertTimerPrev);
// pInsertTimer->prev->next = pNewTimer
Write32Bits(InsertTimerPrev + 0x00, NewTimer);
// pInsertTimer->prev = pNewTimer
QuickWrite32Bits(pInsertTimerBase, 0x04, NewTimer);
gGPR[REG_v0]._s64 = (s64)(s32)(NewValue >> 32);
gGPR[REG_v1]._s64 = (s64)(s32)((u32)NewValue);
return PATCH_RET_JR_RA;
}
//*****************************************************************************
//
//*****************************************************************************
u32 Patch___osTimerServicesInit_Mario()
{
TEST_DISABLE_TIMER_FUNCS
// TimeHi/Lo share the same base addr by an offset of 4 bytes, perphaps they are the same u64 type?
// This avoids using VAR_ADDRESS(osSystemTimeLo) which is NULL for Killer Instinct..
u8 * pTimeBase = (u8 *)ReadAddress(VAR_ADDRESS(osSystemTimeHi));
#ifdef DAEDALUS_DEBUG_CONSOLE
DBGConsole_Msg(0, "Initialising Timer Services");
#endif
QuickWrite32Bits(pTimeBase, 0x0, 0); // TimeHi
QuickWrite32Bits(pTimeBase, 0x4, 0); // TimeLo
Write32Bits(VAR_ADDRESS(osSystemCount), 0);
Write32Bits(VAR_ADDRESS(osFrameCount), 0);
u32 timer = Read32Bits(VAR_ADDRESS(osTopTimer));
// Get base from OSTimer struct
u8 * pTimerBase = (u8 *)ReadAddress(timer);
// Make list empty
QuickWrite32Bits(pTimerBase, offsetof(OSTimer, next), timer);
QuickWrite32Bits(pTimerBase, offsetof(OSTimer, prev), timer);
QuickWrite64Bits(pTimerBase, offsetof(OSTimer, interval), 0);
QuickWrite64Bits(pTimerBase, offsetof(OSTimer, value), 0);
QuickWrite64Bits(pTimerBase, offsetof(OSTimer, mq), 0);
QuickWrite64Bits(pTimerBase, offsetof(OSTimer, msg), 0);
return PATCH_RET_JR_RA;
}
//*****************************************************************************
//
//*****************************************************************************
// Same as above, but optimised
u32 Patch___osTimerServicesInit_Rugrats()
{
TEST_DISABLE_TIMER_FUNCS
return Patch___osTimerServicesInit_Mario();
}
//*****************************************************************************
//
//*****************************************************************************
u32 Patch_osSetTime()
{
TEST_DISABLE_TIMER_FUNCS
//DBGConsole_Msg(0, "osSetTime(0x%08x%08x)", TimeHi, TimeLo);
u8 * pTimeBase = (u8 *)ReadAddress(VAR_ADDRESS(osSystemTimeHi));
QuickWrite32Bits(pTimeBase, 0x0, gGPR[REG_a1]._u32_0); // TimeHi
QuickWrite32Bits(pTimeBase, 0x4, gGPR[REG_a0]._u32_0); // TimeLo
return PATCH_RET_JR_RA;
}
//*****************************************************************************
//
//*****************************************************************************
u32 Patch_osGetTime()
{
TEST_DISABLE_TIMER_FUNCS
u8 * pTimeBase = (u8 *)ReadAddress(VAR_ADDRESS(osSystemTimeHi));
u32 LastCount = Read32Bits(VAR_ADDRESS(osSystemCount));
u32 TimeLo = QuickRead32Bits(pTimeBase, 0x4);
u32 TimeHi = QuickRead32Bits(pTimeBase, 0x0);
u32 count = gCPUState.CPUControl[C0_COUNT]._u32;
TimeLo += count - LastCount; // Increase by elapsed time
if (LastCount > count) // If an overflow has occurred, increase top timer
TimeHi++;
gGPR[REG_v0]._s64 = (s64)(s32)TimeHi;
gGPR[REG_v1]._s64 = (s64)(s32)TimeLo;
return PATCH_RET_JR_RA;
}
//*****************************************************************************
//
//*****************************************************************************
//ToDo : Implement
u32 Patch_osSetTimer()
{
return PATCH_RET_NOT_PROCESSED;
}