Timers: Update when sync is used with sysclk source

Fixes hang at boot in Zoku Mikagura Shoujo Tanteidan - Kanketsuhen.
This commit is contained in:
Connor McLaughlin 2020-12-05 19:31:43 +10:00
parent 5e05a14f97
commit d7bd21c06d
3 changed files with 39 additions and 21 deletions

View file

@ -681,10 +681,22 @@ TickCount GPU::GetPendingCommandTicks() const
void GPU::UpdateCRTCTickEvent() void GPU::UpdateCRTCTickEvent()
{ {
// figure out how many GPU ticks until the next vblank or event // figure out how many GPU ticks until the next vblank or event
TickCount lines_until_event = TickCount lines_until_event;
(m_crtc_state.current_scanline >= m_crtc_state.vertical_display_end ? if (g_timers.IsSyncEnabled(HBLANK_TIMER_INDEX))
(m_crtc_state.vertical_total - m_crtc_state.current_scanline + m_crtc_state.vertical_display_end) : {
(m_crtc_state.vertical_display_end - m_crtc_state.current_scanline)); // when the timer sync is enabled we need to sync at vblank start and end
lines_until_event =
(m_crtc_state.current_scanline >= m_crtc_state.vertical_display_end) ?
(m_crtc_state.vertical_total - m_crtc_state.current_scanline + m_crtc_state.vertical_display_start) :
(m_crtc_state.vertical_display_end - m_crtc_state.current_scanline);
}
else
{
lines_until_event =
(m_crtc_state.current_scanline >= m_crtc_state.vertical_display_end ?
(m_crtc_state.vertical_total - m_crtc_state.current_scanline + m_crtc_state.vertical_display_end) :
(m_crtc_state.vertical_display_end - m_crtc_state.current_scanline));
}
if (g_timers.IsExternalIRQEnabled(HBLANK_TIMER_INDEX)) if (g_timers.IsExternalIRQEnabled(HBLANK_TIMER_INDEX))
lines_until_event = std::min(lines_until_event, g_timers.GetTicksUntilIRQ(HBLANK_TIMER_INDEX)); lines_until_event = std::min(lines_until_event, g_timers.GetTicksUntilIRQ(HBLANK_TIMER_INDEX));
@ -693,7 +705,8 @@ void GPU::UpdateCRTCTickEvent()
if (g_timers.IsExternalIRQEnabled(DOT_TIMER_INDEX)) if (g_timers.IsExternalIRQEnabled(DOT_TIMER_INDEX))
{ {
const TickCount dots_until_irq = g_timers.GetTicksUntilIRQ(DOT_TIMER_INDEX); const TickCount dots_until_irq = g_timers.GetTicksUntilIRQ(DOT_TIMER_INDEX);
const TickCount ticks_until_irq = (dots_until_irq * m_crtc_state.dot_clock_divider) - m_crtc_state.fractional_dot_ticks; const TickCount ticks_until_irq =
(dots_until_irq * m_crtc_state.dot_clock_divider) - m_crtc_state.fractional_dot_ticks;
ticks_until_event = std::min(ticks_until_event, std::max<TickCount>(ticks_until_irq, 0)); ticks_until_event = std::min(ticks_until_event, std::max<TickCount>(ticks_until_irq, 0));
} }
@ -1346,8 +1359,8 @@ void GPU::SetDrawMode(u16 value)
FlushRender(); FlushRender();
// Bits 0..10 are returned in the GPU status register. // Bits 0..10 are returned in the GPU status register.
m_GPUSTAT.bits = m_GPUSTAT.bits = (m_GPUSTAT.bits & ~(GPUDrawModeReg::GPUSTAT_MASK)) |
(m_GPUSTAT.bits & ~(GPUDrawModeReg::GPUSTAT_MASK)) | (ZeroExtend32(new_mode_reg.bits) & GPUDrawModeReg::GPUSTAT_MASK); (ZeroExtend32(new_mode_reg.bits) & GPUDrawModeReg::GPUSTAT_MASK);
m_GPUSTAT.texture_disable = m_draw_mode.mode_reg.texture_disable; m_GPUSTAT.texture_disable = m_draw_mode.mode_reg.texture_disable;
} }

View file

@ -82,25 +82,29 @@ void Timers::SetGate(u32 timer, bool state)
cs.gate = state; cs.gate = state;
if (cs.mode.sync_enable) if (!cs.mode.sync_enable)
return;
if (cs.counting_enabled && !cs.use_external_clock)
m_sysclk_event->InvokeEarly();
if (state)
{ {
if (state) switch (cs.mode.sync_mode)
{ {
switch (cs.mode.sync_mode) case SyncMode::ResetOnGate:
{ case SyncMode::ResetAndRunOnGate:
case SyncMode::ResetOnGate: cs.counter = 0;
case SyncMode::ResetAndRunOnGate: break;
cs.counter = 0;
break;
case SyncMode::FreeRunOnGate: case SyncMode::FreeRunOnGate:
cs.mode.sync_enable = false; cs.mode.sync_enable = false;
break; break;
}
} }
UpdateCountingEnabled(cs);
} }
UpdateCountingEnabled(cs);
UpdateSysClkEvent();
} }
TickCount Timers::GetTicksUntilIRQ(u32 timer) const TickCount Timers::GetTicksUntilIRQ(u32 timer) const

View file

@ -28,6 +28,7 @@ public:
// dot clock/hblank/sysclk div 8 // dot clock/hblank/sysclk div 8
ALWAYS_INLINE bool IsUsingExternalClock(u32 timer) const { return m_states[timer].external_counting_enabled; } ALWAYS_INLINE bool IsUsingExternalClock(u32 timer) const { return m_states[timer].external_counting_enabled; }
ALWAYS_INLINE bool IsSyncEnabled(u32 timer) const { return m_states[timer].mode.sync_enable; }
// queries for GPU // queries for GPU
ALWAYS_INLINE bool IsExternalIRQEnabled(u32 timer) const ALWAYS_INLINE bool IsExternalIRQEnabled(u32 timer) const