TimingEvents: Swap to 64-bit global ticks

This commit is contained in:
Stenzek 2024-04-21 14:49:57 +10:00
parent 7d80cabf9f
commit 1546b28f46
No known key found for this signature in database
7 changed files with 110 additions and 122 deletions

View File

@ -316,7 +316,7 @@ static ModeRegister s_mode = {};
static u8 s_interrupt_enable_register = INTERRUPT_REGISTER_MASK; static u8 s_interrupt_enable_register = INTERRUPT_REGISTER_MASK;
static u8 s_interrupt_flag_register = 0; static u8 s_interrupt_flag_register = 0;
static u8 s_pending_async_interrupt = 0; static u8 s_pending_async_interrupt = 0;
static u32 s_last_interrupt_time = 0; static GlobalTicks s_last_interrupt_time = 0;
static CDImage::Position s_setloc_position = {}; static CDImage::Position s_setloc_position = {};
static CDImage::LBA s_requested_lba{}; static CDImage::LBA s_requested_lba{};
@ -324,7 +324,7 @@ static CDImage::LBA s_current_lba{}; // this is the hold position
static CDImage::LBA s_seek_start_lba{}; static CDImage::LBA s_seek_start_lba{};
static CDImage::LBA s_seek_end_lba{}; static CDImage::LBA s_seek_end_lba{};
static CDImage::LBA s_physical_lba{}; // current position of the disc with respect to time static CDImage::LBA s_physical_lba{}; // current position of the disc with respect to time
static u32 s_physical_lba_update_tick = 0; static GlobalTicks s_physical_lba_update_tick = 0;
static u32 s_physical_lba_update_carry = 0; static u32 s_physical_lba_update_carry = 0;
static bool s_setloc_pending = false; static bool s_setloc_pending = false;
static bool s_read_after_seek = false; static bool s_read_after_seek = false;
@ -484,7 +484,7 @@ void CDROM::Reset()
s_mode.read_raw_sector = true; s_mode.read_raw_sector = true;
s_interrupt_enable_register = INTERRUPT_REGISTER_MASK; s_interrupt_enable_register = INTERRUPT_REGISTER_MASK;
s_interrupt_flag_register = 0; s_interrupt_flag_register = 0;
s_last_interrupt_time = System::GetGlobalTickCounter() - MINIMUM_INTERRUPT_DELAY; s_last_interrupt_time = TimingEvents::GetGlobalTickCounter() - MINIMUM_INTERRUPT_DELAY;
ClearAsyncInterrupt(); ClearAsyncInterrupt();
s_setloc_position = {}; s_setloc_position = {};
s_seek_start_lba = 0; s_seek_start_lba = 0;
@ -605,14 +605,14 @@ bool CDROM::DoState(StateWrapper& sw)
sw.Do(&s_interrupt_enable_register); sw.Do(&s_interrupt_enable_register);
sw.Do(&s_interrupt_flag_register); sw.Do(&s_interrupt_flag_register);
sw.DoEx(&s_last_interrupt_time, 57, System::GetGlobalTickCounter() - MINIMUM_INTERRUPT_DELAY); //sw.DoEx(&s_last_interrupt_time, 57, TimingEvents::GetGlobalTickCounter() - MINIMUM_INTERRUPT_DELAY);// TODO: FIXME
sw.Do(&s_pending_async_interrupt); sw.Do(&s_pending_async_interrupt);
sw.DoPOD(&s_setloc_position); sw.DoPOD(&s_setloc_position);
sw.Do(&s_current_lba); sw.Do(&s_current_lba);
sw.Do(&s_seek_start_lba); sw.Do(&s_seek_start_lba);
sw.Do(&s_seek_end_lba); sw.Do(&s_seek_end_lba);
sw.DoEx(&s_physical_lba, 49, s_current_lba); sw.DoEx(&s_physical_lba, 49, s_current_lba);
sw.DoEx(&s_physical_lba_update_tick, 49, static_cast<u32>(0)); //sw.DoEx(&s_physical_lba_update_tick, 49, static_cast<u32>(0)); // TODO FIXME
sw.DoEx(&s_physical_lba_update_carry, 54, static_cast<u32>(0)); sw.DoEx(&s_physical_lba_update_carry, 54, static_cast<u32>(0));
sw.Do(&s_setloc_pending); sw.Do(&s_setloc_pending);
sw.Do(&s_read_after_seek); sw.Do(&s_read_after_seek);
@ -1097,7 +1097,7 @@ bool CDROM::HasPendingAsyncInterrupt()
void CDROM::SetInterrupt(Interrupt interrupt) void CDROM::SetInterrupt(Interrupt interrupt)
{ {
s_interrupt_flag_register = static_cast<u8>(interrupt); s_interrupt_flag_register = static_cast<u8>(interrupt);
s_last_interrupt_time = System::GetGlobalTickCounter(); s_last_interrupt_time = TimingEvents::GetGlobalTickCounter();
UpdateInterruptRequest(); UpdateInterruptRequest();
} }
@ -1138,7 +1138,7 @@ void CDROM::QueueDeliverAsyncInterrupt()
return; return;
// underflows here are okay // underflows here are okay
const u32 diff = System::GetGlobalTickCounter() - s_last_interrupt_time; const GlobalTicks diff = TimingEvents::GetGlobalTickCounter() - s_last_interrupt_time;
if (diff >= MINIMUM_INTERRUPT_DELAY) if (diff >= MINIMUM_INTERRUPT_DELAY)
{ {
DeliverAsyncInterrupt(nullptr, 0, 0); DeliverAsyncInterrupt(nullptr, 0, 0);
@ -2442,13 +2442,13 @@ void CDROM::UpdatePositionWhileSeeking()
s_current_lba = current_lba; s_current_lba = current_lba;
s_physical_lba = current_lba; s_physical_lba = current_lba;
s_physical_lba_update_tick = System::GetGlobalTickCounter(); s_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
s_physical_lba_update_carry = 0; s_physical_lba_update_carry = 0;
} }
void CDROM::UpdatePhysicalPosition(bool update_logical) void CDROM::UpdatePhysicalPosition(bool update_logical)
{ {
const u32 ticks = System::GetGlobalTickCounter(); const u32 ticks = TimingEvents::GetGlobalTickCounter();
if (IsSeeking() || IsReadingOrPlaying() || !IsMotorOn()) if (IsSeeking() || IsReadingOrPlaying() || !IsMotorOn())
{ {
// If we're seeking+reading the first sector (no stat bits set), we need to return the set/current lba, not the last // If we're seeking+reading the first sector (no stat bits set), we need to return the set/current lba, not the last
@ -2539,7 +2539,7 @@ void CDROM::SetHoldPosition(CDImage::LBA lba, bool update_subq)
s_current_lba = lba; s_current_lba = lba;
s_physical_lba = lba; s_physical_lba = lba;
s_physical_lba_update_tick = System::GetGlobalTickCounter(); s_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
s_physical_lba_update_carry = 0; s_physical_lba_update_carry = 0;
} }
@ -2607,7 +2607,7 @@ bool CDROM::CompleteSeek()
} }
s_physical_lba = s_current_lba; s_physical_lba = s_current_lba;
s_physical_lba_update_tick = System::GetGlobalTickCounter(); s_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
s_physical_lba_update_carry = 0; s_physical_lba_update_carry = 0;
return seek_okay; return seek_okay;
} }
@ -2783,7 +2783,7 @@ void CDROM::DoSectorRead()
s_current_lba = s_reader.GetLastReadSector(); s_current_lba = s_reader.GetLastReadSector();
s_physical_lba = s_current_lba; s_physical_lba = s_current_lba;
s_physical_lba_update_tick = System::GetGlobalTickCounter(); s_physical_lba_update_tick = TimingEvents::GetGlobalTickCounter();
s_physical_lba_update_carry = 0; s_physical_lba_update_carry = 0;
s_secondary_status.SetReadingBits(s_drive_state == DriveState::Playing); s_secondary_status.SetReadingBits(s_drive_state == DriveState::Playing);

