mirror of https://github.com/PCSX2/pcsx2.git
GameDB/Patching: Add dynamic EE JIT patching
This commit is contained in:
parent
74c14fdf66
commit
7ee62b8222
|
@ -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"],
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue