Merge pull request #13764 from SuperSamus/patch-invalidate-cache

ActionReplay/PatchEngine: Make writes invalidate cache
This commit is contained in:
JMC47
2025-08-22 19:16:47 -04:00
committed by GitHub
4 changed files with 54 additions and 42 deletions

View File

@@ -42,6 +42,7 @@
#include "Core/AchievementManager.h" #include "Core/AchievementManager.h"
#include "Core/CheatCodes.h" #include "Core/CheatCodes.h"
#include "Core/Config/MainSettings.h" #include "Core/Config/MainSettings.h"
#include "Core/Debugger/PPCDebugInterface.h"
#include "Core/PowerPC/MMU.h" #include "Core/PowerPC/MMU.h"
namespace ActionReplay namespace ActionReplay
@@ -379,7 +380,7 @@ static bool Subtype_RamWriteAndFill(const Core::CPUThreadGuard& guard, const ARA
const u32 repeat = data >> 8; const u32 repeat = data >> 8;
for (u32 i = 0; i <= repeat; ++i) for (u32 i = 0; i <= repeat; ++i)
{ {
PowerPC::MMU::HostWrite_U8(guard, data & 0xFF, new_addr + i); ApplyMemoryPatch<u8>(guard, static_cast<u8>(data), new_addr + i);
LogInfo("Wrote {:08x} to address {:08x}", data & 0xFF, new_addr + i); LogInfo("Wrote {:08x} to address {:08x}", data & 0xFF, new_addr + i);
} }
LogInfo("--------"); LogInfo("--------");
@@ -393,7 +394,7 @@ static bool Subtype_RamWriteAndFill(const Core::CPUThreadGuard& guard, const ARA
const u32 repeat = data >> 16; const u32 repeat = data >> 16;
for (u32 i = 0; i <= repeat; ++i) for (u32 i = 0; i <= repeat; ++i)
{ {
PowerPC::MMU::HostWrite_U16(guard, data & 0xFFFF, new_addr + i * 2); ApplyMemoryPatch<u16>(guard, static_cast<u16>(data), new_addr + i * 2);
LogInfo("Wrote {:08x} to address {:08x}", data & 0xFFFF, new_addr + i * 2); LogInfo("Wrote {:08x} to address {:08x}", data & 0xFFFF, new_addr + i * 2);
} }
LogInfo("--------"); LogInfo("--------");
@@ -404,7 +405,7 @@ static bool Subtype_RamWriteAndFill(const Core::CPUThreadGuard& guard, const ARA
case DATATYPE_32BIT: // Dword write case DATATYPE_32BIT: // Dword write
LogInfo("32-bit Write"); LogInfo("32-bit Write");
LogInfo("--------"); LogInfo("--------");
PowerPC::MMU::HostWrite_U32(guard, data, new_addr); ApplyMemoryPatch<u32>(guard, data, new_addr);
LogInfo("Wrote {:08x} to address {:08x}", data, new_addr); LogInfo("Wrote {:08x} to address {:08x}", data, new_addr);
LogInfo("--------"); LogInfo("--------");
break; break;
@@ -435,12 +436,12 @@ static bool Subtype_WriteToPointer(const Core::CPUThreadGuard& guard, const ARAd
{ {
LogInfo("Write 8-bit to pointer"); LogInfo("Write 8-bit to pointer");
LogInfo("--------"); LogInfo("--------");
const u8 thebyte = data & 0xFF; const u8 thebyte = static_cast<u8>(data);
const u32 offset = data >> 8; const u32 offset = data >> 8;
LogInfo("Pointer: {:08x}", ptr); LogInfo("Pointer: {:08x}", ptr);
LogInfo("Byte: {:08x}", thebyte); LogInfo("Byte: {:08x}", thebyte);
LogInfo("Offset: {:08x}", offset); LogInfo("Offset: {:08x}", offset);
PowerPC::MMU::HostWrite_U8(guard, thebyte, ptr + offset); ApplyMemoryPatch<u8>(guard, thebyte, ptr + offset);
LogInfo("Wrote {:08x} to address {:08x}", thebyte, ptr + offset); LogInfo("Wrote {:08x} to address {:08x}", thebyte, ptr + offset);
LogInfo("--------"); LogInfo("--------");
break; break;
@@ -450,12 +451,12 @@ static bool Subtype_WriteToPointer(const Core::CPUThreadGuard& guard, const ARAd
{ {
LogInfo("Write 16-bit to pointer"); LogInfo("Write 16-bit to pointer");
LogInfo("--------"); LogInfo("--------");
const u16 theshort = data & 0xFFFF; const u16 theshort = static_cast<u16>(data);
const u32 offset = (data >> 16) << 1; const u32 offset = (data >> 16) << 1;
LogInfo("Pointer: {:08x}", ptr); LogInfo("Pointer: {:08x}", ptr);
LogInfo("Byte: {:08x}", theshort); LogInfo("Byte: {:08x}", theshort);
LogInfo("Offset: {:08x}", offset); LogInfo("Offset: {:08x}", offset);
PowerPC::MMU::HostWrite_U16(guard, theshort, ptr + offset); ApplyMemoryPatch<u16>(guard, theshort, ptr + offset);
LogInfo("Wrote {:08x} to address {:08x}", theshort, ptr + offset); LogInfo("Wrote {:08x} to address {:08x}", theshort, ptr + offset);
LogInfo("--------"); LogInfo("--------");
break; break;
@@ -465,7 +466,7 @@ static bool Subtype_WriteToPointer(const Core::CPUThreadGuard& guard, const ARAd
case DATATYPE_32BIT: case DATATYPE_32BIT:
LogInfo("Write 32-bit to pointer"); LogInfo("Write 32-bit to pointer");
LogInfo("--------"); LogInfo("--------");
PowerPC::MMU::HostWrite_U32(guard, data, ptr); ApplyMemoryPatch<u32>(guard, data, ptr);
LogInfo("Wrote {:08x} to address {:08x}", data, ptr); LogInfo("Wrote {:08x} to address {:08x}", data, ptr);
LogInfo("--------"); LogInfo("--------");
break; break;
@@ -493,7 +494,7 @@ static bool Subtype_AddCode(const Core::CPUThreadGuard& guard, const ARAddr& add
case DATATYPE_8BIT: case DATATYPE_8BIT:
LogInfo("8-bit Add"); LogInfo("8-bit Add");
LogInfo("--------"); LogInfo("--------");
PowerPC::MMU::HostWrite_U8(guard, PowerPC::MMU::HostRead_U8(guard, new_addr) + data, new_addr); ApplyMemoryPatch<u8>(guard, PowerPC::MMU::HostRead_U8(guard, new_addr) + data, new_addr);
LogInfo("Wrote {:02x} to address {:08x}", PowerPC::MMU::HostRead_U8(guard, new_addr), new_addr); LogInfo("Wrote {:02x} to address {:08x}", PowerPC::MMU::HostRead_U8(guard, new_addr), new_addr);
LogInfo("--------"); LogInfo("--------");
break; break;
@@ -501,8 +502,7 @@ static bool Subtype_AddCode(const Core::CPUThreadGuard& guard, const ARAddr& add
case DATATYPE_16BIT: case DATATYPE_16BIT:
LogInfo("16-bit Add"); LogInfo("16-bit Add");
LogInfo("--------"); LogInfo("--------");
PowerPC::MMU::HostWrite_U16(guard, PowerPC::MMU::HostRead_U16(guard, new_addr) + data, ApplyMemoryPatch<u16>(guard, PowerPC::MMU::HostRead_U16(guard, new_addr) + data, new_addr);
new_addr);
LogInfo("Wrote {:04x} to address {:08x}", PowerPC::MMU::HostRead_U16(guard, new_addr), LogInfo("Wrote {:04x} to address {:08x}", PowerPC::MMU::HostRead_U16(guard, new_addr),
new_addr); new_addr);
LogInfo("--------"); LogInfo("--------");
@@ -511,8 +511,7 @@ static bool Subtype_AddCode(const Core::CPUThreadGuard& guard, const ARAddr& add
case DATATYPE_32BIT: case DATATYPE_32BIT:
LogInfo("32-bit Add"); LogInfo("32-bit Add");
LogInfo("--------"); LogInfo("--------");
PowerPC::MMU::HostWrite_U32(guard, PowerPC::MMU::HostRead_U32(guard, new_addr) + data, ApplyMemoryPatch<u32>(guard, PowerPC::MMU::HostRead_U32(guard, new_addr) + data, new_addr);
new_addr);
LogInfo("Wrote {:08x} to address {:08x}", PowerPC::MMU::HostRead_U32(guard, new_addr), LogInfo("Wrote {:08x} to address {:08x}", PowerPC::MMU::HostRead_U32(guard, new_addr),
new_addr); new_addr);
LogInfo("--------"); LogInfo("--------");
@@ -528,7 +527,7 @@ static bool Subtype_AddCode(const Core::CPUThreadGuard& guard, const ARAddr& add
// data contains an (unsigned?) integer value // data contains an (unsigned?) integer value
const float fread = read_float + static_cast<float>(data); const float fread = read_float + static_cast<float>(data);
const u32 newval = std::bit_cast<u32>(fread); const u32 newval = std::bit_cast<u32>(fread);
PowerPC::MMU::HostWrite_U32(guard, newval, new_addr); ApplyMemoryPatch<u32>(guard, newval, new_addr);
LogInfo("Old Value {:08x}", read); LogInfo("Old Value {:08x}", read);
LogInfo("Increment {:08x}", data); LogInfo("Increment {:08x}", data);
LogInfo("New value {:08x}", newval); LogInfo("New value {:08x}", newval);
@@ -586,7 +585,7 @@ static bool ZeroCode_FillAndSlide(const Core::CPUThreadGuard& guard, const u32 v
LogInfo("--------"); LogInfo("--------");
for (int i = 0; i < write_num; ++i) for (int i = 0; i < write_num; ++i)
{ {
PowerPC::MMU::HostWrite_U8(guard, val & 0xFF, curr_addr); ApplyMemoryPatch<u32>(guard, static_cast<u8>(val), curr_addr);
curr_addr += addr_incr; curr_addr += addr_incr;
val += val_incr; val += val_incr;
LogInfo("Write {:08x} to address {:08x}", val & 0xFF, curr_addr); LogInfo("Write {:08x} to address {:08x}", val & 0xFF, curr_addr);
@@ -602,7 +601,7 @@ static bool ZeroCode_FillAndSlide(const Core::CPUThreadGuard& guard, const u32 v
LogInfo("--------"); LogInfo("--------");
for (int i = 0; i < write_num; ++i) for (int i = 0; i < write_num; ++i)
{ {
PowerPC::MMU::HostWrite_U16(guard, val & 0xFFFF, curr_addr); ApplyMemoryPatch<u16>(guard, static_cast<u16>(val), curr_addr);
LogInfo("Write {:08x} to address {:08x}", val & 0xFFFF, curr_addr); LogInfo("Write {:08x} to address {:08x}", val & 0xFFFF, curr_addr);
curr_addr += addr_incr * 2; curr_addr += addr_incr * 2;
val += val_incr; val += val_incr;
@@ -617,7 +616,7 @@ static bool ZeroCode_FillAndSlide(const Core::CPUThreadGuard& guard, const u32 v
LogInfo("--------"); LogInfo("--------");
for (int i = 0; i < write_num; ++i) for (int i = 0; i < write_num; ++i)
{ {
PowerPC::MMU::HostWrite_U32(guard, val, curr_addr); ApplyMemoryPatch<u32>(guard, val, curr_addr);
LogInfo("Write {:08x} to address {:08x}", val, curr_addr); LogInfo("Write {:08x} to address {:08x}", val, curr_addr);
curr_addr += addr_incr * 4; curr_addr += addr_incr * 4;
val += val_incr; val += val_incr;
@@ -664,8 +663,7 @@ static bool ZeroCode_MemoryCopy(const Core::CPUThreadGuard& guard, const u32 val
LogInfo("Resolved Src Address to: {:08x}", ptr_src); LogInfo("Resolved Src Address to: {:08x}", ptr_src);
for (int i = 0; i < num_bytes; ++i) for (int i = 0; i < num_bytes; ++i)
{ {
PowerPC::MMU::HostWrite_U8(guard, PowerPC::MMU::HostRead_U8(guard, ptr_src + i), ApplyMemoryPatch<u8>(guard, PowerPC::MMU::HostRead_U8(guard, ptr_src + i), ptr_dest + i);
ptr_dest + i);
LogInfo("Wrote {:08x} to address {:08x}", PowerPC::MMU::HostRead_U8(guard, ptr_src + i), LogInfo("Wrote {:08x} to address {:08x}", PowerPC::MMU::HostRead_U8(guard, ptr_src + i),
ptr_dest + i); ptr_dest + i);
} }
@@ -677,8 +675,7 @@ static bool ZeroCode_MemoryCopy(const Core::CPUThreadGuard& guard, const u32 val
LogInfo("--------"); LogInfo("--------");
for (int i = 0; i < num_bytes; ++i) for (int i = 0; i < num_bytes; ++i)
{ {
PowerPC::MMU::HostWrite_U8(guard, PowerPC::MMU::HostRead_U8(guard, addr_src + i), ApplyMemoryPatch<u8>(guard, PowerPC::MMU::HostRead_U8(guard, addr_src + i), addr_dest + i);
addr_dest + i);
LogInfo("Wrote {:08x} to address {:08x}", PowerPC::MMU::HostRead_U8(guard, addr_src + i), LogInfo("Wrote {:08x} to address {:08x}", PowerPC::MMU::HostRead_U8(guard, addr_src + i),
addr_dest + i); addr_dest + i);
} }

View File

@@ -29,55 +29,58 @@
#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/PowerPC.h"
#include "Core/System.h" #include "Core/System.h"
void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, Common::Debug::MemoryPatch& patch, void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, std::span<u8> value, const u32 address,
bool store_existing_value) bool store_existing_value)
{ {
if (AchievementManager::GetInstance().IsHardcoreModeActive()) if (AchievementManager::GetInstance().IsHardcoreModeActive())
return; return;
if (patch.value.empty()) if (value.empty())
return; return;
const u32 address = patch.address; const std::size_t size = value.size();
const std::size_t size = patch.value.size();
if (!PowerPC::MMU::HostIsRAMAddress(guard, address)) if (!PowerPC::MMU::HostIsRAMAddress(guard, address))
return; return;
auto& power_pc = guard.GetSystem().GetPowerPC(); auto& power_pc = guard.GetSystem().GetPowerPC();
bool should_invalidate_cache = false;
for (u32 offset = 0; offset < size; ++offset) for (u32 offset = 0; offset < size; ++offset)
{ {
if (store_existing_value) u8 old_value = PowerPC::MMU::HostRead_U8(guard, address + offset);
if (old_value != value[offset])
{ {
const u8 value = PowerPC::MMU::HostRead_U8(guard, address + offset); PowerPC::MMU::HostWrite_U8(guard, value[offset], address + offset);
PowerPC::MMU::HostWrite_U8(guard, patch.value[offset], address + offset); should_invalidate_cache = true;
patch.value[offset] = value; if (store_existing_value)
} value[offset] = old_value;
else
{
PowerPC::MMU::HostWrite_U8(guard, patch.value[offset], address + offset);
} }
if (((address + offset) % 4) == 3) if (((address + offset) % 4) == 3)
power_pc.ScheduleInvalidateCacheThreadSafe(Common::AlignDown(address + offset, 4)); {
if (should_invalidate_cache)
power_pc.ScheduleInvalidateCacheThreadSafe(Common::AlignDown(address + offset, 4));
should_invalidate_cache = false;
}
} }
if (((address + size) % 4) != 0) if (should_invalidate_cache)
{ {
power_pc.ScheduleInvalidateCacheThreadSafe( power_pc.ScheduleInvalidateCacheThreadSafe(
Common::AlignDown(address + static_cast<u32>(size), 4)); Common::AlignDown(address + static_cast<u32>(size) - 1, 4));
} }
} }
void PPCPatches::ApplyExistingPatch(const Core::CPUThreadGuard& guard, std::size_t index) void PPCPatches::ApplyExistingPatch(const Core::CPUThreadGuard& guard, std::size_t index)
{ {
auto& patch = m_patches[index]; auto& patch = m_patches[index];
ApplyMemoryPatch(guard, patch, false); ApplyMemoryPatch(guard, patch.value, patch.address, false);
} }
void PPCPatches::Patch(const Core::CPUThreadGuard& guard, std::size_t index) void PPCPatches::Patch(const Core::CPUThreadGuard& guard, std::size_t index)
{ {
auto& patch = m_patches[index]; auto& patch = m_patches[index];
if (patch.type == Common::Debug::MemoryPatch::ApplyType::Once) if (patch.type == Common::Debug::MemoryPatch::ApplyType::Once)
ApplyMemoryPatch(guard, patch); ApplyMemoryPatch(guard, patch.value, patch.address);
else else
PatchEngine::AddMemoryPatch(index); PatchEngine::AddMemoryPatch(index);
} }

View File

@@ -3,12 +3,15 @@
#pragma once #pragma once
#include <concepts>
#include <cstddef> #include <cstddef>
#include <memory> #include <memory>
#include <span>
#include <string> #include <string>
#include "Common/Debug/MemoryPatches.h" #include "Common/Debug/MemoryPatches.h"
#include "Common/Debug/Watches.h" #include "Common/Debug/Watches.h"
#include "Common/Swap.h"
#include "Core/Debugger/DebugInterface.h" #include "Core/Debugger/DebugInterface.h"
#include "Core/NetworkCaptureLogger.h" #include "Core/NetworkCaptureLogger.h"
@@ -19,9 +22,18 @@ class System;
} // namespace Core } // namespace Core
class PPCSymbolDB; class PPCSymbolDB;
void ApplyMemoryPatch(const Core::CPUThreadGuard&, Common::Debug::MemoryPatch& patch, void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, std::span<u8> value, const u32 address,
bool store_existing_value = true); bool store_existing_value = true);
template <std::unsigned_integral T>
void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, T value, const u32 address)
{
Common::BigEndianValue<T> big_endian{value};
auto data =
std::span<u8, sizeof(T)>{reinterpret_cast<u8*>(std::addressof(big_endian)), sizeof(T)};
ApplyMemoryPatch(guard, data, address);
}
class PPCPatches final : public Common::Debug::MemoryPatches class PPCPatches final : public Common::Debug::MemoryPatches
{ {
public: public:

View File

@@ -219,19 +219,19 @@ static void ApplyPatches(const Core::CPUThreadGuard& guard, const std::vector<Pa
if (!entry.conditional || if (!entry.conditional ||
PowerPC::MMU::HostRead_U8(guard, addr) == static_cast<u8>(comparand)) PowerPC::MMU::HostRead_U8(guard, addr) == static_cast<u8>(comparand))
{ {
PowerPC::MMU::HostWrite_U8(guard, static_cast<u8>(value), addr); ApplyMemoryPatch<u8>(guard, static_cast<u8>(value), addr);
} }
break; break;
case PatchType::Patch16Bit: case PatchType::Patch16Bit:
if (!entry.conditional || if (!entry.conditional ||
PowerPC::MMU::HostRead_U16(guard, addr) == static_cast<u16>(comparand)) PowerPC::MMU::HostRead_U16(guard, addr) == static_cast<u16>(comparand))
{ {
PowerPC::MMU::HostWrite_U16(guard, static_cast<u16>(value), addr); ApplyMemoryPatch<u16>(guard, static_cast<u16>(value), addr);
} }
break; break;
case PatchType::Patch32Bit: case PatchType::Patch32Bit:
if (!entry.conditional || PowerPC::MMU::HostRead_U32(guard, addr) == comparand) if (!entry.conditional || PowerPC::MMU::HostRead_U32(guard, addr) == comparand)
PowerPC::MMU::HostWrite_U32(guard, value, addr); ApplyMemoryPatch<u32>(guard, value, addr);
break; break;
default: default:
// unknown patchtype // unknown patchtype