From a6365c758e910f43a6ad14e51c2724c7045bd111 Mon Sep 17 00:00:00 2001 From: omegadox Date: Wed, 15 Oct 2008 05:57:41 +0000 Subject: [PATCH] Moved all the ActionReplay code into its own source/header file. Also updated the scons and vcproj file to include the added files. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@874 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Core/Core.vcproj | 8 + Source/Core/Core/Src/ActionReplay.cpp | 368 ++++++++++++++++++++++++++ Source/Core/Core/Src/ActionReplay.h | 38 +++ Source/Core/Core/Src/PatchEngine.cpp | 21 +- Source/Core/Core/Src/SConscript | 1 + 5 files changed, 419 insertions(+), 17 deletions(-) create mode 100644 Source/Core/Core/Src/ActionReplay.cpp create mode 100644 Source/Core/Core/Src/ActionReplay.h diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj index 2156cdb892..1d9bc5f678 100644 --- a/Source/Core/Core/Core.vcproj +++ b/Source/Core/Core/Core.vcproj @@ -1192,6 +1192,14 @@ > + + + + diff --git a/Source/Core/Core/Src/ActionReplay.cpp b/Source/Core/Core/Src/ActionReplay.cpp new file mode 100644 index 0000000000..1c4d9c8ab8 --- /dev/null +++ b/Source/Core/Core/Src/ActionReplay.cpp @@ -0,0 +1,368 @@ +// 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 +#include +#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::const_iterator iter; +std::vector arCodes; +ARCode code; + +void LoadActionReplayCodes(IniFile &ini) +{ + std::vector lines; + ARCode currentCode; + arCodes.clear(); + + if (!ini.GetLines("ActionReplay", lines)) return; + + for (std::vector::const_iterator it = lines.begin(); it != lines.end(); ++it) + { + std::string line = *it; + + std::vector 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; + } +} \ No newline at end of file diff --git a/Source/Core/Core/Src/ActionReplay.h b/Source/Core/Core/Src/ActionReplay.h new file mode 100644 index 0000000000..f83a8c6f8b --- /dev/null +++ b/Source/Core/Core/Src/ActionReplay.h @@ -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 ops; + bool active; +}; + +extern std::vector 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(); + diff --git a/Source/Core/Core/Src/PatchEngine.cpp b/Source/Core/Core/Src/PatchEngine.cpp index ea1d2f7fce..20d4f9d0e3 100644 --- a/Source/Core/Core/Src/PatchEngine.cpp +++ b/Source/Core/Core/Src/PatchEngine.cpp @@ -36,6 +36,7 @@ #include "PatchEngine.h" #include "IniFile.h" #include "HW/Memmap.h" +#include "ActionReplay.h" enum PatchType @@ -66,23 +67,8 @@ struct Patch std::vector onLoad; std::vector onFrame; -struct AREntry { - u32 cmd_addr; - u32 value; -}; - -struct ARCode { - std::string name; - std::vector ops; - bool active; -}; - -std::vector arCodes; - using namespace Common; -void RunActionReplayCode(const ARCode &code, bool nowIsBootup); - void LoadPatchSection(const char *section, std::vector &patches, IniFile &ini) { std::vector keys; @@ -110,8 +96,6 @@ void LoadPatchSection(const char *section, std::vector &patches, IniFile } } -void LoadActionReplayCodes(IniFile &ini); - void PatchEngine_LoadPatches(const char *gameID) { IniFile ini; @@ -162,6 +146,8 @@ void PatchEngine_ApplyARPatches() if (iter->active) RunActionReplayCode(*iter, false); } +<<<<<<< .mine +}======= } void LoadActionReplayCodes(IniFile &ini) @@ -444,3 +430,4 @@ void RunActionReplayCode(const ARCode &code, bool nowIsBootup) { } } } +>>>>>>> .r873 diff --git a/Source/Core/Core/Src/SConscript b/Source/Core/Core/Src/SConscript index 27ac56c9e8..253f16f3ab 100644 --- a/Source/Core/Core/Src/SConscript +++ b/Source/Core/Core/Src/SConscript @@ -9,6 +9,7 @@ files = ["Console.cpp", "Host.cpp", "LogManager.cpp", "MemTools.cpp", + "ActionReplay.cpp", "PatchEngine.cpp", "State.cpp", "Tracer.cpp",