diff --git a/src/pse-sdl/sdl_interface.cpp b/src/pse-sdl/sdl_interface.cpp index 314542221..e3ea5f356 100644 --- a/src/pse-sdl/sdl_interface.cpp +++ b/src/pse-sdl/sdl_interface.cpp @@ -264,7 +264,7 @@ bool SDLInterface::HandleSDLEvent(const SDL_Event* event) m_controller->SetButtonState(DigitalController::Button::L2, pressed); return true; case SDL_SCANCODE_3: - m_controller->SetButtonState(DigitalController::Button::R3, pressed); + m_controller->SetButtonState(DigitalController::Button::R2, pressed); return true; case SDL_SCANCODE_RETURN: diff --git a/src/pse/cpu_core.cpp b/src/pse/cpu_core.cpp index 2373ca7cb..c67682f5e 100644 --- a/src/pse/cpu_core.cpp +++ b/src/pse/cpu_core.cpp @@ -26,7 +26,8 @@ bool Core::Initialize(Bus* bus) void Core::Reset() { - m_slice_ticks = std::numeric_limits::max(); + m_pending_ticks = 0; + m_downcount = MAX_SLICE_SIZE; m_regs = {}; @@ -47,7 +48,8 @@ void Core::Reset() 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.Do(&m_regs.pc); sw.Do(&m_regs.hi); @@ -312,12 +314,12 @@ void Core::DisassembleAndPrint(u32 addr) PrintInstruction(bits, addr); } -TickCount Core::Execute() +void Core::Execute() { - TickCount executed_ticks = 0; - while (executed_ticks < m_slice_ticks) + while (m_downcount >= 0) { - executed_ticks++; + m_pending_ticks += 3; + m_downcount -= 3; // now executing the instruction we previously fetched 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_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() diff --git a/src/pse/cpu_core.h b/src/pse/cpu_core.h index c1f7666f5..818e00abd 100644 --- a/src/pse/cpu_core.h +++ b/src/pse/cpu_core.h @@ -27,12 +27,16 @@ public: void Reset(); bool DoState(StateWrapper& sw); - TickCount Execute(); + void Execute(); const Registers& GetRegs() const { 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. void SetPC(u32 new_pc); @@ -101,8 +105,9 @@ private: Bus* m_bus = nullptr; - // ticks of master/CPU clock until the next event - TickCount m_slice_ticks = 0; + // ticks the CPU has executed + TickCount m_pending_ticks = 0; + TickCount m_downcount = MAX_SLICE_SIZE; Registers m_regs = {}; Cop0Registers m_cop0_regs = {}; diff --git a/src/pse/gpu.cpp b/src/pse/gpu.cpp index 09e3c6a8f..f67faa946 100644 --- a/src/pse/gpu.cpp +++ b/src/pse/gpu.cpp @@ -256,7 +256,7 @@ void GPU::UpdateCRTCConfig() void GPU::UpdateSliceTicks() { // 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; #else // 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 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) diff --git a/src/pse/interrupt_controller.cpp b/src/pse/interrupt_controller.cpp index 070f7ccc4..c40b721d4 100644 --- a/src/pse/interrupt_controller.cpp +++ b/src/pse/interrupt_controller.cpp @@ -57,7 +57,9 @@ void InterruptController::WriteRegister(u32 offset, u32 value) { 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); UpdateCPUInterruptRequest(); } diff --git a/src/pse/system.cpp b/src/pse/system.cpp index 1df20ac31..58d3de7b5 100644 --- a/src/pse/system.cpp +++ b/src/pse/system.cpp @@ -52,7 +52,7 @@ bool System::Initialize() if (!m_pad->Initialize(m_interrupt_controller.get())) return false; - if (!m_timers->Initialize(m_interrupt_controller.get())) + if (!m_timers->Initialize(this, m_interrupt_controller.get())) return false; return true; @@ -89,8 +89,6 @@ bool System::DoState(StateWrapper& sw) void System::Reset() { - SetSliceTicks(1); - m_cpu->Reset(); m_bus->Reset(); m_dma->Reset(); @@ -119,12 +117,8 @@ void System::RunFrame() u32 current_frame_number = m_frame_number; while (current_frame_number == m_frame_number) { - const TickCount pending_ticks = m_cpu->Execute(); - - // 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); + m_cpu->Execute(); + Synchronize(); } } @@ -215,9 +209,20 @@ bool System::LoadEXE(const char* filename) 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 dev) diff --git a/src/pse/system.h b/src/pse/system.h index 14d1c1996..caca74a54 100644 --- a/src/pse/system.h +++ b/src/pse/system.h @@ -42,7 +42,8 @@ public: bool LoadEXE(const char* filename); - void SetSliceTicks(TickCount downcount); + void SetDowncount(TickCount downcount); + void Synchronize(); void SetPadDevice(u32 slot, std::shared_ptr dev); diff --git a/src/pse/timers.cpp b/src/pse/timers.cpp index 21bea1b5e..2e6693847 100644 --- a/src/pse/timers.cpp +++ b/src/pse/timers.cpp @@ -2,14 +2,16 @@ #include "YBaseLib/Log.h" #include "common/state_wrapper.h" #include "interrupt_controller.h" +#include "system.h" Log_SetChannel(Timers); 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; return true; } @@ -103,6 +105,16 @@ void Timers::AddTicks(u32 timer, u32 count) 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) { const u32 timer_index = (offset >> 4) & u32(0x03); @@ -113,15 +125,20 @@ u32 Timers::ReadRegister(u32 offset) switch (port_offset) { case 0x00: + { + m_system->Synchronize(); return cs.counter; + } case 0x04: { + m_system->Synchronize(); + const u32 bits = cs.mode.bits; cs.mode.reached_overflow = false; cs.mode.reached_target = false; + return bits; } - break; case 0x08: return cs.target; @@ -142,13 +159,17 @@ void Timers::WriteRegister(u32 offset, u32 value) switch (port_offset) { case 0x00: + { Log_DebugPrintf("Timer %u write counter %u", timer_index, value); + m_system->Synchronize(); cs.counter = value & u32(0xFFFF); - break; + } + break; case 0x04: { Log_DebugPrintf("Timer %u write mode register 0x%04X", timer_index, value); + m_system->Synchronize(); cs.mode.bits = value & u32(0x1FFF); cs.use_external_clock = (cs.mode.clock_source & (timer_index == 2 ? 2 : 1)) != 0; cs.counter = 0; @@ -157,9 +178,12 @@ void Timers::WriteRegister(u32 offset, u32 value) break; case 0x08: + { Log_DebugPrintf("Timer %u write target 0x%04X", timer_index, ZeroExtend32(Truncate16(value))); + m_system->Synchronize(); cs.target = value & u32(0xFFFF); - break; + } + break; default: Log_ErrorPrintf("Write unknown register in timer %u (offset 0x%02X, value 0x%X)", offset, value); diff --git a/src/pse/timers.h b/src/pse/timers.h index ec30b5e44..7cfa61eed 100644 --- a/src/pse/timers.h +++ b/src/pse/timers.h @@ -5,6 +5,7 @@ class StateWrapper; +class System; class InterruptController; class Timers @@ -13,7 +14,7 @@ public: Timers(); ~Timers(); - bool Initialize(InterruptController* interrupt_controller); + bool Initialize(System* system, InterruptController* interrupt_controller); void Reset(); bool DoState(StateWrapper& sw); @@ -22,6 +23,7 @@ public: // dot clock/hblank/sysclk div 8 bool IsUsingExternalClock(u32 timer) const { return m_states[timer].external_counting_enabled; } void AddTicks(u32 timer, u32 ticks); + void AddSystemTicks(u32 ticks); u32 ReadRegister(u32 offset); void WriteRegister(u32 offset, u32 value); @@ -70,6 +72,7 @@ private: void UpdateDowncount(); u32 GetSystemTicksForTimerTicks(u32 timer) const; + System* m_system = nullptr; InterruptController* m_interrupt_controller = nullptr; std::array m_states{}; diff --git a/src/pse/types.h b/src/pse/types.h index e7af0d643..79a71a107 100644 --- a/src/pse/types.h +++ b/src/pse/types.h @@ -20,5 +20,5 @@ enum class MemoryAccessSize : u32 using TickCount = s32; 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;