From 275f7e15c0a8c39684057f0fc2a9bbf5886d9a8c Mon Sep 17 00:00:00 2001 From: Nick Renieris Date: Fri, 18 Apr 2025 20:35:02 +0300 Subject: [PATCH] PPU: Fix memory write breakpoints for 13 instructions Specifically: `STVX`, `STVXL`, `STDBRX`, `STWBRX`, `STFSX`, `STFSUX`, `STFDX`, `STFDUX`, `STHBRX`, `STFS`, `STFSU`, `STFD`, `STFDU`. Closes https://github.com/RPCS3/rpcs3/issues/17062. --- rpcs3/Emu/Cell/PPUInterpreter.cpp | 28 +++++++++++++++------------- rpcs3/Emu/Memory/vm.h | 20 ++++++++++++++++++++ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUInterpreter.cpp b/rpcs3/Emu/Cell/PPUInterpreter.cpp index 4f75cd634a..35c2ded508 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/PPUInterpreter.cpp @@ -38,11 +38,13 @@ void ppubreak(ppu_thread& ppu) } } +#define PPU_WRITE(type, addr, value) vm::write(addr, value, &ppu); #define PPU_WRITE_8(addr, value) vm::write8(addr, value, &ppu); #define PPU_WRITE_16(addr, value) vm::write16(addr, value, &ppu); #define PPU_WRITE_32(addr, value) vm::write32(addr, value, &ppu); #define PPU_WRITE_64(addr, value) vm::write64(addr, value, &ppu); #else +#define PPU_WRITE(type, addr, value) vm::write(addr, value); #define PPU_WRITE_8(addr, value) vm::write8(addr, value); #define PPU_WRITE_16(addr, value) vm::write16(addr, value); #define PPU_WRITE_32(addr, value) vm::write32(addr, value); @@ -4573,7 +4575,7 @@ auto STVX() static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~0xfull; - vm::_ref(vm::cast(addr)) = ppu.vr[op.vs]; + PPU_WRITE(v128, vm::cast(addr), ppu.vr[op.vs]); }; RETURN_(ppu, op); } @@ -5074,7 +5076,7 @@ auto STVXL() static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~0xfull; - vm::_ref(vm::cast(addr)) = ppu.vr[op.vs]; + PPU_WRITE(v128, vm::cast(addr), ppu.vr[op.vs]); }; RETURN_(ppu, op); } @@ -5363,7 +5365,7 @@ auto STDBRX() static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - vm::_ref>(vm::cast(addr)) = ppu.gpr[op.rs]; + PPU_WRITE(le_t, vm::cast(addr), ppu.gpr[op.rs]); }; RETURN_(ppu, op); } @@ -5402,7 +5404,7 @@ auto STWBRX() static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - vm::_ref>(vm::cast(addr)) = static_cast(ppu.gpr[op.rs]); + PPU_WRITE(le_t, vm::cast(addr), static_cast(ppu.gpr[op.rs])); }; RETURN_(ppu, op); } @@ -5415,7 +5417,7 @@ auto STFSX() static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - vm::_ref(vm::cast(addr)) = static_cast(ppu.fpr[op.frs]); + PPU_WRITE(f32, vm::cast(addr), static_cast(ppu.fpr[op.frs])); }; RETURN_(ppu, op); } @@ -5446,7 +5448,7 @@ auto STFSUX() static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb]; - vm::_ref(vm::cast(addr)) = static_cast(ppu.fpr[op.frs]); + PPU_WRITE(f32, vm::cast(addr), static_cast(ppu.fpr[op.frs])); ppu.gpr[op.ra] = addr; }; RETURN_(ppu, op); @@ -5496,7 +5498,7 @@ auto STFDX() static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - vm::_ref(vm::cast(addr)) = ppu.fpr[op.frs]; + PPU_WRITE(f64, vm::cast(addr), ppu.fpr[op.frs]); }; RETURN_(ppu, op); } @@ -5509,7 +5511,7 @@ auto STFDUX() static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb]; - vm::_ref(vm::cast(addr)) = ppu.fpr[op.frs]; + PPU_WRITE(f64, vm::cast(addr), ppu.fpr[op.frs]); ppu.gpr[op.ra] = addr; }; RETURN_(ppu, op); @@ -5664,7 +5666,7 @@ auto STHBRX() static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]; - vm::_ref>(vm::cast(addr)) = static_cast(ppu.gpr[op.rs]); + PPU_WRITE(le_t, vm::cast(addr), static_cast(ppu.gpr[op.rs])); }; RETURN_(ppu, op); } @@ -6054,7 +6056,7 @@ auto STFS() static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16; - vm::_ref(vm::cast(addr)) = static_cast(ppu.fpr[op.frs]); + PPU_WRITE(f32, vm::cast(addr), static_cast(ppu.fpr[op.frs])); }; RETURN_(ppu, op); } @@ -6067,7 +6069,7 @@ auto STFSU() static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + op.simm16; - vm::_ref(vm::cast(addr)) = static_cast(ppu.fpr[op.frs]); + PPU_WRITE(f32, vm::cast(addr), static_cast(ppu.fpr[op.frs])); ppu.gpr[op.ra] = addr; }; RETURN_(ppu, op); @@ -6081,7 +6083,7 @@ auto STFD() static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16; - vm::_ref(vm::cast(addr)) = ppu.fpr[op.frs]; + PPU_WRITE(f64, vm::cast(addr), ppu.fpr[op.frs]); }; RETURN_(ppu, op); } @@ -6094,7 +6096,7 @@ auto STFDU() static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { const u64 addr = ppu.gpr[op.ra] + op.simm16; - vm::_ref(vm::cast(addr)) = ppu.fpr[op.frs]; + PPU_WRITE(f64, vm::cast(addr), ppu.fpr[op.frs]); ppu.gpr[op.ra] = addr; }; RETURN_(ppu, op); diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index 915791e2d6..48157c1e63 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -360,6 +360,26 @@ namespace vm #endif } +#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS + template + inline void write(u32 addr, U value, ppu_thread* ppu = nullptr) +#else + template + inline void write(u32 addr, U value) +#endif + { + _ref(addr) = static_cast(value); + +#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS + if (ppu && g_breakpoint_handler.HasBreakpoint(addr, breakpoint_types::bp_write)) + { + debugbp_log.success("BPMW: breakpoint writing(%d) 0x%x at 0x%x", + sizeof(T) * CHAR_BIT, value, addr); + ppubreak(*ppu); + } +#endif + } + void init(); }