Timers: Handle target = 0 case

Fixes Super Gals! Kotobuki Ran Special - Ikemen Get You Gals Party
hanging at boot.
This commit is contained in:
Connor McLaughlin 2021-02-09 01:01:36 +10:00
parent 537f833658
commit ef97131c9d
2 changed files with 15 additions and 8 deletions

View File

@ -129,20 +129,21 @@ void Timers::AddTicks(u32 timer, TickCount count)
CounterState& cs = m_states[timer]; CounterState& cs = m_states[timer];
const u32 old_counter = cs.counter; const u32 old_counter = cs.counter;
cs.counter += static_cast<u32>(count); cs.counter += static_cast<u32>(count);
CheckForIRQ(timer, old_counter);
}
void Timers::CheckForIRQ(u32 timer, u32 old_counter)
{
CounterState& cs = m_states[timer];
bool interrupt_request = false; bool interrupt_request = false;
if (cs.counter >= cs.target && old_counter < cs.target) if (cs.counter >= cs.target && (old_counter < cs.target || cs.target == 0))
{ {
interrupt_request |= cs.mode.irq_at_target; interrupt_request |= cs.mode.irq_at_target;
cs.mode.reached_target = true; cs.mode.reached_target = true;
if (cs.mode.reset_at_target) if (cs.mode.reset_at_target && cs.target > 0)
{ cs.counter %= cs.target;
if (cs.target > 0)
cs.counter %= cs.target;
else
cs.counter = 0;
}
} }
if (cs.counter >= 0xFFFF) if (cs.counter >= 0xFFFF)
{ {
@ -265,12 +266,15 @@ void Timers::WriteRegister(u32 offset, u32 value)
m_sysclk_event->InvokeEarly(); m_sysclk_event->InvokeEarly();
// Strictly speaking these IRQ checks should probably happen on the next tick.
switch (port_offset) switch (port_offset)
{ {
case 0x00: case 0x00:
{ {
const u32 old_counter = cs.counter;
Log_DebugPrintf("Timer %u write counter %u", timer_index, value); Log_DebugPrintf("Timer %u write counter %u", timer_index, value);
cs.counter = value & u32(0xFFFF); cs.counter = value & u32(0xFFFF);
CheckForIRQ(timer_index, old_counter);
if (timer_index == 2 || !cs.external_counting_enabled) if (timer_index == 2 || !cs.external_counting_enabled)
UpdateSysClkEvent(); UpdateSysClkEvent();
} }
@ -287,6 +291,7 @@ void Timers::WriteRegister(u32 offset, u32 value)
cs.irq_done = false; cs.irq_done = false;
UpdateCountingEnabled(cs); UpdateCountingEnabled(cs);
CheckForIRQ(timer_index, cs.counter);
UpdateIRQ(timer_index); UpdateIRQ(timer_index);
UpdateSysClkEvent(); UpdateSysClkEvent();
} }
@ -296,6 +301,7 @@ void Timers::WriteRegister(u32 offset, u32 value)
{ {
Log_DebugPrintf("Timer %u write target 0x%04X", timer_index, ZeroExtend32(Truncate16(value))); Log_DebugPrintf("Timer %u write target 0x%04X", timer_index, ZeroExtend32(Truncate16(value)));
cs.target = value & u32(0xFFFF); cs.target = value & u32(0xFFFF);
CheckForIRQ(timer_index, cs.counter);
if (timer_index == 2 || !cs.external_counting_enabled) if (timer_index == 2 || !cs.external_counting_enabled)
UpdateSysClkEvent(); UpdateSysClkEvent();
} }

View File

@ -85,6 +85,7 @@ private:
}; };
void UpdateCountingEnabled(CounterState& cs); void UpdateCountingEnabled(CounterState& cs);
void CheckForIRQ(u32 index, u32 old_counter);
void UpdateIRQ(u32 index); void UpdateIRQ(u32 index);
void AddSysClkTicks(TickCount sysclk_ticks); void AddSysClkTicks(TickCount sysclk_ticks);