View File

@ -888,7 +888,7 @@ void CPU::CodeCache::LogCurrentState()
"tick=%u dc=%u/%u pc=%08X at=%08X v0=%08X v1=%08X a0=%08X a1=%08X a2=%08X a3=%08X t0=%08X t1=%08X t2=%08X t3=%08X " "tick=%u dc=%u/%u pc=%08X at=%08X v0=%08X v1=%08X a0=%08X a1=%08X a2=%08X a3=%08X t0=%08X t1=%08X t2=%08X t3=%08X "
"t4=%08X t5=%08X t6=%08X t7=%08X s0=%08X s1=%08X s2=%08X s3=%08X s4=%08X s5=%08X s6=%08X s7=%08X t8=%08X t9=%08X " "t4=%08X t5=%08X t6=%08X t7=%08X s0=%08X s1=%08X s2=%08X s3=%08X s4=%08X s5=%08X s6=%08X s7=%08X t8=%08X t9=%08X "
"k0=%08X k1=%08X gp=%08X sp=%08X fp=%08X ra=%08X hi=%08X lo=%08X ldr=%s ldv=%08X cause=%08X sr=%08X gte=%08X\n", "k0=%08X k1=%08X gp=%08X sp=%08X fp=%08X ra=%08X hi=%08X lo=%08X ldr=%s ldv=%08X cause=%08X sr=%08X gte=%08X\n",
System::GetGlobalTickCounter(), g_state.pending_ticks, g_state.downcount, g_state.pc, regs.at, regs.v0, regs.v1, TimingEvents::GetGlobalTickCounter(), g_state.pending_ticks, g_state.downcount, g_state.pc, regs.at, regs.v0, regs.v1,
regs.a0, regs.a1, regs.a2, regs.a3, regs.t0, regs.t1, regs.t2, regs.t3, regs.t4, regs.t5, regs.t6, regs.t7, regs.s0, regs.a0, regs.a1, regs.a2, regs.a3, regs.t0, regs.t1, regs.t2, regs.t3, regs.t4, regs.t5, regs.t6, regs.t7, regs.s0,
regs.s1, regs.s2, regs.s3, regs.s4, regs.s5, regs.s6, regs.s7, regs.t8, regs.t9, regs.k0, regs.k1, regs.gp, regs.sp, regs.s1, regs.s2, regs.s3, regs.s4, regs.s5, regs.s6, regs.s7, regs.t8, regs.t9, regs.k0, regs.k1, regs.gp, regs.sp,
regs.fp, regs.ra, regs.hi, regs.lo, regs.fp, regs.ra, regs.hi, regs.lo,

