diff --git a/Core/Config.h b/Core/Config.h index c4ba00d2b1..1843823047 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -97,6 +97,7 @@ public: // Core bool bIgnoreBadMemAccess; + bool bFastMemory; int iCpuCore; bool bCheckForNewVersion; diff --git a/Core/Core.cpp b/Core/Core.cpp index 41e5c170c0..5445e51b86 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -64,6 +64,8 @@ static double lastKeepAwake = 0.0; static GraphicsContext *graphicsContext; static bool powerSaving = false; +static ExceptionInfo g_exceptionInfo; + void Core_SetGraphicsContext(GraphicsContext *ctx) { graphicsContext = ctx; PSP_CoreParameter().graphicsContext = graphicsContext; @@ -366,19 +368,40 @@ void Core_EnableStepping(bool step) { } } +bool Core_NextFrame() { + if (coreState == CORE_RUNNING) { + coreState = CORE_NEXTFRAME; + return true; + } else { + return false; + } +} + int Core_GetSteppingCounter() { return steppingCounter; } -void Core_MemoryException(u32 address, u32 pc, MemoryExceptionType type) { - const char *desc = ""; +const char *ExceptionTypeToString(ExceptionType type) { switch (type) { - case MemoryExceptionType::READ_WORD: desc = "Read Word"; break; - case MemoryExceptionType::WRITE_WORD: desc = "Write Word"; break; - case MemoryExceptionType::READ_BLOCK: desc = "Read Block"; break; - case MemoryExceptionType::WRITE_BLOCK: desc = "Read/Write Block"; break; + case ExceptionType::MEMORY: return "Memory"; + case ExceptionType::BREAK: return "Break"; + default: return "N/A"; } +} +const char *MemoryExceptionTypeToString(MemoryExceptionType type) { + switch (type) { + case MemoryExceptionType::READ_WORD: return "Read Word"; + case MemoryExceptionType::WRITE_WORD: return "Write Word"; + case MemoryExceptionType::READ_BLOCK: return "Read Block"; + case MemoryExceptionType::WRITE_BLOCK: return "Read/Write Block"; + default: + return "N/A"; + } +} + +void Core_MemoryException(u32 address, u32 pc, MemoryExceptionType type) { + const char *desc = MemoryExceptionTypeToString(type); // In jit, we only flush PC when bIgnoreBadMemAccess is off. if (g_Config.iCpuCore == (int)CPUCore::JIT && g_Config.bIgnoreBadMemAccess) { WARN_LOG(MEMMAP, "%s: Invalid address %08x", desc, address); @@ -386,6 +409,12 @@ void Core_MemoryException(u32 address, u32 pc, MemoryExceptionType type) { WARN_LOG(MEMMAP, "%s: Invalid address %08x PC %08x LR %08x", desc, address, currentMIPS->pc, currentMIPS->r[MIPS_REG_RA]); } + ExceptionInfo &e = g_exceptionInfo; + e = {}; + e.type = ExceptionType::MEMORY; + e.info = ""; + e.memory_type = type; + if (!g_Config.bIgnoreBadMemAccess) { Core_EnableStepping(true); host->SetDebugMode(true); @@ -394,8 +423,18 @@ void Core_MemoryException(u32 address, u32 pc, MemoryExceptionType type) { void Core_Break() { ERROR_LOG(CPU, "BREAK!"); + + ExceptionInfo &e = g_exceptionInfo; + e = {}; + e.type = ExceptionType::BREAK; + e.info = ""; + if (!g_Config.bIgnoreBadMemAccess) { Core_EnableStepping(true); host->SetDebugMode(true); } } + +ExceptionInfo Core_GetExceptionInfo() { + return g_exceptionInfo; +} diff --git a/Core/Core.h b/Core/Core.h index f5cb4ca038..dffdebd0d8 100644 --- a/Core/Core.h +++ b/Core/Core.h @@ -32,6 +32,8 @@ void Core_SetGraphicsContext(GraphicsContext *ctx); // called from gui void Core_EnableStepping(bool step); + +bool Core_NextFrame(); void Core_DoSingleStep(); void Core_UpdateSingleStep(); void Core_ProcessStepping(); @@ -86,3 +88,19 @@ enum class MemoryExceptionType { void Core_MemoryException(u32 address, u32 pc, MemoryExceptionType type); void Core_Break(); + +enum class ExceptionType { + NONE, + MEMORY, + BREAK, +}; + +struct ExceptionInfo { + ExceptionType type; + MemoryExceptionType memory_type; + std::string info; +}; + +ExceptionInfo Core_GetExceptionInfo(); + +const char *MemoryExceptionTypeToString(MemoryExceptionType type); diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index 90f5dfe4dc..1480c03026 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -24,7 +24,6 @@ #include "net/resolve.h" #include "Common/ChunkFile.h" -#include "Core/Config.h" #include "Core/CoreTiming.h" #include "Core/MemMap.h" #include "Core/HLE/HLE.h" diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 56fcf9bfc9..362ad09ce1 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -42,6 +42,7 @@ #include "Core/CoreParameter.h" #include "Core/Host.h" #include "Core/Reporting.h" +#include "Core/Core.h" #include "Core/System.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" @@ -791,8 +792,7 @@ void __DisplayFlip(int cyclesLate) { const bool fbReallyDirty = gpu->FramebufferReallyDirty(); if (fbReallyDirty || noRecentFlip || postEffectRequiresFlip) { // Check first though, might've just quit / been paused. - if (coreState == CORE_RUNNING) { - coreState = CORE_NEXTFRAME; + if (Core_NextFrame()) { gpu->CopyDisplayToOutput(fbReallyDirty); if (fbReallyDirty) { actualFlips++; diff --git a/Core/HW/Camera.cpp b/Core/HW/Camera.cpp index 48d5210432..415ac0a190 100644 --- a/Core/HW/Camera.cpp +++ b/Core/HW/Camera.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "Camera.h" +#include "Core/Config.h" void convert_frame(int inw, int inh, unsigned char *inData, AVPixelFormat inFormat, int outw, int outh, unsigned char **outData, int *outLen) { diff --git a/Core/HW/Camera.h b/Core/HW/Camera.h index fbc691bf64..4e36fbd296 100644 --- a/Core/HW/Camera.h +++ b/Core/HW/Camera.h @@ -18,7 +18,6 @@ #pragma once #include "ppsspp_config.h" -#include "Core/Config.h" #include "Core/HLE/sceUsbCam.h" #include "Log.h" diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 98a7bbd9e3..79035ba076 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -28,10 +28,10 @@ #include "Common/Common.h" #include "Core/Config.h" #include "Core/ConfigValues.h" +#include "Core/Core.h" #include "Core/CoreParameter.h" #include "Core/Host.h" #include "Core/Reporting.h" -#include "Core/System.h" #include "GPU/Common/DrawEngineCommon.h" #include "GPU/Common/FramebufferCommon.h" #include "GPU/Common/PostShader.h" @@ -831,7 +831,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { currentRenderVfb_ = 0; if (displayFramebufPtr_ == 0) { - if (coreState == CORE_STEPPING) + if (Core_IsStepping()) VERBOSE_LOG(FRAMEBUF, "Display disabled, displaying only black"); else DEBUG_LOG(FRAMEBUF, "Display disabled, displaying only black"); @@ -925,7 +925,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) { displayFramebuf_ = vfb; if (vfb->fbo) { - if (coreState == CORE_STEPPING) + if (Core_IsStepping()) VERBOSE_LOG(FRAMEBUF, "Displaying FBO %08x", vfb->fb_address); else DEBUG_LOG(FRAMEBUF, "Displaying FBO %08x", vfb->fb_address); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index cc9dd9205f..e6b837cac2 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -136,7 +136,9 @@ EmuScreen::EmuScreen(const std::string &filename) frameStep_ = false; lastNumFlips = gpuStats.numFlips; startDumping = false; + // Make sure we don't leave it at powerdown after the last game. + // TODO: This really should be handled elsewhere if it isn't. if (coreState == CORE_POWERDOWN) coreState = CORE_STEPPING; @@ -1403,26 +1405,38 @@ void EmuScreen::render() { PSP_RunLoopWhileState(); // Hopefully coreState is now CORE_NEXTFRAME - if (coreState == CORE_NEXTFRAME) { - // set back to running for the next frame + switch (coreState) { + case CORE_NEXTFRAME: + // Reached the end of the frame, all good. Set back to running for the next frame coreState = CORE_RUNNING; - } else if (coreState == CORE_STEPPING) { - // If we're stepping, it's convenient not to clear the screen entirely, so we copy display to output. - // This won't work in non-buffered, but that's fine. - thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_Stepping"); - // Just to make sure. - if (PSP_IsInited()) { - gpu->CopyDisplayToOutput(true); + break; + case CORE_STEPPING: + case CORE_RUNTIME_ERROR: + { + // If there's an exception, display information. + ExceptionInfo info = Core_GetExceptionInfo(); + if (info.type != ExceptionType::NONE) { + // Blue screen + thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE, 0xFF900000 }, "EmuScreen_RuntimeError"); + } else { + // If we're stepping, it's convenient not to clear the screen entirely, so we copy display to output. + // This won't work in non-buffered, but that's fine. + thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_Stepping"); + // Just to make sure. + if (PSP_IsInited()) { + gpu->CopyDisplayToOutput(true); + } } - } else if (coreState == CORE_RUNTIME_ERROR) { - // Blue screen :) - thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE, 0xFF0000FF }, "EmuScreen_RuntimeError"); - } else { + break; + } + default: // Didn't actually reach the end of the frame, ran out of the blockTicks cycles. // In this case we need to bind and wipe the backbuffer, at least. // It's possible we never ended up outputted anything - make sure we have the backbuffer cleared thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR }, "EmuScreen_NoFrame"); + break; } + checkPowerDown(); PSP_EndHostFrame();