From f87c709aa920e9dd2d4dcce4ab53beb3835e0b31 Mon Sep 17 00:00:00 2001 From: hrydgard Date: Sun, 23 Nov 2008 12:59:10 +0000 Subject: [PATCH] Added speed hack engine (way to make block take more cycles). Added example speed hack for Metroid Prime 2 PAL. (Speedhacking is only useful on games with really stupid idle loops, like the Metroids). git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1271 8ced0084-cf51-0410-be5f-012b33b47a6e --- Data/User/GameConfig/G2MP01.ini | 14 +++++ Source/Core/Common/Src/IniFile.cpp | 27 +++++----- Source/Core/Common/Src/IniFile.h | 7 +-- Source/Core/Core/Src/PatchEngine.cpp | 59 ++++++++++++++++++---- Source/Core/Core/Src/PatchEngine.h | 2 + Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp | 4 +- 6 files changed, 84 insertions(+), 29 deletions(-) create mode 100644 Data/User/GameConfig/G2MP01.ini diff --git a/Data/User/GameConfig/G2MP01.ini b/Data/User/GameConfig/G2MP01.ini new file mode 100644 index 0000000000..62b3f3ef33 --- /dev/null +++ b/Data/User/GameConfig/G2MP01.ini @@ -0,0 +1,14 @@ +# G2MP01 - Metroid Prime 2 Echoes +[Core] +#Values set here will override the main dolphin settings. +[Speedhacks] +# Patch OSYieldThread to take more time - MP2's idle loop is really stupid. +0x80375c68=200 +[EmuState] +#The Emulation State. 1 is worst, 5 is best, 0 is not set. +EmulationStateId = 2 +[OnLoad] +#Add memory patches to be loaded once on boot here. +[OnFrame] +#Add memory patches to be applied every frame here. +[ActionReplay] diff --git a/Source/Core/Common/Src/IniFile.cpp b/Source/Core/Common/Src/IniFile.cpp index dc3f8095dd..27114e6d3c 100644 --- a/Source/Core/Common/Src/IniFile.cpp +++ b/Source/Core/Common/Src/IniFile.cpp @@ -51,21 +51,22 @@ Section::Section(const Section& other) lines = other.lines; } +const Section* IniFile::GetSection(const char* sectionName) const +{ + for (std::vector
::const_iterator iter = sections.begin(); iter != sections.end(); ++iter) + if (!strcmp(iter->name.c_str(), sectionName)) + return (&(*iter)); + return 0; +} Section* IniFile::GetSection(const char* sectionName) { for (std::vector
::iterator iter = sections.begin(); iter != sections.end(); ++iter) - { if (!strcmp(iter->name.c_str(), sectionName)) - { - return(&(*iter)); - } - } - - return(0); + return (&(*iter)); + return 0; } - Section* IniFile::GetOrCreateSection(const char* sectionName) { Section* section = GetSection(sectionName); @@ -102,7 +103,7 @@ bool IniFile::DeleteSection(const char* sectionName) } -void IniFile::ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut) +void IniFile::ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut) const { // allow many types of commenting // These MUST be signed! Do not change to size_t @@ -390,9 +391,9 @@ bool IniFile::Save(const char* filename) } -bool IniFile::GetKeys(const char* sectionName, std::vector& keys) +bool IniFile::GetKeys(const char* sectionName, std::vector& keys) const { - Section* section = GetSection(sectionName); + const Section* section = GetSection(sectionName); if (!section) { @@ -412,9 +413,9 @@ bool IniFile::GetKeys(const char* sectionName, std::vector& keys) } -bool IniFile::GetLines(const char* sectionName, std::vector& lines) +bool IniFile::GetLines(const char* sectionName, std::vector& lines) const { - Section* section = GetSection(sectionName); + const Section* section = GetSection(sectionName); if (!section) return false; diff --git a/Source/Core/Common/Src/IniFile.h b/Source/Core/Common/Src/IniFile.h index de4c5836d0..9614bf8b46 100644 --- a/Source/Core/Common/Src/IniFile.h +++ b/Source/Core/Common/Src/IniFile.h @@ -64,20 +64,21 @@ public: bool Get(const char* sectionName, const char* key, bool* value, bool defaultValue = false); bool Get(const char* sectionName, const char* key, std::vector& values); - bool GetKeys(const char* sectionName, std::vector& keys); - bool GetLines(const char* sectionName, std::vector& lines); + bool GetKeys(const char* sectionName, std::vector& keys) const; + bool GetLines(const char* sectionName, std::vector& lines) const; bool DeleteKey(const char* sectionName, const char* key); bool DeleteSection(const char* sectionName); void SortSections(); - void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut); + void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut) const; std::string* GetLine(Section* section, const char* key, std::string* valueOut, std::string* commentOut); private: std::vector
sections; + const Section* GetSection(const char* section) const; Section* GetSection(const char* section); Section* GetOrCreateSection(const char* section); std::string* GetLine(const char* section, const char* key); diff --git a/Source/Core/Core/Src/PatchEngine.cpp b/Source/Core/Core/Src/PatchEngine.cpp index 88ef81feca..f54f1963de 100644 --- a/Source/Core/Core/Src/PatchEngine.cpp +++ b/Source/Core/Core/Src/PatchEngine.cpp @@ -28,6 +28,7 @@ #include #include +#include #include "StringUtil.h" #include "PatchEngine.h" #include "IniFile.h" @@ -41,10 +42,9 @@ namespace std::vector onLoad; std::vector onFrame; +std::map speedHacks; -} // namespace - -void LoadPatchSection(const char *section, std::vector &patches, IniFile &ini) +static void LoadPatchSection(const char *section, std::vector &patches, IniFile &ini) { std::vector keys; ini.GetKeys(section, keys); @@ -59,18 +59,54 @@ void LoadPatchSection(const char *section, std::vector &patches, IniFile std::string val(value); std::vector items; SplitString(val, ":", items); - Patch p; - bool success = true; - success = success && TryParseUInt(std::string(key.c_str()), &p.address); - success = success && TryParseUInt(items[1], &p.value); - p.type = (PatchType)ChooseStringFrom(items[0].c_str(), PatchTypeStrings); - success = success && (p.type != (PatchType)-1); - if (success) - patches.push_back(p); + if (items.size() >= 2) { + Patch p; + bool success = true; + success = success && TryParseUInt(std::string(key.c_str()), &p.address); + success = success && TryParseUInt(items[1], &p.value); + p.type = (PatchType)ChooseStringFrom(items[0].c_str(), PatchTypeStrings); + success = success && (p.type != (PatchType)-1); + if (success) + patches.push_back(p); + } } } } +static void LoadSpeedhacks(const char *section, std::map &hacks, IniFile &ini) { + std::vector keys; + ini.GetKeys(section, keys); + for (std::vector::const_iterator iter = keys.begin(); iter != keys.end(); ++iter) + { + std::string key = *iter; + std::string value; + ini.Get(section, key.c_str(), &value, "BOGUS"); + if (value != "BOGUS") + { + u32 address; + u32 cycles; + bool success = true; + success = success && TryParseUInt(std::string(key.c_str()), &address); + success = success && TryParseUInt(value, &cycles); + if (success) { + speedHacks[address] = (int)cycles; + } + } + } +} + +} // namespace + + +int PatchEngine_GetSpeedhackCycles(u32 addr) +{ + std::map::const_iterator iter = speedHacks.find(addr); + if (iter == speedHacks.end()) + return 0; + else + return iter->second; +} + void PatchEngine_LoadPatches(const char *gameID) { IniFile ini; @@ -79,6 +115,7 @@ void PatchEngine_LoadPatches(const char *gameID) LoadPatchSection("OnLoad", onLoad, ini); LoadPatchSection("OnFrame", onFrame, ini); LoadActionReplayCodes(ini, false); + LoadSpeedhacks("Speedhacks", speedHacks, ini); } } diff --git a/Source/Core/Core/Src/PatchEngine.h b/Source/Core/Core/Src/PatchEngine.h index be475405bf..4f843cb194 100644 --- a/Source/Core/Core/Src/PatchEngine.h +++ b/Source/Core/Core/Src/PatchEngine.h @@ -46,4 +46,6 @@ void PatchEngine_LoadPatches(const char *gameID); void PatchEngine_ApplyLoadPatches(); void PatchEngine_ApplyFramePatches(); void PatchEngine_ApplyARPatches(); +int PatchEngine_GetSpeedhackCycles(u32 addr); + #endif //_PATCHENGINE_H diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index a708973b88..d992392524 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -23,6 +23,7 @@ #include "Thunk.h" #include "../../HLE/HLE.h" #include "../../Core.h" +#include "../../PatchEngine.h" #include "../../CoreTiming.h" #include "../PowerPC.h" #include "../Profiler.h" @@ -371,7 +372,7 @@ namespace Jit64 gpr.Start(js.gpa); fpr.Start(js.fpa); - js.downcountAmount = js.st.numCycles; + js.downcountAmount = js.st.numCycles + PatchEngine_GetSpeedhackCycles(emaddress); js.blockSize = size; // Translate instructions for (int i = 0; i < (int)size; i++) @@ -396,7 +397,6 @@ namespace Jit64 } // const GekkoOpInfo *info = GetOpInfo(); - if (jo.interpretFPU && PPCTables::UsesFPU(ops[i].inst)) Default(ops[i].inst); else