From f0cdd8ace6946c0643fee501e360004d46090b71 Mon Sep 17 00:00:00 2001 From: Eladash Date: Fri, 15 May 2020 18:57:48 +0300 Subject: [PATCH] PPU: Implement PPU Traps Stubbing option --- Utilities/Config.cpp | 11 ++++++++++- rpcs3/Emu/Cell/PPUInterpreter.cpp | 14 +++++++++----- rpcs3/Emu/Cell/PPUThread.cpp | 17 ++++++++++++++--- rpcs3/Emu/system_config.h | 1 + 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/Utilities/Config.cpp b/Utilities/Config.cpp index 5c2dad9d7e..a5012dfe9e 100644 --- a/Utilities/Config.cpp +++ b/Utilities/Config.cpp @@ -65,6 +65,13 @@ bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max) const char* start = &value.front(); const char* end = &value.back() + 1; int base = 10; + int sign = +1; + + if (start[0] == '-') + { + sign = -1; + start += 1; + } if (start[0] == '0' && (start[1] == 'x' || start[1] == 'X')) { @@ -75,12 +82,14 @@ bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max) const auto ret = std::from_chars(start, end, result, base); - if (ret.ec != std::errc() || ret.ptr != end) + if (ret.ec != std::errc() || ret.ptr != end || (start[0] == '-' && sign < 0)) { if (out) cfg_log.error("cfg::try_to_int('%s'): invalid integer", value); return false; } + result *= sign; + if (result < min || result > max) { if (out) cfg_log.error("cfg::try_to_int('%s'): out of bounds (%d..%d)", value, min, max); diff --git a/rpcs3/Emu/Cell/PPUInterpreter.cpp b/rpcs3/Emu/Cell/PPUInterpreter.cpp index 328799c209..7b14110f9b 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/PPUInterpreter.cpp @@ -336,7 +336,7 @@ extern u32 ppu_lwarx(ppu_thread& ppu, u32 addr); extern u64 ppu_ldarx(ppu_thread& ppu, u32 addr); extern bool ppu_stwcx(ppu_thread& ppu, u32 addr, u32 reg_value); extern bool ppu_stdcx(ppu_thread& ppu, u32 addr, u64 reg_value); - +extern void ppu_trap(ppu_thread& ppu, u64 addr); class ppu_scale_table_t @@ -2903,7 +2903,8 @@ bool ppu_interpreter::TDI(ppu_thread& ppu, ppu_opcode_t op) ((op.bo & 0x2) && a_ < b_) || ((op.bo & 0x1) && a_ > b_)) { - fmt::throw_exception("Trap!" HERE); + ppu_trap(ppu, ppu.cia); + return false; } return true; @@ -2920,7 +2921,8 @@ bool ppu_interpreter::TWI(ppu_thread& ppu, ppu_opcode_t op) ((op.bo & 0x2) && a_ < b_) || ((op.bo & 0x1) && a_ > b_)) { - fmt::throw_exception("Trap!" HERE); + ppu_trap(ppu, ppu.cia); + return false; } return true; @@ -3261,7 +3263,8 @@ bool ppu_interpreter::TW(ppu_thread& ppu, ppu_opcode_t op) (static_cast(a) < static_cast(b) && (op.bo & 0x2)) || (static_cast(a) > static_cast(b) && (op.bo & 0x1))) { - fmt::throw_exception("Trap!" HERE); + ppu_trap(ppu, ppu.cia); + return false; } return true; @@ -3474,7 +3477,8 @@ bool ppu_interpreter::TD(ppu_thread& ppu, ppu_opcode_t op) ((op.bo & 0x2) && a_ < b_) || ((op.bo & 0x1) && a_ > b_)) { - fmt::throw_exception("Trap!" HERE); + ppu_trap(ppu, ppu.cia); + return false; } return true; diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 73c370b79e..be49d8f4ac 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -998,10 +998,21 @@ extern __m128i sse_cellbe_lvrx_v0(u64 addr); extern void sse_cellbe_stvlx_v0(u64 addr, __m128i a); extern void sse_cellbe_stvrx_v0(u64 addr, __m128i a); -[[noreturn]] static void ppu_trap(ppu_thread& ppu, u64 addr) +void ppu_trap(ppu_thread& ppu, u64 addr) { - ppu.cia = ::narrow(addr); - fmt::throw_exception("Trap! (0x%llx)", addr); + verify(HERE), (addr & (~u64{UINT32_MAX} | 0x3)) == 0; + ppu.cia = static_cast(addr); + + u32 add = static_cast(g_cfg.core.stub_ppu_traps) * 4; + + // If stubbing is enabled, check current instruction and the following + if (!add || !vm::check_addr(ppu.cia, 4, vm::page_executable) || !vm::check_addr(ppu.cia + add, 4, vm::page_executable)) + { + fmt::throw_exception("PPU Trap!" HERE); + } + + ppu_log.error("PPU Trap: Stubbing %d instructions %s.", std::abs(static_cast(add) / 4), add >> 31 ? "backwards" : "forwards"); + ppu.cia += add; // Skip instructions, hope for valid code (interprter may be invoked temporarily) } [[noreturn]] static void ppu_error(ppu_thread& ppu, u64 addr, u32 op) diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index b0783eeaca..10d15d3a41 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -52,6 +52,7 @@ struct cfg_root : cfg::node cfg::_bool spu_approx_xfloat{ this, "Approximate xfloat", true }; cfg::_bool llvm_accurate_dfma{ this, "LLVM Accurate DFMA", true }; // Enable accurate double-precision FMA for CPUs which do not support it natively cfg::_bool llvm_ppu_accurate_vector_nan{ this, "PPU LLVM Accurate Vector NaN values", false }; + cfg::_int<-64, 64> stub_ppu_traps{ this, "Stub PPU Traps", 0, true }; // Hack, skip PPU traps for rare cases where the trap is continueable (specify relative instructions to skip) cfg::_bool debug_console_mode{ this, "Debug Console Mode", false }; // Debug console emulation, not recommended cfg::_enum lib_loading{ this, "Lib Loader", lib_loading_type::liblv2only };