GPU: Implement dot clock timer (Timer 0)

Fixes softlock in Evil Dead - Hail to the King.
This commit is contained in:
Connor McLaughlin 2020-12-05 15:59:47 +10:00
parent 8b3426a96e
commit d757056891
3 changed files with 25 additions and 6 deletions

View File

@ -91,6 +91,7 @@ void GPU::SoftReset()
m_crtc_state.regs.horizontal_display_range = 0xC60260;
m_crtc_state.regs.vertical_display_range = 0x3FC10;
m_crtc_state.fractional_ticks = 0;
m_crtc_state.fractional_dot_ticks = 0;
m_crtc_state.current_tick_in_scanline = 0;
m_crtc_state.current_scanline = 0;
m_crtc_state.in_hblank = false;
@ -172,6 +173,7 @@ bool GPU::DoState(StateWrapper& sw, bool update_display)
sw.Do(&m_crtc_state.fractional_ticks);
sw.Do(&m_crtc_state.current_tick_in_scanline);
sw.Do(&m_crtc_state.current_scanline);
sw.DoEx(&m_crtc_state.fractional_dot_ticks, 46, 0);
sw.Do(&m_crtc_state.in_hblank);
sw.Do(&m_crtc_state.in_vblank);
sw.Do(&m_crtc_state.interlaced_field);
@ -679,15 +681,21 @@ TickCount GPU::GetPendingCommandTicks() const
void GPU::UpdateCRTCTickEvent()
{
// figure out how many GPU ticks until the next vblank or event
const TickCount lines_until_vblank =
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));
const TickCount lines_until_event = g_timers.IsExternalIRQEnabled(HBLANK_TIMER_INDEX) ?
std::min(g_timers.GetTicksUntilIRQ(HBLANK_TIMER_INDEX), lines_until_vblank) :
lines_until_vblank;
const TickCount ticks_until_event =
if (g_timers.IsExternalIRQEnabled(HBLANK_TIMER_INDEX))
lines_until_event = std::min(lines_until_event, g_timers.GetTicksUntilIRQ(HBLANK_TIMER_INDEX));
TickCount ticks_until_event =
lines_until_event * m_crtc_state.horizontal_total - m_crtc_state.current_tick_in_scanline;
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;
ticks_until_event = std::min(ticks_until_event, std::max<TickCount>(ticks_until_irq, 0));
}
#if 0
const TickCount ticks_until_hblank =
@ -715,6 +723,15 @@ void GPU::CRTCTickEvent(TickCount ticks)
{
const TickCount gpu_ticks = SystemTicksToCRTCTicks(ticks, &m_crtc_state.fractional_ticks);
m_crtc_state.current_tick_in_scanline += gpu_ticks;
if (g_timers.IsUsingExternalClock(DOT_TIMER_INDEX))
{
m_crtc_state.fractional_dot_ticks += gpu_ticks;
const TickCount dots = m_crtc_state.fractional_dot_ticks / m_crtc_state.dot_clock_divider;
m_crtc_state.fractional_dot_ticks = m_crtc_state.fractional_dot_ticks % m_crtc_state.dot_clock_divider;
if (dots > 0)
g_timers.AddTicks(DOT_TIMER_INDEX, dots);
}
}
if (m_crtc_state.current_tick_in_scanline < m_crtc_state.horizontal_total)

View File

@ -501,6 +501,8 @@ protected:
TickCount current_tick_in_scanline;
u32 current_scanline;
TickCount fractional_dot_ticks; // only used when timer0 is enabled
bool in_hblank;
bool in_vblank;

View File

@ -2,7 +2,7 @@
#include "types.h"
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
static constexpr u32 SAVE_STATE_VERSION = 45;
static constexpr u32 SAVE_STATE_VERSION = 46;
static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);