diff --git a/Source/Core/Core/BootManager.cpp b/Source/Core/Core/BootManager.cpp index 585e5d62e9..cac7f1574d 100644 --- a/Source/Core/Core/BootManager.cpp +++ b/Source/Core/Core/BootManager.cpp @@ -75,6 +75,8 @@ private: bool bCPUThread; bool bJITFollowBranch; bool bSyncGPUOnSkipIdleHack; + bool bFloatExceptions; + bool bDivideByZeroExceptions; bool bFPRF; bool bAccurateNaNs; bool bMMU; @@ -109,6 +111,8 @@ void ConfigCache::SaveConfig(const SConfig& config) bCPUThread = config.bCPUThread; bJITFollowBranch = config.bJITFollowBranch; bSyncGPUOnSkipIdleHack = config.bSyncGPUOnSkipIdleHack; + bFloatExceptions = config.bFloatExceptions; + bDivideByZeroExceptions = config.bDivideByZeroExceptions; bFPRF = config.bFPRF; bAccurateNaNs = config.bAccurateNaNs; bDisableICache = config.bDisableICache; @@ -154,6 +158,8 @@ void ConfigCache::RestoreConfig(SConfig* config) config->bCPUThread = bCPUThread; config->bJITFollowBranch = bJITFollowBranch; config->bSyncGPUOnSkipIdleHack = bSyncGPUOnSkipIdleHack; + config->bFloatExceptions = bFloatExceptions; + config->bDivideByZeroExceptions = bDivideByZeroExceptions; config->bFPRF = bFPRF; config->bAccurateNaNs = bAccurateNaNs; config->bDisableICache = bDisableICache; @@ -256,6 +262,9 @@ bool BootCore(std::unique_ptr boot, const WindowSystemInfo& wsi) core_section->Get("JITFollowBranch", &StartUp.bJITFollowBranch, StartUp.bJITFollowBranch); core_section->Get("SyncOnSkipIdle", &StartUp.bSyncGPUOnSkipIdleHack, StartUp.bSyncGPUOnSkipIdleHack); + core_section->Get("FloatExceptions", &StartUp.bFloatExceptions, StartUp.bFloatExceptions); + core_section->Get("DivByZeroExceptions", &StartUp.bDivideByZeroExceptions, + StartUp.bDivideByZeroExceptions); core_section->Get("FPRF", &StartUp.bFPRF, StartUp.bFPRF); core_section->Get("AccurateNaNs", &StartUp.bAccurateNaNs, StartUp.bAccurateNaNs); core_section->Get("DisableICache", &StartUp.bDisableICache, StartUp.bDisableICache); @@ -370,6 +379,8 @@ bool BootCore(std::unique_ptr boot, const WindowSystemInfo& wsi) StartUp.bAccurateNaNs = netplay_settings.m_AccurateNaNs; StartUp.bDisableICache = netplay_settings.m_DisableICache; StartUp.bSyncGPUOnSkipIdleHack = netplay_settings.m_SyncOnSkipIdle; + StartUp.bFloatExceptions = netplay_settings.m_FloatExceptions; + StartUp.bDivideByZeroExceptions = netplay_settings.m_DivideByZeroExceptions; StartUp.bSyncGPU = netplay_settings.m_SyncGPU; StartUp.iSyncGpuMaxDistance = netplay_settings.m_SyncGpuMaxDistance; StartUp.iSyncGpuMinDistance = netplay_settings.m_SyncGpuMinDistance; diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 550e1bdd89..ca48d4c9f8 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -86,6 +86,9 @@ const Info MAIN_SYNC_GPU_MIN_DISTANCE{{System::Main, "Core", "SyncGpuMinDis const Info MAIN_SYNC_GPU_OVERCLOCK{{System::Main, "Core", "SyncGpuOverclock"}, 1.0f}; const Info MAIN_FAST_DISC_SPEED{{System::Main, "Core", "FastDiscSpeed"}, false}; const Info MAIN_LOW_DCBZ_HACK{{System::Main, "Core", "LowDCBZHack"}, false}; +const Info MAIN_FLOAT_EXCEPTIONS{{System::Main, "Core", "FloatExceptions"}, false}; +const Info MAIN_DIVIDE_BY_ZERO_EXCEPTIONS{{System::Main, "Core", "DivByZeroExceptions"}, + false}; const Info MAIN_FPRF{{System::Main, "Core", "FPRF"}, false}; const Info MAIN_ACCURATE_NANS{{System::Main, "Core", "AccurateNaNs"}, false}; const Info MAIN_DISABLE_ICACHE{{System::Main, "Core", "DisableICache"}, false}; diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index 413f2c85b9..14867978ac 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -68,6 +68,8 @@ extern const Info MAIN_SYNC_GPU_MIN_DISTANCE; extern const Info MAIN_SYNC_GPU_OVERCLOCK; extern const Info MAIN_FAST_DISC_SPEED; extern const Info MAIN_LOW_DCBZ_HACK; +extern const Info MAIN_FLOAT_EXCEPTIONS; +extern const Info MAIN_DIVIDE_BY_ZERO_EXCEPTIONS; extern const Info MAIN_FPRF; extern const Info MAIN_ACCURATE_NANS; extern const Info MAIN_DISABLE_ICACHE; diff --git a/Source/Core/Core/ConfigLoaders/NetPlayConfigLoader.cpp b/Source/Core/Core/ConfigLoaders/NetPlayConfigLoader.cpp index 983bf27040..c2eb753e28 100644 --- a/Source/Core/Core/ConfigLoaders/NetPlayConfigLoader.cpp +++ b/Source/Core/Core/ConfigLoaders/NetPlayConfigLoader.cpp @@ -69,6 +69,8 @@ public: layer->Set(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES, m_settings.m_SafeTextureCacheColorSamples); layer->Set(Config::GFX_PERF_QUERIES_ENABLE, m_settings.m_PerfQueriesEnable); + layer->Set(Config::MAIN_FLOAT_EXCEPTIONS, m_settings.m_FloatExceptions); + layer->Set(Config::MAIN_DIVIDE_BY_ZERO_EXCEPTIONS, m_settings.m_DivideByZeroExceptions); layer->Set(Config::MAIN_FPRF, m_settings.m_FPRF); layer->Set(Config::MAIN_ACCURATE_NANS, m_settings.m_AccurateNaNs); layer->Set(Config::MAIN_DISABLE_ICACHE, m_settings.m_DisableICache); diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index 56985b1c3d..5b6bd5713e 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -213,6 +213,8 @@ void SConfig::SaveCoreSettings(IniFile& ini) core->Set("SyncGpuMaxDistance", iSyncGpuMaxDistance); core->Set("SyncGpuMinDistance", iSyncGpuMinDistance); core->Set("SyncGpuOverclock", fSyncGpuOverclock); + core->Set("FloatExceptions", bFloatExceptions); + core->Set("DivByZeroExceptions", bDivideByZeroExceptions); core->Set("FPRF", bFPRF); core->Set("AccurateNaNs", bAccurateNaNs); core->Set("SelectedLanguage", SelectedLanguage); @@ -509,6 +511,8 @@ void SConfig::LoadCoreSettings(IniFile& ini) core->Get("SyncGpuOverclock", &fSyncGpuOverclock, 1.0f); core->Get("FastDiscSpeed", &bFastDiscSpeed, false); core->Get("LowDCBZHack", &bLowDCBZHack, false); + core->Get("FloatExceptions", &bFloatExceptions, false); + core->Get("DivByZeroExceptions", &bDivideByZeroExceptions, false); core->Get("FPRF", &bFPRF, false); core->Get("AccurateNaNs", &bAccurateNaNs, false); core->Get("DisableICache", &bDisableICache, false); @@ -747,6 +751,8 @@ void SConfig::LoadDefaults() bRunCompareServer = false; bDSPHLE = true; bFastmem = true; + bFloatExceptions = false; + bDivideByZeroExceptions = false; bFPRF = false; bAccurateNaNs = false; bDisableICache = false; diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 50d8ebd3fe..4ed0924b4f 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -108,6 +108,8 @@ struct SConfig bool bJITRegisterCacheOff = false; bool bFastmem; + bool bFloatExceptions = false; + bool bDivideByZeroExceptions = false; bool bFPRF = false; bool bAccurateNaNs = false; bool bDisableICache = false; diff --git a/Source/Core/Core/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp index 8f730038ef..e4cba66429 100644 --- a/Source/Core/Core/NetPlayClient.cpp +++ b/Source/Core/Core/NetPlayClient.cpp @@ -831,6 +831,8 @@ void NetPlayClient::OnStartGame(sf::Packet& packet) packet >> m_net_settings.m_EFBEmulateFormatChanges; packet >> m_net_settings.m_SafeTextureCacheColorSamples; packet >> m_net_settings.m_PerfQueriesEnable; + packet >> m_net_settings.m_FloatExceptions; + packet >> m_net_settings.m_DivideByZeroExceptions; packet >> m_net_settings.m_FPRF; packet >> m_net_settings.m_AccurateNaNs; packet >> m_net_settings.m_DisableICache; diff --git a/Source/Core/Core/NetPlayProto.h b/Source/Core/Core/NetPlayProto.h index 4d3cf436fb..537b820701 100644 --- a/Source/Core/Core/NetPlayProto.h +++ b/Source/Core/Core/NetPlayProto.h @@ -58,6 +58,8 @@ struct NetSettings bool m_EFBEmulateFormatChanges; int m_SafeTextureCacheColorSamples; bool m_PerfQueriesEnable; + bool m_FloatExceptions; + bool m_DivideByZeroExceptions; bool m_FPRF; bool m_AccurateNaNs; bool m_DisableICache; diff --git a/Source/Core/Core/NetPlayServer.cpp b/Source/Core/Core/NetPlayServer.cpp index 806f4967ac..bc96d0f952 100644 --- a/Source/Core/Core/NetPlayServer.cpp +++ b/Source/Core/Core/NetPlayServer.cpp @@ -1329,6 +1329,8 @@ bool NetPlayServer::SetupNetSettings() settings.m_SafeTextureCacheColorSamples = Config::Get(Config::GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES); settings.m_PerfQueriesEnable = Config::Get(Config::GFX_PERF_QUERIES_ENABLE); + settings.m_FloatExceptions = Config::Get(Config::MAIN_FLOAT_EXCEPTIONS); + settings.m_DivideByZeroExceptions = Config::Get(Config::MAIN_DIVIDE_BY_ZERO_EXCEPTIONS); settings.m_FPRF = Config::Get(Config::MAIN_FPRF); settings.m_AccurateNaNs = Config::Get(Config::MAIN_ACCURATE_NANS); settings.m_DisableICache = Config::Get(Config::MAIN_DISABLE_ICACHE); @@ -1505,6 +1507,8 @@ bool NetPlayServer::StartGame() spac << m_settings.m_EFBEmulateFormatChanges; spac << m_settings.m_SafeTextureCacheColorSamples; spac << m_settings.m_PerfQueriesEnable; + spac << m_settings.m_FloatExceptions; + spac << m_settings.m_DivideByZeroExceptions; spac << m_settings.m_FPRF; spac << m_settings.m_AccurateNaNs; spac << m_settings.m_DisableICache; diff --git a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp index 834af98a5e..e75994fc96 100644 --- a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp +++ b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp @@ -58,7 +58,7 @@ void CachedInterpreter::Init() jo.enableBlocklink = false; m_block_cache.Init(); - UpdateMemoryOptions(); + UpdateMemoryAndExceptionOptions(); code_block.m_stats = &js.st; code_block.m_gpa = &js.gpa; @@ -180,6 +180,17 @@ static bool CheckDSI(u32 data) return false; } +static bool CheckProgramException(u32 data) +{ + if (PowerPC::ppcState.Exceptions & EXCEPTION_PROGRAM) + { + PowerPC::CheckExceptions(); + PowerPC::ppcState.downcount -= data; + return true; + } + return false; +} + static bool CheckBreakpoint(u32 data) { PowerPC::CheckBreakPoints(); @@ -267,26 +278,26 @@ void CachedInterpreter::Jit(u32 address) const bool check_fpu = (op.opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound; const bool endblock = (op.opinfo->flags & FL_ENDBLOCK) != 0; const bool memcheck = (op.opinfo->flags & FL_LOADSTORE) && jo.memcheck; + const bool check_program_exception = !endblock && ShouldHandleFPExceptionForInstruction(&op); const bool idle_loop = op.branchIsIdleLoop; - if (breakpoint) - { + if (breakpoint || check_fpu || endblock || memcheck || check_program_exception) m_code.emplace_back(WritePC, op.address); + + if (breakpoint) m_code.emplace_back(CheckBreakpoint, js.downcountAmount); - } if (check_fpu) { - m_code.emplace_back(WritePC, op.address); m_code.emplace_back(CheckFPU, js.downcountAmount); js.firstFPInstructionFound = true; } - if (endblock || memcheck) - m_code.emplace_back(WritePC, op.address); m_code.emplace_back(PPCTables::GetInterpreterOp(op.inst), op.inst); if (memcheck) m_code.emplace_back(CheckDSI, js.downcountAmount); + if (check_program_exception) + m_code.emplace_back(CheckProgramException, js.downcountAmount); if (idle_loop) m_code.emplace_back(CheckIdle, js.blockStart); if (endblock) @@ -316,5 +327,5 @@ void CachedInterpreter::ClearCache() { m_code.clear(); m_block_cache.Clear(); - UpdateMemoryOptions(); + UpdateMemoryAndExceptionOptions(); } diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp index 45c1f8b9b4..f7eefbd585 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp @@ -94,14 +94,14 @@ static std::array primarytable = static std::array table4 = {{ //SUBOP10 - {0, Interpreter::ps_cmpu0, {"ps_cmpu0", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {32, Interpreter::ps_cmpo0, {"ps_cmpo0", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, + {0, Interpreter::ps_cmpu0, {"ps_cmpu0", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {32, Interpreter::ps_cmpo0, {"ps_cmpo0", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, {40, Interpreter::ps_neg, {"ps_neg", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, {136, Interpreter::ps_nabs, {"ps_nabs", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, {264, Interpreter::ps_abs, {"ps_abs", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {64, Interpreter::ps_cmpu1, {"ps_cmpu1", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, + {64, Interpreter::ps_cmpu1, {"ps_cmpu1", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, {72, Interpreter::ps_mr, {"ps_mr", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {96, Interpreter::ps_cmpo1, {"ps_cmpo1", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, + {96, Interpreter::ps_cmpo1, {"ps_cmpo1", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, {528, Interpreter::ps_merge00, {"ps_merge00", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, {560, Interpreter::ps_merge01, {"ps_merge01", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, {592, Interpreter::ps_merge10, {"ps_merge10", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, @@ -112,23 +112,23 @@ static std::array table4 = static std::array table4_2 = {{ - {10, Interpreter::ps_sum0, {"ps_sum0", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {11, Interpreter::ps_sum1, {"ps_sum1", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {12, Interpreter::ps_muls0, {"ps_muls0", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {13, Interpreter::ps_muls1, {"ps_muls1", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {14, Interpreter::ps_madds0, {"ps_madds0", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {15, Interpreter::ps_madds1, {"ps_madds1", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {18, Interpreter::ps_div, {"ps_div", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 17, 0, 0, 0}}, - {20, Interpreter::ps_sub, {"ps_sub", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {21, Interpreter::ps_add, {"ps_add", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, + {10, Interpreter::ps_sum0, {"ps_sum0", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {11, Interpreter::ps_sum1, {"ps_sum1", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {12, Interpreter::ps_muls0, {"ps_muls0", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {13, Interpreter::ps_muls1, {"ps_muls1", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {14, Interpreter::ps_madds0, {"ps_madds0", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {15, Interpreter::ps_madds1, {"ps_madds1", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {18, Interpreter::ps_div, {"ps_div", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 17, 0, 0, 0}}, + {20, Interpreter::ps_sub, {"ps_sub", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {21, Interpreter::ps_add, {"ps_add", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, {23, Interpreter::ps_sel, {"ps_sel", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_IN_FLOAT_BC_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {24, Interpreter::ps_res, {"ps_res", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {25, Interpreter::ps_mul, {"ps_mul", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {26, Interpreter::ps_rsqrte, {"ps_rsqrte", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 2, 0, 0, 0}}, - {28, Interpreter::ps_msub, {"ps_msub", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {29, Interpreter::ps_madd, {"ps_madd", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {30, Interpreter::ps_nmsub, {"ps_nmsub", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {31, Interpreter::ps_nmadd, {"ps_nmadd", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, + {24, Interpreter::ps_res, {"ps_res", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 1, 0, 0, 0}}, + {25, Interpreter::ps_mul, {"ps_mul", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {26, Interpreter::ps_rsqrte, {"ps_rsqrte", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 2, 0, 0, 0}}, + {28, Interpreter::ps_msub, {"ps_msub", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {29, Interpreter::ps_madd, {"ps_madd", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {30, Interpreter::ps_nmsub, {"ps_nmsub", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {31, Interpreter::ps_nmadd, {"ps_nmadd", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, }}; @@ -280,7 +280,7 @@ static std::array table31 = {19, Interpreter::mfcr, {"mfcr", OpType::System, FL_OUT_D, 1, 0, 0, 0}}, {83, Interpreter::mfmsr, {"mfmsr", OpType::System, FL_OUT_D | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, {144, Interpreter::mtcrf, {"mtcrf", OpType::System, FL_IN_S | FL_SET_CRn, 1, 0, 0, 0}}, - {146, Interpreter::mtmsr, {"mtmsr", OpType::System, FL_IN_S | FL_ENDBLOCK | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, + {146, Interpreter::mtmsr, {"mtmsr", OpType::System, FL_IN_S | FL_ENDBLOCK | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, {210, Interpreter::mtsr, {"mtsr", OpType::System, FL_IN_S | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, {242, Interpreter::mtsrin, {"mtsrin", OpType::System, FL_IN_SB | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, {339, Interpreter::mfspr, {"mfspr", OpType::SPR, FL_OUT_D | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, @@ -304,15 +304,15 @@ static std::array table31 = static std::array table59 = {{ - {18, Interpreter::fdivsx, {"fdivsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 17, 0, 0, 0}}, // TODO - {20, Interpreter::fsubsx, {"fsubsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, - {21, Interpreter::faddsx, {"faddsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, - {24, Interpreter::fresx, {"fresx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, - {25, Interpreter::fmulsx, {"fmulsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, - {28, Interpreter::fmsubsx, {"fmsubsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, - {29, Interpreter::fmaddsx, {"fmaddsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, - {30, Interpreter::fnmsubsx, {"fnmsubsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, - {31, Interpreter::fnmaddsx, {"fnmaddsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, + {18, Interpreter::fdivsx, {"fdivsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 17, 0, 0, 0}}, // TODO + {20, Interpreter::fsubsx, {"fsubsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {21, Interpreter::faddsx, {"faddsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {24, Interpreter::fresx, {"fresx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 1, 0, 0, 0}}, + {25, Interpreter::fmulsx, {"fmulsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {28, Interpreter::fmsubsx, {"fmsubsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {29, Interpreter::fmaddsx, {"fmaddsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {30, Interpreter::fnmsubsx, {"fnmsubsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {31, Interpreter::fnmaddsx, {"fnmaddsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, }}; static std::array table63 = @@ -323,36 +323,36 @@ static std::array table63 = // we don't actually need to calculate or store them here. So FL_READ_FPRF and FL_SET_FPRF is not // an ideal representation of fcmp's effect on FPRF flags and might result in // slightly sub-optimal code. - {32, Interpreter::fcmpo, {"fcmpo", OpType::DoubleFP, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF, 1, 0, 0, 0}}, - {0, Interpreter::fcmpu, {"fcmpu", OpType::DoubleFP, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF, 1, 0, 0, 0}}, + {32, Interpreter::fcmpo, {"fcmpo", OpType::DoubleFP, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {0, Interpreter::fcmpu, {"fcmpu", OpType::DoubleFP, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {14, Interpreter::fctiwx, {"fctiwx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU, 1, 0, 0, 0}}, - {15, Interpreter::fctiwzx, {"fctiwzx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU, 1, 0, 0, 0}}, + {14, Interpreter::fctiwx, {"fctiwx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {15, Interpreter::fctiwzx, {"fctiwzx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, {72, Interpreter::fmrx, {"fmrx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU, 1, 0, 0, 0}}, {136, Interpreter::fnabsx, {"fnabsx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_IN_FLOAT_B_BITEXACT | FL_USE_FPU, 1, 0, 0, 0}}, {40, Interpreter::fnegx, {"fnegx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_IN_FLOAT_B_BITEXACT | FL_USE_FPU, 1, 0, 0, 0}}, - {12, Interpreter::frspx, {"frspx", OpType::DoubleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, + {12, Interpreter::frspx, {"frspx", OpType::DoubleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, {64, Interpreter::mcrfs, {"mcrfs", OpType::SystemFP, FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF, 1, 0, 0, 0}}, {583, Interpreter::mffsx, {"mffsx", OpType::SystemFP, FL_RC_BIT_F | FL_INOUT_FLOAT_D | FL_USE_FPU | FL_READ_FPRF, 1, 0, 0, 0}}, {70, Interpreter::mtfsb0x, {"mtfsb0x", OpType::SystemFP, FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF, 3, 0, 0, 0}}, - {38, Interpreter::mtfsb1x, {"mtfsb1x", OpType::SystemFP, FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF, 3, 0, 0, 0}}, - {134, Interpreter::mtfsfix, {"mtfsfix", OpType::SystemFP, FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF, 3, 0, 0, 0}}, - {711, Interpreter::mtfsfx, {"mtfsfx", OpType::SystemFP, FL_RC_BIT_F | FL_IN_FLOAT_B | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF, 3, 0, 0, 0}}, + {38, Interpreter::mtfsb1x, {"mtfsb1x", OpType::SystemFP, FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 3, 0, 0, 0}}, + {134, Interpreter::mtfsfix, {"mtfsfix", OpType::SystemFP, FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 3, 0, 0, 0}}, + {711, Interpreter::mtfsfx, {"mtfsfx", OpType::SystemFP, FL_RC_BIT_F | FL_IN_FLOAT_B | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 3, 0, 0, 0}}, }}; static std::array table63_2 = {{ - {18, Interpreter::fdivx, {"fdivx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 31, 0, 0, 0}}, - {20, Interpreter::fsubx, {"fsubx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, - {21, Interpreter::faddx, {"faddx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, + {18, Interpreter::fdivx, {"fdivx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 31, 0, 0, 0}}, + {20, Interpreter::fsubx, {"fsubx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {21, Interpreter::faddx, {"faddx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, {23, Interpreter::fselx, {"fselx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_IN_FLOAT_BC_BITEXACT | FL_RC_BIT_F | FL_USE_FPU, 1, 0, 0, 0}}, - {25, Interpreter::fmulx, {"fmulx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, - {26, Interpreter::frsqrtex, {"frsqrtex", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, - {28, Interpreter::fmsubx, {"fmsubx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, - {29, Interpreter::fmaddx, {"fmaddx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, - {30, Interpreter::fnmsubx, {"fnmsubx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, - {31, Interpreter::fnmaddx, {"fnmaddx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF, 1, 0, 0, 0}}, + {25, Interpreter::fmulx, {"fmulx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {26, Interpreter::frsqrtex, {"frsqrtex", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 1, 0, 0, 0}}, + {28, Interpreter::fmsubx, {"fmsubx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {29, Interpreter::fmaddx, {"fmaddx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {30, Interpreter::fnmsubx, {"fnmsubx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, + {31, Interpreter::fnmaddx, {"fnmaddx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, }}; // clang-format on diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index 0a4bfeed4d..dba9520290 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -335,7 +335,7 @@ void Jit64::Init() jo.fastmem_arena = SConfig::GetInstance().bFastmem && Memory::InitFastmemArena(); jo.optimizeGatherPipe = true; jo.accurateSinglePrecision = true; - UpdateMemoryOptions(); + UpdateMemoryAndExceptionOptions(); js.fastmemLoadStore = nullptr; js.compilerPC = 0; @@ -389,7 +389,7 @@ void Jit64::ClearCache() m_const_pool.Clear(); ClearCodeSpace(); Clear(); - UpdateMemoryOptions(); + UpdateMemoryAndExceptionOptions(); ResetFreeMemoryRanges(); } @@ -453,6 +453,24 @@ void Jit64::FallBackToInterpreter(UGeckoInstruction inst) SetJumpTarget(c); } } + else if (ShouldHandleFPExceptionForInstruction(js.op)) + { + TEST(32, PPCSTATE(Exceptions), Imm32(EXCEPTION_PROGRAM)); + FixupBranch exception = J_CC(CC_NZ, true); + + SwitchToFarCode(); + SetJumpTarget(exception); + + RCForkGuard gpr_guard = gpr.Fork(); + RCForkGuard fpr_guard = fpr.Fork(); + + gpr.Flush(); + fpr.Flush(); + + MOV(32, PPCSTATE(pc), Imm32(js.op->address)); + WriteExceptionExit(); + SwitchToNearCode(); + } } void Jit64::HLEFunction(u32 hook_index) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp index ace5e193d1..9d2aad1b27 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp @@ -208,6 +208,7 @@ void Jit64::fp_arith(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions || (jo.div_by_zero_exceptions && inst.SUBOP5 == 18)); int a = inst.FA; int b = inst.FB; @@ -292,6 +293,7 @@ void Jit64::fmaddXX(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); // We would like to emulate FMA instructions accurately without rounding error if possible, but // unfortunately emulating FMA in software is just too slow on CPUs that are too old to have FMA @@ -733,6 +735,7 @@ void Jit64::fcmpX(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(jo.fp_exceptions); FloatCompare(inst); } @@ -742,6 +745,7 @@ void Jit64::fctiwx(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); int d = inst.RD; int b = inst.RB; @@ -784,6 +788,7 @@ void Jit64::frspx(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); int b = inst.FB; int d = inst.FD; bool packed = js.op->fprIsDuplicated[b] && !cpu_info.bAtom; @@ -800,6 +805,7 @@ void Jit64::frsqrtex(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions || jo.div_by_zero_exceptions); int b = inst.FB; int d = inst.FD; @@ -818,6 +824,7 @@ void Jit64::fresx(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions || jo.div_by_zero_exceptions); int b = inst.FB; int d = inst.FD; diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_Paired.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_Paired.cpp index 0b28fed61c..023d0d834a 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_Paired.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_Paired.cpp @@ -33,6 +33,7 @@ void Jit64::ps_sum(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); int d = inst.FD; int a = inst.FA; @@ -84,6 +85,7 @@ void Jit64::ps_muls(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); int d = inst.FD; int a = inst.FA; @@ -152,6 +154,7 @@ void Jit64::ps_rsqrte(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions || jo.div_by_zero_exceptions); int b = inst.FB; int d = inst.FD; @@ -176,6 +179,7 @@ void Jit64::ps_res(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions || jo.div_by_zero_exceptions); int b = inst.FB; int d = inst.FD; @@ -199,6 +203,7 @@ void Jit64::ps_cmpXX(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(jo.fp_exceptions); FloatCompare(inst, !!(inst.SUBOP10 & 64)); } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp index 3117ef563f..2806879bcb 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -424,6 +424,7 @@ void Jit64::mtmsr(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITSystemRegistersOff); + FALLBACK_IF(jo.fp_exceptions); { RCOpArg Rs = gpr.BindOrImm(inst.RS, RCMode::Read); @@ -777,6 +778,7 @@ void Jit64::mtfsb1x(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITSystemRegistersOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); const u32 mask = 0x80000000 >> inst.CRBD; @@ -814,6 +816,7 @@ void Jit64::mtfsfix(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITSystemRegistersOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); u8 imm = (inst.hex >> (31 - 19)) & 0xF; u32 mask = 0xF0000000 >> (4 * inst.CRFD); @@ -844,6 +847,7 @@ void Jit64::mtfsfx(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITSystemRegistersOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); u32 mask = 0; for (int i = 0; i < 8; i++) diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index 3191be64eb..a68fc078ee 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -50,7 +50,7 @@ void JitArm64::Init() jo.fastmem_arena = SConfig::GetInstance().bFastmem && Memory::InitFastmemArena(); jo.enableBlocklink = true; jo.optimizeGatherPipe = true; - UpdateMemoryOptions(); + UpdateMemoryAndExceptionOptions(); gpr.Init(this); fpr.Init(this); blocks.Init(); @@ -129,7 +129,7 @@ void JitArm64::ClearCache() const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes; ClearCodeSpace(); farcode.ClearCodeSpace(); - UpdateMemoryOptions(); + UpdateMemoryAndExceptionOptions(); GenerateAsm(); } @@ -193,25 +193,14 @@ void JitArm64::FallBackToInterpreter(UGeckoInstruction inst) gpr.Unlock(WA); } } + else if (ShouldHandleFPExceptionForInstruction(js.op)) + { + WriteConditionalExceptionExit(EXCEPTION_PROGRAM); + } if (jo.memcheck && (js.op->opinfo->flags & FL_LOADSTORE)) { - ARM64Reg WA = gpr.GetReg(); - LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); - FixupBranch noException = TBZ(WA, IntLog2(EXCEPTION_DSI)); - - FixupBranch handleException = B(); - SwitchToFarCode(); - SetJumpTarget(handleException); - - gpr.Flush(FlushMode::MaintainState, WA); - fpr.Flush(FlushMode::MaintainState, ARM64Reg::INVALID_REG); - - WriteExceptionExit(js.compilerPC, false, true); - - SwitchToNearCode(); - SetJumpTarget(noException); - gpr.Unlock(WA); + WriteConditionalExceptionExit(EXCEPTION_DSI); } } @@ -495,6 +484,26 @@ void JitArm64::WriteExceptionExit(ARM64Reg dest, bool only_external, bool always B(dispatcher); } +void JitArm64::WriteConditionalExceptionExit(int exception) +{ + ARM64Reg WA = gpr.GetReg(); + LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(Exceptions)); + FixupBranch noException = TBZ(WA, IntLog2(exception)); + + FixupBranch handleException = B(); + SwitchToFarCode(); + SetJumpTarget(handleException); + + gpr.Flush(FlushMode::MaintainState, WA); + fpr.Flush(FlushMode::MaintainState, ARM64Reg::INVALID_REG); + + WriteExceptionExit(js.compilerPC, false, true); + + SwitchToNearCode(); + SetJumpTarget(noException); + gpr.Unlock(WA); +} + bool JitArm64::HandleFunctionHooking(u32 address) { return HLE::ReplaceFunctionIfPossible(address, [&](u32 hook_index, HLE::HookType type) { diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h index f19bd33d55..bc831360c1 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h @@ -268,6 +268,7 @@ protected: bool always_exception = false); void WriteExceptionExit(Arm64Gen::ARM64Reg dest, bool only_external = false, bool always_exception = false); + void WriteConditionalExceptionExit(int exception); void FakeLKExit(u32 exit_address_after_return); void WriteBLRExit(Arm64Gen::ARM64Reg dest); diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp index e8b15ce16a..c4d63802a9 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp @@ -67,6 +67,7 @@ void JitArm64::fp_arith(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions || (jo.div_by_zero_exceptions && inst.SUBOP5 == 18)); u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; u32 op5 = inst.SUBOP5; @@ -339,6 +340,7 @@ void JitArm64::frspx(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); const u32 b = inst.FB; const u32 d = inst.FD; @@ -500,6 +502,7 @@ void JitArm64::fcmpX(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); + FALLBACK_IF(jo.fp_exceptions); FloatCompare(inst); } @@ -509,6 +512,7 @@ void JitArm64::fctiwzx(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); const u32 b = inst.FB; const u32 d = inst.FD; @@ -551,6 +555,7 @@ void JitArm64::fresx(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions || jo.div_by_zero_exceptions); const u32 b = inst.FB; const u32 d = inst.FD; @@ -579,6 +584,7 @@ void JitArm64::frsqrtex(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITFloatingPointOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions || jo.div_by_zero_exceptions); const u32 b = inst.FB; const u32 d = inst.FD; diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Paired.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Paired.cpp index 1e8edb5036..5690bbc481 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Paired.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Paired.cpp @@ -75,6 +75,7 @@ void JitArm64::ps_mulsX(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); const u32 a = inst.FA; const u32 c = inst.FC; @@ -125,6 +126,7 @@ void JitArm64::ps_maddXX(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); const u32 a = inst.FA; const u32 b = inst.FB; @@ -316,6 +318,7 @@ void JitArm64::ps_sumX(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); const u32 a = inst.FA; const u32 b = inst.FB; @@ -362,6 +365,7 @@ void JitArm64::ps_res(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions || jo.div_by_zero_exceptions); const u32 b = inst.FB; const u32 d = inst.FD; @@ -394,6 +398,7 @@ void JitArm64::ps_rsqrte(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITPairedOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions || jo.div_by_zero_exceptions); const u32 b = inst.FB; const u32 d = inst.FD; @@ -425,6 +430,7 @@ void JitArm64::ps_cmpXX(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITPairedOff); + FALLBACK_IF(jo.fp_exceptions); const bool upper = inst.SUBOP10 & 64; FloatCompare(inst, upper); diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp index 568d3072f3..63aa016322 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp @@ -86,6 +86,7 @@ void JitArm64::mtmsr(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(bJITSystemRegistersOff); + FALLBACK_IF(jo.fp_exceptions); gpr.BindToRegister(inst.RS, true); STR(IndexType::Unsigned, gpr.R(inst.RS), PPC_REG, PPCSTATE_OFF(msr)); @@ -815,6 +816,7 @@ void JitArm64::mtfsb1x(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITSystemRegistersOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); const u32 mask = 0x80000000 >> inst.CRBD; @@ -850,6 +852,7 @@ void JitArm64::mtfsfix(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITSystemRegistersOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); u8 imm = (inst.hex >> (31 - 19)) & 0xF; u8 shift = 28 - 4 * inst.CRFD; @@ -891,6 +894,7 @@ void JitArm64::mtfsfx(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(bJITSystemRegistersOff); FALLBACK_IF(inst.Rc); + FALLBACK_IF(jo.fp_exceptions); u32 mask = 0; for (int i = 0; i < 8; i++) diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp b/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp index c42fce554e..1d67d61046 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp +++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.cpp @@ -41,9 +41,21 @@ bool JitBase::CanMergeNextInstructions(int count) const return true; } -void JitBase::UpdateMemoryOptions() +void JitBase::UpdateMemoryAndExceptionOptions() { bool any_watchpoints = PowerPC::memchecks.HasAny(); jo.fastmem = SConfig::GetInstance().bFastmem && jo.fastmem_arena && (MSR.DR || !any_watchpoints); jo.memcheck = SConfig::GetInstance().bMMU || any_watchpoints; + jo.fp_exceptions = SConfig::GetInstance().bFloatExceptions; + jo.div_by_zero_exceptions = SConfig::GetInstance().bDivideByZeroExceptions; +} + +bool JitBase::ShouldHandleFPExceptionForInstruction(const PPCAnalyst::CodeOp* op) +{ + if (jo.fp_exceptions) + return (op->opinfo->flags & FL_FLOAT_EXCEPTION) != 0; + else if (jo.div_by_zero_exceptions) + return (op->opinfo->flags & FL_FLOAT_DIV) != 0; + else + return false; } diff --git a/Source/Core/Core/PowerPC/JitCommon/JitBase.h b/Source/Core/Core/PowerPC/JitCommon/JitBase.h index 18784ff095..b34d16365c 100644 --- a/Source/Core/Core/PowerPC/JitCommon/JitBase.h +++ b/Source/Core/Core/PowerPC/JitCommon/JitBase.h @@ -63,6 +63,8 @@ protected: bool fastmem; bool fastmem_arena; bool memcheck; + bool fp_exceptions; + bool div_by_zero_exceptions; bool profile_blocks; }; struct JitState @@ -113,7 +115,9 @@ protected: bool CanMergeNextInstructions(int count) const; - void UpdateMemoryOptions(); + void UpdateMemoryAndExceptionOptions(); + + bool ShouldHandleFPExceptionForInstruction(const PPCAnalyst::CodeOp* op); public: JitBase(); diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/PowerPC/PPCAnalyst.cpp index bd1f0d0324..d02cc10e0c 100644 --- a/Source/Core/Core/PowerPC/PPCAnalyst.cpp +++ b/Source/Core/Core/PowerPC/PPCAnalyst.cpp @@ -524,8 +524,12 @@ void PPCAnalyzer::SetInstructionStats(CodeBlock* block, CodeOp* code, const Gekk code->wantsCR0 = false; code->wantsCR1 = false; + bool first_fpu_instruction = false; if (opinfo->flags & FL_USE_FPU) + { + first_fpu_instruction = !block->m_fpa->any; block->m_fpa->any = true; + } if (opinfo->flags & FL_TIMER) block->m_gpa->anyTimer = true; @@ -550,9 +554,10 @@ void PPCAnalyzer::SetInstructionStats(CodeBlock* block, CodeOp* code, const Gekk code->outputFPRF = (opinfo->flags & FL_SET_FPRF) != 0; code->canEndBlock = (opinfo->flags & FL_ENDBLOCK) != 0; - // TODO: Is it possible to determine that some FPU instructions never cause exceptions? code->canCauseException = - (opinfo->flags & (FL_LOADSTORE | FL_USE_FPU | FL_PROGRAMEXCEPTION)) != 0; + first_fpu_instruction || (opinfo->flags & (FL_LOADSTORE | FL_PROGRAMEXCEPTION)) != 0 || + (SConfig::GetInstance().bFloatExceptions && (opinfo->flags & FL_FLOAT_EXCEPTION)) || + (SConfig::GetInstance().bDivideByZeroExceptions && (opinfo->flags & FL_FLOAT_DIV)); code->wantsCA = (opinfo->flags & FL_READ_CA) != 0; code->outputCA = (opinfo->flags & FL_SET_CA) != 0; @@ -928,14 +933,14 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer, std: const bool opWantsCR1 = op.wantsCR1; const bool opWantsFPRF = op.wantsFPRF; const bool opWantsCA = op.wantsCA; - op.wantsCR0 = wantsCR0 || op.canEndBlock; - op.wantsCR1 = wantsCR1 || op.canEndBlock; - op.wantsFPRF = wantsFPRF || op.canEndBlock; - op.wantsCA = wantsCA || op.canEndBlock; - wantsCR0 |= opWantsCR0 || op.canEndBlock; - wantsCR1 |= opWantsCR1 || op.canEndBlock; - wantsFPRF |= opWantsFPRF || op.canEndBlock; - wantsCA |= opWantsCA || op.canEndBlock; + op.wantsCR0 = wantsCR0 || op.canEndBlock || op.canCauseException; + op.wantsCR1 = wantsCR1 || op.canEndBlock || op.canCauseException; + op.wantsFPRF = wantsFPRF || op.canEndBlock || op.canCauseException; + op.wantsCA = wantsCA || op.canEndBlock || op.canCauseException; + wantsCR0 |= opWantsCR0 || op.canEndBlock || op.canCauseException; + wantsCR1 |= opWantsCR1 || op.canEndBlock || op.canCauseException; + wantsFPRF |= opWantsFPRF || op.canEndBlock || op.canCauseException; + wantsCA |= opWantsCA || op.canEndBlock || op.canCauseException; wantsCR0 &= !op.outputCR0 || opWantsCR0; wantsCR1 &= !op.outputCR1 || opWantsCR1; wantsFPRF &= !op.outputFPRF || opWantsFPRF; diff --git a/Source/Core/Core/PowerPC/PPCTables.h b/Source/Core/Core/PowerPC/PPCTables.h index c53510f221..f88d5d8ef3 100644 --- a/Source/Core/Core/PowerPC/PPCTables.h +++ b/Source/Core/Core/PowerPC/PPCTables.h @@ -64,7 +64,9 @@ enum InstructionFlags : u64 FL_IN_FLOAT_C_BITEXACT = (1ull << 31), // The output is based on the exact bits in frC. FL_IN_FLOAT_AB_BITEXACT = FL_IN_FLOAT_A_BITEXACT | FL_IN_FLOAT_B_BITEXACT, FL_IN_FLOAT_BC_BITEXACT = FL_IN_FLOAT_B_BITEXACT | FL_IN_FLOAT_C_BITEXACT, - FL_PROGRAMEXCEPTION = (1ull << 32), // May generate a system exception. + FL_PROGRAMEXCEPTION = (1ull << 32), // May generate a program exception (not floating point). + FL_FLOAT_EXCEPTION = (1ull << 33), // May generate a program exception (floating point). + FL_FLOAT_DIV = (1ull << 34), // May generate a program exception (FP) due to division by 0. }; enum class OpType