mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-04-27 09:15:42 -04:00
Refactor timing to allow sync/updates in the middle of a slice
This commit is contained in:
parent
ad316162f3
commit
c988af453c
@ -264,7 +264,7 @@ bool SDLInterface::HandleSDLEvent(const SDL_Event* event)
|
|||||||
m_controller->SetButtonState(DigitalController::Button::L2, pressed);
|
m_controller->SetButtonState(DigitalController::Button::L2, pressed);
|
||||||
return true;
|
return true;
|
||||||
case SDL_SCANCODE_3:
|
case SDL_SCANCODE_3:
|
||||||
m_controller->SetButtonState(DigitalController::Button::R3, pressed);
|
m_controller->SetButtonState(DigitalController::Button::R2, pressed);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case SDL_SCANCODE_RETURN:
|
case SDL_SCANCODE_RETURN:
|
||||||
|
@ -26,7 +26,8 @@ bool Core::Initialize(Bus* bus)
|
|||||||
|
|
||||||
void Core::Reset()
|
void Core::Reset()
|
||||||
{
|
{
|
||||||
m_slice_ticks = std::numeric_limits<decltype(m_slice_ticks)>::max();
|
m_pending_ticks = 0;
|
||||||
|
m_downcount = MAX_SLICE_SIZE;
|
||||||
|
|
||||||
m_regs = {};
|
m_regs = {};
|
||||||
|
|
||||||
@ -47,7 +48,8 @@ void Core::Reset()
|
|||||||
|
|
||||||
bool Core::DoState(StateWrapper& sw)
|
bool Core::DoState(StateWrapper& sw)
|
||||||
{
|
{
|
||||||
sw.Do(&m_slice_ticks);
|
sw.Do(&m_pending_ticks);
|
||||||
|
sw.Do(&m_downcount);
|
||||||
sw.DoArray(m_regs.r, countof(m_regs.r));
|
sw.DoArray(m_regs.r, countof(m_regs.r));
|
||||||
sw.Do(&m_regs.pc);
|
sw.Do(&m_regs.pc);
|
||||||
sw.Do(&m_regs.hi);
|
sw.Do(&m_regs.hi);
|
||||||
@ -312,12 +314,12 @@ void Core::DisassembleAndPrint(u32 addr)
|
|||||||
PrintInstruction(bits, addr);
|
PrintInstruction(bits, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TickCount Core::Execute()
|
void Core::Execute()
|
||||||
{
|
{
|
||||||
TickCount executed_ticks = 0;
|
while (m_downcount >= 0)
|
||||||
while (executed_ticks < m_slice_ticks)
|
|
||||||
{
|
{
|
||||||
executed_ticks++;
|
m_pending_ticks += 3;
|
||||||
|
m_downcount -= 3;
|
||||||
|
|
||||||
// now executing the instruction we previously fetched
|
// now executing the instruction we previously fetched
|
||||||
const Instruction inst = m_next_instruction;
|
const Instruction inst = m_next_instruction;
|
||||||
@ -340,10 +342,6 @@ TickCount Core::Execute()
|
|||||||
m_load_delay_old_value = m_next_load_delay_old_value;
|
m_load_delay_old_value = m_next_load_delay_old_value;
|
||||||
m_next_load_delay_old_value = 0;
|
m_next_load_delay_old_value = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset slice ticks, it'll be updated when the components execute
|
|
||||||
m_slice_ticks = MAX_CPU_SLICE_SIZE;
|
|
||||||
return executed_ticks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Core::FetchInstruction()
|
bool Core::FetchInstruction()
|
||||||
|
@ -27,12 +27,16 @@ public:
|
|||||||
void Reset();
|
void Reset();
|
||||||
bool DoState(StateWrapper& sw);
|
bool DoState(StateWrapper& sw);
|
||||||
|
|
||||||
TickCount Execute();
|
void Execute();
|
||||||
|
|
||||||
const Registers& GetRegs() const { return m_regs; }
|
const Registers& GetRegs() const { return m_regs; }
|
||||||
Registers& GetRegs() { return m_regs; }
|
Registers& GetRegs() { return m_regs; }
|
||||||
|
|
||||||
void SetSliceTicks(TickCount downcount) { m_slice_ticks = (downcount < m_slice_ticks ? downcount : m_slice_ticks); }
|
TickCount GetPendingTicks() const { return m_pending_ticks; }
|
||||||
|
void ResetPendingTicks() { m_pending_ticks = 0; }
|
||||||
|
|
||||||
|
void SetDowncount(TickCount downcount) { m_downcount = (downcount < m_downcount) ? downcount : m_downcount; }
|
||||||
|
void ResetDowncount() { m_downcount = MAX_SLICE_SIZE; }
|
||||||
|
|
||||||
// Sets the PC and flushes the pipeline.
|
// Sets the PC and flushes the pipeline.
|
||||||
void SetPC(u32 new_pc);
|
void SetPC(u32 new_pc);
|
||||||
@ -101,8 +105,9 @@ private:
|
|||||||
|
|
||||||
Bus* m_bus = nullptr;
|
Bus* m_bus = nullptr;
|
||||||
|
|
||||||
// ticks of master/CPU clock until the next event
|
// ticks the CPU has executed
|
||||||
TickCount m_slice_ticks = 0;
|
TickCount m_pending_ticks = 0;
|
||||||
|
TickCount m_downcount = MAX_SLICE_SIZE;
|
||||||
|
|
||||||
Registers m_regs = {};
|
Registers m_regs = {};
|
||||||
Cop0Registers m_cop0_regs = {};
|
Cop0Registers m_cop0_regs = {};
|
||||||
|
@ -256,7 +256,7 @@ void GPU::UpdateCRTCConfig()
|
|||||||
void GPU::UpdateSliceTicks()
|
void GPU::UpdateSliceTicks()
|
||||||
{
|
{
|
||||||
// the next event is at the end of the next scanline
|
// the next event is at the end of the next scanline
|
||||||
#if 1
|
#if 0
|
||||||
const TickCount ticks_until_next_event = m_crtc_state.ticks_per_scanline - m_crtc_state.current_tick_in_scanline;
|
const TickCount ticks_until_next_event = m_crtc_state.ticks_per_scanline - m_crtc_state.current_tick_in_scanline;
|
||||||
#else
|
#else
|
||||||
// or at vblank. this will depend on the timer config..
|
// or at vblank. this will depend on the timer config..
|
||||||
@ -267,7 +267,7 @@ void GPU::UpdateSliceTicks()
|
|||||||
|
|
||||||
// convert to master clock, rounding up as we want to overshoot not undershoot
|
// convert to master clock, rounding up as we want to overshoot not undershoot
|
||||||
const TickCount system_ticks = (ticks_until_next_event * 7 + 10) / 11;
|
const TickCount system_ticks = (ticks_until_next_event * 7 + 10) / 11;
|
||||||
m_system->SetSliceTicks(system_ticks);
|
m_system->SetDowncount(system_ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU::Execute(TickCount ticks)
|
void GPU::Execute(TickCount ticks)
|
||||||
|
@ -57,7 +57,9 @@ void InterruptController::WriteRegister(u32 offset, u32 value)
|
|||||||
{
|
{
|
||||||
case 0x00: // I_STATUS
|
case 0x00: // I_STATUS
|
||||||
{
|
{
|
||||||
Log_DebugPrintf("Clearing bits 0x%08X", value);
|
if ((m_interrupt_status_register & ~value) != 0)
|
||||||
|
Log_DebugPrintf("Clearing bits 0x%08X", (m_interrupt_status_register & ~value));
|
||||||
|
|
||||||
m_interrupt_status_register = m_interrupt_status_register & (value & REGISTER_WRITE_MASK);
|
m_interrupt_status_register = m_interrupt_status_register & (value & REGISTER_WRITE_MASK);
|
||||||
UpdateCPUInterruptRequest();
|
UpdateCPUInterruptRequest();
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ bool System::Initialize()
|
|||||||
if (!m_pad->Initialize(m_interrupt_controller.get()))
|
if (!m_pad->Initialize(m_interrupt_controller.get()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!m_timers->Initialize(m_interrupt_controller.get()))
|
if (!m_timers->Initialize(this, m_interrupt_controller.get()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -89,8 +89,6 @@ bool System::DoState(StateWrapper& sw)
|
|||||||
|
|
||||||
void System::Reset()
|
void System::Reset()
|
||||||
{
|
{
|
||||||
SetSliceTicks(1);
|
|
||||||
|
|
||||||
m_cpu->Reset();
|
m_cpu->Reset();
|
||||||
m_bus->Reset();
|
m_bus->Reset();
|
||||||
m_dma->Reset();
|
m_dma->Reset();
|
||||||
@ -119,12 +117,8 @@ void System::RunFrame()
|
|||||||
u32 current_frame_number = m_frame_number;
|
u32 current_frame_number = m_frame_number;
|
||||||
while (current_frame_number == m_frame_number)
|
while (current_frame_number == m_frame_number)
|
||||||
{
|
{
|
||||||
const TickCount pending_ticks = m_cpu->Execute();
|
m_cpu->Execute();
|
||||||
|
Synchronize();
|
||||||
// run pending ticks from CPU for other components
|
|
||||||
m_gpu->Execute(pending_ticks * 3);
|
|
||||||
|
|
||||||
m_timers->AddTicks(2, m_timers->IsUsingExternalClock(2) ? (pending_ticks / 8) : pending_ticks);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,9 +209,20 @@ bool System::LoadEXE(const char* filename)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::SetSliceTicks(TickCount downcount)
|
void System::Synchronize()
|
||||||
{
|
{
|
||||||
m_cpu->SetSliceTicks(downcount);
|
m_cpu->ResetDowncount();
|
||||||
|
|
||||||
|
const TickCount pending_ticks = m_cpu->GetPendingTicks();
|
||||||
|
m_cpu->ResetPendingTicks();
|
||||||
|
|
||||||
|
m_gpu->Execute(pending_ticks);
|
||||||
|
m_timers->AddSystemTicks(pending_ticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
void System::SetDowncount(TickCount downcount)
|
||||||
|
{
|
||||||
|
m_cpu->SetDowncount(downcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::SetPadDevice(u32 slot, std::shared_ptr<PadDevice> dev)
|
void System::SetPadDevice(u32 slot, std::shared_ptr<PadDevice> dev)
|
||||||
|
@ -42,7 +42,8 @@ public:
|
|||||||
|
|
||||||
bool LoadEXE(const char* filename);
|
bool LoadEXE(const char* filename);
|
||||||
|
|
||||||
void SetSliceTicks(TickCount downcount);
|
void SetDowncount(TickCount downcount);
|
||||||
|
void Synchronize();
|
||||||
|
|
||||||
void SetPadDevice(u32 slot, std::shared_ptr<PadDevice> dev);
|
void SetPadDevice(u32 slot, std::shared_ptr<PadDevice> dev);
|
||||||
|
|
||||||
|
@ -2,14 +2,16 @@
|
|||||||
#include "YBaseLib/Log.h"
|
#include "YBaseLib/Log.h"
|
||||||
#include "common/state_wrapper.h"
|
#include "common/state_wrapper.h"
|
||||||
#include "interrupt_controller.h"
|
#include "interrupt_controller.h"
|
||||||
|
#include "system.h"
|
||||||
Log_SetChannel(Timers);
|
Log_SetChannel(Timers);
|
||||||
|
|
||||||
Timers::Timers() = default;
|
Timers::Timers() = default;
|
||||||
|
|
||||||
Timers::~Timers() = default;
|
Timers::~Timers() = default;
|
||||||
|
|
||||||
bool Timers::Initialize(InterruptController* interrupt_controller)
|
bool Timers::Initialize(System* system, InterruptController* interrupt_controller)
|
||||||
{
|
{
|
||||||
|
m_system = system;
|
||||||
m_interrupt_controller = interrupt_controller;
|
m_interrupt_controller = interrupt_controller;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -103,6 +105,16 @@ void Timers::AddTicks(u32 timer, u32 count)
|
|||||||
cs.counter = 0;
|
cs.counter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Timers::AddSystemTicks(u32 ticks)
|
||||||
|
{
|
||||||
|
if (!m_states[0].external_counting_enabled && m_states[0].counting_enabled)
|
||||||
|
AddTicks(0, ticks);
|
||||||
|
if (!m_states[1].external_counting_enabled && m_states[1].counting_enabled)
|
||||||
|
AddTicks(1, ticks);
|
||||||
|
if (m_states[2].counting_enabled)
|
||||||
|
AddTicks(2, m_states[2].external_counting_enabled ? (ticks / 8) : (ticks));
|
||||||
|
}
|
||||||
|
|
||||||
u32 Timers::ReadRegister(u32 offset)
|
u32 Timers::ReadRegister(u32 offset)
|
||||||
{
|
{
|
||||||
const u32 timer_index = (offset >> 4) & u32(0x03);
|
const u32 timer_index = (offset >> 4) & u32(0x03);
|
||||||
@ -113,15 +125,20 @@ u32 Timers::ReadRegister(u32 offset)
|
|||||||
switch (port_offset)
|
switch (port_offset)
|
||||||
{
|
{
|
||||||
case 0x00:
|
case 0x00:
|
||||||
|
{
|
||||||
|
m_system->Synchronize();
|
||||||
return cs.counter;
|
return cs.counter;
|
||||||
|
}
|
||||||
|
|
||||||
case 0x04:
|
case 0x04:
|
||||||
{
|
{
|
||||||
|
m_system->Synchronize();
|
||||||
|
|
||||||
const u32 bits = cs.mode.bits;
|
const u32 bits = cs.mode.bits;
|
||||||
cs.mode.reached_overflow = false;
|
cs.mode.reached_overflow = false;
|
||||||
cs.mode.reached_target = false;
|
cs.mode.reached_target = false;
|
||||||
|
return bits;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x08:
|
case 0x08:
|
||||||
return cs.target;
|
return cs.target;
|
||||||
@ -142,13 +159,17 @@ void Timers::WriteRegister(u32 offset, u32 value)
|
|||||||
switch (port_offset)
|
switch (port_offset)
|
||||||
{
|
{
|
||||||
case 0x00:
|
case 0x00:
|
||||||
|
{
|
||||||
Log_DebugPrintf("Timer %u write counter %u", timer_index, value);
|
Log_DebugPrintf("Timer %u write counter %u", timer_index, value);
|
||||||
|
m_system->Synchronize();
|
||||||
cs.counter = value & u32(0xFFFF);
|
cs.counter = value & u32(0xFFFF);
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x04:
|
case 0x04:
|
||||||
{
|
{
|
||||||
Log_DebugPrintf("Timer %u write mode register 0x%04X", timer_index, value);
|
Log_DebugPrintf("Timer %u write mode register 0x%04X", timer_index, value);
|
||||||
|
m_system->Synchronize();
|
||||||
cs.mode.bits = value & u32(0x1FFF);
|
cs.mode.bits = value & u32(0x1FFF);
|
||||||
cs.use_external_clock = (cs.mode.clock_source & (timer_index == 2 ? 2 : 1)) != 0;
|
cs.use_external_clock = (cs.mode.clock_source & (timer_index == 2 ? 2 : 1)) != 0;
|
||||||
cs.counter = 0;
|
cs.counter = 0;
|
||||||
@ -157,9 +178,12 @@ void Timers::WriteRegister(u32 offset, u32 value)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x08:
|
case 0x08:
|
||||||
|
{
|
||||||
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)));
|
||||||
|
m_system->Synchronize();
|
||||||
cs.target = value & u32(0xFFFF);
|
cs.target = value & u32(0xFFFF);
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Log_ErrorPrintf("Write unknown register in timer %u (offset 0x%02X, value 0x%X)", offset, value);
|
Log_ErrorPrintf("Write unknown register in timer %u (offset 0x%02X, value 0x%X)", offset, value);
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
class StateWrapper;
|
class StateWrapper;
|
||||||
|
|
||||||
|
class System;
|
||||||
class InterruptController;
|
class InterruptController;
|
||||||
|
|
||||||
class Timers
|
class Timers
|
||||||
@ -13,7 +14,7 @@ public:
|
|||||||
Timers();
|
Timers();
|
||||||
~Timers();
|
~Timers();
|
||||||
|
|
||||||
bool Initialize(InterruptController* interrupt_controller);
|
bool Initialize(System* system, InterruptController* interrupt_controller);
|
||||||
void Reset();
|
void Reset();
|
||||||
bool DoState(StateWrapper& sw);
|
bool DoState(StateWrapper& sw);
|
||||||
|
|
||||||
@ -22,6 +23,7 @@ public:
|
|||||||
// dot clock/hblank/sysclk div 8
|
// dot clock/hblank/sysclk div 8
|
||||||
bool IsUsingExternalClock(u32 timer) const { return m_states[timer].external_counting_enabled; }
|
bool IsUsingExternalClock(u32 timer) const { return m_states[timer].external_counting_enabled; }
|
||||||
void AddTicks(u32 timer, u32 ticks);
|
void AddTicks(u32 timer, u32 ticks);
|
||||||
|
void AddSystemTicks(u32 ticks);
|
||||||
|
|
||||||
u32 ReadRegister(u32 offset);
|
u32 ReadRegister(u32 offset);
|
||||||
void WriteRegister(u32 offset, u32 value);
|
void WriteRegister(u32 offset, u32 value);
|
||||||
@ -70,6 +72,7 @@ private:
|
|||||||
void UpdateDowncount();
|
void UpdateDowncount();
|
||||||
u32 GetSystemTicksForTimerTicks(u32 timer) const;
|
u32 GetSystemTicksForTimerTicks(u32 timer) const;
|
||||||
|
|
||||||
|
System* m_system = nullptr;
|
||||||
InterruptController* m_interrupt_controller = nullptr;
|
InterruptController* m_interrupt_controller = nullptr;
|
||||||
|
|
||||||
std::array<CounterState, NUM_TIMERS> m_states{};
|
std::array<CounterState, NUM_TIMERS> m_states{};
|
||||||
|
@ -20,5 +20,5 @@ enum class MemoryAccessSize : u32
|
|||||||
using TickCount = s32;
|
using TickCount = s32;
|
||||||
|
|
||||||
static constexpr TickCount MASTER_CLOCK = 44100 * 0x300; // 33868800Hz or 33.8688MHz, also used as CPU clock
|
static constexpr TickCount MASTER_CLOCK = 44100 * 0x300; // 33868800Hz or 33.8688MHz, also used as CPU clock
|
||||||
static constexpr TickCount MAX_CPU_SLICE_SIZE = MASTER_CLOCK / 10;
|
static constexpr TickCount MAX_SLICE_SIZE = MASTER_CLOCK / 10;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user