GPU: Implement dot clock timer (Timer 0)
Fixes softlock in Evil Dead - Hail to the King.
This commit is contained in:
parent
8b3426a96e
commit
d757056891
|
@ -91,6 +91,7 @@ void GPU::SoftReset()
|
||||||
m_crtc_state.regs.horizontal_display_range = 0xC60260;
|
m_crtc_state.regs.horizontal_display_range = 0xC60260;
|
||||||
m_crtc_state.regs.vertical_display_range = 0x3FC10;
|
m_crtc_state.regs.vertical_display_range = 0x3FC10;
|
||||||
m_crtc_state.fractional_ticks = 0;
|
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_tick_in_scanline = 0;
|
||||||
m_crtc_state.current_scanline = 0;
|
m_crtc_state.current_scanline = 0;
|
||||||
m_crtc_state.in_hblank = false;
|
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.fractional_ticks);
|
||||||
sw.Do(&m_crtc_state.current_tick_in_scanline);
|
sw.Do(&m_crtc_state.current_tick_in_scanline);
|
||||||
sw.Do(&m_crtc_state.current_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_hblank);
|
||||||
sw.Do(&m_crtc_state.in_vblank);
|
sw.Do(&m_crtc_state.in_vblank);
|
||||||
sw.Do(&m_crtc_state.interlaced_field);
|
sw.Do(&m_crtc_state.interlaced_field);
|
||||||
|
@ -679,15 +681,21 @@ 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
|
||||||
const TickCount lines_until_vblank =
|
TickCount lines_until_event =
|
||||||
(m_crtc_state.current_scanline >= m_crtc_state.vertical_display_end ?
|
(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_total - m_crtc_state.current_scanline + m_crtc_state.vertical_display_end) :
|
||||||
(m_crtc_state.vertical_display_end - m_crtc_state.current_scanline));
|
(m_crtc_state.vertical_display_end - m_crtc_state.current_scanline));
|
||||||
const TickCount lines_until_event = g_timers.IsExternalIRQEnabled(HBLANK_TIMER_INDEX) ?
|
if (g_timers.IsExternalIRQEnabled(HBLANK_TIMER_INDEX))
|
||||||
std::min(g_timers.GetTicksUntilIRQ(HBLANK_TIMER_INDEX), lines_until_vblank) :
|
lines_until_event = std::min(lines_until_event, g_timers.GetTicksUntilIRQ(HBLANK_TIMER_INDEX));
|
||||||
lines_until_vblank;
|
|
||||||
const TickCount ticks_until_event =
|
TickCount ticks_until_event =
|
||||||
lines_until_event * m_crtc_state.horizontal_total - m_crtc_state.current_tick_in_scanline;
|
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
|
#if 0
|
||||||
const TickCount ticks_until_hblank =
|
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);
|
const TickCount gpu_ticks = SystemTicksToCRTCTicks(ticks, &m_crtc_state.fractional_ticks);
|
||||||
m_crtc_state.current_tick_in_scanline += gpu_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)
|
if (m_crtc_state.current_tick_in_scanline < m_crtc_state.horizontal_total)
|
||||||
|
|
|
@ -501,6 +501,8 @@ protected:
|
||||||
TickCount current_tick_in_scanline;
|
TickCount current_tick_in_scanline;
|
||||||
u32 current_scanline;
|
u32 current_scanline;
|
||||||
|
|
||||||
|
TickCount fractional_dot_ticks; // only used when timer0 is enabled
|
||||||
|
|
||||||
bool in_hblank;
|
bool in_hblank;
|
||||||
bool in_vblank;
|
bool in_vblank;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
|
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 constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;
|
||||||
|
|
||||||
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);
|
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);
|
||||||
|
|
Loading…
Reference in New Issue