Re-committed code from R874, but fixed the build problem, and made some code cleanup.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@880 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
bbbe898839
commit
a3a948ac1d
|
@ -1192,6 +1192,14 @@
|
|||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\Src\ActionReplay.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\ActionReplay.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Src\Console.cpp"
|
||||
>
|
||||
|
|
|
@ -0,0 +1,370 @@
|
|||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "StringUtil.h"
|
||||
#include "IniFile.h"
|
||||
#include "HW/Memmap.h"
|
||||
#include "ActionReplay.h"
|
||||
|
||||
u32 cmd_addr;
|
||||
u8 cmd;
|
||||
u32 addr;
|
||||
u32 data;
|
||||
u8 subtype;
|
||||
u8 w;
|
||||
u8 type;
|
||||
u8 z;
|
||||
std::vector<AREntry>::const_iterator iter;
|
||||
std::vector<ARCode> arCodes;
|
||||
ARCode code;
|
||||
|
||||
void LoadActionReplayCodes(IniFile &ini)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
ARCode currentCode;
|
||||
arCodes.clear();
|
||||
|
||||
if (!ini.GetLines("ActionReplay", lines)) return;
|
||||
|
||||
for (std::vector<std::string>::const_iterator it = lines.begin(); it != lines.end(); ++it)
|
||||
{
|
||||
std::string line = *it;
|
||||
|
||||
std::vector<std::string> pieces;
|
||||
SplitString(line, " ", pieces);
|
||||
if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8)
|
||||
{
|
||||
// Smells like a decrypted Action Replay code, great! Decode!
|
||||
AREntry op;
|
||||
bool success = TryParseUInt(std::string("0x") + pieces[0], &op.cmd_addr);
|
||||
success |= TryParseUInt(std::string("0x") + pieces[1], &op.value);
|
||||
if (!success)
|
||||
PanicAlert("Invalid AR code line: %s", line.c_str());
|
||||
else
|
||||
currentCode.ops.push_back(op);
|
||||
}
|
||||
else
|
||||
{
|
||||
SplitString(line, "-", pieces);
|
||||
if (pieces.size() == 3 && pieces[0].size() == 4 && pieces[1].size() == 4 && pieces[2].size() == 4)
|
||||
{
|
||||
// Encrypted AR code
|
||||
PanicAlert("Dolphin does not yet support encrypted AR codes.");
|
||||
}
|
||||
else if (line.size() > 1)
|
||||
{
|
||||
// OK, name line. This is the start of a new code. Push the old one, prepare the new one.
|
||||
if (currentCode.ops.size())
|
||||
arCodes.push_back(currentCode);
|
||||
currentCode.name = "(invalid)";
|
||||
currentCode.ops.clear();
|
||||
|
||||
if (line[0] == '+')
|
||||
{
|
||||
// Active code - name line.
|
||||
line = StripSpaces(line.substr(1));
|
||||
currentCode.name = line;
|
||||
currentCode.active = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Inactive code.
|
||||
currentCode.name = line;
|
||||
currentCode.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the last code correctly.
|
||||
if (currentCode.ops.size())
|
||||
arCodes.push_back(currentCode);
|
||||
}
|
||||
|
||||
|
||||
// The mechanism is slightly different than what the real AR uses, so there may be compatibility problems.
|
||||
// For example, some authors have created codes that add features to AR. Hacks for popular ones can be added here,
|
||||
// but the problem is not generally solvable.
|
||||
void RunActionReplayCode(const ARCode &arcode, bool nowIsBootup) {
|
||||
code = arcode;
|
||||
for (iter = code.ops.begin(); iter != code.ops.end(); ++iter)
|
||||
{
|
||||
cmd_addr = iter->cmd_addr;
|
||||
cmd = iter->cmd_addr>>24;
|
||||
addr = (iter->cmd_addr & 0x01FFFFFF);
|
||||
data = iter->value;
|
||||
subtype = ((addr >> 30) & 0x03);
|
||||
w = (cmd - ((cmd >> 4) << 4));
|
||||
type = ((addr >> 27) & 0x07);
|
||||
z = (cmd >> 4);
|
||||
|
||||
if (addr >= 0x00002000 && addr < 0x00003000) {
|
||||
PanicAlert("This action replay simulator does not support codes that modify Action Replay itself.");
|
||||
return;
|
||||
}
|
||||
|
||||
// End of sequence. Dunno why anybody would use it.
|
||||
if (iter->cmd_addr == 0) {
|
||||
// Special command!
|
||||
if ((data >> 28) == 0x8) { // Fill 'n' slide
|
||||
PanicAlert("Fill'n'slide command not yet supported.");
|
||||
++iter; /*
|
||||
u32 x = data;
|
||||
u32 size = (addr >> 25) & 3;
|
||||
addr &= 0x01FFFFFF;*/
|
||||
}
|
||||
else {
|
||||
if (data == 0x40000000)
|
||||
{
|
||||
// Resume normal execution. Don't need to do anything here.
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("This action replay command (%08x %08x) not yet supported.", cmd_addr, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// skip these weird init lines
|
||||
if (iter == code.ops.begin() && cmd == 1) continue;
|
||||
|
||||
// SubType selector
|
||||
switch(z)
|
||||
{
|
||||
case 0x0: // Ram write (and fill)
|
||||
{
|
||||
DoARSubtype_RamWriteAndFill(); continue;
|
||||
}
|
||||
case 0x4: // Write to pointer
|
||||
{
|
||||
DoARSubtype_WriteToPointer(); continue;
|
||||
}
|
||||
case 0x8: // Add code
|
||||
{
|
||||
DoARSubtype_AddCode(); continue;
|
||||
}
|
||||
case 0xC: // Master Code & Write to CCXXXXXX
|
||||
{
|
||||
DoARSubtype_MasterCodeAndWriteToCCXXXXXX(); // TODO: This is not implemented yet
|
||||
}
|
||||
default: // non-specific z codes (hacks)
|
||||
{
|
||||
DoARSubtype_Other();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoARSubtype_RamWriteAndFill()
|
||||
{
|
||||
if(w < 0x8) // Check the value W in 0xZWXXXXXXX
|
||||
{
|
||||
u32 new_addr = (addr | 0x80000000);
|
||||
switch ((new_addr >> 25) & 0x03)
|
||||
{
|
||||
case 0x00: // Byte write
|
||||
{
|
||||
u8 repeat = data >> 8;
|
||||
for (int i = 0; i <= repeat; i++) {
|
||||
Memory::Write_U8(data & 0xFF, new_addr + i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x01: // Short write
|
||||
{
|
||||
u16 repeat = data >> 16;
|
||||
for (int i = 0; i <= repeat; i++) {
|
||||
Memory::Write_U16(data & 0xFFFF, new_addr + i * 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case 0x02: // Dword write
|
||||
{
|
||||
Memory::Write_U32(data, new_addr);
|
||||
break;
|
||||
}
|
||||
default: break; // TODO(Omega): maybe add a PanicAlert here?
|
||||
}
|
||||
}
|
||||
}
|
||||
void DoARSubtype_WriteToPointer()
|
||||
{
|
||||
if(w < 0x8)
|
||||
{
|
||||
u32 new_addr = (addr | 0x80000000);
|
||||
switch ((new_addr >> 25) & 0x03)
|
||||
{
|
||||
case 0x00: // Byte write to pointer
|
||||
{
|
||||
u32 ptr = Memory::Read_U32(new_addr);
|
||||
u8 thebyte = data & 0xFF;
|
||||
u32 offset = data >> 8;
|
||||
Memory::Write_U8(thebyte, ptr + offset);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x01: // Short write to pointer
|
||||
{
|
||||
u32 ptr = Memory::Read_U32(new_addr);
|
||||
u16 theshort = data & 0xFFFF;
|
||||
u32 offset = (data >> 16) << 1;
|
||||
Memory::Write_U16(theshort, ptr + offset);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case 0x02: // Dword write to pointer
|
||||
{
|
||||
u32 ptr = Memory::Read_U32(new_addr);
|
||||
Memory::Write_U32(data, ptr);
|
||||
break;
|
||||
}
|
||||
default: PanicAlert("AR Method Error (Write To Pointer): w = %08x, addr = %08x",w,addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoARSubtype_AddCode()
|
||||
{
|
||||
if(w < 0x8)
|
||||
{
|
||||
u32 new_addr = (addr | 0x81FFFFFF);
|
||||
switch((new_addr >> 25) & 0x03)
|
||||
{
|
||||
case 0x0: // Byte add
|
||||
{
|
||||
Memory::Write_U8(Memory::Read_U8(new_addr) + (data & 0xFF), new_addr); break;
|
||||
}
|
||||
case 0x1: // Short add
|
||||
{
|
||||
Memory::Write_U16(Memory::Read_U16(new_addr) + (data & 0xFFFF), new_addr); break;
|
||||
}
|
||||
case 0x2: // DWord add
|
||||
{
|
||||
Memory::Write_U32(Memory::Read_U32(new_addr) + data, new_addr); break;
|
||||
}
|
||||
case 0x3: // Float add (not working?)
|
||||
{
|
||||
union { u32 u; float f;} fu, d;
|
||||
fu.u = Memory::Read_U32(new_addr);
|
||||
d.u = data;
|
||||
fu.f += data;
|
||||
Memory::Write_U32(fu.u, new_addr);
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DoARSubtype_MasterCodeAndWriteToCCXXXXXX()
|
||||
{
|
||||
// code not yet implemented - TODO
|
||||
|
||||
//if(w < 0x8)
|
||||
//{
|
||||
// u32 new_addr = (addr | 0x80000000);
|
||||
// switch((new_addr >> 25) & 0x03)
|
||||
// {
|
||||
// case 0x2:
|
||||
// {
|
||||
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
void DoARSubtype_Other()
|
||||
{
|
||||
switch (cmd & 0xFE)
|
||||
{
|
||||
case 0x90: if (Memory::Read_U32(addr) == data) return; // IF 32 bit equal, exit
|
||||
case 0x08: // IF 8 bit equal, execute next opcode
|
||||
case 0x48: // (double)
|
||||
{
|
||||
if (Memory::Read_U16(addr) != (data & 0xFFFF)) {
|
||||
if (++iter == code.ops.end()) return;
|
||||
if (cmd == 0x48) if (++iter == code.ops.end()) return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x0A: // IF 16 bit equal, execute next opcode
|
||||
case 0x4A: // (double)
|
||||
{
|
||||
if (Memory::Read_U16(addr) != (data & 0xFFFF)) {
|
||||
if (++iter == code.ops.end()) return;
|
||||
if (cmd == 0x4A) if (++iter == code.ops.end()) return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x0C: // IF 32 bit equal, execute next opcode
|
||||
case 0x4C: // (double)
|
||||
{
|
||||
if (Memory::Read_U32(addr) != data) {
|
||||
if (++iter == code.ops.end()) return;
|
||||
if (cmd == 0x4C) if (++iter == code.ops.end()) return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x10: // IF NOT 8 bit equal, execute next opcode
|
||||
case 0x50: // (double)
|
||||
{
|
||||
if (Memory::Read_U8(addr) == (data & 0xFF)) {
|
||||
if (++iter == code.ops.end()) return;
|
||||
if (cmd == 0x50) if (++iter == code.ops.end()) return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x12: // IF NOT 16 bit equal, execute next opcode
|
||||
case 0x52: // (double)
|
||||
{
|
||||
if (Memory::Read_U16(addr) == (data & 0xFFFF)) {
|
||||
if (++iter == code.ops.end()) return;
|
||||
if (cmd == 0x52) if (++iter == code.ops.end()) return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x14: // IF NOT 32 bit equal, execute next opcode
|
||||
case 0x54: // (double)
|
||||
{
|
||||
if (Memory::Read_U32(addr) == data) {
|
||||
if (++iter == code.ops.end()) return;
|
||||
if (cmd == 0x54) if (++iter == code.ops.end()) return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0xC4: // "Master Code" - configure the AR
|
||||
{
|
||||
u8 number = data & 0xFF;
|
||||
if (number == 0)
|
||||
{
|
||||
// Normal master code - execute once.
|
||||
} else {
|
||||
// PanicAlert("Not supporting multiple master codes.");
|
||||
}
|
||||
// u8 numOpsPerFrame = (data >> 8) & 0xFF;
|
||||
// Blah, we generally ignore master codes.
|
||||
break;
|
||||
}
|
||||
default: PanicAlert("Unknown Action Replay command %02x (%08x %08x)", cmd, iter->cmd_addr, iter->value); break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (C) 2003-2008 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
struct AREntry {
|
||||
u32 cmd_addr;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
struct ARCode {
|
||||
std::string name;
|
||||
std::vector<AREntry> ops;
|
||||
bool active;
|
||||
};
|
||||
|
||||
extern std::vector<ARCode> arCodes;
|
||||
|
||||
void RunActionReplayCode(const ARCode &arcode, bool nowIsBootup);
|
||||
void LoadActionReplayCodes(IniFile &ini);
|
||||
void DoARSubtype_RamWriteAndFill();
|
||||
void DoARSubtype_WriteToPointer();
|
||||
void DoARSubtype_AddCode();
|
||||
void DoARSubtype_MasterCodeAndWriteToCCXXXXXX();
|
||||
void DoARSubtype_Other();
|
||||
|
|
@ -15,73 +15,29 @@
|
|||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// PatchEngine
|
||||
|
||||
// [Tue Aug 21 2007] [18:30:40] <Knuckles-> 0x802904b4 in US released
|
||||
// [Tue Aug 21 2007] [18:30:53] <Knuckles-> 0x80294d54 in EUR Demo version
|
||||
// [Tue Aug 21 2007] [18:31:10] <Knuckles-> we just patch a blr on it (0x4E800020)
|
||||
// A little present to our dear hacker friends
|
||||
// (A partial Action Replay engine)
|
||||
// And a temporary "solution" to Zelda item glitch...
|
||||
|
||||
// [OnLoad]
|
||||
// 0x80020394=dword,0x4e800020
|
||||
|
||||
// #define BLR_OP 0x4e800020
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "StringUtil.h"
|
||||
#include "PatchEngine.h"
|
||||
#include "IniFile.h"
|
||||
#include "HW/Memmap.h"
|
||||
|
||||
|
||||
enum PatchType
|
||||
{
|
||||
PATCH_8BIT,
|
||||
PATCH_16BIT,
|
||||
PATCH_32BIT,
|
||||
};
|
||||
|
||||
static const char *PatchTypeStrings[] =
|
||||
{
|
||||
"byte",
|
||||
"word",
|
||||
"dword",
|
||||
0
|
||||
};
|
||||
|
||||
|
||||
struct Patch
|
||||
{
|
||||
Patch() {}
|
||||
Patch(PatchType _t, u32 _addr, u32 _value) : type(_t), address(_addr), value(_value) {}
|
||||
PatchType type;
|
||||
u32 address;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
std::vector<Patch> onLoad;
|
||||
std::vector<Patch> onFrame;
|
||||
|
||||
struct AREntry {
|
||||
u32 cmd_addr;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
struct ARCode {
|
||||
std::string name;
|
||||
std::vector<AREntry> ops;
|
||||
bool active;
|
||||
};
|
||||
|
||||
std::vector<ARCode> arCodes;
|
||||
#include "ActionReplay.h"
|
||||
|
||||
using namespace Common;
|
||||
|
||||
void RunActionReplayCode(const ARCode &code, bool nowIsBootup);
|
||||
std::vector<Patch> onLoad;
|
||||
std::vector<Patch> onFrame;
|
||||
|
||||
void LoadPatchSection(const char *section, std::vector<Patch> &patches, IniFile &ini)
|
||||
{
|
||||
|
@ -110,8 +66,6 @@ void LoadPatchSection(const char *section, std::vector<Patch> &patches, IniFile
|
|||
}
|
||||
}
|
||||
|
||||
void LoadActionReplayCodes(IniFile &ini);
|
||||
|
||||
void PatchEngine_LoadPatches(const char *gameID)
|
||||
{
|
||||
IniFile ini;
|
||||
|
@ -156,291 +110,11 @@ void PatchEngine_ApplyFramePatches()
|
|||
{
|
||||
ApplyPatches(onFrame);
|
||||
}
|
||||
|
||||
void PatchEngine_ApplyARPatches()
|
||||
{
|
||||
for (std::vector<ARCode>::const_iterator iter = arCodes.begin(); iter != arCodes.end(); ++iter) {
|
||||
if (iter->active)
|
||||
RunActionReplayCode(*iter, false);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadActionReplayCodes(IniFile &ini)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
ARCode currentCode;
|
||||
arCodes.clear();
|
||||
|
||||
if (!ini.GetLines("ActionReplay", lines))
|
||||
return;
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
|
||||
{
|
||||
std::string line = *iter;
|
||||
|
||||
std::vector<std::string> pieces;
|
||||
SplitString(line, " ", pieces);
|
||||
if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8)
|
||||
{
|
||||
// Smells like a decrypted Action Replay code, great! Decode!
|
||||
AREntry op;
|
||||
bool success = TryParseUInt(std::string("0x") + pieces[0], &op.cmd_addr);
|
||||
success |= TryParseUInt(std::string("0x") + pieces[1], &op.value);
|
||||
if (!success)
|
||||
PanicAlert("Invalid AR code line: %s", line.c_str());
|
||||
else
|
||||
currentCode.ops.push_back(op);
|
||||
}
|
||||
else
|
||||
{
|
||||
SplitString(line, "-", pieces);
|
||||
if (pieces.size() == 3 && pieces[0].size() == 4 && pieces[1].size() == 4 && pieces[2].size() == 5)
|
||||
{
|
||||
// Encrypted AR code
|
||||
PanicAlert("Dolphin does not support encrypted AR codes");
|
||||
}
|
||||
else if (line.size() > 1)
|
||||
{
|
||||
// OK, name line. This is the start of a new code. Push the old one, prepare the new one.
|
||||
if (currentCode.ops.size())
|
||||
arCodes.push_back(currentCode);
|
||||
currentCode.name = "(invalid)";
|
||||
currentCode.ops.clear();
|
||||
|
||||
if (line[0] == '+')
|
||||
{
|
||||
// Active code - name line.
|
||||
line = StripSpaces(line.substr(1));
|
||||
currentCode.name = line;
|
||||
currentCode.active = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Inactive code.
|
||||
currentCode.name = line;
|
||||
currentCode.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the last code correctly.
|
||||
if (currentCode.ops.size())
|
||||
arCodes.push_back(currentCode);
|
||||
}
|
||||
|
||||
// The mechanism is slightly different than what the real AR uses, so there may be compatibility problems.
|
||||
// For example, some authors have created codes that add features to AR. Hacks for popular ones can be added here,
|
||||
// but the problem is not generally solvable.
|
||||
void RunActionReplayCode(const ARCode &code, bool nowIsBootup) {
|
||||
for (std::vector<AREntry>::const_iterator iter = code.ops.begin(); iter != code.ops.end(); ++iter) {
|
||||
u32 cmd_addr = iter->cmd_addr;
|
||||
u8 cmd = iter->cmd_addr>>24;
|
||||
u32 addr = (iter->cmd_addr & 0x01FFFFFF);
|
||||
u32 data = iter->value;
|
||||
u8 z = (cmd >> 4);
|
||||
u8 w = (cmd - ((cmd >> 4) << 4));
|
||||
|
||||
if (addr >= 0x00002000 && addr < 0x00003000) {
|
||||
PanicAlert("This action replay simulator does not support codes that modify Action Replay itself.");
|
||||
return;
|
||||
}
|
||||
|
||||
// End of sequence. Dunno why anybody would use it.
|
||||
if (iter->cmd_addr == 0) {
|
||||
// Special command!
|
||||
if ((data >> 28) == 0x8) { // Fill 'n' slide
|
||||
PanicAlert("Fill'n'slide command not yet supported.");
|
||||
++iter; /*
|
||||
u32 x = data;
|
||||
u32 size = (addr >> 25) & 3;
|
||||
addr &= 0x01FFFFFF;*/
|
||||
}
|
||||
else {
|
||||
if (data == 0x40000000)
|
||||
{
|
||||
// Resume normal execution. Don't need to do anything here.
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("This action replay command (%08x %08x) not yet supported.", cmd_addr, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// skip these weird init lines
|
||||
if (iter == code.ops.begin() && cmd == 1) continue;
|
||||
|
||||
switch(z)
|
||||
{
|
||||
case 0x00: // Ram write (and fill)
|
||||
{
|
||||
if(w < 0x8) // Check the value W in 0xZWXXXXXXX
|
||||
{
|
||||
u32 new_addr = (addr | 0x80000000);
|
||||
switch ((new_addr >> 25) & 0x03)
|
||||
{
|
||||
case 0x00: // Byte write
|
||||
{
|
||||
u8 repeat = data >> 8;
|
||||
for (int i = 0; i <= repeat; i++) {
|
||||
Memory::Write_U8(data & 0xFF, new_addr + i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x01: // Short write
|
||||
{
|
||||
u16 repeat = data >> 16;
|
||||
for (int i = 0; i <= repeat; i++) {
|
||||
Memory::Write_U16(data & 0xFFFF, new_addr + i * 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case 0x02: // Dword write
|
||||
{
|
||||
Memory::Write_U32(data, new_addr);
|
||||
break;
|
||||
}
|
||||
default: break; // TODO(Omega): maybe add a PanicAlert here?
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case 0x04: // Write to pointer
|
||||
{
|
||||
if(w < 0x8)
|
||||
{
|
||||
u32 new_addr = (addr | 0x80000000);
|
||||
switch ((new_addr >> 25) & 0x03)
|
||||
{
|
||||
case 0x00: // Byte write to pointer
|
||||
{
|
||||
u32 ptr = Memory::Read_U32(new_addr);
|
||||
u8 thebyte = data & 0xFF;
|
||||
u32 offset = data >> 8;
|
||||
Memory::Write_U8(thebyte, ptr + offset);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x01: // Short write to pointer
|
||||
{
|
||||
u32 ptr = Memory::Read_U32(new_addr);
|
||||
u16 theshort = data & 0xFFFF;
|
||||
u32 offset = (data >> 16) << 1;
|
||||
Memory::Write_U16(theshort, ptr + offset);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case 0x02: // Dword write to pointer
|
||||
{
|
||||
u32 ptr = Memory::Read_U32(new_addr);
|
||||
Memory::Write_U32(data, ptr);
|
||||
break;
|
||||
}
|
||||
default: break; // TODO(Omega): maybe add a PanicAlert here?
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
{
|
||||
switch (cmd & 0xFE)
|
||||
{
|
||||
case 0x80: // Byte add
|
||||
Memory::Write_U8(Memory::Read_U8(addr) + (data & 0xFF), addr);
|
||||
break;
|
||||
case 0x82: // Short add
|
||||
Memory::Write_U16(Memory::Read_U16(addr) + (data & 0xFFFF), addr);
|
||||
break;
|
||||
case 0x84: // DWord add
|
||||
Memory::Write_U32(Memory::Read_U32(addr) + data, addr);
|
||||
break;
|
||||
case 0x86: // Float add (not working?)
|
||||
{
|
||||
union {
|
||||
u32 u;
|
||||
float f;
|
||||
} fu, d;
|
||||
fu.u = Memory::Read_U32(addr);
|
||||
d.u = data;
|
||||
fu.f += data;
|
||||
Memory::Write_U32(fu.u, addr);
|
||||
break;
|
||||
}
|
||||
case 0x90: if (Memory::Read_U32(addr) == data) return; // IF 32 bit equal, exit
|
||||
case 0x08: // IF 8 bit equal, execute next opcode
|
||||
case 0x48: // (double)
|
||||
{
|
||||
if (Memory::Read_U16(addr) != (data & 0xFFFF)) {
|
||||
if (++iter == code.ops.end()) return;
|
||||
if (cmd == 0x48) if (++iter == code.ops.end()) return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x0A: // IF 16 bit equal, execute next opcode
|
||||
case 0x4A: // (double)
|
||||
{
|
||||
if (Memory::Read_U16(addr) != (data & 0xFFFF)) {
|
||||
if (++iter == code.ops.end()) return;
|
||||
if (cmd == 0x4A) if (++iter == code.ops.end()) return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x0C: // IF 32 bit equal, execute next opcode
|
||||
case 0x4C: // (double)
|
||||
{
|
||||
if (Memory::Read_U32(addr) != data) {
|
||||
if (++iter == code.ops.end()) return;
|
||||
if (cmd == 0x4C) if (++iter == code.ops.end()) return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x10: // IF NOT 8 bit equal, execute next opcode
|
||||
case 0x50: // (double)
|
||||
{
|
||||
if (Memory::Read_U8(addr) == (data & 0xFF)) {
|
||||
if (++iter == code.ops.end()) return;
|
||||
if (cmd == 0x50) if (++iter == code.ops.end()) return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x12: // IF NOT 16 bit equal, execute next opcode
|
||||
case 0x52: // (double)
|
||||
{
|
||||
if (Memory::Read_U16(addr) == (data & 0xFFFF)) {
|
||||
if (++iter == code.ops.end()) return;
|
||||
if (cmd == 0x52) if (++iter == code.ops.end()) return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x14: // IF NOT 32 bit equal, execute next opcode
|
||||
case 0x54: // (double)
|
||||
{
|
||||
if (Memory::Read_U32(addr) == data) {
|
||||
if (++iter == code.ops.end()) return;
|
||||
if (cmd == 0x54) if (++iter == code.ops.end()) return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0xC4: // "Master Code" - configure the AR
|
||||
{
|
||||
u8 number = data & 0xFF;
|
||||
if (number == 0)
|
||||
{
|
||||
// Normal master code - execute once.
|
||||
} else {
|
||||
// PanicAlert("Not supporting multiple master codes.");
|
||||
}
|
||||
// u8 numOpsPerFrame = (data >> 8) & 0xFF;
|
||||
// Blah, we generally ignore master codes.
|
||||
break;
|
||||
}
|
||||
default: PanicAlert("Unknown Action Replay command %02x (%08x %08x)", cmd, iter->cmd_addr, iter->value); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,9 +18,30 @@
|
|||
#ifndef _PATCHENGINE_H
|
||||
#define _PATCHENGINE_H
|
||||
|
||||
// see comments in patchengine.cpp
|
||||
// TODO(ector): Actually call these functions somewhere,
|
||||
// and figure out where to place patch files
|
||||
enum PatchType
|
||||
{
|
||||
PATCH_8BIT,
|
||||
PATCH_16BIT,
|
||||
PATCH_32BIT,
|
||||
};
|
||||
|
||||
static const char *PatchTypeStrings[] =
|
||||
{
|
||||
"byte",
|
||||
"word",
|
||||
"dword",
|
||||
0
|
||||
};
|
||||
|
||||
struct Patch
|
||||
{
|
||||
Patch() {}
|
||||
Patch(PatchType _t, u32 _addr, u32 _value) : type(_t), address(_addr), value(_value) {}
|
||||
PatchType type;
|
||||
u32 address;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
void PatchEngine_LoadPatches(const char *gameID);
|
||||
void PatchEngine_ApplyLoadPatches();
|
||||
void PatchEngine_ApplyFramePatches();
|
||||
|
|
|
@ -9,6 +9,7 @@ files = ["Console.cpp",
|
|||
"Host.cpp",
|
||||
"LogManager.cpp",
|
||||
"MemTools.cpp",
|
||||
"ActionReplay.cpp",
|
||||
"PatchEngine.cpp",
|
||||
"State.cpp",
|
||||
"Tracer.cpp",
|
||||
|
@ -25,7 +26,7 @@ files = ["Console.cpp",
|
|||
# "Debugger/GClibloc.cpp", #Outdated
|
||||
"HW/AudioInterface.cpp",
|
||||
"HW/CommandProcessor.cpp",
|
||||
"HW/CPU.cpp",
|
||||
"HW/CPU.cpp",
|
||||
"HW/CPUCompare.cpp",
|
||||
"HW/DSP.cpp",
|
||||
"HW/DVDInterface.cpp",
|
||||
|
|
Loading…
Reference in New Issue