PPU: Implement PPU Traps Stubbing option

This commit is contained in:
Eladash 2020-05-15 18:57:48 +03:00 committed by Ivan
parent 8e9d2fa70e
commit f0cdd8ace6
4 changed files with 34 additions and 9 deletions

View File

@ -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);

View File

@ -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<u32>(a) < static_cast<u32>(b) && (op.bo & 0x2)) ||
(static_cast<u32>(a) > static_cast<u32>(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;

View File

@ -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<u32>(addr);
fmt::throw_exception("Trap! (0x%llx)", addr);
verify(HERE), (addr & (~u64{UINT32_MAX} | 0x3)) == 0;
ppu.cia = static_cast<u32>(addr);
u32 add = static_cast<u32>(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<s32>(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)

View File

@ -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_type> lib_loading{ this, "Lib Loader", lib_loading_type::liblv2only };