View File

@ -213,7 +213,7 @@ static System::FrameTimeHistory s_frame_time_history;
static u32 s_frame_time_history_pos = 0; static u32 s_frame_time_history_pos = 0;
static u32 s_last_frame_number = 0; static u32 s_last_frame_number = 0;
static u32 s_last_internal_frame_number = 0; static u32 s_last_internal_frame_number = 0;
static u32 s_last_global_tick_counter = 0; static GlobalTicks s_last_global_tick_counter = 0;
static u64 s_last_cpu_time = 0; static u64 s_last_cpu_time = 0;
static u64 s_last_sw_time = 0; static u64 s_last_sw_time = 0;
static u32 s_presents_since_last_update = 0; static u32 s_presents_since_last_update = 0;
@ -403,11 +403,6 @@ void System::UpdateOverclock()
UpdateThrottlePeriod(); UpdateThrottlePeriod();
} }
u32 System::GetGlobalTickCounter()
{
return TimingEvents::GetGlobalTickCounter() + CPU::GetPendingTicks();
}
u32 System::GetFrameNumber() u32 System::GetFrameNumber()
{ {
return s_frame_number; return s_frame_number;
@ -2611,7 +2606,7 @@ void System::UpdatePerformanceCounters()
const u32 frames_run = s_frame_number - s_last_frame_number; const u32 frames_run = s_frame_number - s_last_frame_number;
const float frames_runf = static_cast<float>(frames_run); const float frames_runf = static_cast<float>(frames_run);
const u32 global_tick_counter = GetGlobalTickCounter(); const GlobalTicks global_tick_counter = TimingEvents::GetGlobalTickCounter();
// TODO: Make the math here less rubbish // TODO: Make the math here less rubbish
const double pct_divider = const double pct_divider =
@ -2672,7 +2667,7 @@ void System::ResetPerformanceCounters()
{ {
s_last_frame_number = s_frame_number; s_last_frame_number = s_frame_number;
s_last_internal_frame_number = s_internal_frame_number; s_last_internal_frame_number = s_internal_frame_number;
s_last_global_tick_counter = GetGlobalTickCounter(); s_last_global_tick_counter = TimingEvents::GetGlobalTickCounter();
s_last_cpu_time = s_cpu_thread_handle ? s_cpu_thread_handle.GetCPUTime() : 0; s_last_cpu_time = s_cpu_thread_handle ? s_cpu_thread_handle.GetCPUTime() : 0;
if (const Threading::Thread* sw_thread = g_gpu->GetSWThread(); sw_thread) if (const Threading::Thread* sw_thread = g_gpu->GetSWThread(); sw_thread)
s_last_sw_time = sw_thread->GetCPUTime(); s_last_sw_time = sw_thread->GetCPUTime();

View File

@ -195,7 +195,6 @@ void UpdateOverclock();
/// direct execution to this executable. /// direct execution to this executable.
bool InjectEXEFromBuffer(const void* buffer, u32 buffer_size, bool patch_loader = true); bool InjectEXEFromBuffer(const void* buffer, u32 buffer_size, bool patch_loader = true);
u32 GetGlobalTickCounter();
u32 GetFrameNumber(); u32 GetFrameNumber();
u32 GetInternalFrameNumber(); u32 GetInternalFrameNumber();
void IncrementInternalFrameNumber(); void IncrementInternalFrameNumber();

View File

@ -16,16 +16,16 @@ static TimingEvent* s_active_events_head;
static TimingEvent* s_active_events_tail; static TimingEvent* s_active_events_tail;
static TimingEvent* s_current_event = nullptr; static TimingEvent* s_current_event = nullptr;
static u32 s_active_event_count = 0; static u32 s_active_event_count = 0;
static u32 s_global_tick_counter = 0; static GlobalTicks s_global_tick_counter = 0;
static u32 s_event_run_tick_counter = 0; static GlobalTicks s_event_run_tick_counter = 0;
static bool s_frame_done = false; static bool s_frame_done = false;
u32 GetGlobalTickCounter() GlobalTicks GetGlobalTickCounter()
{ {
return s_global_tick_counter; return s_global_tick_counter + CPU::GetPendingTicks();
} }
u32 GetEventRunTickCounter() GlobalTicks GetEventRunTickCounter()
{ {
return s_event_run_tick_counter; return s_event_run_tick_counter;
} }
@ -38,6 +38,7 @@ void Initialize()
void Reset() void Reset()
{ {
s_global_tick_counter = 0; s_global_tick_counter = 0;
s_event_run_tick_counter = 0;
} }
void Shutdown() void Shutdown()
@ -58,7 +59,8 @@ std::unique_ptr<TimingEvent> CreateTimingEvent(std::string name, TickCount perio
void UpdateCPUDowncount() void UpdateCPUDowncount()
{ {
const u32 event_downcount = s_active_events_head->GetDowncount(); DebugAssert(s_active_events_head->GetNextRunTime() >= s_global_tick_counter);
const u32 event_downcount = static_cast<u32>(s_active_events_head->GetNextRunTime() - s_global_tick_counter);
CPU::g_state.downcount = CPU::HasPendingInterrupt() ? 0 : event_downcount; CPU::g_state.downcount = CPU::HasPendingInterrupt() ? 0 : event_downcount;
} }
@ -69,13 +71,13 @@ TimingEvent** GetHeadEventPtr()
static void SortEvent(TimingEvent* event) static void SortEvent(TimingEvent* event)
{ {
const TickCount event_downcount = event->m_downcount; const GlobalTicks event_runtime = event->GetNextRunTime();
if (event->prev && event->prev->m_downcount > event_downcount) if (event->prev && event->prev->GetNextRunTime() > event_runtime)
{ {
// move backwards // move backwards
TimingEvent* current = event->prev; TimingEvent* current = event->prev;
while (current && current->m_downcount > event_downcount) while (current && current->GetNextRunTime() > event_runtime)
current = current->prev; current = current->prev;
// unlink // unlink
@ -111,11 +113,11 @@ static void SortEvent(TimingEvent* event)
UpdateCPUDowncount(); UpdateCPUDowncount();
} }
} }
else if (event->next && event_downcount > event->next->m_downcount) else if (event->next && event_runtime > event->next->GetNextRunTime())
{ {
// move forwards // move forwards
TimingEvent* current = event->next; TimingEvent* current = event->next;
while (current && event_downcount > current->m_downcount) while (current && event_runtime > current->GetNextRunTime())
current = current->next; current = current->next;
// unlink // unlink
@ -168,9 +170,10 @@ static void AddActiveEvent(TimingEvent* event)
DebugAssert(!event->prev && !event->next); DebugAssert(!event->prev && !event->next);
s_active_event_count++; s_active_event_count++;
const GlobalTicks event_runtime = event->GetNextRunTime();
TimingEvent* current = nullptr; TimingEvent* current = nullptr;
TimingEvent* next = s_active_events_head; TimingEvent* next = s_active_events_head;
while (next && event->m_downcount > next->m_downcount) while (next && event_runtime > next->GetNextRunTime())
{ {
current = next; current = next;
next = next->next; next = next->next;
@ -231,7 +234,7 @@ static void RemoveActiveEvent(TimingEvent* event)
else else
{ {
s_active_events_head = event->next; s_active_events_head = event->next;
if (s_active_events_head) if (s_active_events_head && !s_current_event)
UpdateCPUDowncount(); UpdateCPUDowncount();
} }
@ -295,45 +298,37 @@ void RunEvents()
if (CPU::HasPendingInterrupt()) if (CPU::HasPendingInterrupt())
CPU::DispatchInterrupt(); CPU::DispatchInterrupt();
TickCount pending_ticks = CPU::GetPendingTicks(); // TODO: Get rid of pending completely...
if (pending_ticks >= s_active_events_head->GetDowncount()) const GlobalTicks new_global_ticks = s_global_tick_counter + static_cast<GlobalTicks>(CPU::GetPendingTicks());
if (new_global_ticks >= s_active_events_head->m_next_run_time)
{ {
CPU::ResetPendingTicks(); CPU::ResetPendingTicks();
s_event_run_tick_counter = s_global_tick_counter + static_cast<u32>(pending_ticks); s_event_run_tick_counter = new_global_ticks; // TODO: Might be wrong... should move below?but then it'd ping-pong.
do do
{ {
const TickCount time = std::min(pending_ticks, s_active_events_head->GetDowncount()); s_global_tick_counter = std::min(new_global_ticks, s_active_events_head->m_next_run_time);
s_global_tick_counter += static_cast<u32>(time);
pending_ticks -= time;
// Apply downcount to all events.
// This will result in a negative downcount for those events which are late.
for (TimingEvent* event = s_active_events_head; event; event = event->next)
{
event->m_downcount -= time;
event->m_time_since_last_run += time;
}
// Now we can actually run the callbacks. // Now we can actually run the callbacks.
while (s_active_events_head->m_downcount <= 0) TimingEvent* event;
while (s_global_tick_counter >= (event = s_active_events_head)->m_next_run_time)
{ {
// move it to the end, since that'll likely be its new position
TimingEvent* event = s_active_events_head;
s_current_event = event; s_current_event = event;
// Factor late time into the time for the next invocation. // Factor late time into the time for the next invocation.
const TickCount ticks_late = -event->m_downcount; const TickCount ticks_late =
const TickCount ticks_to_execute = event->m_time_since_last_run; static_cast<TickCount>(s_global_tick_counter - s_active_events_head->m_next_run_time);
event->m_downcount += event->m_interval; const TickCount ticks_to_execute =
event->m_time_since_last_run = 0; static_cast<TickCount>(s_global_tick_counter - s_active_events_head->m_last_run_time);
s_active_events_head->m_next_run_time += static_cast<GlobalTicks>(event->m_interval);
s_active_events_head->m_last_run_time = s_global_tick_counter;
// The cycles_late is only an indicator, it doesn't modify the cycles to execute. // The cycles_late is only an indicator, it doesn't modify the cycles to execute.
event->m_callback(event->m_callback_param, ticks_to_execute, ticks_late); event->m_callback(event->m_callback_param, ticks_to_execute, ticks_late);
if (event->m_active) if (event->m_active)
SortEvent(event); SortEvent(event);
} }
} while (pending_ticks > 0); } while (new_global_ticks > s_event_run_tick_counter);
s_current_event = nullptr; s_current_event = nullptr;
} }
@ -379,8 +374,9 @@ bool DoState(StateWrapper& sw)
} }
// Using reschedule is safe here since we call sort afterwards. // Using reschedule is safe here since we call sort afterwards.
event->m_downcount = downcount; Panic("Fixme");
event->m_time_since_last_run = time_since_last_run; //event->m_downcount = downcount;
//event->m_time_since_last_run = time_since_last_run;
event->m_period = period; event->m_period = period;
event->m_interval = interval; event->m_interval = interval;
} }
@ -402,8 +398,8 @@ bool DoState(StateWrapper& sw)
for (TimingEvent* event = s_active_events_head; event; event = event->next) for (TimingEvent* event = s_active_events_head; event; event = event->next)
{ {
sw.Do(&event->m_name); sw.Do(&event->m_name);
sw.Do(&event->m_downcount); //sw.Do(&event->m_downcount);
sw.Do(&event->m_time_since_last_run); //sw.Do(&event->m_time_since_last_run);
sw.Do(&event->m_period); sw.Do(&event->m_period);
sw.Do(&event->m_interval); sw.Do(&event->m_interval);
} }
@ -418,7 +414,7 @@ bool DoState(StateWrapper& sw)
TimingEvent::TimingEvent(std::string name, TickCount period, TickCount interval, TimingEventCallback callback, TimingEvent::TimingEvent(std::string name, TickCount period, TickCount interval, TimingEventCallback callback,
void* callback_param) void* callback_param)
: m_callback(callback), m_callback_param(callback_param), m_downcount(interval), m_time_since_last_run(0), : m_callback(callback), m_callback_param(callback_param), m_next_run_time(TimingEvents::GetGlobalTickCounter() + static_cast<GlobalTicks>(interval)), m_last_run_time(TimingEvents::GetGlobalTickCounter()),
m_period(period), m_interval(interval), m_name(std::move(name)) m_period(period), m_interval(interval), m_name(std::move(name))
{ {
} }
@ -429,16 +425,6 @@ TimingEvent::~TimingEvent()
TimingEvents::RemoveActiveEvent(this); TimingEvents::RemoveActiveEvent(this);
} }
TickCount TimingEvent::GetTicksSinceLastExecution() const
{
return CPU::GetPendingTicks() + m_time_since_last_run;
}
TickCount TimingEvent::GetTicksUntilNextExecution() const
{
return std::max(m_downcount - CPU::GetPendingTicks(), static_cast<TickCount>(0));
}
void TimingEvent::Delay(TickCount ticks) void TimingEvent::Delay(TickCount ticks)
{ {
if (!m_active) if (!m_active)
@ -447,7 +433,7 @@ void TimingEvent::Delay(TickCount ticks)
return; return;
} }
m_downcount += ticks; m_next_run_time += static_cast<GlobalTicks>(ticks);
DebugAssert(TimingEvents::s_current_event != this); DebugAssert(TimingEvents::s_current_event != this);
TimingEvents::SortEvent(this); TimingEvents::SortEvent(this);
@ -457,13 +443,13 @@ void TimingEvent::Delay(TickCount ticks)
void TimingEvent::Schedule(TickCount ticks) void TimingEvent::Schedule(TickCount ticks)
{ {
const TickCount pending_ticks = CPU::GetPendingTicks(); const GlobalTicks current_ticks = TimingEvents::GetGlobalTickCounter();
m_downcount = pending_ticks + ticks; m_next_run_time = current_ticks + static_cast<GlobalTicks>(ticks);
if (!m_active) if (!m_active)
{ {
// Event is going active, so we want it to only execute ticks from the current timestamp. // Event is going active, so we want it to only execute ticks from the current timestamp.
m_time_since_last_run = -pending_ticks; m_last_run_time = current_ticks;
m_active = true; m_active = true;
TimingEvents::AddActiveEvent(this); TimingEvents::AddActiveEvent(this);
} }
@ -498,8 +484,9 @@ void TimingEvent::Reset()
if (!m_active) if (!m_active)
return; return;
m_downcount = m_interval; const GlobalTicks current_ticks = TimingEvents::GetGlobalTickCounter();
m_time_since_last_run = 0; m_next_run_time = current_ticks + static_cast<GlobalTicks>(m_interval);
m_last_run_time = current_ticks;
if (TimingEvents::s_current_event != this) if (TimingEvents::s_current_event != this)
{ {
TimingEvents::SortEvent(this); TimingEvents::SortEvent(this);
@ -513,13 +500,15 @@ void TimingEvent::InvokeEarly(bool force /* = false */)
if (!m_active) if (!m_active)
return; return;
const TickCount pending_ticks = CPU::GetPendingTicks(); const GlobalTicks current_ticks = TimingEvents::GetGlobalTickCounter();
const TickCount ticks_to_execute = m_time_since_last_run + pending_ticks; DebugAssert(current_ticks >= m_last_run_time);
const TickCount ticks_to_execute = static_cast<TickCount>(current_ticks - m_last_run_time);
if ((!force && ticks_to_execute < m_period) || ticks_to_execute <= 0) if ((!force && ticks_to_execute < m_period) || ticks_to_execute <= 0)
return; return;
m_downcount = pending_ticks + m_interval; m_next_run_time = current_ticks + static_cast<GlobalTicks>(m_interval);
m_time_since_last_run -= ticks_to_execute; m_last_run_time = current_ticks;
m_callback(m_callback_param, ticks_to_execute, 0); m_callback(m_callback_param, ticks_to_execute, 0);
// Since we've changed the downcount, we need to re-sort the events. // Since we've changed the downcount, we need to re-sort the events.
@ -534,10 +523,9 @@ void TimingEvent::Activate()
if (m_active) if (m_active)
return; return;
// leave the downcount intact const GlobalTicks current_ticks = TimingEvents::GetGlobalTickCounter();
const TickCount pending_ticks = CPU::GetPendingTicks(); m_next_run_time = current_ticks + static_cast<GlobalTicks>(m_interval);
m_downcount += pending_ticks; m_last_run_time = current_ticks;
m_time_since_last_run -= pending_ticks;
m_active = true; m_active = true;
TimingEvents::AddActiveEvent(this); TimingEvents::AddActiveEvent(this);
@ -548,10 +536,6 @@ void TimingEvent::Deactivate()
if (!m_active) if (!m_active)
return; return;
const TickCount pending_ticks = CPU::GetPendingTicks();
m_downcount -= pending_ticks;
m_time_since_last_run += pending_ticks;
m_active = false; m_active = false;
TimingEvents::RemoveActiveEvent(this); TimingEvents::RemoveActiveEvent(this);
} }

View File

@ -11,9 +11,37 @@
class StateWrapper; class StateWrapper;
class TimingEvent;
// Event callback type. Second parameter is the number of cycles the event was executed "late". // Event callback type. Second parameter is the number of cycles the event was executed "late".
using TimingEventCallback = void (*)(void* param, TickCount ticks, TickCount ticks_late); using TimingEventCallback = void (*)(void* param, TickCount ticks, TickCount ticks_late);
namespace TimingEvents {
GlobalTicks GetGlobalTickCounter();
GlobalTicks GetEventRunTickCounter();
void Initialize();
void Reset();
void Shutdown();
/// Creates a new event.
std::unique_ptr<TimingEvent> CreateTimingEvent(std::string name, TickCount period, TickCount interval,
TimingEventCallback callback, void* callback_param, bool activate);
/// Serialization.
bool DoState(StateWrapper& sw);
bool IsRunningEvents();
void SetFrameDone();
void RunEvents();
void UpdateCPUDowncount();
TimingEvent** GetHeadEventPtr();
} // namespace TimingEvents
class TimingEvent class TimingEvent
{ {
public: public:
@ -27,11 +55,18 @@ public:
// Returns the number of ticks between each event. // Returns the number of ticks between each event.
ALWAYS_INLINE TickCount GetPeriod() const { return m_period; } ALWAYS_INLINE TickCount GetPeriod() const { return m_period; }
ALWAYS_INLINE TickCount GetInterval() const { return m_interval; } ALWAYS_INLINE TickCount GetInterval() const { return m_interval; }
ALWAYS_INLINE TickCount GetDowncount() const { return m_downcount; } ALWAYS_INLINE GlobalTicks GetNextRunTime() const { return m_next_run_time; }
ALWAYS_INLINE GlobalTicks GetLastRunTime() const { return m_last_run_time; }
// Includes pending time. // Includes pending time.
TickCount GetTicksSinceLastExecution() const; ALWAYS_INLINE TickCount GetTicksSinceLastExecution() const
TickCount GetTicksUntilNextExecution() const; {
return static_cast<TickCount>(TimingEvents::GetGlobalTickCounter() - m_last_run_time);
}
ALWAYS_INLINE TickCount GetTicksUntilNextExecution() const
{
return static_cast<TickCount>(m_next_run_time - TimingEvents::GetGlobalTickCounter());
}
// Adds ticks to current execution. // Adds ticks to current execution.
void Delay(TickCount ticks); void Delay(TickCount ticks);
@ -69,37 +104,11 @@ public:
TimingEventCallback m_callback; TimingEventCallback m_callback;
void* m_callback_param; void* m_callback_param;
TickCount m_downcount; GlobalTicks m_next_run_time;
TickCount m_time_since_last_run; GlobalTicks m_last_run_time;
TickCount m_period; TickCount m_period;
TickCount m_interval; TickCount m_interval;
bool m_active = false; bool m_active = false;
std::string m_name; std::string m_name;
}; };
namespace TimingEvents {
u32 GetGlobalTickCounter();
u32 GetEventRunTickCounter();
void Initialize();
void Reset();
void Shutdown();
/// Creates a new event.
std::unique_ptr<TimingEvent> CreateTimingEvent(std::string name, TickCount period, TickCount interval,
TimingEventCallback callback, void* callback_param, bool activate);
/// Serialization.
bool DoState(StateWrapper& sw);
bool IsRunningEvents();
void SetFrameDone();
void RunEvents();
void UpdateCPUDowncount();
TimingEvent** GetHeadEventPtr();
} // namespace TimingEvents

View File

@ -20,7 +20,8 @@ enum class MemoryAccessSize : u32
Word Word
}; };
using TickCount = s32; using TickCount = s32; // TODO: Make u32
using GlobalTicks = u64;
enum class ConsoleRegion enum class ConsoleRegion
{ {