summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZach Hilman <zachhilman@gmail.com>2019-09-22 00:13:10 +0200
committerZach Hilman <zachhilman@gmail.com>2019-09-22 03:45:05 +0200
commit682174b1123c5721b12eaf8472da46251fea3b1d (patch)
tree1c368bfb5bb3ff731f3651c833ff8c883d91c2c9
parentcore: Initialize cheats after load to avoid VMManager crash (diff)
downloadyuzu-682174b1123c5721b12eaf8472da46251fea3b1d.tar
yuzu-682174b1123c5721b12eaf8472da46251fea3b1d.tar.gz
yuzu-682174b1123c5721b12eaf8472da46251fea3b1d.tar.bz2
yuzu-682174b1123c5721b12eaf8472da46251fea3b1d.tar.lz
yuzu-682174b1123c5721b12eaf8472da46251fea3b1d.tar.xz
yuzu-682174b1123c5721b12eaf8472da46251fea3b1d.tar.zst
yuzu-682174b1123c5721b12eaf8472da46251fea3b1d.zip
-rw-r--r--src/core/core.cpp3
-rw-r--r--src/core/memory/cheat_engine.cpp6
-rw-r--r--src/core/memory/dmnt_cheat_vm.cpp1496
-rw-r--r--src/core/memory/dmnt_cheat_vm.h227
4 files changed, 862 insertions, 870 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index fc7039421..76bb2bae9 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -17,6 +17,7 @@
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/mode.h"
+#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs_factory.h"
#include "core/file_sys/savedata_factory.h"
@@ -43,8 +44,6 @@
#include "core/settings.h"
#include "core/telemetry_session.h"
#include "core/tools/freezer.h"
-#include "file_sys/cheat_engine.h"
-#include "file_sys/patch_manager.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index ea5c76fc0..b56cb0627 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -102,7 +102,7 @@ std::vector<CheatEntry> TextCheatParser::Parse(const Core::System& system,
std::optional<u64> current_entry = std::nullopt;
for (std::size_t i = 0; i < data.size(); ++i) {
- if (std::isspace(data[i])) {
+ if (::isspace(data[i])) {
continue;
}
@@ -143,7 +143,7 @@ std::vector<CheatEntry> TextCheatParser::Parse(const Core::System& system,
'\0';
i += name.length() + 1;
- } else if (std::isxdigit(data[i])) {
+ } else if (::isxdigit(data[i])) {
if (!current_entry || out[*current_entry].definition.num_opcodes >=
out[*current_entry].definition.opcodes.size()) {
return {};
@@ -188,7 +188,7 @@ CheatEngine::~CheatEngine() {
void CheatEngine::Initialize() {
event = core_timing.RegisterEvent(
- "CheatEngine::FrameCallback::" + Common::HexArrayToString(metadata.main_nso_build_id),
+ "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id),
[this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); });
core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS, event);
diff --git a/src/core/memory/dmnt_cheat_vm.cpp b/src/core/memory/dmnt_cheat_vm.cpp
index a3f450dac..cc16d15a4 100644
--- a/src/core/memory/dmnt_cheat_vm.cpp
+++ b/src/core/memory/dmnt_cheat_vm.cpp
@@ -29,264 +29,272 @@
namespace Memory {
+DmntCheatVm::DmntCheatVm(std::unique_ptr<Callbacks> callbacks) : callbacks(std::move(callbacks)) {}
+
+DmntCheatVm::~DmntCheatVm() = default;
+
void DmntCheatVm::DebugLog(u32 log_id, u64 value) {
callbacks->DebugLog(static_cast<u8>(log_id), value);
}
void DmntCheatVm::LogOpcode(const CheatVmOpcode& opcode) {
- switch (opcode.opcode) {
- case CheatVmOpcodeType_StoreStatic:
- this->LogToDebugFile("Opcode: Store Static\n");
- this->LogToDebugFile("Bit Width: %x\n", opcode.store_static.bit_width);
- this->LogToDebugFile("Mem Type: %x\n", opcode.store_static.mem_type);
- this->LogToDebugFile("Reg Idx: %x\n", opcode.store_static.offset_register);
- this->LogToDebugFile("Rel Addr: %lx\n", opcode.store_static.rel_address);
- this->LogToDebugFile("Value: %lx\n", opcode.store_static.value.bit64);
- break;
- case CheatVmOpcodeType_BeginConditionalBlock:
- this->LogToDebugFile("Opcode: Begin Conditional\n");
- this->LogToDebugFile("Bit Width: %x\n", opcode.begin_cond.bit_width);
- this->LogToDebugFile("Mem Type: %x\n", opcode.begin_cond.mem_type);
- this->LogToDebugFile("Cond Type: %x\n", opcode.begin_cond.cond_type);
- this->LogToDebugFile("Rel Addr: %lx\n", opcode.begin_cond.rel_address);
- this->LogToDebugFile("Value: %lx\n", opcode.begin_cond.value.bit64);
- break;
- case CheatVmOpcodeType_EndConditionalBlock:
- this->LogToDebugFile("Opcode: End Conditional\n");
- break;
- case CheatVmOpcodeType_ControlLoop:
- if (opcode.ctrl_loop.start_loop) {
- this->LogToDebugFile("Opcode: Start Loop\n");
- this->LogToDebugFile("Reg Idx: %x\n", opcode.ctrl_loop.reg_index);
- this->LogToDebugFile("Num Iters: %x\n", opcode.ctrl_loop.num_iters);
+ if (auto store_static = std::get_if<StoreStaticOpcode>(&opcode.opcode)) {
+ callbacks->CommandLog("Opcode: Store Static");
+ callbacks->CommandLog(fmt::format("Bit Width: {:X}", store_static->bit_width));
+ callbacks->CommandLog(
+ fmt::format("Mem Type: {:X}", static_cast<u32>(store_static->mem_type)));
+ callbacks->CommandLog(fmt::format("Reg Idx: {:X}", store_static->offset_register));
+ callbacks->CommandLog(fmt::format("Rel Addr: {:X}", store_static->rel_address));
+ callbacks->CommandLog(fmt::format("Value: {:X}", store_static->value.bit64));
+ } else if (auto begin_cond = std::get_if<BeginConditionalOpcode>(&opcode.opcode)) {
+ callbacks->CommandLog("Opcode: Begin Conditional");
+ callbacks->CommandLog(fmt::format("Bit Width: {:X}", begin_cond->bit_width));
+ callbacks->CommandLog(
+ fmt::format("Mem Type: {:X}", static_cast<u32>(begin_cond->mem_type)));
+ callbacks->CommandLog(
+ fmt::format("Cond Type: {:X}", static_cast<u32>(begin_cond->cond_type)));
+ callbacks->CommandLog(fmt::format("Rel Addr: {:X}", begin_cond->rel_address));
+ callbacks->CommandLog(fmt::format("Value: {:X}", begin_cond->value.bit64));
+ } else if (auto end_cond = std::get_if<EndConditionalOpcode>(&opcode.opcode)) {
+ callbacks->CommandLog("Opcode: End Conditional");
+ } else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&opcode.opcode)) {
+ if (ctrl_loop->start_loop) {
+ callbacks->CommandLog("Opcode: Start Loop");
+ callbacks->CommandLog(fmt::format("Reg Idx: {:X}", ctrl_loop->reg_index));
+ callbacks->CommandLog(fmt::format("Num Iters: {:X}", ctrl_loop->num_iters));
} else {
- this->LogToDebugFile("Opcode: End Loop\n");
- this->LogToDebugFile("Reg Idx: %x\n", opcode.ctrl_loop.reg_index);
+ callbacks->CommandLog("Opcode: End Loop");
+ callbacks->CommandLog(fmt::format("Reg Idx: {:X}", ctrl_loop->reg_index));
}
- break;
- case CheatVmOpcodeType_LoadRegisterStatic:
- this->LogToDebugFile("Opcode: Load Register Static\n");
- this->LogToDebugFile("Reg Idx: %x\n", opcode.ldr_static.reg_index);
- this->LogToDebugFile("Value: %lx\n", opcode.ldr_static.value);
- break;
- case CheatVmOpcodeType_LoadRegisterMemory:
- this->LogToDebugFile("Opcode: Load Register Memory\n");
- this->LogToDebugFile("Bit Width: %x\n", opcode.ldr_memory.bit_width);
- this->LogToDebugFile("Reg Idx: %x\n", opcode.ldr_memory.reg_index);
- this->LogToDebugFile("Mem Type: %x\n", opcode.ldr_memory.mem_type);
- this->LogToDebugFile("From Reg: %d\n", opcode.ldr_memory.load_from_reg);
- this->LogToDebugFile("Rel Addr: %lx\n", opcode.ldr_memory.rel_address);
- break;
- case CheatVmOpcodeType_StoreStaticToAddress:
- this->LogToDebugFile("Opcode: Store Static to Address\n");
- this->LogToDebugFile("Bit Width: %x\n", opcode.str_static.bit_width);
- this->LogToDebugFile("Reg Idx: %x\n", opcode.str_static.reg_index);
- if (opcode.str_static.add_offset_reg) {
- this->LogToDebugFile("O Reg Idx: %x\n", opcode.str_static.offset_reg_index);
+ } else if (auto ldr_static = std::get_if<LoadRegisterStaticOpcode>(&opcode.opcode)) {
+ callbacks->CommandLog("Opcode: Load Register Static");
+ callbacks->CommandLog(fmt::format("Reg Idx: {:X}", ldr_static->reg_index));
+ callbacks->CommandLog(fmt::format("Value: {:X}", ldr_static->value));
+ } else if (auto ldr_memory = std::get_if<LoadRegisterMemoryOpcode>(&opcode.opcode)) {
+ callbacks->CommandLog("Opcode: Load Register Memory");
+ callbacks->CommandLog(fmt::format("Bit Width: {:X}", ldr_memory->bit_width));
+ callbacks->CommandLog(fmt::format("Reg Idx: {:X}", ldr_memory->reg_index));
+ callbacks->CommandLog(
+ fmt::format("Mem Type: {:X}", static_cast<u32>(ldr_memory->mem_type)));
+ callbacks->CommandLog(fmt::format("From Reg: {:d}", ldr_memory->load_from_reg));
+ callbacks->CommandLog(fmt::format("Rel Addr: {:X}", ldr_memory->rel_address));
+ } else if (auto str_static = std::get_if<StoreStaticToAddressOpcode>(&opcode.opcode)) {
+ callbacks->CommandLog("Opcode: Store Static to Address");
+ callbacks->CommandLog(fmt::format("Bit Width: {:X}", str_static->bit_width));
+ callbacks->CommandLog(fmt::format("Reg Idx: {:X}", str_static->reg_index));
+ if (str_static->add_offset_reg) {
+ callbacks->CommandLog(fmt::format("O Reg Idx: {:X}", str_static->offset_reg_index));
}
- this->LogToDebugFile("Incr Reg: %d\n", opcode.str_static.increment_reg);
- this->LogToDebugFile("Value: %lx\n", opcode.str_static.value);
- break;
- case CheatVmOpcodeType_PerformArithmeticStatic:
- this->LogToDebugFile("Opcode: Perform Static Arithmetic\n");
- this->LogToDebugFile("Bit Width: %x\n", opcode.perform_math_static.bit_width);
- this->LogToDebugFile("Reg Idx: %x\n", opcode.perform_math_static.reg_index);
- this->LogToDebugFile("Math Type: %x\n", opcode.perform_math_static.math_type);
- this->LogToDebugFile("Value: %lx\n", opcode.perform_math_static.value);
- break;
- case CheatVmOpcodeType_BeginKeypressConditionalBlock:
- this->LogToDebugFile("Opcode: Begin Keypress Conditional\n");
- this->LogToDebugFile("Key Mask: %x\n", opcode.begin_keypress_cond.key_mask);
- break;
- case CheatVmOpcodeType_PerformArithmeticRegister:
- this->LogToDebugFile("Opcode: Perform Register Arithmetic\n");
- this->LogToDebugFile("Bit Width: %x\n", opcode.perform_math_reg.bit_width);
- this->LogToDebugFile("Dst Idx: %x\n", opcode.perform_math_reg.dst_reg_index);
- this->LogToDebugFile("Src1 Idx: %x\n", opcode.perform_math_reg.src_reg_1_index);
- if (opcode.perform_math_reg.has_immediate) {
- this->LogToDebugFile("Value: %lx\n", opcode.perform_math_reg.value.bit64);
+ callbacks->CommandLog(fmt::format("Incr Reg: {:d}", str_static->increment_reg));
+ callbacks->CommandLog(fmt::format("Value: {:X}", str_static->value));
+ } else if (auto perform_math_static =
+ std::get_if<PerformArithmeticStaticOpcode>(&opcode.opcode)) {
+ callbacks->CommandLog("Opcode: Perform Static Arithmetic");
+ callbacks->CommandLog(fmt::format("Bit Width: {:X}", perform_math_static->bit_width));
+ callbacks->CommandLog(fmt::format("Reg Idx: {:X}", perform_math_static->reg_index));
+ callbacks->CommandLog(
+ fmt::format("Math Type: {:X}", static_cast<u32>(perform_math_static->math_type)));
+ callbacks->CommandLog(fmt::format("Value: {:X}", perform_math_static->value));
+ } else if (auto begin_keypress_cond =
+ std::get_if<BeginKeypressConditionalOpcode>(&opcode.opcode)) {
+ callbacks->CommandLog("Opcode: Begin Keypress Conditional");
+ callbacks->CommandLog(fmt::format("Key Mask: {:X}", begin_keypress_cond->key_mask));
+ } else if (auto perform_math_reg =
+ std::get_if<PerformArithmeticRegisterOpcode>(&opcode.opcode)) {
+ callbacks->CommandLog("Opcode: Perform Register Arithmetic");
+ callbacks->CommandLog(fmt::format("Bit Width: {:X}", perform_math_reg->bit_width));
+ callbacks->CommandLog(fmt::format("Dst Idx: {:X}", perform_math_reg->dst_reg_index));
+ callbacks->CommandLog(fmt::format("Src1 Idx: {:X}", perform_math_reg->src_reg_1_index));
+ if (perform_math_reg->has_immediate) {
+ callbacks->CommandLog(fmt::format("Value: {:X}", perform_math_reg->value.bit64));
} else {
- this->LogToDebugFile("Src2 Idx: %x\n", opcode.perform_math_reg.src_reg_2_index);
+ callbacks->CommandLog(
+ fmt::format("Src2 Idx: {:X}", perform_math_reg->src_reg_2_index));
}
- break;
- case CheatVmOpcodeType_StoreRegisterToAddress:
- this->LogToDebugFile("Opcode: Store Register to Address\n");
- this->LogToDebugFile("Bit Width: %x\n", opcode.str_register.bit_width);
- this->LogToDebugFile("S Reg Idx: %x\n", opcode.str_register.str_reg_index);
- this->LogToDebugFile("A Reg Idx: %x\n", opcode.str_register.addr_reg_index);
- this->LogToDebugFile("Incr Reg: %d\n", opcode.str_register.increment_reg);
- switch (opcode.str_register.ofs_type) {
- case StoreRegisterOffsetType_None:
+ } else if (auto str_register = std::get_if<StoreRegisterToAddressOpcode>(&opcode.opcode)) {
+ callbacks->CommandLog("Opcode: Store Register to Address");
+ callbacks->CommandLog(fmt::format("Bit Width: {:X}", str_register->bit_width));
+ callbacks->CommandLog(fmt::format("S Reg Idx: {:X}", str_register->str_reg_index));
+ callbacks->CommandLog(fmt::format("A Reg Idx: {:X}", str_register->addr_reg_index));
+ callbacks->CommandLog(fmt::format("Incr Reg: {:d}", str_register->increment_reg));
+ switch (str_register->ofs_type) {
+ case StoreRegisterOffsetType::None:
break;
- case StoreRegisterOffsetType_Reg:
- this->LogToDebugFile("O Reg Idx: %x\n", opcode.str_register.ofs_reg_index);
+ case StoreRegisterOffsetType::Reg:
+ callbacks->CommandLog(fmt::format("O Reg Idx: {:X}", str_register->ofs_reg_index));
break;
- case StoreRegisterOffsetType_Imm:
- this->LogToDebugFile("Rel Addr: %lx\n", opcode.str_register.rel_address);
+ case StoreRegisterOffsetType::Imm:
+ callbacks->CommandLog(fmt::format("Rel Addr: {:X}", str_register->rel_address));
break;
- case StoreRegisterOffsetType_MemReg:
- this->LogToDebugFile("Mem Type: %x\n", opcode.str_register.mem_type);
+ case StoreRegisterOffsetType::MemReg:
+ callbacks->CommandLog(
+ fmt::format("Mem Type: {:X}", static_cast<u32>(str_register->mem_type)));
break;
- case StoreRegisterOffsetType_MemImm:
- case StoreRegisterOffsetType_MemImmReg:
- this->LogToDebugFile("Mem Type: %x\n", opcode.str_register.mem_type);
- this->LogToDebugFile("Rel Addr: %lx\n", opcode.str_register.rel_address);
+ case StoreRegisterOffsetType::MemImm:
+ case StoreRegisterOffsetType::MemImmReg:
+ callbacks->CommandLog(
+ fmt::format("Mem Type: {:X}", static_cast<u32>(str_register->mem_type)));
+ callbacks->CommandLog(fmt::format("Rel Addr: {:X}", str_register->rel_address));
break;
}
- break;
- case CheatVmOpcodeType_BeginRegisterConditionalBlock:
- this->LogToDebugFile("Opcode: Begin Register Conditional\n");
- this->LogToDebugFile("Bit Width: %x\n", opcode.begin_reg_cond.bit_width);
- this->LogToDebugFile("Cond Type: %x\n", opcode.begin_reg_cond.cond_type);
- this->LogToDebugFile("V Reg Idx: %x\n", opcode.begin_reg_cond.val_reg_index);
- switch (opcode.begin_reg_cond.comp_type) {
- case CompareRegisterValueType_StaticValue:
- this->LogToDebugFile("Comp Type: Static Value\n");
- this->LogToDebugFile("Value: %lx\n", opcode.begin_reg_cond.value.bit64);
+ } else if (auto begin_reg_cond = std::get_if<BeginRegisterConditionalOpcode>(&opcode.opcode)) {
+ callbacks->CommandLog("Opcode: Begin Register Conditional");
+ callbacks->CommandLog(fmt::format("Bit Width: {:X}", begin_reg_cond->bit_width));
+ callbacks->CommandLog(
+ fmt::format("Cond Type: {:X}", static_cast<u32>(begin_reg_cond->cond_type)));
+ callbacks->CommandLog(fmt::format("V Reg Idx: {:X}", begin_reg_cond->val_reg_index));
+ switch (begin_reg_cond->comp_type) {
+ case CompareRegisterValueType::StaticValue:
+ callbacks->CommandLog("Comp Type: Static Value");
+ callbacks->CommandLog(fmt::format("Value: {:X}", begin_reg_cond->value.bit64));
break;
- case CompareRegisterValueType_OtherRegister:
- this->LogToDebugFile("Comp Type: Other Register\n");
- this->LogToDebugFile("X Reg Idx: %x\n", opcode.begin_reg_cond.other_reg_index);
+ case CompareRegisterValueType::OtherRegister:
+ callbacks->CommandLog("Comp Type: Other Register");
+ callbacks->CommandLog(fmt::format("X Reg Idx: {:X}", begin_reg_cond->other_reg_index));
break;
- case CompareRegisterValueType_MemoryRelAddr:
- this->LogToDebugFile("Comp Type: Memory Relative Address\n");
- this->LogToDebugFile("Mem Type: %x\n", opcode.begin_reg_cond.mem_type);
- this->LogToDebugFile("Rel Addr: %lx\n", opcode.begin_reg_cond.rel_address);
+ case CompareRegisterValueType::MemoryRelAddr:
+ callbacks->CommandLog("Comp Type: Memory Relative Address");
+ callbacks->CommandLog(
+ fmt::format("Mem Type: {:X}", static_cast<u32>(begin_reg_cond->mem_type)));
+ callbacks->CommandLog(fmt::format("Rel Addr: {:X}", begin_reg_cond->rel_address));
break;
- case CompareRegisterValueType_MemoryOfsReg:
- this->LogToDebugFile("Comp Type: Memory Offset Register\n");
- this->LogToDebugFile("Mem Type: %x\n", opcode.begin_reg_cond.mem_type);
- this->LogToDebugFile("O Reg Idx: %x\n", opcode.begin_reg_cond.ofs_reg_index);
+ case CompareRegisterValueType::MemoryOfsReg:
+ callbacks->CommandLog("Comp Type: Memory Offset Register");
+ callbacks->CommandLog(
+ fmt::format("Mem Type: {:X}", static_cast<u32>(begin_reg_cond->mem_type)));
+ callbacks->CommandLog(fmt::format("O Reg Idx: {:X}", begin_reg_cond->ofs_reg_index));
break;
- case CompareRegisterValueType_RegisterRelAddr:
- this->LogToDebugFile("Comp Type: Register Relative Address\n");
- this->LogToDebugFile("A Reg Idx: %x\n", opcode.begin_reg_cond.addr_reg_index);
- this->LogToDebugFile("Rel Addr: %lx\n", opcode.begin_reg_cond.rel_address);
+ case CompareRegisterValueType::RegisterRelAddr:
+ callbacks->CommandLog("Comp Type: Register Relative Address");
+ callbacks->CommandLog(fmt::format("A Reg Idx: {:X}", begin_reg_cond->addr_reg_index));
+ callbacks->CommandLog(fmt::format("Rel Addr: {:X}", begin_reg_cond->rel_address));
break;
- case CompareRegisterValueType_RegisterOfsReg:
- this->LogToDebugFile("Comp Type: Register Offset Register\n");
- this->LogToDebugFile("A Reg Idx: %x\n", opcode.begin_reg_cond.addr_reg_index);
- this->LogToDebugFile("O Reg Idx: %x\n", opcode.begin_reg_cond.ofs_reg_index);
+ case CompareRegisterValueType::RegisterOfsReg:
+ callbacks->CommandLog("Comp Type: Register Offset Register");
+ callbacks->CommandLog(fmt::format("A Reg Idx: {:X}", begin_reg_cond->addr_reg_index));
+ callbacks->CommandLog(fmt::format("O Reg Idx: {:X}", begin_reg_cond->ofs_reg_index));
break;
}
- break;
- case CheatVmOpcodeType_SaveRestoreRegister:
- this->LogToDebugFile("Opcode: Save or Restore Register\n");
- this->LogToDebugFile("Dst Idx: %x\n", opcode.save_restore_reg.dst_index);
- this->LogToDebugFile("Src Idx: %x\n", opcode.save_restore_reg.src_index);
- this->LogToDebugFile("Op Type: %d\n", opcode.save_restore_reg.op_type);
- break;
- case CheatVmOpcodeType_SaveRestoreRegisterMask:
- this->LogToDebugFile("Opcode: Save or Restore Register Mask\n");
- this->LogToDebugFile("Op Type: %d\n", opcode.save_restore_regmask.op_type);
- for (size_t i = 0; i < NumRegisters; i++) {
- this->LogToDebugFile("Act[%02x]: %d\n", i,
- opcode.save_restore_regmask.should_operate[i]);
+ } else if (auto save_restore_reg = std::get_if<SaveRestoreRegisterOpcode>(&opcode.opcode)) {
+ callbacks->CommandLog("Opcode: Save or Restore Register");
+ callbacks->CommandLog(fmt::format("Dst Idx: {:X}", save_restore_reg->dst_index));
+ callbacks->CommandLog(fmt::format("Src Idx: {:X}", save_restore_reg->src_index));
+ callbacks->CommandLog(
+ fmt::format("Op Type: {:d}", static_cast<u32>(save_restore_reg->op_type)));
+ } else if (auto save_restore_regmask =
+ std::get_if<SaveRestoreRegisterMaskOpcode>(&opcode.opcode)) {
+ callbacks->CommandLog("Opcode: Save or Restore Register Mask");
+ callbacks->CommandLog(
+ fmt::format("Op Type: {:d}", static_cast<u32>(save_restore_regmask->op_type)));
+ for (std::size_t i = 0; i < NumRegisters; i++) {
+ callbacks->CommandLog(
+ fmt::format("Act[{:02X}]: {:d}", i, save_restore_regmask->should_operate[i]));
}
- break;
- case CheatVmOpcodeType_DebugLog:
- this->LogToDebugFile("Opcode: Debug Log\n");
- this->LogToDebugFile("Bit Width: %x\n", opcode.debug_log.bit_width);
- this->LogToDebugFile("Log ID: %x\n", opcode.debug_log.log_id);
- this->LogToDebugFile("Val Type: %x\n", opcode.debug_log.val_type);
- switch (opcode.debug_log.val_type) {
- case DebugLogValueType_RegisterValue:
- this->LogToDebugFile("Val Type: Register Value\n");
- this->LogToDebugFile("X Reg Idx: %x\n", opcode.debug_log.val_reg_index);
+ } else if (auto debug_log = std::get_if<DebugLogOpcode>(&opcode.opcode)) {
+ callbacks->CommandLog("Opcode: Debug Log");
+ callbacks->CommandLog(fmt::format("Bit Width: {:X}", debug_log->bit_width));
+ callbacks->CommandLog(fmt::format("Log ID: {:X}", debug_log->log_id));
+ callbacks->CommandLog(
+ fmt::format("Val Type: {:X}", static_cast<u32>(debug_log->val_type)));
+ switch (debug_log->val_type) {
+ case DebugLogValueType::RegisterValue:
+ callbacks->CommandLog("Val Type: Register Value");
+ callbacks->CommandLog(fmt::format("X Reg Idx: {:X}", debug_log->val_reg_index));
break;
- case DebugLogValueType_MemoryRelAddr:
- this->LogToDebugFile("Val Type: Memory Relative Address\n");
- this->LogToDebugFile("Mem Type: %x\n", opcode.debug_log.mem_type);
- this->LogToDebugFile("Rel Addr: %lx\n", opcode.debug_log.rel_address);
+ case DebugLogValueType::MemoryRelAddr:
+ callbacks->CommandLog("Val Type: Memory Relative Address");
+ callbacks->CommandLog(
+ fmt::format("Mem Type: {:X}", static_cast<u32>(debug_log->mem_type)));
+ callbacks->CommandLog(fmt::format("Rel Addr: {:X}", debug_log->rel_address));
break;
- case DebugLogValueType_MemoryOfsReg:
- this->LogToDebugFile("Val Type: Memory Offset Register\n");
- this->LogToDebugFile("Mem Type: %x\n", opcode.debug_log.mem_type);
- this->LogToDebugFile("O Reg Idx: %x\n", opcode.debug_log.ofs_reg_index);
+ case DebugLogValueType::MemoryOfsReg:
+ callbacks->CommandLog("Val Type: Memory Offset Register");
+ callbacks->CommandLog(
+ fmt::format("Mem Type: {:X}", static_cast<u32>(debug_log->mem_type)));
+ callbacks->CommandLog(fmt::format("O Reg Idx: {:X}", debug_log->ofs_reg_index));
break;
- case DebugLogValueType_RegisterRelAddr:
- this->LogToDebugFile("Val Type: Register Relative Address\n");
- this->LogToDebugFile("A Reg Idx: %x\n", opcode.debug_log.addr_reg_index);
- this->LogToDebugFile("Rel Addr: %lx\n", opcode.debug_log.rel_address);
+ case DebugLogValueType::RegisterRelAddr:
+ callbacks->CommandLog("Val Type: Register Relative Address");
+ callbacks->CommandLog(fmt::format("A Reg Idx: {:X}", debug_log->addr_reg_index));
+ callbacks->CommandLog(fmt::format("Rel Addr: {:X}", debug_log->rel_address));
break;
- case DebugLogValueType_RegisterOfsReg:
- this->LogToDebugFile("Val Type: Register Offset Register\n");
- this->LogToDebugFile("A Reg Idx: %x\n", opcode.debug_log.addr_reg_index);
- this->LogToDebugFile("O Reg Idx: %x\n", opcode.debug_log.ofs_reg_index);
+ case DebugLogValueType::RegisterOfsReg:
+ callbacks->CommandLog("Val Type: Register Offset Register");
+ callbacks->CommandLog(fmt::format("A Reg Idx: {:X}", debug_log->addr_reg_index));
+ callbacks->CommandLog(fmt::format("O Reg Idx: {:X}", debug_log->ofs_reg_index));
break;
}
- default:
- this->LogToDebugFile("Unknown opcode: %x\n", opcode.opcode);
- break;
+ } else if (auto instr = std::get_if<UnrecognizedInstruction>(&opcode.opcode)) {
+ callbacks->CommandLog(fmt::format("Unknown opcode: {:X}", static_cast<u32>(instr->opcode)));
}
}
DmntCheatVm::Callbacks::~Callbacks() = default;
bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
- /* If we've ever seen a decode failure, return false. */
- bool valid = this->decode_success;
+ // If we've ever seen a decode failure, return false.
+ bool valid = decode_success;
CheatVmOpcode opcode = {};
SCOPE_EXIT({
- this->decode_success &= valid;
+ decode_success &= valid;
if (valid) {
out = opcode;
}
});
- /* Helper function for getting instruction dwords. */
- auto GetNextDword = [&]() {
- if (this->instruction_ptr >= this->num_opcodes) {
+ // Helper function for getting instruction dwords.
+ const auto GetNextDword = [&] {
+ if (instruction_ptr >= num_opcodes) {
valid = false;
return static_cast<u32>(0);
}
- return this->program[this->instruction_ptr++];
+ return program[instruction_ptr++];
};
- /* Helper function for parsing a VmInt. */
- auto GetNextVmInt = [&](const u32 bit_width) {
- VmInt val = {0};
+ // Helper function for parsing a VmInt.
+ const auto GetNextVmInt = [&](const u32 bit_width) {
+ VmInt val{};
const u32 first_dword = GetNextDword();
switch (bit_width) {
case 1:
- val.bit8 = (u8)first_dword;
+ val.bit8 = static_cast<u8>(first_dword);
break;
case 2:
- val.bit16 = (u16)first_dword;
+ val.bit16 = static_cast<u16>(first_dword);
break;
case 4:
val.bit32 = first_dword;
break;
case 8:
- val.bit64 = (((u64)first_dword) << 32ul) | ((u64)GetNextDword());
+ val.bit64 = (static_cast<u64>(first_dword) << 32ul) | static_cast<u64>(GetNextDword());
break;
}
return val;
};
- /* Read opcode. */
+ // Read opcode.
const u32 first_dword = GetNextDword();
if (!valid) {
return valid;
}
- opcode.opcode = (CheatVmOpcodeType)(((first_dword >> 28) & 0xF));
- if (opcode.opcode >= CheatVmOpcodeType_ExtendedWidth) {
- opcode.opcode =
- (CheatVmOpcodeType)((((u32)opcode.opcode) << 4) | ((first_dword >> 24) & 0xF));
+ auto opcode_type = static_cast<CheatVmOpcodeType>(((first_dword >> 28) & 0xF));
+ if (opcode_type >= CheatVmOpcodeType::ExtendedWidth) {
+ opcode_type = static_cast<CheatVmOpcodeType>((static_cast<u32>(opcode_type) << 4) |
+ ((first_dword >> 24) & 0xF));
}
- if (opcode.opcode >= CheatVmOpcodeType_DoubleExtendedWidth) {
- opcode.opcode =
- (CheatVmOpcodeType)((((u32)opcode.opcode) << 4) | ((first_dword >> 20) & 0xF));
+ if (opcode_type >= CheatVmOpcodeType::DoubleExtendedWidth) {
+ opcode_type = static_cast<CheatVmOpcodeType>((static_cast<u32>(opcode_type) << 4) |
+ ((first_dword >> 20) & 0xF));
}
- /* detect condition start. */
- switch (opcode.opcode) {
- case CheatVmOpcodeType_BeginConditionalBlock:
- case CheatVmOpcodeType_BeginKeypressConditionalBlock:
- case CheatVmOpcodeType_BeginRegisterConditionalBlock:
+ // detect condition start.
+ switch (opcode_type) {
+ case CheatVmOpcodeType::BeginConditionalBlock:
+ case CheatVmOpcodeType::BeginKeypressConditionalBlock:
+ case CheatVmOpcodeType::BeginRegisterConditionalBlock:
opcode.begin_conditional_block = true;
break;
default:
@@ -294,299 +302,335 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
break;
}
- switch (opcode.opcode) {
- case CheatVmOpcodeType_StoreStatic: {
- /* 0TMR00AA AAAAAAAA YYYYYYYY (YYYYYYYY) */
- /* Read additional words. */
+ switch (opcode_type) {
+ case CheatVmOpcodeType::StoreStatic: {
+ StoreStaticOpcode store_static{};
+ // 0TMR00AA AAAAAAAA YYYYYYYY (YYYYYYYY)
+ // Read additional words.
const u32 second_dword = GetNextDword();
- opcode.store_static.bit_width = (first_dword >> 24) & 0xF;
- opcode.store_static.mem_type = (MemoryAccessType)((first_dword >> 20) & 0xF);
- opcode.store_static.offset_register = ((first_dword >> 16) & 0xF);
- opcode.store_static.rel_address = ((u64)(first_dword & 0xFF) << 32ul) | ((u64)second_dword);
- opcode.store_static.value = GetNextVmInt(opcode.store_static.bit_width);
+ store_static.bit_width = (first_dword >> 24) & 0xF;
+ store_static.mem_type = static_cast<MemoryAccessType>((first_dword >> 20) & 0xF);
+ store_static.offset_register = ((first_dword >> 16) & 0xF);
+ store_static.rel_address =
+ (static_cast<u64>(first_dword & 0xFF) << 32ul) | static_cast<u64>(second_dword);
+ store_static.value = GetNextVmInt(store_static.bit_width);
+ opcode.opcode = store_static;
} break;
- case CheatVmOpcodeType_BeginConditionalBlock: {
- /* 1TMC00AA AAAAAAAA YYYYYYYY (YYYYYYYY) */
- /* Read additional words. */
+ case CheatVmOpcodeType::BeginConditionalBlock: {
+ BeginConditionalOpcode begin_cond{};
+ // 1TMC00AA AAAAAAAA YYYYYYYY (YYYYYYYY)
+ // Read additional words.
const u32 second_dword = GetNextDword();
- opcode.begin_cond.bit_width = (first_dword >> 24) & 0xF;
- opcode.begin_cond.mem_type = (MemoryAccessType)((first_dword >> 20) & 0xF);
- opcode.begin_cond.cond_type = (ConditionalComparisonType)((first_dword >> 16) & 0xF);
- opcode.begin_cond.rel_address = ((u64)(first_dword & 0xFF) << 32ul) | ((u64)second_dword);
- opcode.begin_cond.value = GetNextVmInt(opcode.store_static.bit_width);
+ begin_cond.bit_width = (first_dword >> 24) & 0xF;
+ begin_cond.mem_type = static_cast<MemoryAccessType>((first_dword >> 20) & 0xF);
+ begin_cond.cond_type = static_cast<ConditionalComparisonType>((first_dword >> 16) & 0xF);
+ begin_cond.rel_address =
+ (static_cast<u64>(first_dword & 0xFF) << 32ul) | static_cast<u64>(second_dword);
+ begin_cond.value = GetNextVmInt(begin_cond.bit_width);
+ opcode.opcode = begin_cond;
} break;
- case CheatVmOpcodeType_EndConditionalBlock: {
- /* 20000000 */
- /* There's actually nothing left to process here! */
+ case CheatVmOpcodeType::EndConditionalBlock: {
+ // 20000000
+ // There's actually nothing left to process here!
+ opcode.opcode = EndConditionalOpcode{};
} break;
- case CheatVmOpcodeType_ControlLoop: {
- /* 300R0000 VVVVVVVV */
- /* 310R0000 */
- /* Parse register, whether loop start or loop end. */
- opcode.ctrl_loop.start_loop = ((first_dword >> 24) & 0xF) == 0;
- opcode.ctrl_loop.reg_index = ((first_dword >> 20) & 0xF);
+ case CheatVmOpcodeType::ControlLoop: {
+ ControlLoopOpcode ctrl_loop{};
+ // 300R0000 VVVVVVVV
+ // 310R0000
+ // Parse register, whether loop start or loop end.
+ ctrl_loop.start_loop = ((first_dword >> 24) & 0xF) == 0;
+ ctrl_loop.reg_index = ((first_dword >> 20) & 0xF);
- /* Read number of iters if loop start. */
- if (opcode.ctrl_loop.start_loop) {
- opcode.ctrl_loop.num_iters = GetNextDword();
+ // Read number of iters if loop start.
+ if (ctrl_loop.start_loop) {
+ ctrl_loop.num_iters = GetNextDword();
}
+ opcode.opcode = ctrl_loop;
} break;
- case CheatVmOpcodeType_LoadRegisterStatic: {
- /* 400R0000 VVVVVVVV VVVVVVVV */
- /* Read additional words. */
- opcode.ldr_static.reg_index = ((first_dword >> 16) & 0xF);
- opcode.ldr_static.value = (((u64)GetNextDword()) << 32ul) | ((u64)GetNextDword());
+ case CheatVmOpcodeType::LoadRegisterStatic: {
+ LoadRegisterStaticOpcode ldr_static{};
+ // 400R0000 VVVVVVVV VVVVVVVV
+ // Read additional words.
+ ldr_static.reg_index = ((first_dword >> 16) & 0xF);
+ ldr_static.value =
+ (static_cast<u64>(GetNextDword()) << 32ul) | static_cast<u64>(GetNextDword());
+ opcode.opcode = ldr_static;
} break;
- case CheatVmOpcodeType_LoadRegisterMemory: {
- /* 5TMRI0AA AAAAAAAA */
- /* Read additional words. */
+ case CheatVmOpcodeType::LoadRegisterMemory: {
+ LoadRegisterMemoryOpcode ldr_memory{};
+ // 5TMRI0AA AAAAAAAA
+ // Read additional words.
const u32 second_dword = GetNextDword();
- opcode.ldr_memory.bit_width = (first_dword >> 24) & 0xF;
- opcode.ldr_memory.mem_type = (MemoryAccessType)((first_dword >> 20) & 0xF);
- opcode.ldr_memory.reg_index = ((first_dword >> 16) & 0xF);
- opcode.ldr_memory.load_from_reg = ((first_dword >> 12) & 0xF) != 0;
- opcode.ldr_memory.rel_address = ((u64)(first_dword & 0xFF) << 32ul) | ((u64)second_dword);
+ ldr_memory.bit_width = (first_dword >> 24) & 0xF;
+ ldr_memory.mem_type = static_cast<MemoryAccessType>((first_dword >> 20) & 0xF);
+ ldr_memory.reg_index = ((first_dword >> 16) & 0xF);
+ ldr_memory.load_from_reg = ((first_dword >> 12) & 0xF) != 0;
+ ldr_memory.rel_address =
+ (static_cast<u64>(first_dword & 0xFF) << 32ul) | static_cast<u64>(second_dword);
+ opcode.opcode = ldr_memory;
} break;
- case CheatVmOpcodeType_StoreStaticToAddress: {
- /* 6T0RIor0 VVVVVVVV VVVVVVVV */
- /* Read additional words. */
- opcode.str_static.bit_width = (first_dword >> 24) & 0xF;
- opcode.str_static.reg_index = ((first_dword >> 16) & 0xF);
- opcode.str_static.increment_reg = ((first_dword >> 12) & 0xF) != 0;
- opcode.str_static.add_offset_reg = ((first_dword >> 8) & 0xF) != 0;
- opcode.str_static.offset_reg_index = ((first_dword >> 4) & 0xF);
- opcode.str_static.value = (((u64)GetNextDword()) << 32ul) | ((u64)GetNextDword());
+ case CheatVmOpcodeType::StoreStaticToAddress: {
+ StoreStaticToAddressOpcode str_static{};
+ // 6T0RIor0 VVVVVVVV VVVVVVVV
+ // Read additional words.
+ str_static.bit_width = (first_dword >> 24) & 0xF;
+ str_static.reg_index = ((first_dword >> 16) & 0xF);
+ str_static.increment_reg = ((first_dword >> 12) & 0xF) != 0;
+ str_static.add_offset_reg = ((first_dword >> 8) & 0xF) != 0;
+ str_static.offset_reg_index = ((first_dword >> 4) & 0xF);
+ str_static.value =
+ (static_cast<u64>(GetNextDword()) << 32ul) | static_cast<u64>(GetNextDword());
+ opcode.opcode = str_static;
} break;
- case CheatVmOpcodeType_PerformArithmeticStatic: {
- /* 7T0RC000 VVVVVVVV */
- /* Read additional words. */
- opcode.perform_math_static.bit_width = (first_dword >> 24) & 0xF;
- opcode.perform_math_static.reg_index = ((first_dword >> 16) & 0xF);
- opcode.perform_math_static.math_type = (RegisterArithmeticType)((first_dword >> 12) & 0xF);
- opcode.perform_math_static.value = GetNextDword();
+ case CheatVmOpcodeType::PerformArithmeticStatic: {
+ PerformArithmeticStaticOpcode perform_math_static{};
+ // 7T0RC000 VVVVVVVV
+ // Read additional words.
+ perform_math_static.bit_width = (first_dword >> 24) & 0xF;
+ perform_math_static.reg_index = ((first_dword >> 16) & 0xF);
+ perform_math_static.math_type =
+ static_cast<RegisterArithmeticType>((first_dword >> 12) & 0xF);
+ perform_math_static.value = GetNextDword();
+ opcode.opcode = perform_math_static;
} break;
- case CheatVmOpcodeType_BeginKeypressConditionalBlock: {
- /* 8kkkkkkk */
- /* Just parse the mask. */
- opcode.begin_keypress_cond.key_mask = first_dword & 0x0FFFFFFF;
+ case CheatVmOpcodeType::BeginKeypressConditionalBlock: {
+ BeginKeypressConditionalOpcode begin_keypress_cond{};
+ // 8kkkkkkk
+ // Just parse the mask.
+ begin_keypress_cond.key_mask = first_dword & 0x0FFFFFFF;
} break;
- case CheatVmOpcodeType_PerformArithmeticRegister: {
- /* 9TCRSIs0 (VVVVVVVV (VVVVVVVV)) */
- opcode.perform_math_reg.bit_width = (first_dword >> 24) & 0xF;
- opcode.perform_math_reg.math_type = (RegisterArithmeticType)((first_dword >> 20) & 0xF);
- opcode.perform_math_reg.dst_reg_index = ((first_dword >> 16) & 0xF);
- opcode.perform_math_reg.src_reg_1_index = ((first_dword >> 12) & 0xF);
- opcode.perform_math_reg.has_immediate = ((first_dword >> 8) & 0xF) != 0;
- if (opcode.perform_math_reg.has_immediate) {
- opcode.perform_math_reg.src_reg_2_index = 0;
- opcode.perform_math_reg.value = GetNextVmInt(opcode.perform_math_reg.bit_width);
+ case CheatVmOpcodeType::PerformArithmeticRegister: {
+ PerformArithmeticRegisterOpcode perform_math_reg{};
+ // 9TCRSIs0 (VVVVVVVV (VVVVVVVV))
+ perform_math_reg.bit_width = (first_dword >> 24) & 0xF;
+ perform_math_reg.math_type = static_cast<RegisterArithmeticType>((first_dword >> 20) & 0xF);
+ perform_math_reg.dst_reg_index = ((first_dword >> 16) & 0xF);
+ perform_math_reg.src_reg_1_index = ((first_dword >> 12) & 0xF);
+ perform_math_reg.has_immediate = ((first_dword >> 8) & 0xF) != 0;
+ if (perform_math_reg.has_immediate) {
+ perform_math_reg.src_reg_2_index = 0;
+ perform_math_reg.value = GetNextVmInt(perform_math_reg.bit_width);
} else {
- opcode.perform_math_reg.src_reg_2_index = ((first_dword >> 4) & 0xF);
+ perform_math_reg.src_reg_2_index = ((first_dword >> 4) & 0xF);
}
+ opcode.opcode = perform_math_reg;
} break;
- case CheatVmOpcodeType_StoreRegisterToAddress: {
- /* ATSRIOxa (aaaaaaaa) */
- /* A = opcode 10 */
- /* T = bit width */
- /* S = src register index */
- /* R = address register index */
- /* I = 1 if increment address register, 0 if not increment address register */
- /* O = offset type, 0 = None, 1 = Register, 2 = Immediate, 3 = Memory Region,
- 4 = Memory Region + Relative Address (ignore address register), 5 = Memory Region +
- Relative Address */
- /* x = offset register (for offset type 1), memory type (for offset type 3) */
- /* a = relative address (for offset type 2+3) */
- opcode.str_register.bit_width = (first_dword >> 24) & 0xF;
- opcode.str_register.str_reg_index = ((first_dword >> 20) & 0xF);
- opcode.str_register.addr_reg_index = ((first_dword >> 16) & 0xF);
- opcode.str_register.increment_reg = ((first_dword >> 12) & 0xF) != 0;
- opcode.str_register.ofs_type = (StoreRegisterOffsetType)(((first_dword >> 8) & 0xF));
- opcode.str_register.ofs_reg_index = ((first_dword >> 4) & 0xF);
- switch (opcode.str_register.ofs_type) {
- case StoreRegisterOffsetType_None:
- case StoreRegisterOffsetType_Reg:
- /* Nothing more to do */
+ case CheatVmOpcodeType::StoreRegisterToAddress: {
+ StoreRegisterToAddressOpcode str_register{};
+ // ATSRIOxa (aaaaaaaa)
+ // A = opcode 10
+ // T = bit width
+ // S = src register index
+ // R = address register index
+ // I = 1 if increment address register, 0 if not increment address register
+ // O = offset type, 0 = None, 1 = Register, 2 = Immediate, 3 = Memory Region,
+ // 4 = Memory Region + Relative Address (ignore address register), 5 = Memory Region +
+ // Relative Address
+ // x = offset register (for offset type 1), memory type (for offset type 3)
+ // a = relative address (for offset type 2+3)
+ str_register.bit_width = (first_dword >> 24) & 0xF;
+ str_register.str_reg_index = ((first_dword >> 20) & 0xF);
+ str_register.addr_reg_index = ((first_dword >> 16) & 0xF);
+ str_register.increment_reg = ((first_dword >> 12) & 0xF) != 0;
+ str_register.ofs_type = static_cast<StoreRegisterOffsetType>(((first_dword >> 8) & 0xF));
+ str_register.ofs_reg_index = ((first_dword >> 4) & 0xF);
+ switch (str_register.ofs_type) {
+ case StoreRegisterOffsetType::None:
+ case StoreRegisterOffsetType::Reg:
+ // Nothing more to do
break;
- case StoreRegisterOffsetType_Imm:
- opcode.str_register.rel_address =
- (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
+ case StoreRegisterOffsetType::Imm:
+ str_register.rel_address =
+ ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
break;
- case StoreRegisterOffsetType_MemReg:
- opcode.str_register.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
+ case StoreRegisterOffsetType::MemReg:
+ str_register.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
break;
- case StoreRegisterOffsetType_MemImm:
- case StoreRegisterOffsetType_MemImmReg:
- opcode.str_register.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
- opcode.str_register.rel_address =
- (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
+ case StoreRegisterOffsetType::MemImm:
+ case StoreRegisterOffsetType::MemImmReg:
+ str_register.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
+ str_register.rel_address =
+ ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
break;
default:
- opcode.str_register.ofs_type = StoreRegisterOffsetType_None;
+ str_register.ofs_type = StoreRegisterOffsetType::None;
break;
}
+ opcode.opcode = str_register;
} break;
- case CheatVmOpcodeType_BeginRegisterConditionalBlock: {
- /* C0TcSX## */
- /* C0TcS0Ma aaaaaaaa */
- /* C0TcS1Mr */
- /* C0TcS2Ra aaaaaaaa */
- /* C0TcS3Rr */
- /* C0TcS400 VVVVVVVV (VVVVVVVV) */
- /* C0TcS5X0 */
- /* C0 = opcode 0xC0 */
- /* T = bit width */
- /* c = condition type. */
- /* S = source register. */
- /* X = value operand type, 0 = main/heap with relative offset, 1 = main/heap with offset
- * register, */
- /* 2 = register with relative offset, 3 = register with offset register, 4 = static
- * value, 5 = other register. */
- /* M = memory type. */
- /* R = address register. */
- /* a = relative address. */
- /* r = offset register. */
- /* X = other register. */
- /* V = value. */
- opcode.begin_reg_cond.bit_width = (first_dword >> 20) & 0xF;
- opcode.begin_reg_cond.cond_type = (ConditionalComparisonType)((first_dword >> 16) & 0xF);
- opcode.begin_reg_cond.val_reg_index = ((first_dword >> 12) & 0xF);
- opcode.begin_reg_cond.comp_type = (CompareRegisterValueType)((first_dword >> 8) & 0xF);
+ case CheatVmOpcodeType::BeginRegisterConditionalBlock: {
+ BeginRegisterConditionalOpcode begin_reg_cond{};
+ // C0TcSX##
+ // C0TcS0Ma aaaaaaaa
+ // C0TcS1Mr
+ // C0TcS2Ra aaaaaaaa
+ // C0TcS3Rr
+ // C0TcS400 VVVVVVVV (VVVVVVVV)
+ // C0TcS5X0
+ // C0 = opcode 0xC0
+ // T = bit width
+ // c = condition type.
+ // S = source register.
+ // X = value operand type, 0 = main/heap with relative offset, 1 = main/heap with offset
+ // register,
+ // 2 = register with relative offset, 3 = register with offset register, 4 = static
+ // value, 5 = other register.
+ // M = memory type.
+ // R = address register.
+ // a = relative address.
+ // r = offset register.
+ // X = other register.
+ // V = value.
+ begin_reg_cond.bit_width = (first_dword >> 20) & 0xF;
+ begin_reg_cond.cond_type =
+ static_cast<ConditionalComparisonType>((first_dword >> 16) & 0xF);
+ begin_reg_cond.val_reg_index = ((first_dword >> 12) & 0xF);
+ begin_reg_cond.comp_type = static_cast<CompareRegisterValueType>((first_dword >> 8) & 0xF);
- switch (opcode.begin_reg_cond.comp_type) {
- case CompareRegisterValueType_StaticValue:
- opcode.begin_reg_cond.value = GetNextVmInt(opcode.begin_reg_cond.bit_width);
+ switch (begin_reg_cond.comp_type) {
+ case CompareRegisterValueType::StaticValue:
+ begin_reg_cond.value = GetNextVmInt(begin_reg_cond.bit_width);
break;
- case CompareRegisterValueType_OtherRegister:
- opcode.begin_reg_cond.other_reg_index = ((first_dword >> 4) & 0xF);
+ case CompareRegisterValueType::OtherRegister:
+ begin_reg_cond.other_reg_index = ((first_dword >> 4) & 0xF);
break;
- case CompareRegisterValueType_MemoryRelAddr:
- opcode.begin_reg_cond.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
- opcode.begin_reg_cond.rel_address =
- (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
+ case CompareRegisterValueType::MemoryRelAddr:
+ begin_reg_cond.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
+ begin_reg_cond.rel_address =
+ ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
break;
- case CompareRegisterValueType_MemoryOfsReg:
- opcode.begin_reg_cond.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
- opcode.begin_reg_cond.ofs_reg_index = (first_dword & 0xF);
+ case CompareRegisterValueType::MemoryOfsReg:
+ begin_reg_cond.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
+ begin_reg_cond.ofs_reg_index = (first_dword & 0xF);
break;
- case CompareRegisterValueType_RegisterRelAddr:
- opcode.begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF);
- opcode.begin_reg_cond.rel_address =
- (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
+ case CompareRegisterValueType::RegisterRelAddr:
+ begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF);
+ begin_reg_cond.rel_address =
+ ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
break;
- case CompareRegisterValueType_RegisterOfsReg:
- opcode.begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF);
- opcode.begin_reg_cond.ofs_reg_index = (first_dword & 0xF);
+ case CompareRegisterValueType::RegisterOfsReg:
+ begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF);
+ begin_reg_cond.ofs_reg_index = (first_dword & 0xF);
break;
}
+ opcode.opcode = begin_reg_cond;
} break;
- case CheatVmOpcodeType_SaveRestoreRegister: {
- /* C10D0Sx0 */
- /* C1 = opcode 0xC1 */
- /* D = destination index. */
- /* S = source index. */
- /* x = 3 if clearing reg, 2 if clearing saved value, 1 if saving a register, 0 if restoring
- * a register. */
- /* NOTE: If we add more save slots later, current encoding is backwards compatible. */
- opcode.save_restore_reg.dst_index = (first_dword >> 16) & 0xF;
- opcode.save_restore_reg.src_index = (first_dword >> 8) & 0xF;
- opcode.save_restore_reg.op_type = (SaveRestoreRegisterOpType)((first_dword >> 4) & 0xF);
+ case CheatVmOpcodeType::SaveRestoreRegister: {
+ SaveRestoreRegisterOpcode save_restore_reg{};
+ // C10D0Sx0
+ // C1 = opcode 0xC1
+ // D = destination index.
+ // S = source index.
+ // x = 3 if clearing reg, 2 if clearing saved value, 1 if saving a register, 0 if restoring
+ // a register.
+ // NOTE: If we add more save slots later, current encoding is backwards compatible.
+ save_restore_reg.dst_index = (first_dword >> 16) & 0xF;
+ save_restore_reg.src_index = (first_dword >> 8) & 0xF;
+ save_restore_reg.op_type = static_cast<SaveRestoreRegisterOpType>((first_dword >> 4) & 0xF);
+ opcode.opcode = save_restore_reg;
} break;
- case CheatVmOpcodeType_SaveRestoreRegisterMask: {
- /* C2x0XXXX */
- /* C2 = opcode 0xC2 */
- /* x = 3 if clearing reg, 2 if clearing saved value, 1 if saving, 0 if restoring. */
- /* X = 16-bit bitmask, bit i --> save or restore register i. */
- opcode.save_restore_regmask.op_type =
- (SaveRestoreRegisterOpType)((first_dword >> 20) & 0xF);
- for (size_t i = 0; i < NumRegisters; i++) {
- opcode.save_restore_regmask.should_operate[i] = (first_dword & (1u << i)) != 0;
+ case CheatVmOpcodeType::SaveRestoreRegisterMask: {
+ SaveRestoreRegisterMaskOpcode save_restore_regmask{};
+ // C2x0XXXX
+ // C2 = opcode 0xC2
+ // x = 3 if clearing reg, 2 if clearing saved value, 1 if saving, 0 if restoring.
+ // X = 16-bit bitmask, bit i --> save or restore register i.
+ save_restore_regmask.op_type =
+ static_cast<SaveRestoreRegisterOpType>((first_dword >> 20) & 0xF);
+ for (std::size_t i = 0; i < NumRegisters; i++) {
+ save_restore_regmask.should_operate[i] = (first_dword & (1u << i)) != 0;
}
+ opcode.opcode = save_restore_regmask;
} break;
- case CheatVmOpcodeType_DebugLog: {
- /* FFFTIX## */
- /* FFFTI0Ma aaaaaaaa */
- /* FFFTI1Mr */
- /* FFFTI2Ra aaaaaaaa */
- /* FFFTI3Rr */
- /* FFFTI4X0 */
- /* FFF = opcode 0xFFF */
- /* T = bit width. */
- /* I = log id. */
- /* X = value operand type, 0 = main/heap with relative offset, 1 = main/heap with offset
- * register, */
- /* 2 = register with relative offset, 3 = register with offset register, 4 = register
- * value. */
- /* M = memory type. */
- /* R = address register. */
- /* a = relative address. */
- /* r = offset register. */
- /* X = value register. */
- opcode.debug_log.bit_width = (first_dword >> 16) & 0xF;
- opcode.debug_log.log_id = ((first_dword >> 12) & 0xF);
- opcode.debug_log.val_type = (DebugLogValueType)((first_dword >> 8) & 0xF);
+ case CheatVmOpcodeType::DebugLog: {
+ DebugLogOpcode debug_log{};
+ // FFFTIX##
+ // FFFTI0Ma aaaaaaaa
+ // FFFTI1Mr
+ // FFFTI2Ra aaaaaaaa
+ // FFFTI3Rr
+ // FFFTI4X0
+ // FFF = opcode 0xFFF
+ // T = bit width.
+ // I = log id.
+ // X = value operand type, 0 = main/heap with relative offset, 1 = main/heap with offset
+ // register,
+ // 2 = register with relative offset, 3 = register with offset register, 4 = register
+ // value.
+ // M = memory type.
+ // R = address register.
+ // a = relative address.
+ // r = offset register.
+ // X = value register.
+ debug_log.bit_width = (first_dword >> 16) & 0xF;
+ debug_log.log_id = ((first_dword >> 12) & 0xF);
+ debug_log.val_type = static_cast<DebugLogValueType>((first_dword >> 8) & 0xF);
- switch (opcode.debug_log.val_type) {
- case DebugLogValueType_RegisterValue:
- opcode.debug_log.val_reg_index = ((first_dword >> 4) & 0xF);
+ switch (debug_log.val_type) {
+ case DebugLogValueType::RegisterValue:
+ debug_log.val_reg_index = ((first_dword >> 4) & 0xF);
break;
- case DebugLogValueType_MemoryRelAddr:
- opcode.debug_log.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
- opcode.debug_log.rel_address =
- (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
+ case DebugLogValueType::MemoryRelAddr:
+ debug_log.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
+ debug_log.rel_address =
+ ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
break;
- case DebugLogValueType_MemoryOfsReg:
- opcode.debug_log.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
- opcode.debug_log.ofs_reg_index = (first_dword & 0xF);
+ case DebugLogValueType::MemoryOfsReg:
+ debug_log.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
+ debug_log.ofs_reg_index = (first_dword & 0xF);
break;
- case DebugLogValueType_RegisterRelAddr:
- opcode.debug_log.addr_reg_index = ((first_dword >> 4) & 0xF);
- opcode.debug_log.rel_address =
- (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
+ case DebugLogValueType::RegisterRelAddr:
+ debug_log.addr_reg_index = ((first_dword >> 4) & 0xF);
+ debug_log.rel_address =
+ ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
break;
- case DebugLogValueType_RegisterOfsReg:
- opcode.debug_log.addr_reg_index = ((first_dword >> 4) & 0xF);
- opcode.debug_log.ofs_reg_index = (first_dword & 0xF);
+ case DebugLogValueType::RegisterOfsReg:
+ debug_log.addr_reg_index = ((first_dword >> 4) & 0xF);
+ debug_log.ofs_reg_index = (first_dword & 0xF);
break;
}
+ opcode.opcode = debug_log;
} break;
- case CheatVmOpcodeType_ExtendedWidth:
- case CheatVmOpcodeType_DoubleExtendedWidth:
+ case CheatVmOpcodeType::ExtendedWidth:
+ case CheatVmOpcodeType::DoubleExtendedWidth:
default:
- /* Unrecognized instruction cannot be decoded. */
+ // Unrecognized instruction cannot be decoded.
valid = false;
+ opcode.opcode = UnrecognizedInstruction{opcode_type};
break;
}
- /* End decoding. */
+ // End decoding.
return valid;
}
void DmntCheatVm::SkipConditionalBlock() {
- if (this->condition_depth > 0) {
- /* We want to continue until we're out of the current block. */
- const size_t desired_depth = this->condition_depth - 1;
+ if (condition_depth > 0) {
+ // We want to continue until we're out of the current block.
+ const std::size_t desired_depth = condition_depth - 1;
CheatVmOpcode skip_opcode{};
- while (this->condition_depth > desired_depth && this->DecodeNextOpcode(skip_opcode)) {
- /* Decode instructions until we see end of the current conditional block. */
- /* NOTE: This is broken in gateway's implementation. */
- /* Gateway currently checks for "0x2" instead of "0x20000000" */
- /* In addition, they do a linear scan instead of correctly decoding opcodes. */
- /* This causes issues if "0x2" appears as an immediate in the conditional block... */
+ while (condition_depth > desired_depth && DecodeNextOpcode(skip_opcode)) {
+ // Decode instructions until we see end of the current conditional block.
+ // NOTE: This is broken in gateway's implementation.
+ // Gateway currently checks for "0x2" instead of "0x20000000"
+ // In addition, they do a linear scan instead of correctly decoding opcodes.
+ // This causes issues if "0x2" appears as an immediate in the conditional block...
- /* We also support nesting of conditional blocks, and Gateway does not. */
+ // We also support nesting of conditional blocks, and Gateway does not.
if (skip_opcode.begin_conditional_block) {
- this->condition_depth++;
- } else if (skip_opcode.opcode == CheatVmOpcodeType_EndConditionalBlock) {
- this->condition_depth--;
+ condition_depth++;
+ } else if (std::holds_alternative<EndConditionalOpcode>(skip_opcode.opcode)) {
+ condition_depth--;
}
}
} else {
- /* Skipping, but this->condition_depth = 0. */
- /* This is an error condition. */
- /* However, I don't actually believe it is possible for this to happen. */
- /* I guess we'll throw a fatal error here, so as to encourage me to fix the VM */
- /* in the event that someone triggers it? I don't know how you'd do that. */
+ // Skipping, but condition_depth = 0.
+ // This is an error condition.
+ // However, I don't actually believe it is possible for this to happen.
+ // I guess we'll throw a fatal error here, so as to encourage me to fix the VM
+ // in the event that someone triggers it? I don't know how you'd do that.
UNREACHABLE_MSG("Invalid condition depth in DMNT Cheat VM");
}
}
@@ -602,7 +646,7 @@ u64 DmntCheatVm::GetVmInt(VmInt value, u32 bit_width) {
case 8:
return value.bit64;
default:
- /* Invalid bit width -> return 0. */
+ // Invalid bit width -> return 0.
return 0;
}
}
@@ -610,39 +654,37 @@ u64 DmntCheatVm::GetVmInt(VmInt value, u32 bit_width) {
u64 DmntCheatVm::GetCheatProcessAddress(const CheatProcessMetadata& metadata,
MemoryAccessType mem_type, u64 rel_address) {
switch (mem_type) {
- case MemoryAccessType_MainNso:
+ case MemoryAccessType::MainNso:
default:
return metadata.main_nso_extents.base + rel_address;
- case MemoryAccessType_Heap:
+ case MemoryAccessType::Heap:
return metadata.heap_extents.base + rel_address;
}
}
void DmntCheatVm::ResetState() {
- for (size_t i = 0; i < DmntCheatVm::NumRegisters; i++) {
- this->registers[i] = 0;
- this->saved_values[i] = 0;
- this->loop_tops[i] = 0;
- }
- this->instruction_ptr = 0;
- this->condition_depth = 0;
- this->decode_success = true;
+ registers.fill(0);
+ saved_values.fill(0);
+ loop_tops.fill(0);
+ instruction_ptr = 0;
+ condition_depth = 0;
+ decode_success = true;
}
bool DmntCheatVm::LoadProgram(const std::vector<CheatEntry>& entries) {
- /* Reset opcode count. */
- this->num_opcodes = 0;
+ // Reset opcode count.
+ num_opcodes = 0;
- for (size_t i = 0; i < entries.size(); i++) {
+ for (std::size_t i = 0; i < entries.size(); i++) {
if (entries[i].enabled) {
- /* Bounds check. */
- if (entries[i].definition.num_opcodes + this->num_opcodes > MaximumProgramOpcodeCount) {
- this->num_opcodes = 0;
+ // Bounds check.
+ if (entries[i].definition.num_opcodes + num_opcodes > MaximumProgramOpcodeCount) {
+ num_opcodes = 0;
return false;
}
- for (size_t n = 0; n < entries[i].definition.num_opcodes; n++) {
- this->program[this->num_opcodes++] = entries[i].definition.opcodes[n];
+ for (std::size_t n = 0; n < entries[i].definition.num_opcodes; n++) {
+ program[num_opcodes++] = entries[i].definition.opcodes[n];
}
}
}
@@ -653,262 +695,249 @@ bool DmntCheatVm::LoadProgram(const std::vector<CheatEntry>& entries) {
void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
CheatVmOpcode cur_opcode{};
- /* Get Keys down. */
+ // Get Keys down.
u64 kDown = callbacks->HidKeysDown();
- this->LogToDebugFile("Started VM execution.\n");
- this->LogToDebugFile("Main NSO: %012lx\n", metadata.main_nso_extents.base);
- this->LogToDebugFile("Heap: %012lx\n", metadata.main_nso_extents.base);
- this->LogToDebugFile("Keys Down: %08x\n", (u32)(kDown & 0x0FFFFFFF));
+ callbacks->CommandLog("Started VM execution.");
+ callbacks->CommandLog(fmt::format("Main NSO: {:012X}", metadata.main_nso_extents.base));
+ callbacks->CommandLog(fmt::format("Heap: {:012X}", metadata.main_nso_extents.base));
+ callbacks->CommandLog(fmt::format("Keys Down: {:08X}", static_cast<u32>(kDown & 0x0FFFFFFF)));
- /* Clear VM state. */
- this->ResetState();
+ // Clear VM state.
+ ResetState();
- /* Loop until program finishes. */
- while (this->DecodeNextOpcode(cur_opcode)) {
- this->LogToDebugFile("Instruction Ptr: %04x\n", (u32)this->instruction_ptr);
+ // Loop until program finishes.
+ while (DecodeNextOpcode(cur_opcode)) {
+ callbacks->CommandLog(
+ fmt::format("Instruction Ptr: {:04X}", static_cast<u32>(instruction_ptr)));
- for (size_t i = 0; i < NumRegisters; i++) {
- this->LogToDebugFile("Registers[%02x]: %016lx\n", i, this->registers[i]);
+ for (std::size_t i = 0; i < NumRegisters; i++) {
+ callbacks->CommandLog(fmt::format("Registers[{:02X}]: {:016X}", i, registers[i]));
}
- for (size_t i = 0; i < NumRegisters; i++) {
- this->LogToDebugFile("SavedRegs[%02x]: %016lx\n", i, this->saved_values[i]);
+ for (std::size_t i = 0; i < NumRegisters; i++) {
+ callbacks->CommandLog(fmt::format("SavedRegs[{:02X}]: {:016X}", i, saved_values[i]));
}
- this->LogOpcode(cur_opcode);
+ LogOpcode(cur_opcode);
- /* Increment conditional depth, if relevant. */
+ // Increment conditional depth, if relevant.
if (cur_opcode.begin_conditional_block) {
- this->condition_depth++;
+ condition_depth++;
}
- switch (cur_opcode.opcode) {
- case CheatVmOpcodeType_StoreStatic: {
- /* Calculate address, write value to memory. */
- u64 dst_address = GetCheatProcessAddress(
- metadata, cur_opcode.store_static.mem_type,
- cur_opcode.store_static.rel_address +
- this->registers[cur_opcode.store_static.offset_register]);
- u64 dst_value =
- GetVmInt(cur_opcode.store_static.value, cur_opcode.store_static.bit_width);
- switch (cur_opcode.store_static.bit_width) {
+ if (auto store_static = std::get_if<StoreStaticOpcode>(&cur_opcode.opcode)) {
+ // Calculate address, write value to memory.
+ u64 dst_address = GetCheatProcessAddress(metadata, store_static->mem_type,
+ store_static->rel_address +
+ registers[store_static->offset_register]);
+ u64 dst_value = GetVmInt(store_static->value, store_static->bit_width);
+ switch (store_static->bit_width) {
case 1:
case 2:
case 4:
case 8:
- callbacks->MemoryWrite(dst_address, &dst_value, cur_opcode.store_static.bit_width);
+ callbacks->MemoryWrite(dst_address, &dst_value, store_static->bit_width);
break;
}
- } break;
- case CheatVmOpcodeType_BeginConditionalBlock: {
- /* Read value from memory. */
- u64 src_address = GetCheatProcessAddress(metadata, cur_opcode.begin_cond.mem_type,
- cur_opcode.begin_cond.rel_address);
+ } else if (auto begin_cond = std::get_if<BeginConditionalOpcode>(&cur_opcode.opcode)) {
+ // Read value from memory.
+ u64 src_address =
+ GetCheatProcessAddress(metadata, begin_cond->mem_type, begin_cond->rel_address);
u64 src_value = 0;
- switch (cur_opcode.store_static.bit_width) {
+ switch (store_static->bit_width) {
case 1:
case 2:
case 4:
case 8:
- callbacks->MemoryRead(src_address, &src_value, cur_opcode.begin_cond.bit_width);
+ callbacks->MemoryRead(src_address, &src_value, begin_cond->bit_width);
break;
}
- /* Check against condition. */
- u64 cond_value = GetVmInt(cur_opcode.begin_cond.value, cur_opcode.begin_cond.bit_width);
+ // Check against condition.
+ u64 cond_value = GetVmInt(begin_cond->value, begin_cond->bit_width);
bool cond_met = false;
- switch (cur_opcode.begin_cond.cond_type) {
- case ConditionalComparisonType_GT:
+ switch (begin_cond->cond_type) {
+ case ConditionalComparisonType::GT:
cond_met = src_value > cond_value;
break;
- case ConditionalComparisonType_GE:
+ case ConditionalComparisonType::GE:
cond_met = src_value >= cond_value;
break;
- case ConditionalComparisonType_LT:
+ case ConditionalComparisonType::LT:
cond_met = src_value < cond_value;
break;
- case ConditionalComparisonType_LE:
+ case ConditionalComparisonType::LE:
cond_met = src_value <= cond_value;
break;
- case ConditionalComparisonType_EQ:
+ case ConditionalComparisonType::EQ:
cond_met = src_value == cond_value;
break;
- case ConditionalComparisonType_NE:
+ case ConditionalComparisonType::NE:
cond_met = src_value != cond_value;
break;
}
- /* Skip conditional block if condition not met. */
+ // Skip conditional block if condition not met.
if (!cond_met) {
- this->SkipConditionalBlock();
+ SkipConditionalBlock();
}
- } break;
- case CheatVmOpcodeType_EndConditionalBlock:
- /* Decrement the condition depth. */
- /* We will assume, graciously, that mismatched conditional block ends are a nop. */
- if (this->condition_depth > 0) {
- this->condition_depth--;
+ } else if (auto end_cond = std::get_if<EndConditionalOpcode>(&cur_opcode.opcode)) {
+ // Decrement the condition depth.
+ // We will assume, graciously, that mismatched conditional block ends are a nop.
+ if (condition_depth > 0) {
+ condition_depth--;
}
- break;
- case CheatVmOpcodeType_ControlLoop:
- if (cur_opcode.ctrl_loop.start_loop) {
- /* Start a loop. */
- this->registers[cur_opcode.ctrl_loop.reg_index] = cur_opcode.ctrl_loop.num_iters;
- this->loop_tops[cur_opcode.ctrl_loop.reg_index] = this->instruction_ptr;
+ } else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&cur_opcode.opcode)) {
+ if (ctrl_loop->start_loop) {
+ // Start a loop.
+ registers[ctrl_loop->reg_index] = ctrl_loop->num_iters;
+ loop_tops[ctrl_loop->reg_index] = instruction_ptr;
} else {
- /* End a loop. */
- this->registers[cur_opcode.ctrl_loop.reg_index]--;
- if (this->registers[cur_opcode.ctrl_loop.reg_index] != 0) {
- this->instruction_ptr = this->loop_tops[cur_opcode.ctrl_loop.reg_index];
+ // End a loop.
+ registers[ctrl_loop->reg_index]--;
+ if (registers[ctrl_loop->reg_index] != 0) {
+ instruction_ptr = loop_tops[ctrl_loop->reg_index];
}
}
- break;
- case CheatVmOpcodeType_LoadRegisterStatic:
- /* Set a register to a static value. */
- this->registers[cur_opcode.ldr_static.reg_index] = cur_opcode.ldr_static.value;
- break;
- case CheatVmOpcodeType_LoadRegisterMemory: {
- /* Choose source address. */
+ } else if (auto ldr_static = std::get_if<LoadRegisterStaticOpcode>(&cur_opcode.opcode)) {
+ // Set a register to a static value.
+ registers[ldr_static->reg_index] = ldr_static->value;
+ } else if (auto ldr_memory = std::get_if<LoadRegisterMemoryOpcode>(&cur_opcode.opcode)) {
+ // Choose source address.
u64 src_address;
- if (cur_opcode.ldr_memory.load_from_reg) {
- src_address = this->registers[cur_opcode.ldr_memory.reg_index] +
- cur_opcode.ldr_memory.rel_address;
+ if (ldr_memory->load_from_reg) {
+ src_address = registers[ldr_memory->reg_index] + ldr_memory->rel_address;
} else {
- src_address = GetCheatProcessAddress(metadata, cur_opcode.ldr_memory.mem_type,
- cur_opcode.ldr_memory.rel_address);
+ src_address =
+ GetCheatProcessAddress(metadata, ldr_memory->mem_type, ldr_memory->rel_address);
}
- /* Read into register. Gateway only reads on valid bitwidth. */
- switch (cur_opcode.ldr_memory.bit_width) {
+ // Read into register. Gateway only reads on valid bitwidth.
+ switch (ldr_memory->bit_width) {
case 1:
case 2:
case 4:
case 8:
- callbacks->MemoryRead(src_address,
- &this->registers[cur_opcode.ldr_memory.reg_index],
- cur_opcode.ldr_memory.bit_width);
+ callbacks->MemoryRead(src_address, &registers[ldr_memory->reg_index],
+ ldr_memory->bit_width);
break;
}
- } break;
- case CheatVmOpcodeType_StoreStaticToAddress: {
- /* Calculate address. */
- u64 dst_address = this->registers[cur_opcode.str_static.reg_index];
- u64 dst_value = cur_opcode.str_static.value;
- if (cur_opcode.str_static.add_offset_reg) {
- dst_address += this->registers[cur_opcode.str_static.offset_reg_index];
+ } else if (auto str_static = std::get_if<StoreStaticToAddressOpcode>(&cur_opcode.opcode)) {
+ // Calculate address.
+ u64 dst_address = registers[str_static->reg_index];
+ u64 dst_value = str_static->value;
+ if (str_static->add_offset_reg) {
+ dst_address += registers[str_static->offset_reg_index];
}
- /* Write value to memory. Gateway only writes on valid bitwidth. */
- switch (cur_opcode.str_static.bit_width) {
+ // Write value to memory. Gateway only writes on valid bitwidth.
+ switch (str_static->bit_width) {
case 1:
case 2:
case 4:
case 8:
- callbacks->MemoryWrite(dst_address, &dst_value, cur_opcode.str_static.bit_width);
+ callbacks->MemoryWrite(dst_address, &dst_value, str_static->bit_width);
break;
}
- /* Increment register if relevant. */
- if (cur_opcode.str_static.increment_reg) {
- this->registers[cur_opcode.str_static.reg_index] += cur_opcode.str_static.bit_width;
+ // Increment register if relevant.
+ if (str_static->increment_reg) {
+ registers[str_static->reg_index] += str_static->bit_width;
}
- } break;
- case CheatVmOpcodeType_PerformArithmeticStatic: {
- /* Do requested math. */
- switch (cur_opcode.perform_math_static.math_type) {
- case RegisterArithmeticType_Addition:
- this->registers[cur_opcode.perform_math_static.reg_index] +=
- (u64)cur_opcode.perform_math_static.value;
+ } else if (auto perform_math_static =
+ std::get_if<PerformArithmeticStaticOpcode>(&cur_opcode.opcode)) {
+ // Do requested math.
+ switch (perform_math_static->math_type) {
+ case RegisterArithmeticType::Addition:
+ registers[perform_math_static->reg_index] +=
+ static_cast<u64>(perform_math_static->value);
break;
- case RegisterArithmeticType_Subtraction:
- this->registers[cur_opcode.perform_math_static.reg_index] -=
- (u64)cur_opcode.perform_math_static.value;
+ case RegisterArithmeticType::Subtraction:
+ registers[perform_math_static->reg_index] -=
+ static_cast<u64>(perform_math_static->value);
break;
- case RegisterArithmeticType_Multiplication:
- this->registers[cur_opcode.perform_math_static.reg_index] *=
- (u64)cur_opcode.perform_math_static.value;
+ case RegisterArithmeticType::Multiplication:
+ registers[perform_math_static->reg_index] *=
+ static_cast<u64>(perform_math_static->value);
break;
- case RegisterArithmeticType_LeftShift:
- this->registers[cur_opcode.perform_math_static.reg_index] <<=
- (u64)cur_opcode.perform_math_static.value;
+ case RegisterArithmeticType::LeftShift:
+ registers[perform_math_static->reg_index] <<=
+ static_cast<u64>(perform_math_static->value);
break;
- case RegisterArithmeticType_RightShift:
- this->registers[cur_opcode.perform_math_static.reg_index] >>=
- (u64)cur_opcode.perform_math_static.value;
+ case RegisterArithmeticType::RightShift:
+ registers[perform_math_static->reg_index] >>=
+ static_cast<u64>(perform_math_static->value);
break;
default:
- /* Do not handle extensions here. */
+ // Do not handle extensions here.
break;
}
- /* Apply bit width. */
- switch (cur_opcode.perform_math_static.bit_width) {
+ // Apply bit width.
+ switch (perform_math_static->bit_width) {
case 1:
- this->registers[cur_opcode.perform_math_static.reg_index] =
- static_cast<u8>(this->registers[cur_opcode.perform_math_static.reg_index]);
+ registers[perform_math_static->reg_index] =
+ static_cast<u8>(registers[perform_math_static->reg_index]);
break;
case 2:
- this->registers[cur_opcode.perform_math_static.reg_index] =
- static_cast<u16>(this->registers[cur_opcode.perform_math_static.reg_index]);
+ registers[perform_math_static->reg_index] =
+ static_cast<u16>(registers[perform_math_static->reg_index]);
break;
case 4:
- this->registers[cur_opcode.perform_math_static.reg_index] =
- static_cast<u32>(this->registers[cur_opcode.perform_math_static.reg_index]);
+ registers[perform_math_static->reg_index] =
+ static_cast<u32>(registers[perform_math_static->reg_index]);
break;
case 8:
- this->registers[cur_opcode.perform_math_static.reg_index] =
- static_cast<u64>(this->registers[cur_opcode.perform_math_static.reg_index]);
+ registers[perform_math_static->reg_index] =
+ static_cast<u64>(registers[perform_math_static->reg_index]);
break;
}
- } break;
- case CheatVmOpcodeType_BeginKeypressConditionalBlock:
- /* Check for keypress. */
- if ((cur_opcode.begin_keypress_cond.key_mask & kDown) !=
- cur_opcode.begin_keypress_cond.key_mask) {
- /* Keys not pressed. Skip conditional block. */
- this->SkipConditionalBlock();
+ } else if (auto begin_keypress_cond =
+ std::get_if<BeginKeypressConditionalOpcode>(&cur_opcode.opcode)) {
+ // Check for keypress.
+ if ((begin_keypress_cond->key_mask & kDown) != begin_keypress_cond->key_mask) {
+ // Keys not pressed. Skip conditional block.
+ SkipConditionalBlock();
}
- break;
- case CheatVmOpcodeType_PerformArithmeticRegister: {
- const u64 operand_1_value =
- this->registers[cur_opcode.perform_math_reg.src_reg_1_index];
+ } else if (auto perform_math_reg =
+ std::get_if<PerformArithmeticRegisterOpcode>(&cur_opcode.opcode)) {
+ const u64 operand_1_value = registers[perform_math_reg->src_reg_1_index];
const u64 operand_2_value =
- cur_opcode.perform_math_reg.has_immediate
- ? GetVmInt(cur_opcode.perform_math_reg.value,
- cur_opcode.perform_math_reg.bit_width)
- : this->registers[cur_opcode.perform_math_reg.src_reg_2_index];
+ perform_math_reg->has_immediate
+ ? GetVmInt(perform_math_reg->value, perform_math_reg->bit_width)
+ : registers[perform_math_reg->src_reg_2_index];
u64 res_val = 0;
- /* Do requested math. */
- switch (cur_opcode.perform_math_reg.math_type) {
- case RegisterArithmeticType_Addition:
+ // Do requested math.
+ switch (perform_math_reg->math_type) {
+ case RegisterArithmeticType::Addition:
res_val = operand_1_value + operand_2_value;
break;
- case RegisterArithmeticType_Subtraction:
+ case RegisterArithmeticType::Subtraction:
res_val = operand_1_value - operand_2_value;
break;
- case RegisterArithmeticType_Multiplication:
+ case RegisterArithmeticType::Multiplication:
res_val = operand_1_value * operand_2_value;
break;
- case RegisterArithmeticType_LeftShift:
+ case RegisterArithmeticType::LeftShift:
res_val = operand_1_value << operand_2_value;
break;
- case RegisterArithmeticType_RightShift:
+ case RegisterArithmeticType::RightShift:
res_val = operand_1_value >> operand_2_value;
break;
- case RegisterArithmeticType_LogicalAnd:
+ case RegisterArithmeticType::LogicalAnd:
res_val = operand_1_value & operand_2_value;
break;
- case RegisterArithmeticType_LogicalOr:
+ case RegisterArithmeticType::LogicalOr:
res_val = operand_1_value | operand_2_value;
break;
- case RegisterArithmeticType_LogicalNot:
+ case RegisterArithmeticType::LogicalNot:
res_val = ~operand_1_value;
break;
- case RegisterArithmeticType_LogicalXor:
+ case RegisterArithmeticType::LogicalXor:
res_val = operand_1_value ^ operand_2_value;
break;
- case RegisterArithmeticType_None:
+ case RegisterArithmeticType::None:
res_val = operand_1_value;
break;
}
- /* Apply bit width. */
- switch (cur_opcode.perform_math_reg.bit_width) {
+ // Apply bit width.
+ switch (perform_math_reg->bit_width) {
case 1:
res_val = static_cast<u8>(res_val);
break;
@@ -923,282 +952,259 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
break;
}
- /* Save to register. */
- this->registers[cur_opcode.perform_math_reg.dst_reg_index] = res_val;
- } break;
- case CheatVmOpcodeType_StoreRegisterToAddress: {
- /* Calculate address. */
- u64 dst_value = this->registers[cur_opcode.str_register.str_reg_index];
- u64 dst_address = this->registers[cur_opcode.str_register.addr_reg_index];
- switch (cur_opcode.str_register.ofs_type) {
- case StoreRegisterOffsetType_None:
- /* Nothing more to do */
+ // Save to register.
+ registers[perform_math_reg->dst_reg_index] = res_val;
+ } else if (auto str_register =
+ std::get_if<StoreRegisterToAddressOpcode>(&cur_opcode.opcode)) {
+ // Calculate address.
+ u64 dst_value = registers[str_register->str_reg_index];
+ u64 dst_address = registers[str_register->addr_reg_index];
+ switch (str_register->ofs_type) {
+ case StoreRegisterOffsetType::None:
+ // Nothing more to do
break;
- case StoreRegisterOffsetType_Reg:
- dst_address += this->registers[cur_opcode.str_register.ofs_reg_index];
+ case StoreRegisterOffsetType::Reg:
+ dst_address += registers[str_register->ofs_reg_index];
break;
- case StoreRegisterOffsetType_Imm:
- dst_address += cur_opcode.str_register.rel_address;
+ case StoreRegisterOffsetType::Imm:
+ dst_address += str_register->rel_address;
break;
- case StoreRegisterOffsetType_MemReg:
- dst_address =
- GetCheatProcessAddress(metadata, cur_opcode.str_register.mem_type,
- this->registers[cur_opcode.str_register.addr_reg_index]);
+ case StoreRegisterOffsetType::MemReg:
+ dst_address = GetCheatProcessAddress(metadata, str_register->mem_type,
+ registers[str_register->addr_reg_index]);
break;
- case StoreRegisterOffsetType_MemImm:
- dst_address = GetCheatProcessAddress(metadata, cur_opcode.str_register.mem_type,
- cur_opcode.str_register.rel_address);
+ case StoreRegisterOffsetType::MemImm:
+ dst_address = GetCheatProcessAddress(metadata, str_register->mem_type,
+ str_register->rel_address);
break;
- case StoreRegisterOffsetType_MemImmReg:
- dst_address =
- GetCheatProcessAddress(metadata, cur_opcode.str_register.mem_type,
- this->registers[cur_opcode.str_register.addr_reg_index] +
- cur_opcode.str_register.rel_address);
+ case StoreRegisterOffsetType::MemImmReg:
+ dst_address = GetCheatProcessAddress(metadata, str_register->mem_type,
+ registers[str_register->addr_reg_index] +
+ str_register->rel_address);
break;
}
- /* Write value to memory. Write only on valid bitwidth. */
- switch (cur_opcode.str_register.bit_width) {
+ // Write value to memory. Write only on valid bitwidth.
+ switch (str_register->bit_width) {
case 1:
case 2:
case 4:
case 8:
- callbacks->MemoryWrite(dst_address, &dst_value, cur_opcode.str_register.bit_width);
+ callbacks->MemoryWrite(dst_address, &dst_value, str_register->bit_width);
break;
}
- /* Increment register if relevant. */
- if (cur_opcode.str_register.increment_reg) {
- this->registers[cur_opcode.str_register.addr_reg_index] +=
- cur_opcode.str_register.bit_width;
+ // Increment register if relevant.
+ if (str_register->increment_reg) {
+ registers[str_register->addr_reg_index] += str_register->bit_width;
}
- } break;
- case CheatVmOpcodeType_BeginRegisterConditionalBlock: {
- /* Get value from register. */
+ } else if (auto begin_reg_cond =
+ std::get_if<BeginRegisterConditionalOpcode>(&cur_opcode.opcode)) {
+ // Get value from register.
u64 src_value = 0;
- switch (cur_opcode.begin_reg_cond.bit_width) {
+ switch (begin_reg_cond->bit_width) {
case 1:
- src_value = static_cast<u8>(
- this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFul);
+ src_value = static_cast<u8>(registers[begin_reg_cond->val_reg_index] & 0xFFul);
break;
case 2:
- src_value = static_cast<u16>(
- this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFul);
+ src_value = static_cast<u16>(registers[begin_reg_cond->val_reg_index] & 0xFFFFul);
break;
case 4:
- src_value = static_cast<u32>(
- this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFFFFFul);
+ src_value =
+ static_cast<u32>(registers[begin_reg_cond->val_reg_index] & 0xFFFFFFFFul);
break;
case 8:
- src_value =
- static_cast<u64>(this->registers[cur_opcode.begin_reg_cond.val_reg_index] &
- 0xFFFFFFFFFFFFFFFFul);
+ src_value = static_cast<u64>(registers[begin_reg_cond->val_reg_index] &
+ 0xFFFFFFFFFFFFFFFFul);
break;
}
- /* Read value from memory. */
+ // Read value from memory.
u64 cond_value = 0;
- if (cur_opcode.begin_reg_cond.comp_type == CompareRegisterValueType_StaticValue) {
- cond_value =
- GetVmInt(cur_opcode.begin_reg_cond.value, cur_opcode.begin_reg_cond.bit_width);
- } else if (cur_opcode.begin_reg_cond.comp_type ==
- CompareRegisterValueType_OtherRegister) {
- switch (cur_opcode.begin_reg_cond.bit_width) {
+ if (begin_reg_cond->comp_type == CompareRegisterValueType::StaticValue) {
+ cond_value = GetVmInt(begin_reg_cond->value, begin_reg_cond->bit_width);
+ } else if (begin_reg_cond->comp_type == CompareRegisterValueType::OtherRegister) {
+ switch (begin_reg_cond->bit_width) {
case 1:
- cond_value = static_cast<u8>(
- this->registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFul);
+ cond_value =
+ static_cast<u8>(registers[begin_reg_cond->other_reg_index] & 0xFFul);
break;
case 2:
- cond_value = static_cast<u16>(
- this->registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFFFul);
+ cond_value =
+ static_cast<u16>(registers[begin_reg_cond->other_reg_index] & 0xFFFFul);
break;
case 4:
- cond_value = static_cast<u32>(
- this->registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFFFFFFFul);
+ cond_value =
+ static_cast<u32>(registers[begin_reg_cond->other_reg_index] & 0xFFFFFFFFul);
break;
case 8:
- cond_value = static_cast<u64>(
- this->registers[cur_opcode.begin_reg_cond.other_reg_index] &
- 0xFFFFFFFFFFFFFFFFul);
+ cond_value = static_cast<u64>(registers[begin_reg_cond->other_reg_index] &
+ 0xFFFFFFFFFFFFFFFFul);
break;
}
} else {
u64 cond_address = 0;
- switch (cur_opcode.begin_reg_cond.comp_type) {
- case CompareRegisterValueType_MemoryRelAddr:
- cond_address =
- GetCheatProcessAddress(metadata, cur_opcode.begin_reg_cond.mem_type,
- cur_opcode.begin_reg_cond.rel_address);
+ switch (begin_reg_cond->comp_type) {
+ case CompareRegisterValueType::MemoryRelAddr:
+ cond_address = GetCheatProcessAddress(metadata, begin_reg_cond->mem_type,
+ begin_reg_cond->rel_address);
break;
- case CompareRegisterValueType_MemoryOfsReg:
- cond_address = GetCheatProcessAddress(
- metadata, cur_opcode.begin_reg_cond.mem_type,
- this->registers[cur_opcode.begin_reg_cond.ofs_reg_index]);
+ case CompareRegisterValueType::MemoryOfsReg:
+ cond_address = GetCheatProcessAddress(metadata, begin_reg_cond->mem_type,
+ registers[begin_reg_cond->ofs_reg_index]);
break;
- case CompareRegisterValueType_RegisterRelAddr:
- cond_address = this->registers[cur_opcode.begin_reg_cond.addr_reg_index] +
- cur_opcode.begin_reg_cond.rel_address;
+ case CompareRegisterValueType::RegisterRelAddr:
+ cond_address =
+ registers[begin_reg_cond->addr_reg_index] + begin_reg_cond->rel_address;
break;
- case CompareRegisterValueType_RegisterOfsReg:
- cond_address = this->registers[cur_opcode.begin_reg_cond.addr_reg_index] +
- this->registers[cur_opcode.begin_reg_cond.ofs_reg_index];
+ case CompareRegisterValueType::RegisterOfsReg:
+ cond_address = registers[begin_reg_cond->addr_reg_index] +
+ registers[begin_reg_cond->ofs_reg_index];
break;
default:
break;
}
- switch (cur_opcode.begin_reg_cond.bit_width) {
+ switch (begin_reg_cond->bit_width) {
case 1:
case 2:
case 4:
case 8:
- callbacks->MemoryRead(cond_address, &cond_value,
- cur_opcode.begin_reg_cond.bit_width);
+ callbacks->MemoryRead(cond_address, &cond_value, begin_reg_cond->bit_width);
break;
}
}
- /* Check against condition. */
+ // Check against condition.
bool cond_met = false;
- switch (cur_opcode.begin_reg_cond.cond_type) {
- case ConditionalComparisonType_GT:
+ switch (begin_reg_cond->cond_type) {
+ case ConditionalComparisonType::GT:
cond_met = src_value > cond_value;
break;
- case ConditionalComparisonType_GE:
+ case ConditionalComparisonType::GE:
cond_met = src_value >= cond_value;
break;
- case ConditionalComparisonType_LT:
+ case ConditionalComparisonType::LT:
cond_met = src_value < cond_value;
break;
- case ConditionalComparisonType_LE:
+ case ConditionalComparisonType::LE:
cond_met = src_value <= cond_value;
break;
- case ConditionalComparisonType_EQ:
+ case ConditionalComparisonType::EQ:
cond_met = src_value == cond_value;
break;
- case ConditionalComparisonType_NE:
+ case ConditionalComparisonType::NE:
cond_met = src_value != cond_value;
break;
}
- /* Skip conditional block if condition not met. */
+ // Skip conditional block if condition not met.
if (!cond_met) {
- this->SkipConditionalBlock();
+ SkipConditionalBlock();
}
- } break;
- case CheatVmOpcodeType_SaveRestoreRegister:
- /* Save or restore a register. */
- switch (cur_opcode.save_restore_reg.op_type) {
- case SaveRestoreRegisterOpType_ClearRegs:
- this->registers[cur_opcode.save_restore_reg.dst_index] = 0ul;
+ } else if (auto save_restore_reg =
+ std::get_if<SaveRestoreRegisterOpcode>(&cur_opcode.opcode)) {
+ // Save or restore a register.
+ switch (save_restore_reg->op_type) {
+ case SaveRestoreRegisterOpType::ClearRegs:
+ registers[save_restore_reg->dst_index] = 0ul;
break;
- case SaveRestoreRegisterOpType_ClearSaved:
- this->saved_values[cur_opcode.save_restore_reg.dst_index] = 0ul;
+ case SaveRestoreRegisterOpType::ClearSaved:
+ saved_values[save_restore_reg->dst_index] = 0ul;
break;
- case SaveRestoreRegisterOpType_Save:
- this->saved_values[cur_opcode.save_restore_reg.dst_index] =
- this->registers[cur_opcode.save_restore_reg.src_index];
+ case SaveRestoreRegisterOpType::Save:
+ saved_values[save_restore_reg->dst_index] = registers[save_restore_reg->src_index];
break;
- case SaveRestoreRegisterOpType_Restore:
+ case SaveRestoreRegisterOpType::Restore:
default:
- this->registers[cur_opcode.save_restore_reg.dst_index] =
- this->saved_values[cur_opcode.save_restore_reg.src_index];
+ registers[save_restore_reg->dst_index] = saved_values[save_restore_reg->src_index];
break;
}
- break;
- case CheatVmOpcodeType_SaveRestoreRegisterMask:
- /* Save or restore register mask. */
+ } else if (auto save_restore_regmask =
+ std::get_if<SaveRestoreRegisterMaskOpcode>(&cur_opcode.opcode)) {
+ // Save or restore register mask.
u64* src;
u64* dst;
- switch (cur_opcode.save_restore_regmask.op_type) {
- case SaveRestoreRegisterOpType_ClearSaved:
- case SaveRestoreRegisterOpType_Save:
- src = this->registers.data();
- dst = this->saved_values.data();
+ switch (save_restore_regmask->op_type) {
+ case SaveRestoreRegisterOpType::ClearSaved:
+ case SaveRestoreRegisterOpType::Save:
+ src = registers.data();
+ dst = saved_values.data();
break;
- case SaveRestoreRegisterOpType_ClearRegs:
- case SaveRestoreRegisterOpType_Restore:
+ case SaveRestoreRegisterOpType::ClearRegs:
+ case SaveRestoreRegisterOpType::Restore:
default:
- src = this->registers.data();
- dst = this->saved_values.data();
+ src = registers.data();
+ dst = saved_values.data();
break;
}
- for (size_t i = 0; i < NumRegisters; i++) {
- if (cur_opcode.save_restore_regmask.should_operate[i]) {
- switch (cur_opcode.save_restore_regmask.op_type) {
- case SaveRestoreRegisterOpType_ClearSaved:
- case SaveRestoreRegisterOpType_ClearRegs:
+ for (std::size_t i = 0; i < NumRegisters; i++) {
+ if (save_restore_regmask->should_operate[i]) {
+ switch (save_restore_regmask->op_type) {
+ case SaveRestoreRegisterOpType::ClearSaved:
+ case SaveRestoreRegisterOpType::ClearRegs:
dst[i] = 0ul;
break;
- case SaveRestoreRegisterOpType_Save:
- case SaveRestoreRegisterOpType_Restore:
+ case SaveRestoreRegisterOpType::Save:
+ case SaveRestoreRegisterOpType::Restore:
default:
dst[i] = src[i];
break;
}
}
}
- break;
- case CheatVmOpcodeType_DebugLog: {
- /* Read value from memory. */
+ } else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) {
+ // Read value from memory.
u64 log_value = 0;
- if (cur_opcode.debug_log.val_type == DebugLogValueType_RegisterValue) {
- switch (cur_opcode.debug_log.bit_width) {
+ if (debug_log->val_type == DebugLogValueType::RegisterValue) {
+ switch (debug_log->bit_width) {
case 1:
- log_value = static_cast<u8>(
- this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFul);
+ log_value = static_cast<u8>(registers[debug_log->val_reg_index] & 0xFFul);
break;
case 2:
- log_value = static_cast<u16>(
- this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFFFul);
+ log_value = static_cast<u16>(registers[debug_log->val_reg_index] & 0xFFFFul);
break;
case 4:
- log_value = static_cast<u32>(
- this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFFFFFFFul);
+ log_value =
+ static_cast<u32>(registers[debug_log->val_reg_index] & 0xFFFFFFFFul);
break;
case 8:
- log_value = static_cast<u64>(
- this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFFFFFFFFFFFFFFFul);
+ log_value = static_cast<u64>(registers[debug_log->val_reg_index] &
+ 0xFFFFFFFFFFFFFFFFul);
break;
}
} else {
u64 val_address = 0;
- switch (cur_opcode.debug_log.val_type) {
- case DebugLogValueType_MemoryRelAddr:
- val_address = GetCheatProcessAddress(metadata, cur_opcode.debug_log.mem_type,
- cur_opcode.debug_log.rel_address);
+ switch (debug_log->val_type) {
+ case DebugLogValueType::MemoryRelAddr:
+ val_address = GetCheatProcessAddress(metadata, debug_log->mem_type,
+ debug_log->rel_address);
break;
- case DebugLogValueType_MemoryOfsReg:
- val_address =
- GetCheatProcessAddress(metadata, cur_opcode.debug_log.mem_type,
- this->registers[cur_opcode.debug_log.ofs_reg_index]);
+ case DebugLogValueType::MemoryOfsReg:
+ val_address = GetCheatProcessAddress(metadata, debug_log->mem_type,
+ registers[debug_log->ofs_reg_index]);
break;
- case DebugLogValueType_RegisterRelAddr:
- val_address = this->registers[cur_opcode.debug_log.addr_reg_index] +
- cur_opcode.debug_log.rel_address;
+ case DebugLogValueType::RegisterRelAddr:
+ val_address = registers[debug_log->addr_reg_index] + debug_log->rel_address;
break;
- case DebugLogValueType_RegisterOfsReg:
- val_address = this->registers[cur_opcode.debug_log.addr_reg_index] +
- this->registers[cur_opcode.debug_log.ofs_reg_index];
+ case DebugLogValueType::RegisterOfsReg:
+ val_address =
+ registers[debug_log->addr_reg_index] + registers[debug_log->ofs_reg_index];
break;
default:
break;
}
- switch (cur_opcode.debug_log.bit_width) {
+ switch (debug_log->bit_width) {
case 1:
case 2:
case 4:
case 8:
- callbacks->MemoryRead(val_address, &log_value, cur_opcode.debug_log.bit_width);
+ callbacks->MemoryRead(val_address, &log_value, debug_log->bit_width);
break;
}
}
- /* Log value. */
- this->DebugLog(cur_opcode.debug_log.log_id, log_value);
- } break;
- default:
- /* By default, we do a no-op. */
- break;
+ // Log value.
+ DebugLog(debug_log->log_id, log_value);
}
}
}
diff --git a/src/core/memory/dmnt_cheat_vm.h b/src/core/memory/dmnt_cheat_vm.h
index bea451db4..d1580d7f6 100644
--- a/src/core/memory/dmnt_cheat_vm.h
+++ b/src/core/memory/dmnt_cheat_vm.h
@@ -24,6 +24,7 @@
#pragma once
+#include <variant>
#include <vector>
#include <fmt/printf.h>
#include "common/common_types.h"
@@ -31,100 +32,100 @@
namespace Memory {
-enum CheatVmOpcodeType : u32 {
- CheatVmOpcodeType_StoreStatic = 0,
- CheatVmOpcodeType_BeginConditionalBlock = 1,
- CheatVmOpcodeType_EndConditionalBlock = 2,
- CheatVmOpcodeType_ControlLoop = 3,
- CheatVmOpcodeType_LoadRegisterStatic = 4,
- CheatVmOpcodeType_LoadRegisterMemory = 5,
- CheatVmOpcodeType_StoreStaticToAddress = 6,
- CheatVmOpcodeType_PerformArithmeticStatic = 7,
- CheatVmOpcodeType_BeginKeypressConditionalBlock = 8,
-
- /* These are not implemented by Gateway's VM. */
- CheatVmOpcodeType_PerformArithmeticRegister = 9,
- CheatVmOpcodeType_StoreRegisterToAddress = 10,
- CheatVmOpcodeType_Reserved11 = 11,
-
- /* This is a meta entry, and not a real opcode. */
- /* This is to facilitate multi-nybble instruction decoding. */
- CheatVmOpcodeType_ExtendedWidth = 12,
-
- /* Extended width opcodes. */
- CheatVmOpcodeType_BeginRegisterConditionalBlock = 0xC0,
- CheatVmOpcodeType_SaveRestoreRegister = 0xC1,
- CheatVmOpcodeType_SaveRestoreRegisterMask = 0xC2,
-
- /* This is a meta entry, and not a real opcode. */
- /* This is to facilitate multi-nybble instruction decoding. */
- CheatVmOpcodeType_DoubleExtendedWidth = 0xF0,
-
- /* Double-extended width opcodes. */
- CheatVmOpcodeType_DebugLog = 0xFFF,
+enum class CheatVmOpcodeType : u32 {
+ StoreStatic = 0,
+ BeginConditionalBlock = 1,
+ EndConditionalBlock = 2,
+ ControlLoop = 3,
+ LoadRegisterStatic = 4,
+ LoadRegisterMemory = 5,
+ StoreStaticToAddress = 6,
+ PerformArithmeticStatic = 7,
+ BeginKeypressConditionalBlock = 8,
+
+ // These are not implemented by Gateway's VM.
+ PerformArithmeticRegister = 9,
+ StoreRegisterToAddress = 10,
+ Reserved11 = 11,
+
+ // This is a meta entry, and not a real opcode.
+ // This is to facilitate multi-nybble instruction decoding.
+ ExtendedWidth = 12,
+
+ // Extended width opcodes.
+ BeginRegisterConditionalBlock = 0xC0,
+ SaveRestoreRegister = 0xC1,
+ SaveRestoreRegisterMask = 0xC2,
+
+ // This is a meta entry, and not a real opcode.
+ // This is to facilitate multi-nybble instruction decoding.
+ DoubleExtendedWidth = 0xF0,
+
+ // Double-extended width opcodes.
+ DebugLog = 0xFFF,
};
-enum MemoryAccessType : u32 {
- MemoryAccessType_MainNso = 0,
- MemoryAccessType_Heap = 1,
+enum class MemoryAccessType : u32 {
+ MainNso = 0,
+ Heap = 1,
};
-enum ConditionalComparisonType : u32 {
- ConditionalComparisonType_GT = 1,
- ConditionalComparisonType_GE = 2,
- ConditionalComparisonType_LT = 3,
- ConditionalComparisonType_LE = 4,
- ConditionalComparisonType_EQ = 5,
- ConditionalComparisonType_NE = 6,
+enum class ConditionalComparisonType : u32 {
+ GT = 1,
+ GE = 2,
+ LT = 3,
+ LE = 4,
+ EQ = 5,
+ NE = 6,
};
-enum RegisterArithmeticType : u32 {
- RegisterArithmeticType_Addition = 0,
- RegisterArithmeticType_Subtraction = 1,
- RegisterArithmeticType_Multiplication = 2,
- RegisterArithmeticType_LeftShift = 3,
- RegisterArithmeticType_RightShift = 4,
+enum class RegisterArithmeticType : u32 {
+ Addition = 0,
+ Subtraction = 1,
+ Multiplication = 2,
+ LeftShift = 3,
+ RightShift = 4,
- /* These are not supported by Gateway's VM. */
- RegisterArithmeticType_LogicalAnd = 5,
- RegisterArithmeticType_LogicalOr = 6,
- RegisterArithmeticType_LogicalNot = 7,
- RegisterArithmeticType_LogicalXor = 8,
+ // These are not supported by Gateway's VM.
+ LogicalAnd = 5,
+ LogicalOr = 6,
+ LogicalNot = 7,
+ LogicalXor = 8,
- RegisterArithmeticType_None = 9,
+ None = 9,
};
-enum StoreRegisterOffsetType : u32 {
- StoreRegisterOffsetType_None = 0,
- StoreRegisterOffsetType_Reg = 1,
- StoreRegisterOffsetType_Imm = 2,
- StoreRegisterOffsetType_MemReg = 3,
- StoreRegisterOffsetType_MemImm = 4,
- StoreRegisterOffsetType_MemImmReg = 5,
+enum class StoreRegisterOffsetType : u32 {
+ None = 0,
+ Reg = 1,
+ Imm = 2,
+ MemReg = 3,
+ MemImm = 4,
+ MemImmReg = 5,
};
-enum CompareRegisterValueType : u32 {
- CompareRegisterValueType_MemoryRelAddr = 0,
- CompareRegisterValueType_MemoryOfsReg = 1,
- CompareRegisterValueType_RegisterRelAddr = 2,
- CompareRegisterValueType_RegisterOfsReg = 3,
- CompareRegisterValueType_StaticValue = 4,
- CompareRegisterValueType_OtherRegister = 5,
+enum class CompareRegisterValueType : u32 {
+ MemoryRelAddr = 0,
+ MemoryOfsReg = 1,
+ RegisterRelAddr = 2,
+ RegisterOfsReg = 3,
+ StaticValue = 4,
+ OtherRegister = 5,
};
-enum SaveRestoreRegisterOpType : u32 {
- SaveRestoreRegisterOpType_Restore = 0,
- SaveRestoreRegisterOpType_Save = 1,
- SaveRestoreRegisterOpType_ClearSaved = 2,
- SaveRestoreRegisterOpType_ClearRegs = 3,
+enum class SaveRestoreRegisterOpType : u32 {
+ Restore = 0,
+ Save = 1,
+ ClearSaved = 2,
+ ClearRegs = 3,
};
-enum DebugLogValueType : u32 {
- DebugLogValueType_MemoryRelAddr = 0,
- DebugLogValueType_MemoryOfsReg = 1,
- DebugLogValueType_RegisterRelAddr = 2,
- DebugLogValueType_RegisterOfsReg = 3,
- DebugLogValueType_RegisterValue = 4,
+enum class DebugLogValueType : u32 {
+ MemoryRelAddr = 0,
+ MemoryOfsReg = 1,
+ RegisterRelAddr = 2,
+ RegisterOfsReg = 3,
+ RegisterValue = 4,
};
union VmInt {
@@ -247,26 +248,19 @@ struct DebugLogOpcode {
u64 rel_address;
};
-struct CheatVmOpcode {
+struct UnrecognizedInstruction {
CheatVmOpcodeType opcode;
+};
+
+struct CheatVmOpcode {
bool begin_conditional_block;
- union {
- StoreStaticOpcode store_static;
- BeginConditionalOpcode begin_cond;
- EndConditionalOpcode end_cond;
- ControlLoopOpcode ctrl_loop;
- LoadRegisterStaticOpcode ldr_static;
- LoadRegisterMemoryOpcode ldr_memory;
- StoreStaticToAddressOpcode str_static;
- PerformArithmeticStaticOpcode perform_math_static;
- BeginKeypressConditionalOpcode begin_keypress_cond;
- PerformArithmeticRegisterOpcode perform_math_reg;
- StoreRegisterToAddressOpcode str_register;
- BeginRegisterConditionalOpcode begin_reg_cond;
- SaveRestoreRegisterOpcode save_restore_reg;
- SaveRestoreRegisterMaskOpcode save_restore_regmask;
- DebugLogOpcode debug_log;
- };
+ std::variant<StoreStaticOpcode, BeginConditionalOpcode, EndConditionalOpcode, ControlLoopOpcode,
+ LoadRegisterStaticOpcode, LoadRegisterMemoryOpcode, StoreStaticToAddressOpcode,
+ PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
+ PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
+ BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
+ SaveRestoreRegisterMaskOpcode, DebugLogOpcode, UnrecognizedInstruction>
+ opcode;
};
class DmntCheatVm {
@@ -285,50 +279,43 @@ public:
virtual void CommandLog(std::string_view data) = 0;
};
- constexpr static size_t MaximumProgramOpcodeCount = 0x400;
- constexpr static size_t NumRegisters = 0x10;
+ static constexpr std::size_t MaximumProgramOpcodeCount = 0x400;
+ static constexpr std::size_t NumRegisters = 0x10;
+
+ explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks);
+ ~DmntCheatVm();
+
+ std::size_t GetProgramSize() const {
+ return this->num_opcodes;
+ }
+
+ bool LoadProgram(const std::vector<CheatEntry>& cheats);
+ void Execute(const CheatProcessMetadata& metadata);
private:
std::unique_ptr<Callbacks> callbacks;
- size_t num_opcodes = 0;
- size_t instruction_ptr = 0;
- size_t condition_depth = 0;
+ std::size_t num_opcodes = 0;
+ std::size_t instruction_ptr = 0;
+ std::size_t condition_depth = 0;
bool decode_success = false;
std::array<u32, MaximumProgramOpcodeCount> program{};
std::array<u64, NumRegisters> registers{};
std::array<u64, NumRegisters> saved_values{};
- std::array<size_t, NumRegisters> loop_tops{};
+ std::array<std::size_t, NumRegisters> loop_tops{};
-private:
bool DecodeNextOpcode(CheatVmOpcode& out);
void SkipConditionalBlock();
void ResetState();
- /* For implementing the DebugLog opcode. */
+ // For implementing the DebugLog opcode.
void DebugLog(u32 log_id, u64 value);
- /* For debugging. These will be IFDEF'd out normally. */
- template <typename... Args>
- void LogToDebugFile(const char* format, const Args&... args) {
- callbacks->CommandLog(fmt::sprintf(format, args...));
- }
-
void LogOpcode(const CheatVmOpcode& opcode);
static u64 GetVmInt(VmInt value, u32 bit_width);
static u64 GetCheatProcessAddress(const CheatProcessMetadata& metadata,
MemoryAccessType mem_type, u64 rel_address);
-
-public:
- DmntCheatVm(std::unique_ptr<Callbacks> callbacks) : callbacks(std::move(callbacks)) {}
-
- size_t GetProgramSize() {
- return this->num_opcodes;
- }
-
- bool LoadProgram(const std::vector<CheatEntry>& cheats);
- void Execute(const CheatProcessMetadata& metadata);
};
}; // namespace Memory