project64/Source/Project64-core/N64System/Mips/SystemTiming.cpp

470 lines
14 KiB
C++
Raw Normal View History

#include "stdafx.h"
2022-10-10 00:22:17 +00:00
#include <Project64-core/3rdParty/zip.h>
#include <Project64-core/N64System/MemoryHandler/AudioInterfaceHandler.h>
#include <Project64-core/N64System/Mips/Disk.h>
2022-10-10 00:22:17 +00:00
#include <Project64-core/N64System/Mips/Register.h>
#include <Project64-core/N64System/Mips/SystemTiming.h>
2021-04-14 05:34:15 +00:00
#include <Project64-core/N64System/N64System.h>
2022-10-10 00:22:17 +00:00
#include <Project64-core/N64System/SystemGlobals.h>
CSystemTimer::CSystemTimer(CN64System & System) :
m_System(System),
m_LastUpdate(0),
m_NextTimer(System.m_NextTimer),
m_Current(UnknownTimer),
m_inFixTimer(false),
m_Reg(System.m_Reg),
m_RomMemoryHandler(System.m_MMU_VM.RomMemory()),
m_AudioInterface(System.m_MMU_VM.AudioInterface())
{
memset(m_TimerDetatils, 0, sizeof(m_TimerDetatils));
}
void CSystemTimer::Reset()
{
// Initialize structure
2015-12-13 06:58:08 +00:00
for (int i = 0; i < MaxTimer; i++)
{
m_TimerDetatils[i].Active = false;
m_TimerDetatils[i].CyclesToTimer = 0;
}
m_Current = UnknownTimer;
m_LastUpdate = 0;
m_NextTimer = 0;
2015-12-13 06:58:08 +00:00
SetTimer(ViTimer, 50000, false);
SetCompareTimer();
}
2015-12-13 06:58:08 +00:00
void CSystemTimer::SetTimer(TimerType Type, uint32_t Cycles, bool bRelative)
{
Cycles *= CGameSettings::OverClockModifier();
2015-12-13 06:58:08 +00:00
if (Type >= MaxTimer || Type == UnknownTimer)
{
g_Notify->BreakPoint(__FILE__, __LINE__);
return;
}
UpdateTimers();
m_TimerDetatils[Type].Active = true;
if (bRelative)
{
if (m_TimerDetatils[Type].Active)
{
m_TimerDetatils[Type].CyclesToTimer += Cycles; // Add to the timer
2015-12-13 06:58:08 +00:00
}
else
{
2022-10-10 00:22:17 +00:00
m_TimerDetatils[Type].CyclesToTimer = (int64_t)Cycles - (int64_t)m_NextTimer; // Replace the new cycles
2015-12-13 06:58:08 +00:00
}
}
else
{
2022-10-10 00:22:17 +00:00
m_TimerDetatils[Type].CyclesToTimer = (int64_t)Cycles - (int64_t)m_NextTimer; // Replace the new cycles
2015-12-13 06:58:08 +00:00
}
FixTimers();
}
2015-12-13 06:58:08 +00:00
uint32_t CSystemTimer::GetTimer(TimerType Type)
{
2015-12-13 06:58:08 +00:00
if (Type >= MaxTimer || Type == UnknownTimer)
{
g_Notify->BreakPoint(__FILE__, __LINE__);
return 0;
}
if (!m_TimerDetatils[Type].Active)
{
return 0;
}
int64_t CyclesToTimer = m_TimerDetatils[Type].CyclesToTimer + m_NextTimer;
2015-12-13 06:58:08 +00:00
if (CyclesToTimer < 0)
{
return 0;
}
if (CyclesToTimer > 0x7FFFFFFF)
{
return 0x7FFFFFFF;
}
return (uint32_t)(CyclesToTimer / CGameSettings::OverClockModifier());
}
2015-12-13 06:58:08 +00:00
void CSystemTimer::StopTimer(TimerType Type)
{
2015-12-13 06:58:08 +00:00
if (Type >= MaxTimer || Type == UnknownTimer)
{
g_Notify->BreakPoint(__FILE__, __LINE__);
return;
}
m_TimerDetatils[Type].Active = false;
FixTimers();
}
void CSystemTimer::FixTimers()
{
2015-12-13 06:58:08 +00:00
if (m_inFixTimer)
{
return;
}
m_inFixTimer = true;
2015-12-13 06:58:08 +00:00
UpdateTimers();
if (GetTimer(CompareTimer) > 0x60000000)
{
SetCompareTimer();
}
// Update the cycles for the remaining number of cycles to timer
2015-12-13 06:58:08 +00:00
int count;
for (count = 0; count < MaxTimer; count++)
{
if (!m_TimerDetatils[count].Active)
{
continue;
}
m_TimerDetatils[count].CyclesToTimer += m_NextTimer;
}
// Set max timer
2015-12-13 06:58:08 +00:00
m_NextTimer = 0x7FFFFFFF;
// Find the smallest timer left to go
2015-12-13 06:58:08 +00:00
for (count = 0; count < MaxTimer; count++)
{
if (!m_TimerDetatils[count].Active)
{
continue;
}
if (m_TimerDetatils[count].CyclesToTimer >= m_NextTimer)
{
continue;
}
m_NextTimer = (int)m_TimerDetatils[count].CyclesToTimer;
m_Current = (TimerType)count;
}
// Move the timer back this value
2015-12-13 06:58:08 +00:00
for (count = 0; count < MaxTimer; count++)
{
if (!m_TimerDetatils[count].Active)
{
continue;
}
m_TimerDetatils[count].CyclesToTimer -= m_NextTimer;
}
m_LastUpdate = m_NextTimer;
m_inFixTimer = false;
}
void CSystemTimer::UpdateTimers()
{
int TimeTaken = (m_LastUpdate - m_NextTimer) / CGameSettings::OverClockModifier();
2015-12-13 06:58:08 +00:00
if (TimeTaken != 0)
{
int32_t random, wired;
2015-12-13 06:58:08 +00:00
m_LastUpdate = m_NextTimer;
m_Reg.COUNT_REGISTER += TimeTaken;
2022-09-19 07:06:44 +00:00
random = (uint32_t)m_Reg.RANDOM_REGISTER - ((TimeTaken * CGameSettings::OverClockModifier()) / m_System.CountPerOp());
wired = (uint32_t)m_Reg.WIRED_REGISTER;
if (random < wired)
2015-12-13 06:58:08 +00:00
{
2016-02-06 08:07:15 +00:00
if (wired == 0)
{
random &= 31;
}
else
{
uint32_t increment = 32 - wired;
random += ((wired - random + increment - 1) / increment) * increment;
2016-02-06 08:07:15 +00:00
}
2015-12-13 06:58:08 +00:00
}
m_Reg.RANDOM_REGISTER = random;
2015-12-13 06:58:08 +00:00
}
}
void CSystemTimer::TimerDone()
{
2015-12-13 06:58:08 +00:00
UpdateTimers();
2015-12-13 06:58:08 +00:00
switch (m_Current)
{
case CSystemTimer::CompareTimer:
m_Reg.FAKE_CAUSE_REGISTER |= CAUSE_IP7;
m_Reg.CheckInterrupts();
2015-12-13 06:58:08 +00:00
UpdateCompareTimer();
break;
case CSystemTimer::SoftResetTimer:
StopTimer(CSystemTimer::SoftResetTimer);
m_System.ExternalEvent(SysEvent_ResetCPU_SoftDone);
2015-12-13 06:58:08 +00:00
break;
case CSystemTimer::SiTimer:
StopTimer(CSystemTimer::SiTimer);
m_Reg.MI_INTR_REG |= MI_INTR_SI;
m_Reg.SI_STATUS_REG |= SI_STATUS_INTERRUPT;
m_Reg.CheckInterrupts();
2015-12-13 06:58:08 +00:00
break;
case CSystemTimer::PiTimer:
StopTimer(CSystemTimer::PiTimer);
m_Reg.PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY;
2022-07-04 07:44:27 +00:00
m_Reg.PI_STATUS_REG |= PI_STATUS_INTERRUPT;
m_Reg.MI_INTR_REG |= MI_INTR_PI;
m_Reg.CheckInterrupts();
2015-12-13 06:58:08 +00:00
break;
case CSystemTimer::DDPiTimer:
StopTimer(CSystemTimer::DDPiTimer);
m_Reg.PI_STATUS_REG &= ~PI_STATUS_DMA_BUSY;
DiskBMUpdate();
m_Reg.MI_INTR_REG |= MI_INTR_PI;
2022-07-04 07:44:27 +00:00
m_Reg.PI_STATUS_REG |= PI_STATUS_INTERRUPT;
m_Reg.CheckInterrupts();
break;
case CSystemTimer::DDSeekTimer:
StopTimer(CSystemTimer::DDSeekTimer);
m_Reg.ASIC_STATUS |= DD_STATUS_MECHA_INT;
m_Reg.FAKE_CAUSE_REGISTER |= CAUSE_IP3;
m_Reg.CheckInterrupts();
break;
case CSystemTimer::DDMotorTimer:
StopTimer(CSystemTimer::DDMotorTimer);
m_Reg.ASIC_STATUS |= DD_STATUS_MTR_N_SPIN;
break;
2015-12-13 06:58:08 +00:00
case CSystemTimer::ViTimer:
try
{
m_System.RefreshScreen();
2015-12-13 06:58:08 +00:00
}
catch (...)
{
WriteTrace(TraceN64System, TraceError, "Exception caught\nFile: %s\nLine: %d", __FILE__, __LINE__);
2015-12-13 06:58:08 +00:00
}
m_Reg.MI_INTR_REG |= MI_INTR_VI;
m_Reg.CheckInterrupts();
2015-12-13 06:58:08 +00:00
break;
case CSystemTimer::RspTimer:
StopTimer(CSystemTimer::RspTimer);
2015-12-13 06:58:08 +00:00
try
{
m_System.RunRSP();
2015-12-13 06:58:08 +00:00
}
catch (...)
{
g_Notify->BreakPoint(__FILE__, __LINE__);
}
break;
case CSystemTimer::RSPTimerDlist:
StopTimer(CSystemTimer::RSPTimerDlist);
m_Reg.m_GfxIntrReg |= MI_INTR_DP;
m_Reg.CheckInterrupts();
2015-12-13 06:58:08 +00:00
break;
case CSystemTimer::AiTimerInterrupt:
StopTimer(CSystemTimer::AiTimerInterrupt);
m_AudioInterface.TimerInterrupt();
2015-12-13 06:58:08 +00:00
break;
case CSystemTimer::AiTimerBusy:
StopTimer(CSystemTimer::AiTimerBusy);
m_AudioInterface.TimerBusy();
2015-12-13 06:58:08 +00:00
break;
case CSystemTimer::RomWriteDecay:
m_RomMemoryHandler.RomWriteDecayed();
break;
2015-12-13 06:58:08 +00:00
default:
g_Notify->BreakPoint(__FILE__, __LINE__);
}
//CheckTimer();
/*if (Profiling)
{
StartTimer(LastTimer);
}*/
}
void CSystemTimer::SetCompareTimer()
{
2015-12-13 06:58:08 +00:00
uint32_t NextCompare = 0x7FFFFFFF;
2022-09-19 07:06:44 +00:00
NextCompare = (uint32_t)m_Reg.COMPARE_REGISTER - (uint32_t)m_Reg.COUNT_REGISTER;
if ((NextCompare & 0x80000000) != 0)
2015-12-13 06:58:08 +00:00
{
NextCompare = 0x7FFFFFFF;
2015-12-13 06:58:08 +00:00
}
SetTimer(CompareTimer, NextCompare, false);
}
2015-12-13 06:58:08 +00:00
void CSystemTimer::UpdateCompareTimer(void)
{
2015-12-13 06:58:08 +00:00
SetCompareTimer();
}
2015-12-13 06:58:08 +00:00
bool CSystemTimer::SaveAllowed(void)
{
2015-12-13 06:58:08 +00:00
if (GetTimer(CompareTimer) <= 0)
{
return false;
}
for (int i = 0; i < MaxTimer; i++)
{
if (i == CompareTimer)
{
continue;
}
if (i == ViTimer)
{
continue;
}
if (m_TimerDetatils[i].Active)
{
return false;
}
}
return true;
}
void CSystemTimer::SaveData(zipFile & file) const
{
2015-12-13 06:58:08 +00:00
uint32_t TimerDetailsSize = sizeof(TIMER_DETAILS);
uint32_t Entries = sizeof(m_TimerDetatils) / sizeof(m_TimerDetatils[0]);
zipWriteInFileInZip(file, &TimerDetailsSize, sizeof(TimerDetailsSize));
zipWriteInFileInZip(file, &Entries, sizeof(Entries));
zipWriteInFileInZip(file, (void *)&m_TimerDetatils, sizeof(m_TimerDetatils));
zipWriteInFileInZip(file, (void *)&m_LastUpdate, sizeof(m_LastUpdate));
zipWriteInFileInZip(file, &m_NextTimer, sizeof(m_NextTimer));
zipWriteInFileInZip(file, (void *)&m_Current, sizeof(m_Current));
}
void CSystemTimer::SaveData(CFile & file) const
{
uint32_t TimerDetailsSize = sizeof(TIMER_DETAILS);
uint32_t Entries = sizeof(m_TimerDetatils) / sizeof(m_TimerDetatils[0]);
2016-08-11 07:53:01 +00:00
file.Write(&TimerDetailsSize, sizeof(TimerDetailsSize));
file.Write(&Entries, sizeof(Entries));
file.Write((void *)&m_TimerDetatils, sizeof(m_TimerDetatils));
file.Write((void *)&m_LastUpdate, sizeof(m_LastUpdate));
file.Write(&m_NextTimer, sizeof(m_NextTimer));
file.Write((void *)&m_Current, sizeof(m_Current));
}
void CSystemTimer::LoadData(zipFile & file)
{
2015-12-13 06:58:08 +00:00
uint32_t TimerDetailsSize, Entries;
2015-12-13 06:58:08 +00:00
unzReadCurrentFile(file, &TimerDetailsSize, sizeof(TimerDetailsSize));
unzReadCurrentFile(file, &Entries, sizeof(Entries));
2015-12-13 06:58:08 +00:00
if (TimerDetailsSize != sizeof(TIMER_DETAILS))
{
g_Notify->BreakPoint(__FILE__, __LINE__);
return;
}
if (Entries != sizeof(m_TimerDetatils) / sizeof(m_TimerDetatils[0]))
{
2016-08-11 07:53:01 +00:00
if (Entries < (sizeof(m_TimerDetatils) / sizeof(m_TimerDetatils[0])))
{
memset((void *)&m_TimerDetatils, 0, sizeof(m_TimerDetatils));
unzReadCurrentFile(file, (void *)&m_TimerDetatils, Entries * sizeof(m_TimerDetatils[0]));
}
else
{
g_Notify->BreakPoint(__FILE__, __LINE__);
return;
}
}
else
{
unzReadCurrentFile(file, (void *)&m_TimerDetatils, sizeof(m_TimerDetatils));
2015-12-13 06:58:08 +00:00
}
unzReadCurrentFile(file, (void *)&m_LastUpdate, sizeof(m_LastUpdate));
unzReadCurrentFile(file, &m_NextTimer, sizeof(m_NextTimer));
unzReadCurrentFile(file, (void *)&m_Current, sizeof(m_Current));
}
void CSystemTimer::LoadData(CFile & file)
{
uint32_t TimerDetailsSize, Entries;
file.Read(&TimerDetailsSize, sizeof(TimerDetailsSize));
file.Read(&Entries, sizeof(Entries));
if (TimerDetailsSize != sizeof(TIMER_DETAILS))
{
g_Notify->BreakPoint(__FILE__, __LINE__);
return;
}
if (Entries != sizeof(m_TimerDetatils) / sizeof(m_TimerDetatils[0]))
{
g_Notify->BreakPoint(__FILE__, __LINE__);
return;
}
file.Read((void *)&m_TimerDetatils, sizeof(m_TimerDetatils));
file.Read((void *)&m_LastUpdate, sizeof(m_LastUpdate));
file.Read(&m_NextTimer, sizeof(m_NextTimer));
file.Read((void *)&m_Current, sizeof(m_Current));
}
2022-10-10 00:22:17 +00:00
void CSystemTimer::RecordDifference(CLog & LogFile, const CSystemTimer & rSystemTimer)
{
2015-12-13 06:58:08 +00:00
if (m_LastUpdate != rSystemTimer.m_LastUpdate)
{
LogFile.LogF("Timer-LastUpdate: %X %X\r\n", m_LastUpdate, rSystemTimer.m_LastUpdate);
}
if (m_NextTimer != rSystemTimer.m_NextTimer)
{
LogFile.LogF("Timer-NextTimer: %X %X\r\n", m_NextTimer, rSystemTimer.m_NextTimer);
}
if (m_Current != rSystemTimer.m_Current)
{
LogFile.LogF("Timer-Current %X %X\r\n", m_Current, rSystemTimer.m_Current);
}
if (m_inFixTimer != rSystemTimer.m_inFixTimer)
{
LogFile.LogF("Timer-inFixTimer %X %X\r\n", (int)m_inFixTimer, (int)rSystemTimer.m_inFixTimer);
}
2015-12-13 06:58:08 +00:00
for (int i = 0; i < MaxTimer; i++)
{
if (m_TimerDetatils[i].Active != rSystemTimer.m_TimerDetatils[i].Active)
{
LogFile.LogF("Timer-m_TimerDetatils[%d] %X %X\r\n", i, (int)m_TimerDetatils[i].Active, (int)rSystemTimer.m_TimerDetatils[i].Active);
}
if (m_TimerDetatils[i].CyclesToTimer != rSystemTimer.m_TimerDetatils[i].CyclesToTimer)
{
LogFile.LogF("Timer-m_TimerDetatils[%d] 0x%08X, 0x%08X\r\n", i, (uint32_t)m_TimerDetatils[i].CyclesToTimer, (uint32_t)rSystemTimer.m_TimerDetatils[i].CyclesToTimer);
}
}
}
2022-10-10 00:22:17 +00:00
bool CSystemTimer::operator==(const CSystemTimer & rSystemTimer) const
{
2015-12-13 06:58:08 +00:00
if (m_LastUpdate != rSystemTimer.m_LastUpdate)
{
return false;
}
if (m_NextTimer != rSystemTimer.m_NextTimer)
{
return false;
}
if (m_Current != rSystemTimer.m_Current)
{
return false;
}
if (m_inFixTimer != rSystemTimer.m_inFixTimer)
{
return false;
}
2015-12-13 06:58:08 +00:00
for (int i = 0; i < MaxTimer; i++)
{
if (m_TimerDetatils[i].Active != rSystemTimer.m_TimerDetatils[i].Active)
{
return false;
}
if (m_TimerDetatils[i].CyclesToTimer != rSystemTimer.m_TimerDetatils[i].CyclesToTimer)
{
return false;
}
}
return true;
}
2022-10-10 00:22:17 +00:00
bool CSystemTimer::operator!=(const CSystemTimer & rSystemTimer) const
{
return !(*this == rSystemTimer);
2015-12-13 06:58:08 +00:00
}