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
|
"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"],
|
"required": ["name", "region"],
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
#include "GameDatabase.h"
|
#include "GameDatabase.h"
|
||||||
#include "Host.h"
|
#include "Host.h"
|
||||||
#include "Patch.h"
|
|
||||||
#include "vtlb.h"
|
#include "vtlb.h"
|
||||||
|
|
||||||
#include "common/FileSystem.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));
|
s_game_db.emplace(std::move(serial), std::move(gameEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
#include "Patch.h"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
@ -102,6 +103,7 @@ namespace GameDatabaseSchema
|
||||||
std::vector<std::pair<GSHWFixId, s32>> gsHWFixes;
|
std::vector<std::pair<GSHWFixId, s32>> gsHWFixes;
|
||||||
std::vector<std::string> memcardFilters;
|
std::vector<std::string> memcardFilters;
|
||||||
std::unordered_map<u32, std::string> patches;
|
std::unordered_map<u32, std::string> patches;
|
||||||
|
std::vector<DynamicPatch> dynaPatches;
|
||||||
|
|
||||||
// Returns the list of memory card serials as a `/` delimited string
|
// Returns the list of memory card serials as a `/` delimited string
|
||||||
std::string memcardFiltersAsString() const;
|
std::string memcardFiltersAsString() const;
|
||||||
|
|
|
@ -33,8 +33,10 @@
|
||||||
// the only consumer, so it's not made public via Patch.h
|
// 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.
|
// Applies a single patch line to emulation memory regardless of its "place" value.
|
||||||
extern void _ApplyPatch(IniPatch* p);
|
extern void _ApplyPatch(IniPatch* p);
|
||||||
|
extern void _ApplyDynaPatch(const DynamicPatch& patch, u32 address);
|
||||||
|
|
||||||
static std::vector<IniPatch> Patch;
|
static std::vector<IniPatch> Patch;
|
||||||
|
static std::vector<DynamicPatch> DynaPatch;
|
||||||
|
|
||||||
struct PatchTextTable
|
struct PatchTextTable
|
||||||
{
|
{
|
||||||
|
@ -139,6 +141,7 @@ int LoadPatchesFromString(const std::string& patches)
|
||||||
void ForgetLoadedPatches()
|
void ForgetLoadedPatches()
|
||||||
{
|
{
|
||||||
Patch.clear();
|
Patch.clear();
|
||||||
|
DynaPatch.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This routine loads patches from a zip file
|
// This routine loads patches from a zip file
|
||||||
|
@ -286,3 +289,18 @@ void ApplyLoadedPatches(patch_place_type place)
|
||||||
_ApplyPatch(&i);
|
_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 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
|
// - 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 "common/Pcsx2Defs.h"
|
||||||
#include "SysForwardDefs.h"
|
#include "SysForwardDefs.h"
|
||||||
#include "GameDatabase.h"
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
|
struct IConsoleWriter;
|
||||||
|
|
||||||
enum patch_cpu_type {
|
enum patch_cpu_type {
|
||||||
NO_CPU,
|
NO_CPU,
|
||||||
CPU_EE,
|
CPU_EE,
|
||||||
|
@ -97,6 +97,18 @@ struct IniPatch
|
||||||
u64 data;
|
u64 data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DynamicPatchEntry
|
||||||
|
{
|
||||||
|
u32 offset;
|
||||||
|
u32 value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DynamicPatch
|
||||||
|
{
|
||||||
|
std::vector<DynamicPatchEntry> pattern;
|
||||||
|
std::vector<DynamicPatchEntry> replacement;
|
||||||
|
};
|
||||||
|
|
||||||
namespace PatchFunc
|
namespace PatchFunc
|
||||||
{
|
{
|
||||||
PATCHTABLEFUNC author;
|
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 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);
|
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.
|
// 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
|
// 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,
|
// 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)
|
u64 SwapEndian(u64 InputNum, u8 BitLength)
|
||||||
{
|
{
|
||||||
if (BitLength == 64) // DOUBLE_LE_T
|
if (BitLength == 64) // DOUBLE_LE_T
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "DEV9/DEV9.h"
|
#include "DEV9/DEV9.h"
|
||||||
#include "Elfheader.h"
|
#include "Elfheader.h"
|
||||||
#include "FW.h"
|
#include "FW.h"
|
||||||
|
#include "GameDatabase.h"
|
||||||
#include "GS.h"
|
#include "GS.h"
|
||||||
#include "GSDumpReplayer.h"
|
#include "GSDumpReplayer.h"
|
||||||
#include "HostDisplay.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);
|
PatchesCon->WriteLn(Color_Green, "(GameDB) Patches Loaded: %d", patch_count);
|
||||||
fmt::format_to(std::back_inserter(message), "{} game patches", patch_count);
|
fmt::format_to(std::back_inserter(message), "{} game patches", patch_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LoadDynamicPatches(game->dynaPatches);
|
||||||
}
|
}
|
||||||
|
|
||||||
// regular cheat patches
|
// regular cheat patches
|
||||||
|
|
|
@ -1709,6 +1709,9 @@ void recompileNextInstruction(bool delayslot, bool swapped_delay_slot)
|
||||||
u32 i;
|
u32 i;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
|
if (EmuConfig.EnablePatches)
|
||||||
|
ApplyDynamicPatches(pc);
|
||||||
|
|
||||||
// add breakpoint
|
// add breakpoint
|
||||||
if (!delayslot)
|
if (!delayslot)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue