2012-11-01 16:19:01 +01:00
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
2012-11-04 23:01:49 +01:00
// the Free Software Foundation, version 2.0 or later versions.
2012-11-01 16:19:01 +01:00
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
2017-02-24 18:59:41 +01:00
# include "ppsspp_config.h"
2013-09-28 00:32:45 -07:00
# include <set>
2017-12-19 15:38:18 +01:00
# include <chrono>
2021-10-23 16:56:15 -07:00
# include <cstdint>
2017-02-27 21:57:46 +01:00
# include <mutex>
2017-12-19 15:38:18 +01:00
# include <condition_variable>
2013-12-30 10:17:11 +01:00
2020-10-04 10:30:18 +02:00
# include "Common/System/NativeApp.h"
# include "Common/System/System.h"
2020-10-04 10:10:55 +02:00
# include "Common/System/Display.h"
2020-08-15 20:53:08 +02:00
# include "Common/TimeUtil.h"
2020-10-01 09:27:25 +02:00
# include "Common/Thread/ThreadUtil.h"
2020-10-04 10:04:01 +02:00
# include "Common/Profiler/Profiler.h"
2013-03-29 18:50:08 +01:00
2018-05-02 07:14:46 -07:00
# include "Common/GraphicsContext.h"
2020-07-04 20:30:05 +02:00
# include "Common/Log.h"
2013-03-29 18:50:08 +01:00
# include "Core/Core.h"
# include "Core/Config.h"
# include "Core/MemMap.h"
2013-09-14 18:43:23 -07:00
# include "Core/SaveState.h"
2013-03-29 18:50:08 +01:00
# include "Core/System.h"
2023-03-31 10:08:12 +02:00
# include "Core/MemFault.h"
2018-05-02 07:14:46 -07:00
# include "Core/Debugger/Breakpoints.h"
2022-01-30 10:46:50 -08:00
# include "Core/HW/Display.h"
2013-03-29 18:50:08 +01:00
# include "Core/MIPS/MIPS.h"
2018-06-16 13:53:41 -07:00
# include "GPU/Debugger/Stepping.h"
2013-12-30 00:11:29 +01:00
2013-02-18 23:25:06 +01:00
# ifdef _WIN32
2018-02-25 10:27:59 +01:00
# include "Common/CommonWindows.h"
2013-03-29 20:51:14 +01:00
# include "Windows/InputDevice.h"
2013-02-18 23:25:06 +01:00
# endif
2012-11-01 16:19:01 +01:00
2015-02-28 22:20:14 -08:00
// Time until we stop considering the core active without user input.
// Should this be configurable? 2 hours currently.
static const double ACTIVITY_IDLE_TIMEOUT = 2.0 * 3600.0 ;
2017-12-19 15:38:18 +01:00
static std : : condition_variable m_StepCond ;
2017-02-27 21:57:46 +01:00
static std : : mutex m_hStepMutex ;
2017-12-19 15:38:18 +01:00
static std : : condition_variable m_InactiveCond ;
2017-02-27 21:57:46 +01:00
static std : : mutex m_hInactiveMutex ;
2013-09-14 18:43:23 -07:00
static bool singleStepPending = false ;
2018-04-19 21:14:01 -07:00
static int steppingCounter = 0 ;
2021-10-23 16:56:15 -07:00
static const char * steppingReason = " " ;
static uint32_t steppingAddress = 0 ;
2018-06-11 14:54:42 -07:00
static std : : set < CoreLifecycleFunc > lifecycleFuncs ;
static std : : set < CoreStopRequestFunc > stopFuncs ;
2014-06-29 13:11:06 +02:00
static bool windowHidden = false ;
2015-02-28 22:20:14 -08:00
static double lastActivity = 0.0 ;
static double lastKeepAwake = 0.0 ;
2015-12-31 16:59:40 +01:00
static GraphicsContext * graphicsContext ;
2016-07-24 17:04:06 -07:00
static bool powerSaving = false ;
2013-02-23 12:59:40 -08:00
2023-04-28 13:38:16 +02:00
static MIPSExceptionInfo g_exceptionInfo ;
2020-07-04 20:57:05 +02:00
2016-01-01 14:08:23 +01:00
void Core_SetGraphicsContext ( GraphicsContext * ctx ) {
2016-07-24 17:04:06 -07:00
graphicsContext = ctx ;
2016-10-01 11:22:53 -07:00
PSP_CoreParameter ( ) . graphicsContext = graphicsContext ;
2016-01-01 14:08:23 +01:00
}
2014-06-29 13:11:06 +02:00
void Core_NotifyWindowHidden ( bool hidden ) {
windowHidden = hidden ;
// TODO: Wait until we can react?
}
2015-02-28 22:20:14 -08:00
void Core_NotifyActivity ( ) {
lastActivity = time_now_d ( ) ;
}
2018-04-22 08:33:22 -07:00
void Core_ListenLifecycle ( CoreLifecycleFunc func ) {
2018-06-11 14:54:42 -07:00
lifecycleFuncs . insert ( func ) ;
2013-09-28 00:32:45 -07:00
}
2018-04-22 08:33:22 -07:00
void Core_NotifyLifecycle ( CoreLifecycle stage ) {
2021-08-08 23:01:35 -07:00
if ( stage = = CoreLifecycle : : STARTING ) {
2021-08-08 23:15:27 -07:00
Core_ResetException ( ) ;
2021-08-08 23:01:35 -07:00
}
2018-06-11 14:54:42 -07:00
for ( auto func : lifecycleFuncs ) {
func ( stage ) ;
2013-10-12 01:44:12 -07:00
}
2013-09-28 00:32:45 -07:00
}
2018-06-11 14:54:42 -07:00
void Core_ListenStopRequest ( CoreStopRequestFunc func ) {
stopFuncs . insert ( func ) ;
}
2013-10-12 01:44:12 -07:00
void Core_Stop ( ) {
2021-08-08 23:15:27 -07:00
Core_ResetException ( ) ;
2013-02-23 12:59:40 -08:00
Core_UpdateState ( CORE_POWERDOWN ) ;
2018-06-11 14:54:42 -07:00
for ( auto func : stopFuncs ) {
func ( ) ;
}
2012-11-01 16:19:01 +01:00
}
2013-10-12 01:44:12 -07:00
bool Core_IsStepping ( ) {
2012-11-01 16:19:01 +01:00
return coreState = = CORE_STEPPING | | coreState = = CORE_POWERDOWN ;
}
2013-10-12 01:44:12 -07:00
bool Core_IsActive ( ) {
2013-06-08 08:32:07 +08:00
return coreState = = CORE_RUNNING | | coreState = = CORE_NEXTFRAME | | coreStatePending ;
}
2013-10-12 01:44:12 -07:00
bool Core_IsInactive ( ) {
2013-02-23 12:59:40 -08:00
return coreState ! = CORE_RUNNING & & coreState ! = CORE_NEXTFRAME & & ! coreStatePending ;
}
2013-02-23 13:21:28 -08:00
2018-04-30 18:59:48 -07:00
static inline void Core_StateProcessed ( ) {
if ( coreStatePending ) {
std : : lock_guard < std : : mutex > guard ( m_hInactiveMutex ) ;
coreStatePending = false ;
m_InactiveCond . notify_all ( ) ;
}
}
2013-10-12 01:44:12 -07:00
void Core_WaitInactive ( ) {
2022-12-18 21:26:59 -08:00
while ( Core_IsActive ( ) & & ! GPUStepping : : IsStepping ( ) ) {
2017-12-19 15:38:18 +01:00
std : : unique_lock < std : : mutex > guard ( m_hInactiveMutex ) ;
m_InactiveCond . wait ( guard ) ;
2013-10-12 01:44:12 -07:00
}
2013-02-23 12:59:40 -08:00
}
2013-10-12 01:44:12 -07:00
void Core_WaitInactive ( int milliseconds ) {
2022-12-18 21:26:59 -08:00
if ( Core_IsActive ( ) & & ! GPUStepping : : IsStepping ( ) ) {
2017-12-19 15:38:18 +01:00
std : : unique_lock < std : : mutex > guard ( m_hInactiveMutex ) ;
m_InactiveCond . wait_for ( guard , std : : chrono : : milliseconds ( milliseconds ) ) ;
2013-10-12 01:44:12 -07:00
}
2013-02-23 13:21:28 -08:00
}
2016-07-24 17:04:06 -07:00
void Core_SetPowerSaving ( bool mode ) {
powerSaving = mode ;
}
bool Core_GetPowerSaving ( ) {
return powerSaving ;
}
2017-01-17 17:21:00 +07:00
static bool IsWindowSmall ( int pixelWidth , int pixelHeight ) {
// Can't take this from config as it will not be set if windows is maximized.
2023-02-25 13:09:44 +01:00
int w = ( int ) ( pixelWidth * g_display . dpi_scale_x ) ;
int h = ( int ) ( pixelHeight * g_display . dpi_scale_y ) ;
2017-01-17 17:21:00 +07:00
return g_Config . IsPortrait ( ) ? ( h < 480 + 80 ) : ( w < 480 + 80 ) ;
}
2017-01-16 19:08:26 +07:00
// TODO: Feels like this belongs elsewhere.
2017-01-17 17:21:00 +07:00
bool UpdateScreenScale ( int width , int height ) {
bool smallWindow ;
2020-01-05 15:46:27 +08:00
# if defined(USING_QT_UI)
2023-02-25 13:09:44 +01:00
g_display . dpi = System_GetPropertyFloat ( SYSPROP_DISPLAY_DPI ) ;
2020-01-05 15:46:27 +08:00
float g_logical_dpi = System_GetPropertyFloat ( SYSPROP_DISPLAY_LOGICAL_DPI ) ;
2023-02-25 13:09:44 +01:00
g_display . dpi_scale_x = g_logical_dpi / g_display . dpi ;
g_display . dpi_scale_y = g_logical_dpi / g_display . dpi ;
2020-01-05 15:46:27 +08:00
# elif PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
2023-02-25 13:09:44 +01:00
g_display . dpi = System_GetPropertyFloat ( SYSPROP_DISPLAY_DPI ) ;
g_display . dpi_scale_x = 96.0f / g_display . dpi ;
g_display . dpi_scale_y = 96.0f / g_display . dpi ;
2017-01-16 19:08:26 +07:00
# else
2023-02-25 13:09:44 +01:00
g_display . dpi = 96.0f ;
g_display . dpi_scale_x = 1.0f ;
g_display . dpi_scale_y = 1.0f ;
2017-01-16 19:08:26 +07:00
# endif
2023-02-25 13:09:44 +01:00
g_display . dpi_scale_real_x = g_display . dpi_scale_x ;
g_display . dpi_scale_real_y = g_display . dpi_scale_y ;
2017-03-12 12:17:35 -07:00
2017-01-17 19:02:47 +07:00
smallWindow = IsWindowSmall ( width , height ) ;
2017-01-17 17:21:00 +07:00
if ( smallWindow ) {
2023-02-25 13:09:44 +01:00
g_display . dpi / = 2.0f ;
g_display . dpi_scale_x * = 2.0f ;
g_display . dpi_scale_y * = 2.0f ;
2017-01-17 17:21:00 +07:00
}
2023-02-25 13:09:44 +01:00
g_display . pixel_in_dps_x = 1.0f / g_display . dpi_scale_x ;
g_display . pixel_in_dps_y = 1.0f / g_display . dpi_scale_y ;
2014-12-28 13:19:19 -08:00
2023-02-25 13:09:44 +01:00
int new_dp_xres = ( int ) ( width * g_display . dpi_scale_x ) ;
int new_dp_yres = ( int ) ( height * g_display . dpi_scale_y ) ;
2014-12-28 13:19:19 -08:00
2023-02-25 13:09:44 +01:00
bool dp_changed = new_dp_xres ! = g_display . dp_xres | | new_dp_yres ! = g_display . dp_yres ;
bool px_changed = g_display . pixel_xres ! = width | | g_display . pixel_yres ! = height ;
2014-12-28 13:19:19 -08:00
if ( dp_changed | | px_changed ) {
2023-02-25 13:09:44 +01:00
g_display . dp_xres = new_dp_xres ;
g_display . dp_yres = new_dp_yres ;
g_display . pixel_xres = width ;
g_display . pixel_yres = height ;
2014-12-28 13:19:19 -08:00
NativeResized ( ) ;
return true ;
}
return false ;
2013-03-29 18:50:08 +01:00
}
2018-04-29 18:08:41 -07:00
// Note: not used on Android.
2017-03-14 22:01:18 -07:00
void UpdateRunLoop ( ) {
2014-06-30 13:04:44 -04:00
if ( windowHidden & & g_Config . bPauseWhenMinimized ) {
2014-07-01 13:29:39 +10:00
sleep_ms ( 16 ) ;
2014-06-30 00:17:34 +10:00
return ;
2014-07-01 13:29:39 +10:00
}
2017-03-14 22:01:18 -07:00
NativeUpdate ( ) ;
2020-12-23 14:32:24 +01:00
NativeRender ( graphicsContext ) ;
2013-10-12 01:40:33 -07:00
}
2017-12-19 17:59:00 +01:00
void KeepScreenAwake ( ) {
2018-02-05 16:21:39 +01:00
# if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
2017-12-19 17:59:00 +01:00
SetThreadExecutionState ( ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED ) ;
# endif
}
2017-03-14 22:01:18 -07:00
void Core_RunLoop ( GraphicsContext * ctx ) {
2023-01-04 16:33:00 +01:00
float refreshRate = System_GetPropertyFloat ( SYSPROP_DISPLAY_REFRESH_RATE ) ;
2015-12-31 16:59:40 +01:00
graphicsContext = ctx ;
2014-06-22 09:38:46 +02:00
while ( ( GetUIState ( ) ! = UISTATE_INGAME | | ! PSP_IsInited ( ) ) & & GetUIState ( ) ! = UISTATE_EXIT ) {
2018-04-30 18:59:48 -07:00
// In case it was pending, we're not in game anymore. We won't get to Core_Run().
Core_StateProcessed ( ) ;
2013-10-12 01:40:33 -07:00
double startTime = time_now_d ( ) ;
2017-03-14 22:01:18 -07:00
UpdateRunLoop ( ) ;
2013-10-12 01:40:33 -07:00
2013-03-29 18:50:08 +01:00
// Simple throttling to not burn the GPU in the menu.
2013-10-12 01:40:33 -07:00
double diffTime = time_now_d ( ) - startTime ;
2023-01-04 16:33:00 +01:00
int sleepTime = ( int ) ( 1000.0 / refreshRate ) - ( int ) ( diffTime * 1000.0 ) ;
2013-10-12 01:40:33 -07:00
if ( sleepTime > 0 )
2017-12-20 10:22:15 +01:00
sleep_ms ( sleepTime ) ;
2014-06-29 13:11:06 +02:00
if ( ! windowHidden ) {
2015-12-31 16:59:40 +01:00
ctx - > SwapBuffers ( ) ;
2014-06-29 13:11:06 +02:00
}
2013-10-12 01:40:33 -07:00
}
2018-06-23 10:58:30 -07:00
while ( ( coreState = = CORE_RUNNING | | coreState = = CORE_STEPPING ) & & GetUIState ( ) = = UISTATE_INGAME ) {
2017-03-14 22:01:18 -07:00
UpdateRunLoop ( ) ;
2014-07-01 13:29:39 +10:00
if ( ! windowHidden & & ! Core_IsStepping ( ) ) {
2015-12-31 16:59:40 +01:00
ctx - > SwapBuffers ( ) ;
2015-02-28 22:20:14 -08:00
// Keep the system awake for longer than normal for cutscenes and the like.
const double now = time_now_d ( ) ;
if ( now < lastActivity + ACTIVITY_IDLE_TIMEOUT ) {
// Only resetting it ever prime number seconds in case the call is expensive.
// Using a prime number to ensure there's no interaction with other periodic events.
if ( now - lastKeepAwake > 89.0 | | now < lastKeepAwake ) {
2017-12-19 17:59:00 +01:00
KeepScreenAwake ( ) ;
2015-02-28 22:20:14 -08:00
lastKeepAwake = now ;
}
}
2013-03-30 08:34:27 +01:00
}
2013-02-18 23:25:06 +01:00
}
2012-11-01 16:19:01 +01:00
}
2013-10-12 01:44:12 -07:00
void Core_DoSingleStep ( ) {
2018-04-29 18:08:41 -07:00
std : : lock_guard < std : : mutex > guard ( m_hStepMutex ) ;
2013-09-14 18:43:23 -07:00
singleStepPending = true ;
2018-04-19 21:04:47 -07:00
m_StepCond . notify_all ( ) ;
2013-09-14 18:43:23 -07:00
}
2013-10-12 01:44:12 -07:00
void Core_UpdateSingleStep ( ) {
2018-04-29 18:08:41 -07:00
std : : lock_guard < std : : mutex > guard ( m_hStepMutex ) ;
2018-04-19 21:04:47 -07:00
m_StepCond . notify_all ( ) ;
2012-11-01 16:19:01 +01:00
}
2013-10-12 01:44:12 -07:00
void Core_SingleStep ( ) {
2021-08-08 23:15:27 -07:00
Core_ResetException ( ) ;
2012-11-01 16:19:01 +01:00
currentMIPS - > SingleStep ( ) ;
2018-04-29 18:38:17 -07:00
if ( coreState = = CORE_STEPPING )
steppingCounter + + ;
2012-11-01 16:19:01 +01:00
}
2018-04-29 18:38:17 -07:00
static inline bool Core_WaitStepping ( ) {
2018-04-29 18:08:41 -07:00
std : : unique_lock < std : : mutex > guard ( m_hStepMutex ) ;
2018-06-23 10:58:30 -07:00
// We only wait 16ms so that we can still draw UI or react to events.
2022-01-30 10:46:50 -08:00
double sleepStart = time_now_d ( ) ;
2018-04-29 18:08:41 -07:00
if ( ! singleStepPending & & coreState = = CORE_STEPPING )
2018-06-23 10:58:30 -07:00
m_StepCond . wait_for ( guard , std : : chrono : : milliseconds ( 16 ) ) ;
2022-01-30 10:46:50 -08:00
double sleepEnd = time_now_d ( ) ;
DisplayNotifySleep ( sleepEnd - sleepStart ) ;
2018-04-29 18:38:17 -07:00
bool result = singleStepPending ;
singleStepPending = false ;
return result ;
2018-04-29 18:08:41 -07:00
}
void Core_ProcessStepping ( ) {
2018-04-30 18:59:48 -07:00
Core_StateProcessed ( ) ;
2018-04-29 18:08:41 -07:00
// Check if there's any pending save state actions.
SaveState : : Process ( ) ;
if ( coreState ! = CORE_STEPPING ) {
return ;
}
2018-06-16 13:53:41 -07:00
// Or any GPU actions.
GPUStepping : : SingleStep ( ) ;
2018-05-01 22:18:33 -07:00
// We're not inside jit now, so it's safe to clear the breakpoints.
2018-06-23 10:58:30 -07:00
static int lastSteppingCounter = - 1 ;
if ( lastSteppingCounter ! = steppingCounter ) {
CBreakPoints : : ClearTemporaryBreakPoints ( ) ;
2023-03-21 11:21:19 +01:00
System_Notify ( SystemNotification : : DISASSEMBLY ) ;
System_Notify ( SystemNotification : : MEM_VIEW ) ;
2018-06-23 10:58:30 -07:00
lastSteppingCounter = steppingCounter ;
}
2018-04-29 18:08:41 -07:00
// Need to check inside the lock to avoid races.
2018-04-29 18:38:17 -07:00
bool doStep = Core_WaitStepping ( ) ;
2018-04-29 18:08:41 -07:00
// We may still be stepping without singleStepPending to process a save state.
2018-04-29 18:38:17 -07:00
if ( doStep & & coreState = = CORE_STEPPING ) {
2018-04-29 18:08:41 -07:00
Core_SingleStep ( ) ;
// Update disasm dialog.
2023-03-21 11:21:19 +01:00
System_Notify ( SystemNotification : : DISASSEMBLY ) ;
System_Notify ( SystemNotification : : MEM_VIEW ) ;
2018-04-29 18:08:41 -07:00
}
}
2017-12-19 15:42:18 +01:00
// Many platforms, like Android, do not call this function but handle things on their own.
2017-12-19 17:59:00 +01:00
// Instead they simply call NativeRender and NativeUpdate directly.
2022-11-08 21:59:08 +01:00
bool Core_Run ( GraphicsContext * ctx ) {
2023-03-21 11:21:19 +01:00
System_Notify ( SystemNotification : : DISASSEMBLY ) ;
2017-12-19 17:59:00 +01:00
while ( true ) {
2014-06-22 09:38:46 +02:00
if ( GetUIState ( ) ! = UISTATE_INGAME ) {
2018-04-30 18:59:48 -07:00
Core_StateProcessed ( ) ;
2014-06-22 09:38:46 +02:00
if ( GetUIState ( ) = = UISTATE_EXIT ) {
2018-02-07 15:52:19 +01:00
UpdateRunLoop ( ) ;
2022-11-08 21:59:08 +01:00
return false ;
2013-10-12 01:40:33 -07:00
}
2017-03-14 22:01:18 -07:00
Core_RunLoop ( ctx ) ;
2013-10-12 01:40:33 -07:00
continue ;
}
2017-12-19 17:59:00 +01:00
switch ( coreState ) {
2012-11-01 16:19:01 +01:00
case CORE_RUNNING :
2018-04-29 18:38:17 -07:00
case CORE_STEPPING :
2013-09-14 18:43:23 -07:00
// enter a fast runloop
2017-03-14 22:01:18 -07:00
Core_RunLoop ( ctx ) ;
2018-04-29 18:38:17 -07:00
if ( coreState = = CORE_POWERDOWN ) {
2018-04-30 18:59:48 -07:00
Core_StateProcessed ( ) ;
2022-11-08 21:59:08 +01:00
return true ;
2018-04-29 18:38:17 -07:00
}
2012-11-01 16:19:01 +01:00
break ;
2013-11-09 20:56:11 -08:00
case CORE_POWERUP :
2012-11-01 16:19:01 +01:00
case CORE_POWERDOWN :
2020-07-04 20:19:56 +02:00
case CORE_BOOT_ERROR :
case CORE_RUNTIME_ERROR :
2013-09-14 18:43:23 -07:00
// Exit loop!!
2018-04-30 18:59:48 -07:00
Core_StateProcessed ( ) ;
2013-03-23 18:30:52 +01:00
2022-11-08 21:59:08 +01:00
return true ;
2013-02-23 12:59:40 -08:00
case CORE_NEXTFRAME :
2022-11-08 21:59:08 +01:00
return true ;
2012-11-01 16:19:01 +01:00
}
}
}
2021-10-23 16:56:15 -07:00
void Core_EnableStepping ( bool step , const char * reason , u32 relatedAddress ) {
2013-10-12 01:44:12 -07:00
if ( step ) {
2013-02-23 12:59:40 -08:00
Core_UpdateState ( CORE_STEPPING ) ;
2018-04-19 21:14:01 -07:00
steppingCounter + + ;
2021-10-23 16:56:15 -07:00
_assert_msg_ ( reason ! = nullptr , " No reason specified for break " ) ;
steppingReason = reason ;
steppingAddress = relatedAddress ;
2013-10-12 01:44:12 -07:00
} else {
2020-07-12 21:27:24 -07:00
// Clear the exception if we resume.
2021-08-08 23:15:27 -07:00
Core_ResetException ( ) ;
2012-11-01 16:19:01 +01:00
coreState = CORE_RUNNING ;
2013-02-23 12:59:40 -08:00
coreStatePending = false ;
2018-04-19 21:04:47 -07:00
m_StepCond . notify_all ( ) ;
2012-11-01 16:19:01 +01:00
}
2023-03-21 11:40:48 +01:00
System_Notify ( SystemNotification : : DEBUG_MODE_CHANGE ) ;
2012-11-01 16:19:01 +01:00
}
2018-04-19 21:14:01 -07:00
2020-07-04 20:57:05 +02:00
bool Core_NextFrame ( ) {
if ( coreState = = CORE_RUNNING ) {
coreState = CORE_NEXTFRAME ;
return true ;
} else {
return false ;
}
}
2018-04-19 21:14:01 -07:00
int Core_GetSteppingCounter ( ) {
return steppingCounter ;
}
2020-07-04 20:30:05 +02:00
2021-10-23 17:22:09 -07:00
SteppingReason Core_GetSteppingReason ( ) {
SteppingReason r ;
r . reason = steppingReason ;
r . relatedAddress = steppingAddress ;
return r ;
}
2023-04-28 13:38:16 +02:00
const char * ExceptionTypeAsString ( MIPSExceptionType type ) {
2020-07-04 20:57:05 +02:00
switch ( type ) {
2023-04-28 13:38:16 +02:00
case MIPSExceptionType : : MEMORY : return " Invalid Memory Access " ;
case MIPSExceptionType : : BREAK : return " Break " ;
case MIPSExceptionType : : BAD_EXEC_ADDR : return " Bad Execution Address " ;
2020-07-04 20:57:05 +02:00
default : return " N/A " ;
}
}
2019-02-12 13:29:37 +01:00
const char * MemoryExceptionTypeAsString ( MemoryExceptionType type ) {
2020-07-04 20:30:05 +02:00
switch ( type ) {
2020-07-13 09:17:42 +02:00
case MemoryExceptionType : : UNKNOWN : return " Unknown " ;
2020-07-04 20:57:05 +02:00
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 " ;
2022-08-21 13:24:10 -07:00
case MemoryExceptionType : : ALIGNMENT : return " Alignment " ;
2020-07-04 20:57:05 +02:00
default :
return " N/A " ;
2020-07-04 20:30:05 +02:00
}
2020-07-04 20:57:05 +02:00
}
2020-07-04 20:30:05 +02:00
2020-07-12 21:59:08 -07:00
const char * ExecExceptionTypeAsString ( ExecExceptionType type ) {
switch ( type ) {
case ExecExceptionType : : JUMP : return " CPU Jump " ;
case ExecExceptionType : : THREAD : return " Thread switch " ;
default :
return " N/A " ;
}
}
2023-01-01 19:22:41 +01:00
void Core_MemoryException ( u32 address , u32 accessSize , u32 pc , MemoryExceptionType type ) {
2019-02-12 13:29:37 +01:00
const char * desc = MemoryExceptionTypeAsString ( type ) ;
2020-07-04 20:30:05 +02:00
// In jit, we only flush PC when bIgnoreBadMemAccess is off.
if ( g_Config . iCpuCore = = ( int ) CPUCore : : JIT & & g_Config . bIgnoreBadMemAccess ) {
2023-01-01 19:22:41 +01:00
WARN_LOG ( MEMMAP , " %s: Invalid access at %08x (size %08x) " , desc , address , accessSize ) ;
2020-07-04 20:30:05 +02:00
} else {
2023-01-01 19:22:41 +01:00
WARN_LOG ( MEMMAP , " %s: Invalid access at %08x (size %08x) PC %08x LR %08x " , desc , address , accessSize , currentMIPS - > pc , currentMIPS - > r [ MIPS_REG_RA ] ) ;
2020-07-04 20:30:05 +02:00
}
if ( ! g_Config . bIgnoreBadMemAccess ) {
2023-03-31 10:08:12 +02:00
// Try to fetch a call stack, to start with.
std : : vector < MIPSStackWalk : : StackFrame > stackFrames = WalkCurrentStack ( - 1 ) ;
std : : string stackTrace = FormatStackTrace ( stackFrames ) ;
WARN_LOG ( MEMMAP , " \n %s " , stackTrace . c_str ( ) ) ;
2023-04-28 13:38:16 +02:00
MIPSExceptionInfo & e = g_exceptionInfo ;
2019-02-12 13:29:37 +01:00
e = { } ;
2023-04-28 13:38:16 +02:00
e . type = MIPSExceptionType : : MEMORY ;
2022-09-30 12:26:30 +03:00
e . info . clear ( ) ;
2019-02-12 13:29:37 +01:00
e . memory_type = type ;
e . address = address ;
2023-01-01 19:22:41 +01:00
e . accessSize = accessSize ;
2023-03-31 10:08:12 +02:00
e . stackTrace = stackTrace ;
2019-02-12 13:29:37 +01:00
e . pc = pc ;
2021-10-23 16:56:15 -07:00
Core_EnableStepping ( true , " memory.exception " , address ) ;
2020-07-04 20:30:05 +02:00
}
}
2023-04-16 19:10:20 -07:00
void Core_MemoryExceptionInfo ( u32 address , u32 accessSize , u32 pc , MemoryExceptionType type , std : : string additionalInfo , bool forceReport ) {
2020-07-15 12:38:05 +02:00
const char * desc = MemoryExceptionTypeAsString ( type ) ;
// In jit, we only flush PC when bIgnoreBadMemAccess is off.
if ( g_Config . iCpuCore = = ( int ) CPUCore : : JIT & & g_Config . bIgnoreBadMemAccess ) {
2023-01-01 19:22:41 +01:00
WARN_LOG ( MEMMAP , " %s: Invalid access at %08x (size %08x). %s " , desc , address , accessSize , additionalInfo . c_str ( ) ) ;
2020-07-15 12:38:05 +02:00
} else {
2023-01-01 19:22:41 +01:00
WARN_LOG ( MEMMAP , " %s: Invalid access at %08x (size %08x) PC %08x LR %08x %s " , desc , address , accessSize , currentMIPS - > pc , currentMIPS - > r [ MIPS_REG_RA ] , additionalInfo . c_str ( ) ) ;
2020-07-15 12:38:05 +02:00
}
2022-12-30 12:21:05 +01:00
if ( ! g_Config . bIgnoreBadMemAccess | | forceReport ) {
2023-03-31 10:08:12 +02:00
// Try to fetch a call stack, to start with.
std : : vector < MIPSStackWalk : : StackFrame > stackFrames = WalkCurrentStack ( - 1 ) ;
std : : string stackTrace = FormatStackTrace ( stackFrames ) ;
WARN_LOG ( MEMMAP , " \n %s " , stackTrace . c_str ( ) ) ;
2023-04-28 13:38:16 +02:00
MIPSExceptionInfo & e = g_exceptionInfo ;
2020-07-15 12:38:05 +02:00
e = { } ;
2023-04-28 13:38:16 +02:00
e . type = MIPSExceptionType : : MEMORY ;
2020-07-15 12:38:05 +02:00
e . info = additionalInfo ;
e . memory_type = type ;
e . address = address ;
2023-04-16 19:10:20 -07:00
e . accessSize = accessSize ;
2023-03-31 10:08:12 +02:00
e . stackTrace = stackTrace ;
2020-07-15 12:38:05 +02:00
e . pc = pc ;
2021-10-23 16:56:15 -07:00
Core_EnableStepping ( true , " memory.exception " , address ) ;
2020-07-15 12:38:05 +02:00
}
}
2022-12-30 12:21:05 +01:00
// Can't be ignored
2020-07-12 21:59:08 -07:00
void Core_ExecException ( u32 address , u32 pc , ExecExceptionType type ) {
const char * desc = ExecExceptionTypeAsString ( type ) ;
2023-01-01 19:22:41 +01:00
WARN_LOG ( MEMMAP , " %s: Invalid exec address %08x PC %08x LR %08x " , desc , address , pc , currentMIPS - > r [ MIPS_REG_RA ] ) ;
2020-07-12 21:59:08 -07:00
2023-04-28 13:38:16 +02:00
MIPSExceptionInfo & e = g_exceptionInfo ;
2021-02-09 09:38:03 +01:00
e = { } ;
2023-04-28 13:38:16 +02:00
e . type = MIPSExceptionType : : BAD_EXEC_ADDR ;
2022-09-30 12:26:30 +03:00
e . info . clear ( ) ;
2021-02-09 09:38:03 +01:00
e . exec_type = type ;
e . address = address ;
2023-01-01 19:22:41 +01:00
e . accessSize = 4 ; // size of an instruction
2021-02-09 09:38:03 +01:00
e . pc = pc ;
2022-08-21 14:09:52 -07:00
// This just records the closest value that could be useful as reference.
e . ra = currentMIPS - > r [ MIPS_REG_RA ] ;
Core_EnableStepping ( true , " cpu.exception " , address ) ;
2020-07-12 21:59:08 -07:00
}
2022-08-21 14:09:52 -07:00
void Core_Break ( u32 pc ) {
2020-07-04 20:30:05 +02:00
ERROR_LOG ( CPU , " BREAK! " ) ;
2020-07-04 20:57:05 +02:00
2023-04-28 13:38:16 +02:00
MIPSExceptionInfo & e = g_exceptionInfo ;
2020-07-04 20:57:05 +02:00
e = { } ;
2023-04-28 13:38:16 +02:00
e . type = MIPSExceptionType : : BREAK ;
2022-09-30 12:26:30 +03:00
e . info . clear ( ) ;
2022-08-21 14:09:52 -07:00
e . pc = pc ;
2020-07-04 20:57:05 +02:00
2020-07-04 20:30:05 +02:00
if ( ! g_Config . bIgnoreBadMemAccess ) {
2021-10-23 16:56:15 -07:00
Core_EnableStepping ( true , " cpu.breakInstruction " , currentMIPS - > pc ) ;
2020-07-04 20:30:05 +02:00
}
}
2020-07-04 20:57:05 +02:00
2021-08-08 23:15:27 -07:00
void Core_ResetException ( ) {
2023-04-28 13:38:16 +02:00
g_exceptionInfo . type = MIPSExceptionType : : NONE ;
2021-08-08 23:15:27 -07:00
}
2023-04-28 13:38:16 +02:00
const MIPSExceptionInfo & Core_GetExceptionInfo ( ) {
2020-07-04 20:57:05 +02:00
return g_exceptionInfo ;
}