diff --git a/include/cheats.hpp b/include/cheats.hpp index 6ada7d20..be370c24 100644 --- a/include/cheats.hpp +++ b/include/cheats.hpp @@ -13,7 +13,7 @@ class Cheats { public: enum class CheatType { ActionReplay, // CTRPF cheats - Gateway, + // TODO: Other cheat devices and standards? }; struct Cheat { diff --git a/src/core/action_replay.cpp b/src/core/action_replay.cpp index ad391b36..e8467425 100644 --- a/src/core/action_replay.cpp +++ b/src/core/action_replay.cpp @@ -29,14 +29,14 @@ void ActionReplay::runCheat(const Cheat& cheat) { } // Fetch instruction const u32 instruction = cheat[pc++]; - + // Instructions D0000000 00000000 and D2000000 00000000 are unconditional bool isUnconditional = cheat[pc] == 0 && (instruction == 0xD0000000 || instruction == 0xD2000000); if (ifStackIndex > 0 && !isUnconditional && !ifStack[ifStackIndex - 1]) { - pc++; // Eat up dummy word - continue; // Skip conditional instructions where the condition is false + pc++; // Eat up dummy word + continue; // Skip conditional instructions where the condition is false } - + runInstruction(cheat, instruction); } } @@ -96,12 +96,37 @@ void ActionReplay::runInstruction(const Cheat& cheat, u32 instruction) { break; } - // Less Than (YYYYYYYY < [XXXXXXX + offset]) - case 0x4: { +// clang-format off + #define MAKE_IF_INSTRUCTION(opcode, comparator) \ + case opcode: { \ + const u32 baseAddr = Helpers::getBits<0, 28>(instruction); \ + const u32 imm = cheat[pc++]; \ + const u32 value = read32(baseAddr + *activeOffset); \ + \ + pushConditionBlock(imm comparator value); \ + break; \ + } + + // Greater Than (YYYYYYYY > [XXXXXXX + offset]) (Unsigned) + MAKE_IF_INSTRUCTION(3, >) + + // Less Than (YYYYYYYY < [XXXXXXX + offset]) (Unsigned) + MAKE_IF_INSTRUCTION(4, <) + + // Equal to (YYYYYYYY == [XXXXXXX + offset]) + MAKE_IF_INSTRUCTION(5, ==) + + // Not Equal (YYYYYYYY != [XXXXXXX + offset]) + MAKE_IF_INSTRUCTION(6, !=) + #undef MAKE_IF_INSTRUCTION +// clang-format on + + // BXXXXXXX 00000000 - offset = *(XXXXXXX + offset) + case 0xB: { const u32 baseAddr = Helpers::getBits<0, 28>(instruction); - const u32 imm = cheat[pc++]; - const u32 value = read32(baseAddr + *activeOffset); - Helpers::panic("TODO: How do ActionReplay conditional blocks work?"); + *activeOffset = read32(baseAddr + *activeOffset); + + pc++; // Eat up dummy word break; } @@ -185,7 +210,7 @@ void ActionReplay::executeDType(const Cheat& cheat, u32 instruction) { case 0xD2000000: { const u32 subopcode = cheat[pc++]; switch (subopcode) { - // Ends all loop/execute blocks + // Ends all loop/execute blocks case 0: loopStackIndex = 0; ifStackIndex = 0; diff --git a/src/core/cheats.cpp b/src/core/cheats.cpp index 4c63652b..8bf5e316 100644 --- a/src/core/cheats.cpp +++ b/src/core/cheats.cpp @@ -17,12 +17,7 @@ void Cheats::run() { break; } - case CheatType::Gateway: { - Helpers::panic("Gateway cheats not supported yet! Only Action Replay is supported!"); - break; - } - - default: Helpers::panic("Unknown cheat type"); + default: Helpers::panic("Unknown cheat device!"); } } } \ No newline at end of file