GameDB/Patching: Add dynamic EE JIT patching

This commit is contained in:
refractionpcsx2 2022-12-27 21:33:03 +00:00
parent 74c14fdf66
commit 7ee62b8222
8 changed files with 131 additions and 3 deletions

View File

@ -257,6 +257,48 @@
}
},
"additionalProperties": false
},
"dynaPatches": {
"type": "array",
"items": {
"type": "object",
"properties": {
"pattern": {
"type": "array",
"items": {
"type": "object",
"properties": {
"offset": {
"type": "integer"
},
"value": {
"type": "integer"
}
},
"required": ["offset", "value"]
},
"minItems": 1
},
"replacement": {
"type": "array",
"items": {
"type": "object",
"properties": {
"offset": {
"type": "integer"
},
"value": {
"type": "integer"
}
},
"required": ["offset", "value"]
},
"minItems": 1
}
},
"required": ["pattern", "replacement"]
},
"minItems": 1
}
},
"required": ["name", "region"],

View File

@ -17,7 +17,6 @@
#include "GameDatabase.h"
#include "Host.h"
#include "Patch.h"
#include "vtlb.h"
#include "common/FileSystem.h"
@ -265,6 +264,35 @@ void GameDatabase::parseAndInsert(const std::string_view& serial, const c4::yml:
}
}
if (node.has_child("dynaPatches") && node["dynaPatches"].has_children())
{
for (const ryml::NodeRef& n : node["dynaPatches"].children())
{
DynamicPatch patch;
if (n.has_child("pattern") && n["pattern"].has_children())
{
for (const ryml::NodeRef& db_pattern : n["pattern"].children())
{
DynamicPatchEntry entry;
db_pattern["offset"] >> entry.offset;
db_pattern["value"] >> entry.value;
patch.pattern.push_back(entry);
}
for (const ryml::NodeRef& db_replacement : n["replacement"].children())
{
DynamicPatchEntry entry;
db_replacement["offset"] >> entry.offset;
db_replacement["value"] >> entry.value;
patch.replacement.push_back(entry);
}
}
gameEntry.dynaPatches.push_back(patch);
}
}
s_game_db.emplace(std::move(serial), std::move(gameEntry));
}

View File

@ -16,6 +16,7 @@
#pragma once
#include "Config.h"
#include "Patch.h"
#include <optional>
#include <string>
#include <string_view>
@ -102,6 +103,7 @@ namespace GameDatabaseSchema
std::vector<std::pair<GSHWFixId, s32>> gsHWFixes;
std::vector<std::string> memcardFilters;
std::unordered_map<u32, std::string> patches;
std::vector<DynamicPatch> dynaPatches;
// Returns the list of memory card serials as a `/` delimited string
std::string memcardFiltersAsString() const;

View File

@ -33,8 +33,10 @@
// the only consumer, so it's not made public via Patch.h
// Applies a single patch line to emulation memory regardless of its "place" value.
extern void _ApplyPatch(IniPatch* p);
extern void _ApplyDynaPatch(const DynamicPatch& patch, u32 address);
static std::vector<IniPatch> Patch;
static std::vector<DynamicPatch> DynaPatch;
struct PatchTextTable
{
@ -139,6 +141,7 @@ int LoadPatchesFromString(const std::string& patches)
void ForgetLoadedPatches()
{
Patch.clear();
DynaPatch.clear();
}
// This routine loads patches from a zip file
@ -286,3 +289,18 @@ void ApplyLoadedPatches(patch_place_type place)
_ApplyPatch(&i);
}
}
void ApplyDynamicPatches(u32 pc)
{
for (const auto& dynpatch : DynaPatch)
{
_ApplyDynaPatch(dynpatch, pc);
}
}
void LoadDynamicPatches(const std::vector<DynamicPatch>& patches)
{
for (const DynamicPatch& it : patches){
DynaPatch.push_back(it);
}
}

View File

@ -34,13 +34,13 @@
// - The 0 cheats - cheats are enabled but nothing found/loaded from the "cheats" folder.
// - The 6 widescreen patches are 6 pnach-style patch lines loaded either from cheats_ws folder or from cheats_ws.zip
#include "common/Pcsx2Defs.h"
#include "SysForwardDefs.h"
#include "GameDatabase.h"
#include <string>
#include <string_view>
struct IConsoleWriter;
enum patch_cpu_type {
NO_CPU,
CPU_EE,
@ -97,6 +97,18 @@ struct IniPatch
u64 data;
};
struct DynamicPatchEntry
{
u32 offset;
u32 value;
};
struct DynamicPatch
{
std::vector<DynamicPatchEntry> pattern;
std::vector<DynamicPatchEntry> replacement;
};
namespace PatchFunc
{
PATCHTABLEFUNC author;
@ -112,6 +124,10 @@ extern int LoadPatchesFromString(const std::string& patches);
extern int LoadPatchesFromDir(const std::string& crc, const std::string& folder, const char* friendly_name, bool show_error_when_missing);
extern int LoadPatchesFromZip(const std::string& crc, const u8* zip_data, size_t zip_data_size);
// Functions for Dynamic EE patching.
extern void LoadDynamicPatches(const std::vector<DynamicPatch>& patches);
extern void ApplyDynamicPatches(u32 pc);
// Patches the emulation memory by applying all the loaded patches with a specific place value.
// Note: unless you know better, there's no need to check whether or not different patch sources
// are enabled (e.g. ws patches, auto game fixes, etc) before calling ApplyLoadedPatches,

View File

@ -590,6 +590,22 @@ void _ApplyPatch(IniPatch *p)
}
}
void _ApplyDynaPatch(const DynamicPatch& patch, u32 address)
{
for (const auto& pattern : patch.pattern)
{
if (*static_cast<u32*>(PSM(address + pattern.offset)) != pattern.value)
return;
}
PatchesCon->WriteLn("Applying Dynamic Patch to address 0x%08X", address);
// If everything passes, apply the patch.
for (const auto& replacement : patch.replacement)
{
memWrite32(address + replacement.offset, replacement.value);
}
}
u64 SwapEndian(u64 InputNum, u8 BitLength)
{
if (BitLength == 64) // DOUBLE_LE_T

View File

@ -36,6 +36,7 @@
#include "DEV9/DEV9.h"
#include "Elfheader.h"
#include "FW.h"
#include "GameDatabase.h"
#include "GS.h"
#include "GSDumpReplayer.h"
#include "HostDisplay.h"
@ -564,6 +565,8 @@ void VMManager::LoadPatches(const std::string& serial, u32 crc, bool show_messag
PatchesCon->WriteLn(Color_Green, "(GameDB) Patches Loaded: %d", patch_count);
fmt::format_to(std::back_inserter(message), "{} game patches", patch_count);
}
LoadDynamicPatches(game->dynaPatches);
}
// regular cheat patches

View File

@ -1709,6 +1709,9 @@ void recompileNextInstruction(bool delayslot, bool swapped_delay_slot)
u32 i;
int count;
if (EmuConfig.EnablePatches)
ApplyDynamicPatches(pc);
// add breakpoint
if (!delayslot)
{