From 08596c1a24a0a9f2801250eb80dc89fb3942a1db Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Thu, 20 Jul 2023 16:10:32 +0300 Subject: [PATCH] [AR] More opcodes --- include/action_replay.hpp | 2 +- src/core/action_replay.cpp | 106 +++++++++++++++++++++++++++++++++++-- 2 files changed, 102 insertions(+), 6 deletions(-) diff --git a/include/action_replay.hpp b/include/action_replay.hpp index 6c6a8ba2..a7cce230 100644 --- a/include/action_replay.hpp +++ b/include/action_replay.hpp @@ -14,7 +14,7 @@ class ActionReplay { // When an instruction does not specify which offset or data register to use, we use the "active" one // Which is by default #1 and may be changed by certain AR operations - u32 *activeOffset, *activeData; + u32 *activeOffset, *activeData, *activeStorage; // Program counter u32 pc = 0; diff --git a/src/core/action_replay.cpp b/src/core/action_replay.cpp index 65cc1e96..cc3f6d20 100644 --- a/src/core/action_replay.cpp +++ b/src/core/action_replay.cpp @@ -6,6 +6,9 @@ void ActionReplay::reset() { // Default value of storage regs is 0 storage1 = 0; storage2 = 0; + + // TODO: Is the active storage persistent or not? + activeStorage = &storage1; } void ActionReplay::runCheat(const Cheat& cheat) { @@ -33,15 +36,41 @@ u8 ActionReplay::read8(u32 addr) { return mem.read8(addr); } u16 ActionReplay::read16(u32 addr) { return mem.read16(addr); } u32 ActionReplay::read32(u32 addr) { return mem.read32(addr); } -void ActionReplay::write8(u32 addr, u8 value) { mem.write8(addr, value); } -void ActionReplay::write16(u32 addr, u16 value) { mem.write16(addr, value); } -void ActionReplay::write32(u32 addr, u32 value) { mem.write32(addr, value); } +// Some AR cheats seem to want to write to unmapped memory or memory that straight up does not exist + +#define MAKE_WRITE_HANDLER(size) \ + void ActionReplay::write##size(u32 addr, u##size value) { \ + auto pointerWrite = mem.getWritePointer(addr); \ + if (pointerWrite) { \ + *(u##size*)pointerWrite = value; \ + } else { \ + auto pointerRead = mem.getReadPointer(addr); \ + if (pointerRead) { \ + *(u##size*)pointerRead = value; \ + } else { \ + Helpers::warn("AR code tried to write to invalid address: %08X\n", addr); \ + } \ + } \ + } + +MAKE_WRITE_HANDLER(8) +MAKE_WRITE_HANDLER(16) +MAKE_WRITE_HANDLER(32) +#undef MAKE_WRITE_HANDLER void ActionReplay::runInstruction(const Cheat& cheat, u32 instruction) { // Top nibble determines the instruction type const u32 type = instruction >> 28; switch (type) { + // 32-bit write to [XXXXXXX + offset] + case 0x0: { + const u32 baseAddr = Helpers::getBits<0, 28>(instruction); + const u32 value = cheat[pc++]; + write32(baseAddr + *activeOffset, value); + break; + } + // 16-bit write to [XXXXXXX + offset] case 0x1: { const u32 baseAddr = Helpers::getBits<0, 28>(instruction); @@ -50,7 +79,6 @@ void ActionReplay::runInstruction(const Cheat& cheat, u32 instruction) { break; } - // 8-bit write to [XXXXXXX + offset] case 0x2: { const u32 baseAddr = Helpers::getBits<0, 28>(instruction); @@ -74,5 +102,73 @@ void ActionReplay::runInstruction(const Cheat& cheat, u32 instruction) { } void ActionReplay::executeDType(const Cheat& cheat, u32 instruction) { - Helpers::panic("ActionReplay: Unimplemented d-type opcode: %08X", instruction); + switch (instruction) { + case 0xD3000000: offset1 = cheat[pc++]; break; + case 0xD3000001: offset2 = cheat[pc++]; break; + case 0xDC000000: *activeOffset += cheat[pc++]; break; + + // DD000000 XXXXXXXX - if KEYPAD has value XXXXXXXX execute next block + case 0xDD000000: { + const u32 mask = cheat[pc++]; + break; + } + + // Offset register ops + case 0xDF000000: { + const u32 subopcode = cheat[pc++]; + switch (subopcode) { + case 0x00000000: activeOffset = &offset1; break; + case 0x00000001: activeOffset = &offset2; break; + case 0x00010000: offset2 = offset1; break; + case 0x00010001: offset1 = offset2; break; + case 0x00020000: data1 = offset1; break; + case 0x00020001: data2 = offset2; break; + default: + Helpers::warn("Unknown ActionReplay offset operation"); + running = false; + break; + } + break; + } + + // Data register operations + case 0xDF000001: { + const u32 subopcode = cheat[pc++]; + switch (subopcode) { + case 0x00000000: activeData = &data1; break; + case 0x00000001: activeData = &data2; break; + + case 0x00010000: data2 = data1; break; + case 0x00010001: data1 = data2; break; + case 0x00020000: offset1 = data1; break; + case 0x00020001: offset2 = data2; break; + default: + Helpers::warn("Unknown ActionReplay data operation"); + running = false; + break; + } + break; + } + + // Storage register operations + case 0xDF000002: { + const u32 subopcode = cheat[pc++]; + switch (subopcode) { + case 0x00000000: activeStorage = &storage1; break; + case 0x00000001: activeStorage = &storage2; break; + + case 0x00010000: data1 = storage1; break; + case 0x00010001: data2 = storage2; break; + case 0x00020000: storage1 = data1; break; + case 0x00020001: storage2 = data2; break; + default: + Helpers::warn("Unknown ActionReplay data operation"); + running = false; + break; + } + break; + } + + default: Helpers::panic("ActionReplay: Unimplemented d-type opcode: %08X", instruction); break; + } } \ No newline at end of file