diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 229549792..69af1826c 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -681,10 +681,22 @@ TickCount GPU::GetPendingCommandTicks() const void GPU::UpdateCRTCTickEvent() { // figure out how many GPU ticks until the next vblank or event - TickCount 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)); + TickCount lines_until_event; + if (g_timers.IsSyncEnabled(HBLANK_TIMER_INDEX)) + { + // 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)) 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)) { 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(ticks_until_irq, 0)); } @@ -1346,8 +1359,8 @@ void GPU::SetDrawMode(u16 value) FlushRender(); // Bits 0..10 are returned in the GPU status register. - m_GPUSTAT.bits = - (m_GPUSTAT.bits & ~(GPUDrawModeReg::GPUSTAT_MASK)) | (ZeroExtend32(new_mode_reg.bits) & GPUDrawModeReg::GPUSTAT_MASK); + m_GPUSTAT.bits = (m_GPUSTAT.bits & ~(GPUDrawModeReg::GPUSTAT_MASK)) | + (ZeroExtend32(new_mode_reg.bits) & GPUDrawModeReg::GPUSTAT_MASK); m_GPUSTAT.texture_disable = m_draw_mode.mode_reg.texture_disable; } diff --git a/src/core/timers.cpp b/src/core/timers.cpp index be25e13e1..d1936da08 100644 --- a/src/core/timers.cpp +++ b/src/core/timers.cpp @@ -82,25 +82,29 @@ void Timers::SetGate(u32 timer, bool 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: - cs.counter = 0; - break; + case SyncMode::ResetOnGate: + case SyncMode::ResetAndRunOnGate: + cs.counter = 0; + break; - case SyncMode::FreeRunOnGate: - cs.mode.sync_enable = false; - break; - } + case SyncMode::FreeRunOnGate: + cs.mode.sync_enable = false; + break; } - - UpdateCountingEnabled(cs); } + + UpdateCountingEnabled(cs); + UpdateSysClkEvent(); } TickCount Timers::GetTicksUntilIRQ(u32 timer) const diff --git a/src/core/timers.h b/src/core/timers.h index 39c2467e1..aa63f16e0 100644 --- a/src/core/timers.h +++ b/src/core/timers.h @@ -28,6 +28,7 @@ public: // dot clock/hblank/sysclk div 8 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 ALWAYS_INLINE bool IsExternalIRQEnabled(u32 timer) const