summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 @@
17#include "core/file_sys/bis_factory.h" 17#include "core/file_sys/bis_factory.h"
18#include "core/file_sys/card_image.h" 18#include "core/file_sys/card_image.h"
19#include "core/file_sys/mode.h" 19#include "core/file_sys/mode.h"
20#include "core/file_sys/patch_manager.h"
20#include "core/file_sys/registered_cache.h" 21#include "core/file_sys/registered_cache.h"
21#include "core/file_sys/romfs_factory.h" 22#include "core/file_sys/romfs_factory.h"
22#include "core/file_sys/savedata_factory.h" 23#include "core/file_sys/savedata_factory.h"
@@ -43,8 +44,6 @@
43#include "core/settings.h" 44#include "core/settings.h"
44#include "core/telemetry_session.h" 45#include "core/telemetry_session.h"
45#include "core/tools/freezer.h" 46#include "core/tools/freezer.h"
46#include "file_sys/cheat_engine.h"
47#include "file_sys/patch_manager.h"
48#include "video_core/debug_utils/debug_utils.h" 47#include "video_core/debug_utils/debug_utils.h"
49#include "video_core/renderer_base.h" 48#include "video_core/renderer_base.h"
50#include "video_core/video_core.h" 49#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,
102 std::optional<u64> current_entry = std::nullopt; 102 std::optional<u64> current_entry = std::nullopt;
103 103
104 for (std::size_t i = 0; i < data.size(); ++i) { 104 for (std::size_t i = 0; i < data.size(); ++i) {
105 if (std::isspace(data[i])) { 105 if (::isspace(data[i])) {
106 continue; 106 continue;
107 } 107 }
108 108
@@ -143,7 +143,7 @@ std::vector<CheatEntry> TextCheatParser::Parse(const Core::System& system,
143 '\0'; 143 '\0';
144 144
145 i += name.length() + 1; 145 i += name.length() + 1;
146 } else if (std::isxdigit(data[i])) { 146 } else if (::isxdigit(data[i])) {
147 if (!current_entry || out[*current_entry].definition.num_opcodes >= 147 if (!current_entry || out[*current_entry].definition.num_opcodes >=
148 out[*current_entry].definition.opcodes.size()) { 148 out[*current_entry].definition.opcodes.size()) {
149 return {}; 149 return {};
@@ -188,7 +188,7 @@ CheatEngine::~CheatEngine() {
188 188
189void CheatEngine::Initialize() { 189void CheatEngine::Initialize() {
190 event = core_timing.RegisterEvent( 190 event = core_timing.RegisterEvent(
191 "CheatEngine::FrameCallback::" + Common::HexArrayToString(metadata.main_nso_build_id), 191 "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id),
192 [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); }); 192 [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); });
193 core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS, event); 193 core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS, event);
194 194
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 @@
29 29
30namespace Memory { 30namespace Memory {
31 31
32DmntCheatVm::DmntCheatVm(std::unique_ptr<Callbacks> callbacks) : callbacks(std::move(callbacks)) {}
33
34DmntCheatVm::~DmntCheatVm() = default;
35
32void DmntCheatVm::DebugLog(u32 log_id, u64 value) { 36void DmntCheatVm::DebugLog(u32 log_id, u64 value) {
33 callbacks->DebugLog(static_cast<u8>(log_id), value); 37 callbacks->DebugLog(static_cast<u8>(log_id), value);
34} 38}
35 39
36void DmntCheatVm::LogOpcode(const CheatVmOpcode& opcode) { 40void DmntCheatVm::LogOpcode(const CheatVmOpcode& opcode) {
37 switch (opcode.opcode) { 41 if (auto store_static = std::get_if<StoreStaticOpcode>(&opcode.opcode)) {
38 case CheatVmOpcodeType_StoreStatic: 42 callbacks->CommandLog("Opcode: Store Static");
39 this->LogToDebugFile("Opcode: Store Static\n"); 43 callbacks->CommandLog(fmt::format("Bit Width: {:X}", store_static->bit_width));
40 this->LogToDebugFile("Bit Width: %x\n", opcode.store_static.bit_width); 44 callbacks->CommandLog(
41 this->LogToDebugFile("Mem Type: %x\n", opcode.store_static.mem_type); 45 fmt::format("Mem Type: {:X}", static_cast<u32>(store_static->mem_type)));
42 this->LogToDebugFile("Reg Idx: %x\n", opcode.store_static.offset_register); 46 callbacks->CommandLog(fmt::format("Reg Idx: {:X}", store_static->offset_register));
43 this->LogToDebugFile("Rel Addr: %lx\n", opcode.store_static.rel_address); 47 callbacks->CommandLog(fmt::format("Rel Addr: {:X}", store_static->rel_address));
44 this->LogToDebugFile("Value: %lx\n", opcode.store_static.value.bit64); 48 callbacks->CommandLog(fmt::format("Value: {:X}", store_static->value.bit64));
45 break; 49 } else if (auto begin_cond = std::get_if<BeginConditionalOpcode>(&opcode.opcode)) {
46 case CheatVmOpcodeType_BeginConditionalBlock: 50 callbacks->CommandLog("Opcode: Begin Conditional");
47 this->LogToDebugFile("Opcode: Begin Conditional\n"); 51 callbacks->CommandLog(fmt::format("Bit Width: {:X}", begin_cond->bit_width));
48 this->LogToDebugFile("Bit Width: %x\n", opcode.begin_cond.bit_width); 52 callbacks->CommandLog(
49 this->LogToDebugFile("Mem Type: %x\n", opcode.begin_cond.mem_type); 53 fmt::format("Mem Type: {:X}", static_cast<u32>(begin_cond->mem_type)));
50 this->LogToDebugFile("Cond Type: %x\n", opcode.begin_cond.cond_type); 54 callbacks->CommandLog(
51 this->LogToDebugFile("Rel Addr: %lx\n", opcode.begin_cond.rel_address); 55 fmt::format("Cond Type: {:X}", static_cast<u32>(begin_cond->cond_type)));
52 this->LogToDebugFile("Value: %lx\n", opcode.begin_cond.value.bit64); 56 callbacks->CommandLog(fmt::format("Rel Addr: {:X}", begin_cond->rel_address));
53 break; 57 callbacks->CommandLog(fmt::format("Value: {:X}", begin_cond->value.bit64));
54 case CheatVmOpcodeType_EndConditionalBlock: 58 } else if (auto end_cond = std::get_if<EndConditionalOpcode>(&opcode.opcode)) {
55 this->LogToDebugFile("Opcode: End Conditional\n"); 59 callbacks->CommandLog("Opcode: End Conditional");
56 break; 60 } else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&opcode.opcode)) {
57 case CheatVmOpcodeType_ControlLoop: 61 if (ctrl_loop->start_loop) {
58 if (opcode.ctrl_loop.start_loop) { 62 callbacks->CommandLog("Opcode: Start Loop");
59 this->LogToDebugFile("Opcode: Start Loop\n"); 63 callbacks->CommandLog(fmt::format("Reg Idx: {:X}", ctrl_loop->reg_index));
60 this->LogToDebugFile("Reg Idx: %x\n", opcode.ctrl_loop.reg_index); 64 callbacks->CommandLog(fmt::format("Num Iters: {:X}", ctrl_loop->num_iters));
61 this->LogToDebugFile("Num Iters: %x\n", opcode.ctrl_loop.num_iters);
62 } else { 65 } else {
63 this->LogToDebugFile("Opcode: End Loop\n"); 66 callbacks->CommandLog("Opcode: End Loop");
64 this->LogToDebugFile("Reg Idx: %x\n", opcode.ctrl_loop.reg_index); 67 callbacks->CommandLog(fmt::format("Reg Idx: {:X}", ctrl_loop->reg_index));
65 } 68 }
66 break; 69 } else if (auto ldr_static = std::get_if<LoadRegisterStaticOpcode>(&opcode.opcode)) {
67 case CheatVmOpcodeType_LoadRegisterStatic: 70 callbacks->CommandLog("Opcode: Load Register Static");
68 this->LogToDebugFile("Opcode: Load Register Static\n"); 71 callbacks->CommandLog(fmt::format("Reg Idx: {:X}", ldr_static->reg_index));
69 this->LogToDebugFile("Reg Idx: %x\n", opcode.ldr_static.reg_index); 72 callbacks->CommandLog(fmt::format("Value: {:X}", ldr_static->value));
70 this->LogToDebugFile("Value: %lx\n", opcode.ldr_static.value); 73 } else if (auto ldr_memory = std::get_if<LoadRegisterMemoryOpcode>(&opcode.opcode)) {
71 break; 74 callbacks->CommandLog("Opcode: Load Register Memory");
72 case CheatVmOpcodeType_LoadRegisterMemory: 75 callbacks->CommandLog(fmt::format("Bit Width: {:X}", ldr_memory->bit_width));
73 this->LogToDebugFile("Opcode: Load Register Memory\n"); 76 callbacks->CommandLog(fmt::format("Reg Idx: {:X}", ldr_memory->reg_index));
74 this->LogToDebugFile("Bit Width: %x\n", opcode.ldr_memory.bit_width); 77 callbacks->CommandLog(
75 this->LogToDebugFile("Reg Idx: %x\n", opcode.ldr_memory.reg_index); 78 fmt::format("Mem Type: {:X}", static_cast<u32>(ldr_memory->mem_type)));
76 this->LogToDebugFile("Mem Type: %x\n", opcode.ldr_memory.mem_type); 79 callbacks->CommandLog(fmt::format("From Reg: {:d}", ldr_memory->load_from_reg));
77 this->LogToDebugFile("From Reg: %d\n", opcode.ldr_memory.load_from_reg); 80 callbacks->CommandLog(fmt::format("Rel Addr: {:X}", ldr_memory->rel_address));
78 this->LogToDebugFile("Rel Addr: %lx\n", opcode.ldr_memory.rel_address); 81 } else if (auto str_static = std::get_if<StoreStaticToAddressOpcode>(&opcode.opcode)) {
79 break; 82 callbacks->CommandLog("Opcode: Store Static to Address");
80 case CheatVmOpcodeType_StoreStaticToAddress: 83 callbacks->CommandLog(fmt::format("Bit Width: {:X}", str_static->bit_width));
81 this->LogToDebugFile("Opcode: Store Static to Address\n"); 84 callbacks->CommandLog(fmt::format("Reg Idx: {:X}", str_static->reg_index));
82 this->LogToDebugFile("Bit Width: %x\n", opcode.str_static.bit_width); 85 if (str_static->add_offset_reg) {
83 this->LogToDebugFile("Reg Idx: %x\n", opcode.str_static.reg_index); 86 callbacks->CommandLog(fmt::format("O Reg Idx: {:X}", str_static->offset_reg_index));
84 if (opcode.str_static.add_offset_reg) {
85 this->LogToDebugFile("O Reg Idx: %x\n", opcode.str_static.offset_reg_index);
86 } 87 }
87 this->LogToDebugFile("Incr Reg: %d\n", opcode.str_static.increment_reg); 88 callbacks->CommandLog(fmt::format("Incr Reg: {:d}", str_static->increment_reg));
88 this->LogToDebugFile("Value: %lx\n", opcode.str_static.value); 89 callbacks->CommandLog(fmt::format("Value: {:X}", str_static->value));
89 break; 90 } else if (auto perform_math_static =
90 case CheatVmOpcodeType_PerformArithmeticStatic: 91 std::get_if<PerformArithmeticStaticOpcode>(&opcode.opcode)) {
91 this->LogToDebugFile("Opcode: Perform Static Arithmetic\n"); 92 callbacks->CommandLog("Opcode: Perform Static Arithmetic");
92 this->LogToDebugFile("Bit Width: %x\n", opcode.perform_math_static.bit_width); 93 callbacks->CommandLog(fmt::format("Bit Width: {:X}", perform_math_static->bit_width));
93 this->LogToDebugFile("Reg Idx: %x\n", opcode.perform_math_static.reg_index); 94 callbacks->CommandLog(fmt::format("Reg Idx: {:X}", perform_math_static->reg_index));
94 this->LogToDebugFile("Math Type: %x\n", opcode.perform_math_static.math_type); 95 callbacks->CommandLog(
95 this->LogToDebugFile("Value: %lx\n", opcode.perform_math_static.value); 96 fmt::format("Math Type: {:X}", static_cast<u32>(perform_math_static->math_type)));
96 break; 97 callbacks->CommandLog(fmt::format("Value: {:X}", perform_math_static->value));
97 case CheatVmOpcodeType_BeginKeypressConditionalBlock: 98 } else if (auto begin_keypress_cond =
98 this->LogToDebugFile("Opcode: Begin Keypress Conditional\n"); 99 std::get_if<BeginKeypressConditionalOpcode>(&opcode.opcode)) {
99 this->LogToDebugFile("Key Mask: %x\n", opcode.begin_keypress_cond.key_mask); 100 callbacks->CommandLog("Opcode: Begin Keypress Conditional");
100 break; 101 callbacks->CommandLog(fmt::format("Key Mask: {:X}", begin_keypress_cond->key_mask));
101 case CheatVmOpcodeType_PerformArithmeticRegister: 102 } else if (auto perform_math_reg =
102 this->LogToDebugFile("Opcode: Perform Register Arithmetic\n"); 103 std::get_if<PerformArithmeticRegisterOpcode>(&opcode.opcode)) {
103 this->LogToDebugFile("Bit Width: %x\n", opcode.perform_math_reg.bit_width); 104 callbacks->CommandLog("Opcode: Perform Register Arithmetic");
104 this->LogToDebugFile("Dst Idx: %x\n", opcode.perform_math_reg.dst_reg_index); 105 callbacks->CommandLog(fmt::format("Bit Width: {:X}", perform_math_reg->bit_width));
105 this->LogToDebugFile("Src1 Idx: %x\n", opcode.perform_math_reg.src_reg_1_index); 106 callbacks->CommandLog(fmt::format("Dst Idx: {:X}", perform_math_reg->dst_reg_index));
106 if (opcode.perform_math_reg.has_immediate) { 107 callbacks->CommandLog(fmt::format("Src1 Idx: {:X}", perform_math_reg->src_reg_1_index));
107 this->LogToDebugFile("Value: %lx\n", opcode.perform_math_reg.value.bit64); 108 if (perform_math_reg->has_immediate) {
109 callbacks->CommandLog(fmt::format("Value: {:X}", perform_math_reg->value.bit64));
108 } else { 110 } else {
109 this->LogToDebugFile("Src2 Idx: %x\n", opcode.perform_math_reg.src_reg_2_index); 111 callbacks->CommandLog(
112 fmt::format("Src2 Idx: {:X}", perform_math_reg->src_reg_2_index));
110 } 113 }
111 break; 114 } else if (auto str_register = std::get_if<StoreRegisterToAddressOpcode>(&opcode.opcode)) {
112 case CheatVmOpcodeType_StoreRegisterToAddress: 115 callbacks->CommandLog("Opcode: Store Register to Address");
113 this->LogToDebugFile("Opcode: Store Register to Address\n"); 116 callbacks->CommandLog(fmt::format("Bit Width: {:X}", str_register->bit_width));
114 this->LogToDebugFile("Bit Width: %x\n", opcode.str_register.bit_width); 117 callbacks->CommandLog(fmt::format("S Reg Idx: {:X}", str_register->str_reg_index));
115 this->LogToDebugFile("S Reg Idx: %x\n", opcode.str_register.str_reg_index); 118 callbacks->CommandLog(fmt::format("A Reg Idx: {:X}", str_register->addr_reg_index));
116 this->LogToDebugFile("A Reg Idx: %x\n", opcode.str_register.addr_reg_index); 119 callbacks->CommandLog(fmt::format("Incr Reg: {:d}", str_register->increment_reg));
117 this->LogToDebugFile("Incr Reg: %d\n", opcode.str_register.increment_reg); 120 switch (str_register->ofs_type) {
118 switch (opcode.str_register.ofs_type) { 121 case StoreRegisterOffsetType::None:
119 case StoreRegisterOffsetType_None:
120 break; 122 break;
121 case StoreRegisterOffsetType_Reg: 123 case StoreRegisterOffsetType::Reg:
122 this->LogToDebugFile("O Reg Idx: %x\n", opcode.str_register.ofs_reg_index); 124 callbacks->CommandLog(fmt::format("O Reg Idx: {:X}", str_register->ofs_reg_index));
123 break; 125 break;
124 case StoreRegisterOffsetType_Imm: 126 case StoreRegisterOffsetType::Imm:
125 this->LogToDebugFile("Rel Addr: %lx\n", opcode.str_register.rel_address); 127 callbacks->CommandLog(fmt::format("Rel Addr: {:X}", str_register->rel_address));
126 break; 128 break;
127 case StoreRegisterOffsetType_MemReg: 129 case StoreRegisterOffsetType::MemReg:
128 this->LogToDebugFile("Mem Type: %x\n", opcode.str_register.mem_type); 130 callbacks->CommandLog(
131 fmt::format("Mem Type: {:X}", static_cast<u32>(str_register->mem_type)));
129 break; 132 break;
130 case StoreRegisterOffsetType_MemImm: 133 case StoreRegisterOffsetType::MemImm:
131 case StoreRegisterOffsetType_MemImmReg: 134 case StoreRegisterOffsetType::MemImmReg:
132 this->LogToDebugFile("Mem Type: %x\n", opcode.str_register.mem_type); 135 callbacks->CommandLog(
133 this->LogToDebugFile("Rel Addr: %lx\n", opcode.str_register.rel_address); 136 fmt::format("Mem Type: {:X}", static_cast<u32>(str_register->mem_type)));
137 callbacks->CommandLog(fmt::format("Rel Addr: {:X}", str_register->rel_address));
134 break; 138 break;
135 } 139 }
136 break; 140 } else if (auto begin_reg_cond = std::get_if<BeginRegisterConditionalOpcode>(&opcode.opcode)) {
137 case CheatVmOpcodeType_BeginRegisterConditionalBlock: 141 callbacks->CommandLog("Opcode: Begin Register Conditional");
138 this->LogToDebugFile("Opcode: Begin Register Conditional\n"); 142 callbacks->CommandLog(fmt::format("Bit Width: {:X}", begin_reg_cond->bit_width));
139 this->LogToDebugFile("Bit Width: %x\n", opcode.begin_reg_cond.bit_width); 143 callbacks->CommandLog(
140 this->LogToDebugFile("Cond Type: %x\n", opcode.begin_reg_cond.cond_type); 144 fmt::format("Cond Type: {:X}", static_cast<u32>(begin_reg_cond->cond_type)));
141 this->LogToDebugFile("V Reg Idx: %x\n", opcode.begin_reg_cond.val_reg_index); 145 callbacks->CommandLog(fmt::format("V Reg Idx: {:X}", begin_reg_cond->val_reg_index));
142 switch (opcode.begin_reg_cond.comp_type) { 146 switch (begin_reg_cond->comp_type) {
143 case CompareRegisterValueType_StaticValue: 147 case CompareRegisterValueType::StaticValue:
144 this->LogToDebugFile("Comp Type: Static Value\n"); 148 callbacks->CommandLog("Comp Type: Static Value");
145 this->LogToDebugFile("Value: %lx\n", opcode.begin_reg_cond.value.bit64); 149 callbacks->CommandLog(fmt::format("Value: {:X}", begin_reg_cond->value.bit64));
146 break; 150 break;
147 case CompareRegisterValueType_OtherRegister: 151 case CompareRegisterValueType::OtherRegister:
148 this->LogToDebugFile("Comp Type: Other Register\n"); 152 callbacks->CommandLog("Comp Type: Other Register");
149 this->LogToDebugFile("X Reg Idx: %x\n", opcode.begin_reg_cond.other_reg_index); 153 callbacks->CommandLog(fmt::format("X Reg Idx: {:X}", begin_reg_cond->other_reg_index));
150 break; 154 break;
151 case CompareRegisterValueType_MemoryRelAddr: 155 case CompareRegisterValueType::MemoryRelAddr:
152 this->LogToDebugFile("Comp Type: Memory Relative Address\n"); 156 callbacks->CommandLog("Comp Type: Memory Relative Address");
153 this->LogToDebugFile("Mem Type: %x\n", opcode.begin_reg_cond.mem_type); 157 callbacks->CommandLog(
154 this->LogToDebugFile("Rel Addr: %lx\n", opcode.begin_reg_cond.rel_address); 158 fmt::format("Mem Type: {:X}", static_cast<u32>(begin_reg_cond->mem_type)));
159 callbacks->CommandLog(fmt::format("Rel Addr: {:X}", begin_reg_cond->rel_address));
155 break; 160 break;
156 case CompareRegisterValueType_MemoryOfsReg: 161 case CompareRegisterValueType::MemoryOfsReg:
157 this->LogToDebugFile("Comp Type: Memory Offset Register\n"); 162 callbacks->CommandLog("Comp Type: Memory Offset Register");
158 this->LogToDebugFile("Mem Type: %x\n", opcode.begin_reg_cond.mem_type); 163 callbacks->CommandLog(
159 this->LogToDebugFile("O Reg Idx: %x\n", opcode.begin_reg_cond.ofs_reg_index); 164 fmt::format("Mem Type: {:X}", static_cast<u32>(begin_reg_cond->mem_type)));
165 callbacks->CommandLog(fmt::format("O Reg Idx: {:X}", begin_reg_cond->ofs_reg_index));
160 break; 166 break;
161 case CompareRegisterValueType_RegisterRelAddr: 167 case CompareRegisterValueType::RegisterRelAddr:
162 this->LogToDebugFile("Comp Type: Register Relative Address\n"); 168 callbacks->CommandLog("Comp Type: Register Relative Address");
163 this->LogToDebugFile("A Reg Idx: %x\n", opcode.begin_reg_cond.addr_reg_index); 169 callbacks->CommandLog(fmt::format("A Reg Idx: {:X}", begin_reg_cond->addr_reg_index));
164 this->LogToDebugFile("Rel Addr: %lx\n", opcode.begin_reg_cond.rel_address); 170 callbacks->CommandLog(fmt::format("Rel Addr: {:X}", begin_reg_cond->rel_address));
165 break; 171 break;
166 case CompareRegisterValueType_RegisterOfsReg: 172 case CompareRegisterValueType::RegisterOfsReg:
167 this->LogToDebugFile("Comp Type: Register Offset Register\n"); 173 callbacks->CommandLog("Comp Type: Register Offset Register");
168 this->LogToDebugFile("A Reg Idx: %x\n", opcode.begin_reg_cond.addr_reg_index); 174 callbacks->CommandLog(fmt::format("A Reg Idx: {:X}", begin_reg_cond->addr_reg_index));
169 this->LogToDebugFile("O Reg Idx: %x\n", opcode.begin_reg_cond.ofs_reg_index); 175 callbacks->CommandLog(fmt::format("O Reg Idx: {:X}", begin_reg_cond->ofs_reg_index));
170 break; 176 break;
171 } 177 }
172 break; 178 } else if (auto save_restore_reg = std::get_if<SaveRestoreRegisterOpcode>(&opcode.opcode)) {
173 case CheatVmOpcodeType_SaveRestoreRegister: 179 callbacks->CommandLog("Opcode: Save or Restore Register");
174 this->LogToDebugFile("Opcode: Save or Restore Register\n"); 180 callbacks->CommandLog(fmt::format("Dst Idx: {:X}", save_restore_reg->dst_index));
175 this->LogToDebugFile("Dst Idx: %x\n", opcode.save_restore_reg.dst_index); 181 callbacks->CommandLog(fmt::format("Src Idx: {:X}", save_restore_reg->src_index));
176 this->LogToDebugFile("Src Idx: %x\n", opcode.save_restore_reg.src_index); 182 callbacks->CommandLog(
177 this->LogToDebugFile("Op Type: %d\n", opcode.save_restore_reg.op_type); 183 fmt::format("Op Type: {:d}", static_cast<u32>(save_restore_reg->op_type)));
178 break; 184 } else if (auto save_restore_regmask =
179 case CheatVmOpcodeType_SaveRestoreRegisterMask: 185 std::get_if<SaveRestoreRegisterMaskOpcode>(&opcode.opcode)) {
180 this->LogToDebugFile("Opcode: Save or Restore Register Mask\n"); 186 callbacks->CommandLog("Opcode: Save or Restore Register Mask");
181 this->LogToDebugFile("Op Type: %d\n", opcode.save_restore_regmask.op_type); 187 callbacks->CommandLog(
182 for (size_t i = 0; i < NumRegisters; i++) { 188 fmt::format("Op Type: {:d}", static_cast<u32>(save_restore_regmask->op_type)));
183 this->LogToDebugFile("Act[%02x]: %d\n", i, 189 for (std::size_t i = 0; i < NumRegisters; i++) {
184 opcode.save_restore_regmask.should_operate[i]); 190 callbacks->CommandLog(
191 fmt::format("Act[{:02X}]: {:d}", i, save_restore_regmask->should_operate[i]));
185 } 192 }
186 break; 193 } else if (auto debug_log = std::get_if<DebugLogOpcode>(&opcode.opcode)) {
187 case CheatVmOpcodeType_DebugLog: 194 callbacks->CommandLog("Opcode: Debug Log");
188 this->LogToDebugFile("Opcode: Debug Log\n"); 195 callbacks->CommandLog(fmt::format("Bit Width: {:X}", debug_log->bit_width));
189 this->LogToDebugFile("Bit Width: %x\n", opcode.debug_log.bit_width); 196 callbacks->CommandLog(fmt::format("Log ID: {:X}", debug_log->log_id));
190 this->LogToDebugFile("Log ID: %x\n", opcode.debug_log.log_id); 197 callbacks->CommandLog(
191 this->LogToDebugFile("Val Type: %x\n", opcode.debug_log.val_type); 198 fmt::format("Val Type: {:X}", static_cast<u32>(debug_log->val_type)));
192 switch (opcode.debug_log.val_type) { 199 switch (debug_log->val_type) {
193 case DebugLogValueType_RegisterValue: 200 case DebugLogValueType::RegisterValue:
194 this->LogToDebugFile("Val Type: Register Value\n"); 201 callbacks->CommandLog("Val Type: Register Value");
195 this->LogToDebugFile("X Reg Idx: %x\n", opcode.debug_log.val_reg_index); 202 callbacks->CommandLog(fmt::format("X Reg Idx: {:X}", debug_log->val_reg_index));
196 break; 203 break;
197 case DebugLogValueType_MemoryRelAddr: 204 case DebugLogValueType::MemoryRelAddr:
198 this->LogToDebugFile("Val Type: Memory Relative Address\n"); 205 callbacks->CommandLog("Val Type: Memory Relative Address");
199 this->LogToDebugFile("Mem Type: %x\n", opcode.debug_log.mem_type); 206 callbacks->CommandLog(
200 this->LogToDebugFile("Rel Addr: %lx\n", opcode.debug_log.rel_address); 207 fmt::format("Mem Type: {:X}", static_cast<u32>(debug_log->mem_type)));
208 callbacks->CommandLog(fmt::format("Rel Addr: {:X}", debug_log->rel_address));
201 break; 209 break;
202 case DebugLogValueType_MemoryOfsReg: 210 case DebugLogValueType::MemoryOfsReg:
203 this->LogToDebugFile("Val Type: Memory Offset Register\n"); 211 callbacks->CommandLog("Val Type: Memory Offset Register");
204 this->LogToDebugFile("Mem Type: %x\n", opcode.debug_log.mem_type); 212 callbacks->CommandLog(
205 this->LogToDebugFile("O Reg Idx: %x\n", opcode.debug_log.ofs_reg_index); 213 fmt::format("Mem Type: {:X}", static_cast<u32>(debug_log->mem_type)));
214 callbacks->CommandLog(fmt::format("O Reg Idx: {:X}", debug_log->ofs_reg_index));
206 break; 215 break;
207 case DebugLogValueType_RegisterRelAddr: 216 case DebugLogValueType::RegisterRelAddr:
208 this->LogToDebugFile("Val Type: Register Relative Address\n"); 217 callbacks->CommandLog("Val Type: Register Relative Address");
209 this->LogToDebugFile("A Reg Idx: %x\n", opcode.debug_log.addr_reg_index); 218 callbacks->CommandLog(fmt::format("A Reg Idx: {:X}", debug_log->addr_reg_index));
210 this->LogToDebugFile("Rel Addr: %lx\n", opcode.debug_log.rel_address); 219 callbacks->CommandLog(fmt::format("Rel Addr: {:X}", debug_log->rel_address));
211 break; 220 break;
212 case DebugLogValueType_RegisterOfsReg: 221 case DebugLogValueType::RegisterOfsReg:
213 this->LogToDebugFile("Val Type: Register Offset Register\n"); 222 callbacks->CommandLog("Val Type: Register Offset Register");
214 this->LogToDebugFile("A Reg Idx: %x\n", opcode.debug_log.addr_reg_index); 223 callbacks->CommandLog(fmt::format("A Reg Idx: {:X}", debug_log->addr_reg_index));
215 this->LogToDebugFile("O Reg Idx: %x\n", opcode.debug_log.ofs_reg_index); 224 callbacks->CommandLog(fmt::format("O Reg Idx: {:X}", debug_log->ofs_reg_index));
216 break; 225 break;
217 } 226 }
218 default: 227 } else if (auto instr = std::get_if<UnrecognizedInstruction>(&opcode.opcode)) {
219 this->LogToDebugFile("Unknown opcode: %x\n", opcode.opcode); 228 callbacks->CommandLog(fmt::format("Unknown opcode: {:X}", static_cast<u32>(instr->opcode)));
220 break;
221 } 229 }
222} 230}
223 231
224DmntCheatVm::Callbacks::~Callbacks() = default; 232DmntCheatVm::Callbacks::~Callbacks() = default;
225 233
226bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) { 234bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
227 /* If we've ever seen a decode failure, return false. */ 235 // If we've ever seen a decode failure, return false.
228 bool valid = this->decode_success; 236 bool valid = decode_success;
229 CheatVmOpcode opcode = {}; 237 CheatVmOpcode opcode = {};
230 SCOPE_EXIT({ 238 SCOPE_EXIT({
231 this->decode_success &= valid; 239 decode_success &= valid;
232 if (valid) { 240 if (valid) {
233 out = opcode; 241 out = opcode;
234 } 242 }
235 }); 243 });
236 244
237 /* Helper function for getting instruction dwords. */ 245 // Helper function for getting instruction dwords.
238 auto GetNextDword = [&]() { 246 const auto GetNextDword = [&] {
239 if (this->instruction_ptr >= this->num_opcodes) { 247 if (instruction_ptr >= num_opcodes) {
240 valid = false; 248 valid = false;
241 return static_cast<u32>(0); 249 return static_cast<u32>(0);
242 } 250 }
243 return this->program[this->instruction_ptr++]; 251 return program[instruction_ptr++];
244 }; 252 };
245 253
246 /* Helper function for parsing a VmInt. */ 254 // Helper function for parsing a VmInt.
247 auto GetNextVmInt = [&](const u32 bit_width) { 255 const auto GetNextVmInt = [&](const u32 bit_width) {
248 VmInt val = {0}; 256 VmInt val{};
249 257
250 const u32 first_dword = GetNextDword(); 258 const u32 first_dword = GetNextDword();
251 switch (bit_width) { 259 switch (bit_width) {
252 case 1: 260 case 1:
253 val.bit8 = (u8)first_dword; 261 val.bit8 = static_cast<u8>(first_dword);
254 break; 262 break;
255 case 2: 263 case 2:
256 val.bit16 = (u16)first_dword; 264 val.bit16 = static_cast<u16>(first_dword);
257 break; 265 break;
258 case 4: 266 case 4:
259 val.bit32 = first_dword; 267 val.bit32 = first_dword;
260 break; 268 break;
261 case 8: 269 case 8:
262 val.bit64 = (((u64)first_dword) << 32ul) | ((u64)GetNextDword()); 270 val.bit64 = (static_cast<u64>(first_dword) << 32ul) | static_cast<u64>(GetNextDword());
263 break; 271 break;
264 } 272 }
265 273
266 return val; 274 return val;
267 }; 275 };
268 276
269 /* Read opcode. */ 277 // Read opcode.
270 const u32 first_dword = GetNextDword(); 278 const u32 first_dword = GetNextDword();
271 if (!valid) { 279 if (!valid) {
272 return valid; 280 return valid;
273 } 281 }
274 282
275 opcode.opcode = (CheatVmOpcodeType)(((first_dword >> 28) & 0xF)); 283 auto opcode_type = static_cast<CheatVmOpcodeType>(((first_dword >> 28) & 0xF));
276 if (opcode.opcode >= CheatVmOpcodeType_ExtendedWidth) { 284 if (opcode_type >= CheatVmOpcodeType::ExtendedWidth) {
277 opcode.opcode = 285 opcode_type = static_cast<CheatVmOpcodeType>((static_cast<u32>(opcode_type) << 4) |
278 (CheatVmOpcodeType)((((u32)opcode.opcode) << 4) | ((first_dword >> 24) & 0xF)); 286 ((first_dword >> 24) & 0xF));
279 } 287 }
280 if (opcode.opcode >= CheatVmOpcodeType_DoubleExtendedWidth) { 288 if (opcode_type >= CheatVmOpcodeType::DoubleExtendedWidth) {
281 opcode.opcode = 289 opcode_type = static_cast<CheatVmOpcodeType>((static_cast<u32>(opcode_type) << 4) |
282 (CheatVmOpcodeType)((((u32)opcode.opcode) << 4) | ((first_dword >> 20) & 0xF)); 290 ((first_dword >> 20) & 0xF));
283 } 291 }
284 292
285 /* detect condition start. */ 293 // detect condition start.
286 switch (opcode.opcode) { 294 switch (opcode_type) {
287 case CheatVmOpcodeType_BeginConditionalBlock: 295 case CheatVmOpcodeType::BeginConditionalBlock:
288 case CheatVmOpcodeType_BeginKeypressConditionalBlock: 296 case CheatVmOpcodeType::BeginKeypressConditionalBlock:
289 case CheatVmOpcodeType_BeginRegisterConditionalBlock: 297 case CheatVmOpcodeType::BeginRegisterConditionalBlock:
290 opcode.begin_conditional_block = true; 298 opcode.begin_conditional_block = true;
291 break; 299 break;
292 default: 300 default:
@@ -294,299 +302,335 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
294 break; 302 break;
295 } 303 }
296 304
297 switch (opcode.opcode) { 305 switch (opcode_type) {
298 case CheatVmOpcodeType_StoreStatic: { 306 case CheatVmOpcodeType::StoreStatic: {
299 /* 0TMR00AA AAAAAAAA YYYYYYYY (YYYYYYYY) */ 307 StoreStaticOpcode store_static{};
300 /* Read additional words. */ 308 // 0TMR00AA AAAAAAAA YYYYYYYY (YYYYYYYY)
309 // Read additional words.
301 const u32 second_dword = GetNextDword(); 310 const u32 second_dword = GetNextDword();
302 opcode.store_static.bit_width = (first_dword >> 24) & 0xF; 311 store_static.bit_width = (first_dword >> 24) & 0xF;
303 opcode.store_static.mem_type = (MemoryAccessType)((first_dword >> 20) & 0xF); 312 store_static.mem_type = static_cast<MemoryAccessType>((first_dword >> 20) & 0xF);
304 opcode.store_static.offset_register = ((first_dword >> 16) & 0xF); 313 store_static.offset_register = ((first_dword >> 16) & 0xF);
305 opcode.store_static.rel_address = ((u64)(first_dword & 0xFF) << 32ul) | ((u64)second_dword); 314 store_static.rel_address =
306 opcode.store_static.value = GetNextVmInt(opcode.store_static.bit_width); 315 (static_cast<u64>(first_dword & 0xFF) << 32ul) | static_cast<u64>(second_dword);
316 store_static.value = GetNextVmInt(store_static.bit_width);
317 opcode.opcode = store_static;
307 } break; 318 } break;
308 case CheatVmOpcodeType_BeginConditionalBlock: { 319 case CheatVmOpcodeType::BeginConditionalBlock: {
309 /* 1TMC00AA AAAAAAAA YYYYYYYY (YYYYYYYY) */ 320 BeginConditionalOpcode begin_cond{};
310 /* Read additional words. */ 321 // 1TMC00AA AAAAAAAA YYYYYYYY (YYYYYYYY)
322 // Read additional words.
311 const u32 second_dword = GetNextDword(); 323 const u32 second_dword = GetNextDword();
312 opcode.begin_cond.bit_width = (first_dword >> 24) & 0xF; 324 begin_cond.bit_width = (first_dword >> 24) & 0xF;
313 opcode.begin_cond.mem_type = (MemoryAccessType)((first_dword >> 20) & 0xF); 325 begin_cond.mem_type = static_cast<MemoryAccessType>((first_dword >> 20) & 0xF);
314 opcode.begin_cond.cond_type = (ConditionalComparisonType)((first_dword >> 16) & 0xF); 326 begin_cond.cond_type = static_cast<ConditionalComparisonType>((first_dword >> 16) & 0xF);
315 opcode.begin_cond.rel_address = ((u64)(first_dword & 0xFF) << 32ul) | ((u64)second_dword); 327 begin_cond.rel_address =
316 opcode.begin_cond.value = GetNextVmInt(opcode.store_static.bit_width); 328 (static_cast<u64>(first_dword & 0xFF) << 32ul) | static_cast<u64>(second_dword);
329 begin_cond.value = GetNextVmInt(begin_cond.bit_width);
330 opcode.opcode = begin_cond;
317 } break; 331 } break;
318 case CheatVmOpcodeType_EndConditionalBlock: { 332 case CheatVmOpcodeType::EndConditionalBlock: {
319 /* 20000000 */ 333 // 20000000
320 /* There's actually nothing left to process here! */ 334 // There's actually nothing left to process here!
335 opcode.opcode = EndConditionalOpcode{};
321 } break; 336 } break;
322 case CheatVmOpcodeType_ControlLoop: { 337 case CheatVmOpcodeType::ControlLoop: {
323 /* 300R0000 VVVVVVVV */ 338 ControlLoopOpcode ctrl_loop{};
324 /* 310R0000 */ 339 // 300R0000 VVVVVVVV
325 /* Parse register, whether loop start or loop end. */ 340 // 310R0000
326 opcode.ctrl_loop.start_loop = ((first_dword >> 24) & 0xF) == 0; 341 // Parse register, whether loop start or loop end.
327 opcode.ctrl_loop.reg_index = ((first_dword >> 20) & 0xF); 342 ctrl_loop.start_loop = ((first_dword >> 24) & 0xF) == 0;
343 ctrl_loop.reg_index = ((first_dword >> 20) & 0xF);
328 344
329 /* Read number of iters if loop start. */ 345 // Read number of iters if loop start.
330 if (opcode.ctrl_loop.start_loop) { 346 if (ctrl_loop.start_loop) {
331 opcode.ctrl_loop.num_iters = GetNextDword(); 347 ctrl_loop.num_iters = GetNextDword();
332 } 348 }
349 opcode.opcode = ctrl_loop;
333 } break; 350 } break;
334 case CheatVmOpcodeType_LoadRegisterStatic: { 351 case CheatVmOpcodeType::LoadRegisterStatic: {
335 /* 400R0000 VVVVVVVV VVVVVVVV */ 352 LoadRegisterStaticOpcode ldr_static{};
336 /* Read additional words. */ 353 // 400R0000 VVVVVVVV VVVVVVVV
337 opcode.ldr_static.reg_index = ((first_dword >> 16) & 0xF); 354 // Read additional words.
338 opcode.ldr_static.value = (((u64)GetNextDword()) << 32ul) | ((u64)GetNextDword()); 355 ldr_static.reg_index = ((first_dword >> 16) & 0xF);
356 ldr_static.value =
357 (static_cast<u64>(GetNextDword()) << 32ul) | static_cast<u64>(GetNextDword());
358 opcode.opcode = ldr_static;
339 } break; 359 } break;
340 case CheatVmOpcodeType_LoadRegisterMemory: { 360 case CheatVmOpcodeType::LoadRegisterMemory: {
341 /* 5TMRI0AA AAAAAAAA */ 361 LoadRegisterMemoryOpcode ldr_memory{};
342 /* Read additional words. */ 362 // 5TMRI0AA AAAAAAAA
363 // Read additional words.
343 const u32 second_dword = GetNextDword(); 364 const u32 second_dword = GetNextDword();
344 opcode.ldr_memory.bit_width = (first_dword >> 24) & 0xF; 365 ldr_memory.bit_width = (first_dword >> 24) & 0xF;
345 opcode.ldr_memory.mem_type = (MemoryAccessType)((first_dword >> 20) & 0xF); 366 ldr_memory.mem_type = static_cast<MemoryAccessType>((first_dword >> 20) & 0xF);
346 opcode.ldr_memory.reg_index = ((first_dword >> 16) & 0xF); 367 ldr_memory.reg_index = ((first_dword >> 16) & 0xF);
347 opcode.ldr_memory.load_from_reg = ((first_dword >> 12) & 0xF) != 0; 368 ldr_memory.load_from_reg = ((first_dword >> 12) & 0xF) != 0;
348 opcode.ldr_memory.rel_address = ((u64)(first_dword & 0xFF) << 32ul) | ((u64)second_dword); 369 ldr_memory.rel_address =
370 (static_cast<u64>(first_dword & 0xFF) << 32ul) | static_cast<u64>(second_dword);
371 opcode.opcode = ldr_memory;
349 } break; 372 } break;
350 case CheatVmOpcodeType_StoreStaticToAddress: { 373 case CheatVmOpcodeType::StoreStaticToAddress: {
351 /* 6T0RIor0 VVVVVVVV VVVVVVVV */ 374 StoreStaticToAddressOpcode str_static{};
352 /* Read additional words. */ 375 // 6T0RIor0 VVVVVVVV VVVVVVVV
353 opcode.str_static.bit_width = (first_dword >> 24) & 0xF; 376 // Read additional words.
354 opcode.str_static.reg_index = ((first_dword >> 16) & 0xF); 377 str_static.bit_width = (first_dword >> 24) & 0xF;
355 opcode.str_static.increment_reg = ((first_dword >> 12) & 0xF) != 0; 378 str_static.reg_index = ((first_dword >> 16) & 0xF);
356 opcode.str_static.add_offset_reg = ((first_dword >> 8) & 0xF) != 0; 379 str_static.increment_reg = ((first_dword >> 12) & 0xF) != 0;
357 opcode.str_static.offset_reg_index = ((first_dword >> 4) & 0xF); 380 str_static.add_offset_reg = ((first_dword >> 8) & 0xF) != 0;
358 opcode.str_static.value = (((u64)GetNextDword()) << 32ul) | ((u64)GetNextDword()); 381 str_static.offset_reg_index = ((first_dword >> 4) & 0xF);
382 str_static.value =
383 (static_cast<u64>(GetNextDword()) << 32ul) | static_cast<u64>(GetNextDword());
384 opcode.opcode = str_static;
359 } break; 385 } break;
360 case CheatVmOpcodeType_PerformArithmeticStatic: { 386 case CheatVmOpcodeType::PerformArithmeticStatic: {
361 /* 7T0RC000 VVVVVVVV */ 387 PerformArithmeticStaticOpcode perform_math_static{};
362 /* Read additional words. */ 388 // 7T0RC000 VVVVVVVV
363 opcode.perform_math_static.bit_width = (first_dword >> 24) & 0xF; 389 // Read additional words.
364 opcode.perform_math_static.reg_index = ((first_dword >> 16) & 0xF); 390 perform_math_static.bit_width = (first_dword >> 24) & 0xF;
365 opcode.perform_math_static.math_type = (RegisterArithmeticType)((first_dword >> 12) & 0xF); 391 perform_math_static.reg_index = ((first_dword >> 16) & 0xF);
366 opcode.perform_math_static.value = GetNextDword(); 392 perform_math_static.math_type =
393 static_cast<RegisterArithmeticType>((first_dword >> 12) & 0xF);
394 perform_math_static.value = GetNextDword();
395 opcode.opcode = perform_math_static;
367 } break; 396 } break;
368 case CheatVmOpcodeType_BeginKeypressConditionalBlock: { 397 case CheatVmOpcodeType::BeginKeypressConditionalBlock: {
369 /* 8kkkkkkk */ 398 BeginKeypressConditionalOpcode begin_keypress_cond{};
370 /* Just parse the mask. */ 399 // 8kkkkkkk
371 opcode.begin_keypress_cond.key_mask = first_dword & 0x0FFFFFFF; 400 // Just parse the mask.
401 begin_keypress_cond.key_mask = first_dword & 0x0FFFFFFF;
372 } break; 402 } break;
373 case CheatVmOpcodeType_PerformArithmeticRegister: { 403 case CheatVmOpcodeType::PerformArithmeticRegister: {
374 /* 9TCRSIs0 (VVVVVVVV (VVVVVVVV)) */ 404 PerformArithmeticRegisterOpcode perform_math_reg{};
375 opcode.perform_math_reg.bit_width = (first_dword >> 24) & 0xF; 405 // 9TCRSIs0 (VVVVVVVV (VVVVVVVV))
376 opcode.perform_math_reg.math_type = (RegisterArithmeticType)((first_dword >> 20) & 0xF); 406 perform_math_reg.bit_width = (first_dword >> 24) & 0xF;
377 opcode.perform_math_reg.dst_reg_index = ((first_dword >> 16) & 0xF); 407 perform_math_reg.math_type = static_cast<RegisterArithmeticType>((first_dword >> 20) & 0xF);
378 opcode.perform_math_reg.src_reg_1_index = ((first_dword >> 12) & 0xF); 408 perform_math_reg.dst_reg_index = ((first_dword >> 16) & 0xF);
379 opcode.perform_math_reg.has_immediate = ((first_dword >> 8) & 0xF) != 0; 409 perform_math_reg.src_reg_1_index = ((first_dword >> 12) & 0xF);
380 if (opcode.perform_math_reg.has_immediate) { 410 perform_math_reg.has_immediate = ((first_dword >> 8) & 0xF) != 0;
381 opcode.perform_math_reg.src_reg_2_index = 0; 411 if (perform_math_reg.has_immediate) {
382 opcode.perform_math_reg.value = GetNextVmInt(opcode.perform_math_reg.bit_width); 412 perform_math_reg.src_reg_2_index = 0;
413 perform_math_reg.value = GetNextVmInt(perform_math_reg.bit_width);
383 } else { 414 } else {
384 opcode.perform_math_reg.src_reg_2_index = ((first_dword >> 4) & 0xF); 415 perform_math_reg.src_reg_2_index = ((first_dword >> 4) & 0xF);
385 } 416 }
417 opcode.opcode = perform_math_reg;
386 } break; 418 } break;
387 case CheatVmOpcodeType_StoreRegisterToAddress: { 419 case CheatVmOpcodeType::StoreRegisterToAddress: {
388 /* ATSRIOxa (aaaaaaaa) */ 420 StoreRegisterToAddressOpcode str_register{};
389 /* A = opcode 10 */ 421 // ATSRIOxa (aaaaaaaa)
390 /* T = bit width */ 422 // A = opcode 10
391 /* S = src register index */ 423 // T = bit width
392 /* R = address register index */ 424 // S = src register index
393 /* I = 1 if increment address register, 0 if not increment address register */ 425 // R = address register index
394 /* O = offset type, 0 = None, 1 = Register, 2 = Immediate, 3 = Memory Region, 426 // I = 1 if increment address register, 0 if not increment address register
395 4 = Memory Region + Relative Address (ignore address register), 5 = Memory Region + 427 // O = offset type, 0 = None, 1 = Register, 2 = Immediate, 3 = Memory Region,
396 Relative Address */ 428 // 4 = Memory Region + Relative Address (ignore address register), 5 = Memory Region +
397 /* x = offset register (for offset type 1), memory type (for offset type 3) */ 429 // Relative Address
398 /* a = relative address (for offset type 2+3) */ 430 // x = offset register (for offset type 1), memory type (for offset type 3)
399 opcode.str_register.bit_width = (first_dword >> 24) & 0xF; 431 // a = relative address (for offset type 2+3)
400 opcode.str_register.str_reg_index = ((first_dword >> 20) & 0xF); 432 str_register.bit_width = (first_dword >> 24) & 0xF;
401 opcode.str_register.addr_reg_index = ((first_dword >> 16) & 0xF); 433 str_register.str_reg_index = ((first_dword >> 20) & 0xF);
402 opcode.str_register.increment_reg = ((first_dword >> 12) & 0xF) != 0; 434 str_register.addr_reg_index = ((first_dword >> 16) & 0xF);
403 opcode.str_register.ofs_type = (StoreRegisterOffsetType)(((first_dword >> 8) & 0xF)); 435 str_register.increment_reg = ((first_dword >> 12) & 0xF) != 0;
404 opcode.str_register.ofs_reg_index = ((first_dword >> 4) & 0xF); 436 str_register.ofs_type = static_cast<StoreRegisterOffsetType>(((first_dword >> 8) & 0xF));
405 switch (opcode.str_register.ofs_type) { 437 str_register.ofs_reg_index = ((first_dword >> 4) & 0xF);
406 case StoreRegisterOffsetType_None: 438 switch (str_register.ofs_type) {
407 case StoreRegisterOffsetType_Reg: 439 case StoreRegisterOffsetType::None:
408 /* Nothing more to do */ 440 case StoreRegisterOffsetType::Reg:
441 // Nothing more to do
409 break; 442 break;
410 case StoreRegisterOffsetType_Imm: 443 case StoreRegisterOffsetType::Imm:
411 opcode.str_register.rel_address = 444 str_register.rel_address =
412 (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword())); 445 ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
413 break; 446 break;
414 case StoreRegisterOffsetType_MemReg: 447 case StoreRegisterOffsetType::MemReg:
415 opcode.str_register.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF); 448 str_register.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
416 break; 449 break;
417 case StoreRegisterOffsetType_MemImm: 450 case StoreRegisterOffsetType::MemImm:
418 case StoreRegisterOffsetType_MemImmReg: 451 case StoreRegisterOffsetType::MemImmReg:
419 opcode.str_register.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF); 452 str_register.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
420 opcode.str_register.rel_address = 453 str_register.rel_address =
421 (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword())); 454 ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
422 break; 455 break;
423 default: 456 default:
424 opcode.str_register.ofs_type = StoreRegisterOffsetType_None; 457 str_register.ofs_type = StoreRegisterOffsetType::None;
425 break; 458 break;
426 } 459 }
460 opcode.opcode = str_register;
427 } break; 461 } break;
428 case CheatVmOpcodeType_BeginRegisterConditionalBlock: { 462 case CheatVmOpcodeType::BeginRegisterConditionalBlock: {
429 /* C0TcSX## */ 463 BeginRegisterConditionalOpcode begin_reg_cond{};
430 /* C0TcS0Ma aaaaaaaa */ 464 // C0TcSX##
431 /* C0TcS1Mr */ 465 // C0TcS0Ma aaaaaaaa
432 /* C0TcS2Ra aaaaaaaa */ 466 // C0TcS1Mr
433 /* C0TcS3Rr */ 467 // C0TcS2Ra aaaaaaaa
434 /* C0TcS400 VVVVVVVV (VVVVVVVV) */ 468 // C0TcS3Rr
435 /* C0TcS5X0 */ 469 // C0TcS400 VVVVVVVV (VVVVVVVV)
436 /* C0 = opcode 0xC0 */ 470 // C0TcS5X0
437 /* T = bit width */ 471 // C0 = opcode 0xC0
438 /* c = condition type. */ 472 // T = bit width
439 /* S = source register. */ 473 // c = condition type.
440 /* X = value operand type, 0 = main/heap with relative offset, 1 = main/heap with offset 474 // S = source register.
441 * register, */ 475 // X = value operand type, 0 = main/heap with relative offset, 1 = main/heap with offset
442 /* 2 = register with relative offset, 3 = register with offset register, 4 = static 476 // register,
443 * value, 5 = other register. */ 477 // 2 = register with relative offset, 3 = register with offset register, 4 = static
444 /* M = memory type. */ 478 // value, 5 = other register.
445 /* R = address register. */ 479 // M = memory type.
446 /* a = relative address. */ 480 // R = address register.
447 /* r = offset register. */ 481 // a = relative address.
448 /* X = other register. */ 482 // r = offset register.
449 /* V = value. */ 483 // X = other register.
450 opcode.begin_reg_cond.bit_width = (first_dword >> 20) & 0xF; 484 // V = value.
451 opcode.begin_reg_cond.cond_type = (ConditionalComparisonType)((first_dword >> 16) & 0xF); 485 begin_reg_cond.bit_width = (first_dword >> 20) & 0xF;
452 opcode.begin_reg_cond.val_reg_index = ((first_dword >> 12) & 0xF); 486 begin_reg_cond.cond_type =
453 opcode.begin_reg_cond.comp_type = (CompareRegisterValueType)((first_dword >> 8) & 0xF); 487 static_cast<ConditionalComparisonType>((first_dword >> 16) & 0xF);
488 begin_reg_cond.val_reg_index = ((first_dword >> 12) & 0xF);
489 begin_reg_cond.comp_type = static_cast<CompareRegisterValueType>((first_dword >> 8) & 0xF);
454 490
455 switch (opcode.begin_reg_cond.comp_type) { 491 switch (begin_reg_cond.comp_type) {
456 case CompareRegisterValueType_StaticValue: 492 case CompareRegisterValueType::StaticValue:
457 opcode.begin_reg_cond.value = GetNextVmInt(opcode.begin_reg_cond.bit_width); 493 begin_reg_cond.value = GetNextVmInt(begin_reg_cond.bit_width);
458 break; 494 break;
459 case CompareRegisterValueType_OtherRegister: 495 case CompareRegisterValueType::OtherRegister:
460 opcode.begin_reg_cond.other_reg_index = ((first_dword >> 4) & 0xF); 496 begin_reg_cond.other_reg_index = ((first_dword >> 4) & 0xF);
461 break; 497 break;
462 case CompareRegisterValueType_MemoryRelAddr: 498 case CompareRegisterValueType::MemoryRelAddr:
463 opcode.begin_reg_cond.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF); 499 begin_reg_cond.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
464 opcode.begin_reg_cond.rel_address = 500 begin_reg_cond.rel_address =
465 (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword())); 501 ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
466 break; 502 break;
467 case CompareRegisterValueType_MemoryOfsReg: 503 case CompareRegisterValueType::MemoryOfsReg:
468 opcode.begin_reg_cond.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF); 504 begin_reg_cond.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
469 opcode.begin_reg_cond.ofs_reg_index = (first_dword & 0xF); 505 begin_reg_cond.ofs_reg_index = (first_dword & 0xF);
470 break; 506 break;
471 case CompareRegisterValueType_RegisterRelAddr: 507 case CompareRegisterValueType::RegisterRelAddr:
472 opcode.begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF); 508 begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF);
473 opcode.begin_reg_cond.rel_address = 509 begin_reg_cond.rel_address =
474 (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword())); 510 ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
475 break; 511 break;
476 case CompareRegisterValueType_RegisterOfsReg: 512 case CompareRegisterValueType::RegisterOfsReg:
477 opcode.begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF); 513 begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF);
478 opcode.begin_reg_cond.ofs_reg_index = (first_dword & 0xF); 514 begin_reg_cond.ofs_reg_index = (first_dword & 0xF);
479 break; 515 break;
480 } 516 }
517 opcode.opcode = begin_reg_cond;
481 } break; 518 } break;
482 case CheatVmOpcodeType_SaveRestoreRegister: { 519 case CheatVmOpcodeType::SaveRestoreRegister: {
483 /* C10D0Sx0 */ 520 SaveRestoreRegisterOpcode save_restore_reg{};
484 /* C1 = opcode 0xC1 */ 521 // C10D0Sx0
485 /* D = destination index. */ 522 // C1 = opcode 0xC1
486 /* S = source index. */ 523 // D = destination index.
487 /* x = 3 if clearing reg, 2 if clearing saved value, 1 if saving a register, 0 if restoring 524 // S = source index.
488 * a register. */ 525 // x = 3 if clearing reg, 2 if clearing saved value, 1 if saving a register, 0 if restoring
489 /* NOTE: If we add more save slots later, current encoding is backwards compatible. */ 526 // a register.
490 opcode.save_restore_reg.dst_index = (first_dword >> 16) & 0xF; 527 // NOTE: If we add more save slots later, current encoding is backwards compatible.
491 opcode.save_restore_reg.src_index = (first_dword >> 8) & 0xF; 528 save_restore_reg.dst_index = (first_dword >> 16) & 0xF;
492 opcode.save_restore_reg.op_type = (SaveRestoreRegisterOpType)((first_dword >> 4) & 0xF); 529 save_restore_reg.src_index = (first_dword >> 8) & 0xF;
530 save_restore_reg.op_type = static_cast<SaveRestoreRegisterOpType>((first_dword >> 4) & 0xF);
531 opcode.opcode = save_restore_reg;
493 } break; 532 } break;
494 case CheatVmOpcodeType_SaveRestoreRegisterMask: { 533 case CheatVmOpcodeType::SaveRestoreRegisterMask: {
495 /* C2x0XXXX */ 534 SaveRestoreRegisterMaskOpcode save_restore_regmask{};
496 /* C2 = opcode 0xC2 */ 535 // C2x0XXXX
497 /* x = 3 if clearing reg, 2 if clearing saved value, 1 if saving, 0 if restoring. */ 536 // C2 = opcode 0xC2
498 /* X = 16-bit bitmask, bit i --> save or restore register i. */ 537 // x = 3 if clearing reg, 2 if clearing saved value, 1 if saving, 0 if restoring.
499 opcode.save_restore_regmask.op_type = 538 // X = 16-bit bitmask, bit i --> save or restore register i.
500 (SaveRestoreRegisterOpType)((first_dword >> 20) & 0xF); 539 save_restore_regmask.op_type =
501 for (size_t i = 0; i < NumRegisters; i++) { 540 static_cast<SaveRestoreRegisterOpType>((first_dword >> 20) & 0xF);
502 opcode.save_restore_regmask.should_operate[i] = (first_dword & (1u << i)) != 0; 541 for (std::size_t i = 0; i < NumRegisters; i++) {
542 save_restore_regmask.should_operate[i] = (first_dword & (1u << i)) != 0;
503 } 543 }
544 opcode.opcode = save_restore_regmask;
504 } break; 545 } break;
505 case CheatVmOpcodeType_DebugLog: { 546 case CheatVmOpcodeType::DebugLog: {
506 /* FFFTIX## */ 547 DebugLogOpcode debug_log{};
507 /* FFFTI0Ma aaaaaaaa */ 548 // FFFTIX##
508 /* FFFTI1Mr */ 549 // FFFTI0Ma aaaaaaaa
509 /* FFFTI2Ra aaaaaaaa */ 550 // FFFTI1Mr
510 /* FFFTI3Rr */ 551 // FFFTI2Ra aaaaaaaa
511 /* FFFTI4X0 */ 552 // FFFTI3Rr
512 /* FFF = opcode 0xFFF */ 553 // FFFTI4X0
513 /* T = bit width. */ 554 // FFF = opcode 0xFFF
514 /* I = log id. */ 555 // T = bit width.
515 /* X = value operand type, 0 = main/heap with relative offset, 1 = main/heap with offset 556 // I = log id.
516 * register, */ 557 // X = value operand type, 0 = main/heap with relative offset, 1 = main/heap with offset
517 /* 2 = register with relative offset, 3 = register with offset register, 4 = register 558 // register,
518 * value. */ 559 // 2 = register with relative offset, 3 = register with offset register, 4 = register
519 /* M = memory type. */ 560 // value.
520 /* R = address register. */ 561 // M = memory type.
521 /* a = relative address. */ 562 // R = address register.
522 /* r = offset register. */ 563 // a = relative address.
523 /* X = value register. */ 564 // r = offset register.
524 opcode.debug_log.bit_width = (first_dword >> 16) & 0xF; 565 // X = value register.
525 opcode.debug_log.log_id = ((first_dword >> 12) & 0xF); 566 debug_log.bit_width = (first_dword >> 16) & 0xF;
526 opcode.debug_log.val_type = (DebugLogValueType)((first_dword >> 8) & 0xF); 567 debug_log.log_id = ((first_dword >> 12) & 0xF);
568 debug_log.val_type = static_cast<DebugLogValueType>((first_dword >> 8) & 0xF);
527 569
528 switch (opcode.debug_log.val_type) { 570 switch (debug_log.val_type) {
529 case DebugLogValueType_RegisterValue: 571 case DebugLogValueType::RegisterValue:
530 opcode.debug_log.val_reg_index = ((first_dword >> 4) & 0xF); 572 debug_log.val_reg_index = ((first_dword >> 4) & 0xF);
531 break; 573 break;
532 case DebugLogValueType_MemoryRelAddr: 574 case DebugLogValueType::MemoryRelAddr:
533 opcode.debug_log.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF); 575 debug_log.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
534 opcode.debug_log.rel_address = 576 debug_log.rel_address =
535 (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword())); 577 ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
536 break; 578 break;
537 case DebugLogValueType_MemoryOfsReg: 579 case DebugLogValueType::MemoryOfsReg:
538 opcode.debug_log.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF); 580 debug_log.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
539 opcode.debug_log.ofs_reg_index = (first_dword & 0xF); 581 debug_log.ofs_reg_index = (first_dword & 0xF);
540 break; 582 break;
541 case DebugLogValueType_RegisterRelAddr: 583 case DebugLogValueType::RegisterRelAddr:
542 opcode.debug_log.addr_reg_index = ((first_dword >> 4) & 0xF); 584 debug_log.addr_reg_index = ((first_dword >> 4) & 0xF);
543 opcode.debug_log.rel_address = 585 debug_log.rel_address =
544 (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword())); 586 ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
545 break; 587 break;
546 case DebugLogValueType_RegisterOfsReg: 588 case DebugLogValueType::RegisterOfsReg:
547 opcode.debug_log.addr_reg_index = ((first_dword >> 4) & 0xF); 589 debug_log.addr_reg_index = ((first_dword >> 4) & 0xF);
548 opcode.debug_log.ofs_reg_index = (first_dword & 0xF); 590 debug_log.ofs_reg_index = (first_dword & 0xF);
549 break; 591 break;
550 } 592 }
593 opcode.opcode = debug_log;
551 } break; 594 } break;
552 case CheatVmOpcodeType_ExtendedWidth: 595 case CheatVmOpcodeType::ExtendedWidth:
553 case CheatVmOpcodeType_DoubleExtendedWidth: 596 case CheatVmOpcodeType::DoubleExtendedWidth:
554 default: 597 default:
555 /* Unrecognized instruction cannot be decoded. */ 598 // Unrecognized instruction cannot be decoded.
556 valid = false; 599 valid = false;
600 opcode.opcode = UnrecognizedInstruction{opcode_type};
557 break; 601 break;
558 } 602 }
559 603
560 /* End decoding. */ 604 // End decoding.
561 return valid; 605 return valid;
562} 606}
563 607
564void DmntCheatVm::SkipConditionalBlock() { 608void DmntCheatVm::SkipConditionalBlock() {
565 if (this->condition_depth > 0) { 609 if (condition_depth > 0) {
566 /* We want to continue until we're out of the current block. */ 610 // We want to continue until we're out of the current block.
567 const size_t desired_depth = this->condition_depth - 1; 611 const std::size_t desired_depth = condition_depth - 1;
568 612
569 CheatVmOpcode skip_opcode{}; 613 CheatVmOpcode skip_opcode{};
570 while (this->condition_depth > desired_depth && this->DecodeNextOpcode(skip_opcode)) { 614 while (condition_depth > desired_depth && DecodeNextOpcode(skip_opcode)) {
571 /* Decode instructions until we see end of the current conditional block. */ 615 // Decode instructions until we see end of the current conditional block.
572 /* NOTE: This is broken in gateway's implementation. */ 616 // NOTE: This is broken in gateway's implementation.
573 /* Gateway currently checks for "0x2" instead of "0x20000000" */ 617 // Gateway currently checks for "0x2" instead of "0x20000000"
574 /* In addition, they do a linear scan instead of correctly decoding opcodes. */ 618 // In addition, they do a linear scan instead of correctly decoding opcodes.
575 /* This causes issues if "0x2" appears as an immediate in the conditional block... */ 619 // This causes issues if "0x2" appears as an immediate in the conditional block...
576 620
577 /* We also support nesting of conditional blocks, and Gateway does not. */ 621 // We also support nesting of conditional blocks, and Gateway does not.
578 if (skip_opcode.begin_conditional_block) { 622 if (skip_opcode.begin_conditional_block) {
579 this->condition_depth++; 623 condition_depth++;
580 } else if (skip_opcode.opcode == CheatVmOpcodeType_EndConditionalBlock) { 624 } else if (std::holds_alternative<EndConditionalOpcode>(skip_opcode.opcode)) {
581 this->condition_depth--; 625 condition_depth--;
582 } 626 }
583 } 627 }
584 } else { 628 } else {
585 /* Skipping, but this->condition_depth = 0. */ 629 // Skipping, but condition_depth = 0.
586 /* This is an error condition. */ 630 // This is an error condition.
587 /* However, I don't actually believe it is possible for this to happen. */ 631 // However, I don't actually believe it is possible for this to happen.
588 /* I guess we'll throw a fatal error here, so as to encourage me to fix the VM */ 632 // I guess we'll throw a fatal error here, so as to encourage me to fix the VM
589 /* in the event that someone triggers it? I don't know how you'd do that. */ 633 // in the event that someone triggers it? I don't know how you'd do that.
590 UNREACHABLE_MSG("Invalid condition depth in DMNT Cheat VM"); 634 UNREACHABLE_MSG("Invalid condition depth in DMNT Cheat VM");
591 } 635 }
592} 636}
@@ -602,7 +646,7 @@ u64 DmntCheatVm::GetVmInt(VmInt value, u32 bit_width) {
602 case 8: 646 case 8:
603 return value.bit64; 647 return value.bit64;
604 default: 648 default:
605 /* Invalid bit width -> return 0. */ 649 // Invalid bit width -> return 0.
606 return 0; 650 return 0;
607 } 651 }
608} 652}
@@ -610,39 +654,37 @@ u64 DmntCheatVm::GetVmInt(VmInt value, u32 bit_width) {
610u64 DmntCheatVm::GetCheatProcessAddress(const CheatProcessMetadata& metadata, 654u64 DmntCheatVm::GetCheatProcessAddress(const CheatProcessMetadata& metadata,
611 MemoryAccessType mem_type, u64 rel_address) { 655 MemoryAccessType mem_type, u64 rel_address) {
612 switch (mem_type) { 656 switch (mem_type) {
613 case MemoryAccessType_MainNso: 657 case MemoryAccessType::MainNso:
614 default: 658 default:
615 return metadata.main_nso_extents.base + rel_address; 659 return metadata.main_nso_extents.base + rel_address;
616 case MemoryAccessType_Heap: 660 case MemoryAccessType::Heap:
617 return metadata.heap_extents.base + rel_address; 661 return metadata.heap_extents.base + rel_address;
618 } 662 }
619} 663}
620 664
621void DmntCheatVm::ResetState() { 665void DmntCheatVm::ResetState() {
622 for (size_t i = 0; i < DmntCheatVm::NumRegisters; i++) { 666 registers.fill(0);
623 this->registers[i] = 0; 667 saved_values.fill(0);
624 this->saved_values[i] = 0; 668 loop_tops.fill(0);
625 this->loop_tops[i] = 0; 669 instruction_ptr = 0;
626 } 670 condition_depth = 0;
627 this->instruction_ptr = 0; 671 decode_success = true;
628 this->condition_depth = 0;
629 this->decode_success = true;
630} 672}
631 673
632bool DmntCheatVm::LoadProgram(const std::vector<CheatEntry>& entries) { 674bool DmntCheatVm::LoadProgram(const std::vector<CheatEntry>& entries) {
633 /* Reset opcode count. */ 675 // Reset opcode count.
634 this->num_opcodes = 0; 676 num_opcodes = 0;
635 677
636 for (size_t i = 0; i < entries.size(); i++) { 678 for (std::size_t i = 0; i < entries.size(); i++) {
637 if (entries[i].enabled) { 679 if (entries[i].enabled) {
638 /* Bounds check. */ 680 // Bounds check.
639 if (entries[i].definition.num_opcodes + this->num_opcodes > MaximumProgramOpcodeCount) { 681 if (entries[i].definition.num_opcodes + num_opcodes > MaximumProgramOpcodeCount) {
640 this->num_opcodes = 0; 682 num_opcodes = 0;
641 return false; 683 return false;
642 } 684 }
643 685
644 for (size_t n = 0; n < entries[i].definition.num_opcodes; n++) { 686 for (std::size_t n = 0; n < entries[i].definition.num_opcodes; n++) {
645 this->program[this->num_opcodes++] = entries[i].definition.opcodes[n]; 687 program[num_opcodes++] = entries[i].definition.opcodes[n];
646 } 688 }
647 } 689 }
648 } 690 }
@@ -653,262 +695,249 @@ bool DmntCheatVm::LoadProgram(const std::vector<CheatEntry>& entries) {
653void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { 695void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
654 CheatVmOpcode cur_opcode{}; 696 CheatVmOpcode cur_opcode{};
655 697
656 /* Get Keys down. */ 698 // Get Keys down.
657 u64 kDown = callbacks->HidKeysDown(); 699 u64 kDown = callbacks->HidKeysDown();
658 700
659 this->LogToDebugFile("Started VM execution.\n"); 701 callbacks->CommandLog("Started VM execution.");
660 this->LogToDebugFile("Main NSO: %012lx\n", metadata.main_nso_extents.base); 702 callbacks->CommandLog(fmt::format("Main NSO: {:012X}", metadata.main_nso_extents.base));
661 this->LogToDebugFile("Heap: %012lx\n", metadata.main_nso_extents.base); 703 callbacks->CommandLog(fmt::format("Heap: {:012X}", metadata.main_nso_extents.base));
662 this->LogToDebugFile("Keys Down: %08x\n", (u32)(kDown & 0x0FFFFFFF)); 704 callbacks->CommandLog(fmt::format("Keys Down: {:08X}", static_cast<u32>(kDown & 0x0FFFFFFF)));
663 705
664 /* Clear VM state. */ 706 // Clear VM state.
665 this->ResetState(); 707 ResetState();
666 708
667 /* Loop until program finishes. */ 709 // Loop until program finishes.
668 while (this->DecodeNextOpcode(cur_opcode)) { 710 while (DecodeNextOpcode(cur_opcode)) {
669 this->LogToDebugFile("Instruction Ptr: %04x\n", (u32)this->instruction_ptr); 711 callbacks->CommandLog(
712 fmt::format("Instruction Ptr: {:04X}", static_cast<u32>(instruction_ptr)));
670 713
671 for (size_t i = 0; i < NumRegisters; i++) { 714 for (std::size_t i = 0; i < NumRegisters; i++) {
672 this->LogToDebugFile("Registers[%02x]: %016lx\n", i, this->registers[i]); 715 callbacks->CommandLog(fmt::format("Registers[{:02X}]: {:016X}", i, registers[i]));
673 } 716 }
674 717
675 for (size_t i = 0; i < NumRegisters; i++) { 718 for (std::size_t i = 0; i < NumRegisters; i++) {
676 this->LogToDebugFile("SavedRegs[%02x]: %016lx\n", i, this->saved_values[i]); 719 callbacks->CommandLog(fmt::format("SavedRegs[{:02X}]: {:016X}", i, saved_values[i]));
677 } 720 }
678 this->LogOpcode(cur_opcode); 721 LogOpcode(cur_opcode);
679 722
680 /* Increment conditional depth, if relevant. */ 723 // Increment conditional depth, if relevant.
681 if (cur_opcode.begin_conditional_block) { 724 if (cur_opcode.begin_conditional_block) {
682 this->condition_depth++; 725 condition_depth++;
683 } 726 }
684 727
685 switch (cur_opcode.opcode) { 728 if (auto store_static = std::get_if<StoreStaticOpcode>(&cur_opcode.opcode)) {
686 case CheatVmOpcodeType_StoreStatic: { 729 // Calculate address, write value to memory.
687 /* Calculate address, write value to memory. */ 730 u64 dst_address = GetCheatProcessAddress(metadata, store_static->mem_type,
688 u64 dst_address = GetCheatProcessAddress( 731 store_static->rel_address +
689 metadata, cur_opcode.store_static.mem_type, 732 registers[store_static->offset_register]);
690 cur_opcode.store_static.rel_address + 733 u64 dst_value = GetVmInt(store_static->value, store_static->bit_width);
691 this->registers[cur_opcode.store_static.offset_register]); 734 switch (store_static->bit_width) {
692 u64 dst_value =
693 GetVmInt(cur_opcode.store_static.value, cur_opcode.store_static.bit_width);
694 switch (cur_opcode.store_static.bit_width) {
695 case 1: 735 case 1:
696 case 2: 736 case 2:
697 case 4: 737 case 4:
698 case 8: 738 case 8:
699 callbacks->MemoryWrite(dst_address, &dst_value, cur_opcode.store_static.bit_width); 739 callbacks->MemoryWrite(dst_address, &dst_value, store_static->bit_width);
700 break; 740 break;
701 } 741 }
702 } break; 742 } else if (auto begin_cond = std::get_if<BeginConditionalOpcode>(&cur_opcode.opcode)) {
703 case CheatVmOpcodeType_BeginConditionalBlock: { 743 // Read value from memory.
704 /* Read value from memory. */ 744 u64 src_address =
705 u64 src_address = GetCheatProcessAddress(metadata, cur_opcode.begin_cond.mem_type, 745 GetCheatProcessAddress(metadata, begin_cond->mem_type, begin_cond->rel_address);
706 cur_opcode.begin_cond.rel_address);
707 u64 src_value = 0; 746 u64 src_value = 0;
708 switch (cur_opcode.store_static.bit_width) { 747 switch (store_static->bit_width) {
709 case 1: 748 case 1:
710 case 2: 749 case 2:
711 case 4: 750 case 4:
712 case 8: 751 case 8:
713 callbacks->MemoryRead(src_address, &src_value, cur_opcode.begin_cond.bit_width); 752 callbacks->MemoryRead(src_address, &src_value, begin_cond->bit_width);
714 break; 753 break;
715 } 754 }
716 /* Check against condition. */ 755 // Check against condition.
717 u64 cond_value = GetVmInt(cur_opcode.begin_cond.value, cur_opcode.begin_cond.bit_width); 756 u64 cond_value = GetVmInt(begin_cond->value, begin_cond->bit_width);
718 bool cond_met = false; 757 bool cond_met = false;
719 switch (cur_opcode.begin_cond.cond_type) { 758 switch (begin_cond->cond_type) {
720 case ConditionalComparisonType_GT: 759 case ConditionalComparisonType::GT:
721 cond_met = src_value > cond_value; 760 cond_met = src_value > cond_value;
722 break; 761 break;
723 case ConditionalComparisonType_GE: 762 case ConditionalComparisonType::GE:
724 cond_met = src_value >= cond_value; 763 cond_met = src_value >= cond_value;
725 break; 764 break;
726 case ConditionalComparisonType_LT: 765 case ConditionalComparisonType::LT:
727 cond_met = src_value < cond_value; 766 cond_met = src_value < cond_value;
728 break; 767 break;
729 case ConditionalComparisonType_LE: 768 case ConditionalComparisonType::LE:
730 cond_met = src_value <= cond_value; 769 cond_met = src_value <= cond_value;
731 break; 770 break;
732 case ConditionalComparisonType_EQ: 771 case ConditionalComparisonType::EQ:
733 cond_met = src_value == cond_value; 772 cond_met = src_value == cond_value;
734 break; 773 break;
735 case ConditionalComparisonType_NE: 774 case ConditionalComparisonType::NE:
736 cond_met = src_value != cond_value; 775 cond_met = src_value != cond_value;
737 break; 776 break;
738 } 777 }
739 /* Skip conditional block if condition not met. */ 778 // Skip conditional block if condition not met.
740 if (!cond_met) { 779 if (!cond_met) {
741 this->SkipConditionalBlock(); 780 SkipConditionalBlock();
742 } 781 }
743 } break; 782 } else if (auto end_cond = std::get_if<EndConditionalOpcode>(&cur_opcode.opcode)) {
744 case CheatVmOpcodeType_EndConditionalBlock: 783 // Decrement the condition depth.
745 /* Decrement the condition depth. */ 784 // We will assume, graciously, that mismatched conditional block ends are a nop.
746 /* We will assume, graciously, that mismatched conditional block ends are a nop. */ 785 if (condition_depth > 0) {
747 if (this->condition_depth > 0) { 786 condition_depth--;
748 this->condition_depth--;
749 } 787 }
750 break; 788 } else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&cur_opcode.opcode)) {
751 case CheatVmOpcodeType_ControlLoop: 789 if (ctrl_loop->start_loop) {
752 if (cur_opcode.ctrl_loop.start_loop) { 790 // Start a loop.
753 /* Start a loop. */ 791 registers[ctrl_loop->reg_index] = ctrl_loop->num_iters;
754 this->registers[cur_opcode.ctrl_loop.reg_index] = cur_opcode.ctrl_loop.num_iters; 792 loop_tops[ctrl_loop->reg_index] = instruction_ptr;
755 this->loop_tops[cur_opcode.ctrl_loop.reg_index] = this->instruction_ptr;
756 } else { 793 } else {
757 /* End a loop. */ 794 // End a loop.
758 this->registers[cur_opcode.ctrl_loop.reg_index]--; 795 registers[ctrl_loop->reg_index]--;
759 if (this->registers[cur_opcode.ctrl_loop.reg_index] != 0) { 796 if (registers[ctrl_loop->reg_index] != 0) {
760 this->instruction_ptr = this->loop_tops[cur_opcode.ctrl_loop.reg_index]; 797 instruction_ptr = loop_tops[ctrl_loop->reg_index];
761 } 798 }
762 } 799 }
763 break; 800 } else if (auto ldr_static = std::get_if<LoadRegisterStaticOpcode>(&cur_opcode.opcode)) {
764 case CheatVmOpcodeType_LoadRegisterStatic: 801 // Set a register to a static value.
765 /* Set a register to a static value. */ 802 registers[ldr_static->reg_index] = ldr_static->value;
766 this->registers[cur_opcode.ldr_static.reg_index] = cur_opcode.ldr_static.value; 803 } else if (auto ldr_memory = std::get_if<LoadRegisterMemoryOpcode>(&cur_opcode.opcode)) {
767 break; 804 // Choose source address.
768 case CheatVmOpcodeType_LoadRegisterMemory: {
769 /* Choose source address. */
770 u64 src_address; 805 u64 src_address;
771 if (cur_opcode.ldr_memory.load_from_reg) { 806 if (ldr_memory->load_from_reg) {
772 src_address = this->registers[cur_opcode.ldr_memory.reg_index] + 807 src_address = registers[ldr_memory->reg_index] + ldr_memory->rel_address;
773 cur_opcode.ldr_memory.rel_address;
774 } else { 808 } else {
775 src_address = GetCheatProcessAddress(metadata, cur_opcode.ldr_memory.mem_type, 809 src_address =
776 cur_opcode.ldr_memory.rel_address); 810 GetCheatProcessAddress(metadata, ldr_memory->mem_type, ldr_memory->rel_address);
777 } 811 }
778 /* Read into register. Gateway only reads on valid bitwidth. */ 812 // Read into register. Gateway only reads on valid bitwidth.
779 switch (cur_opcode.ldr_memory.bit_width) { 813 switch (ldr_memory->bit_width) {
780 case 1: 814 case 1:
781 case 2: 815 case 2:
782 case 4: 816 case 4:
783 case 8: 817 case 8:
784 callbacks->MemoryRead(src_address, 818 callbacks->MemoryRead(src_address, &registers[ldr_memory->reg_index],
785 &this->registers[cur_opcode.ldr_memory.reg_index], 819 ldr_memory->bit_width);
786 cur_opcode.ldr_memory.bit_width);
787 break; 820 break;
788 } 821 }
789 } break; 822 } else if (auto str_static = std::get_if<StoreStaticToAddressOpcode>(&cur_opcode.opcode)) {
790 case CheatVmOpcodeType_StoreStaticToAddress: { 823 // Calculate address.
791 /* Calculate address. */ 824 u64 dst_address = registers[str_static->reg_index];
792 u64 dst_address = this->registers[cur_opcode.str_static.reg_index]; 825 u64 dst_value = str_static->value;
793 u64 dst_value = cur_opcode.str_static.value; 826 if (str_static->add_offset_reg) {
794 if (cur_opcode.str_static.add_offset_reg) { 827 dst_address += registers[str_static->offset_reg_index];
795 dst_address += this->registers[cur_opcode.str_static.offset_reg_index];
796 } 828 }
797 /* Write value to memory. Gateway only writes on valid bitwidth. */ 829 // Write value to memory. Gateway only writes on valid bitwidth.
798 switch (cur_opcode.str_static.bit_width) { 830 switch (str_static->bit_width) {
799 case 1: 831 case 1:
800 case 2: 832 case 2:
801 case 4: 833 case 4:
802 case 8: 834 case 8:
803 callbacks->MemoryWrite(dst_address, &dst_value, cur_opcode.str_static.bit_width); 835 callbacks->MemoryWrite(dst_address, &dst_value, str_static->bit_width);
804 break; 836 break;
805 } 837 }
806 /* Increment register if relevant. */ 838 // Increment register if relevant.
807 if (cur_opcode.str_static.increment_reg) { 839 if (str_static->increment_reg) {
808 this->registers[cur_opcode.str_static.reg_index] += cur_opcode.str_static.bit_width; 840 registers[str_static->reg_index] += str_static->bit_width;
809 } 841 }
810 } break; 842 } else if (auto perform_math_static =
811 case CheatVmOpcodeType_PerformArithmeticStatic: { 843 std::get_if<PerformArithmeticStaticOpcode>(&cur_opcode.opcode)) {
812 /* Do requested math. */ 844 // Do requested math.
813 switch (cur_opcode.perform_math_static.math_type) { 845 switch (perform_math_static->math_type) {
814 case RegisterArithmeticType_Addition: 846 case RegisterArithmeticType::Addition:
815 this->registers[cur_opcode.perform_math_static.reg_index] += 847 registers[perform_math_static->reg_index] +=
816 (u64)cur_opcode.perform_math_static.value; 848 static_cast<u64>(perform_math_static->value);
817 break; 849 break;
818 case RegisterArithmeticType_Subtraction: 850 case RegisterArithmeticType::Subtraction:
819 this->registers[cur_opcode.perform_math_static.reg_index] -= 851 registers[perform_math_static->reg_index] -=
820 (u64)cur_opcode.perform_math_static.value; 852 static_cast<u64>(perform_math_static->value);
821 break; 853 break;
822 case RegisterArithmeticType_Multiplication: 854 case RegisterArithmeticType::Multiplication:
823 this->registers[cur_opcode.perform_math_static.reg_index] *= 855 registers[perform_math_static->reg_index] *=
824 (u64)cur_opcode.perform_math_static.value; 856 static_cast<u64>(perform_math_static->value);
825 break; 857 break;
826 case RegisterArithmeticType_LeftShift: 858 case RegisterArithmeticType::LeftShift:
827 this->registers[cur_opcode.perform_math_static.reg_index] <<= 859 registers[perform_math_static->reg_index] <<=
828 (u64)cur_opcode.perform_math_static.value; 860 static_cast<u64>(perform_math_static->value);
829 break; 861 break;
830 case RegisterArithmeticType_RightShift: 862 case RegisterArithmeticType::RightShift:
831 this->registers[cur_opcode.perform_math_static.reg_index] >>= 863 registers[perform_math_static->reg_index] >>=
832 (u64)cur_opcode.perform_math_static.value; 864 static_cast<u64>(perform_math_static->value);
833 break; 865 break;
834 default: 866 default:
835 /* Do not handle extensions here. */ 867 // Do not handle extensions here.
836 break; 868 break;
837 } 869 }
838 /* Apply bit width. */ 870 // Apply bit width.
839 switch (cur_opcode.perform_math_static.bit_width) { 871 switch (perform_math_static->bit_width) {
840 case 1: 872 case 1:
841 this->registers[cur_opcode.perform_math_static.reg_index] = 873 registers[perform_math_static->reg_index] =
842 static_cast<u8>(this->registers[cur_opcode.perform_math_static.reg_index]); 874 static_cast<u8>(registers[perform_math_static->reg_index]);
843 break; 875 break;
844 case 2: 876 case 2:
845 this->registers[cur_opcode.perform_math_static.reg_index] = 877 registers[perform_math_static->reg_index] =
846 static_cast<u16>(this->registers[cur_opcode.perform_math_static.reg_index]); 878 static_cast<u16>(registers[perform_math_static->reg_index]);
847 break; 879 break;
848 case 4: 880 case 4:
849 this->registers[cur_opcode.perform_math_static.reg_index] = 881 registers[perform_math_static->reg_index] =
850 static_cast<u32>(this->registers[cur_opcode.perform_math_static.reg_index]); 882 static_cast<u32>(registers[perform_math_static->reg_index]);
851 break; 883 break;
852 case 8: 884 case 8:
853 this->registers[cur_opcode.perform_math_static.reg_index] = 885 registers[perform_math_static->reg_index] =
854 static_cast<u64>(this->registers[cur_opcode.perform_math_static.reg_index]); 886 static_cast<u64>(registers[perform_math_static->reg_index]);
855 break; 887 break;
856 } 888 }
857 } break; 889 } else if (auto begin_keypress_cond =
858 case CheatVmOpcodeType_BeginKeypressConditionalBlock: 890 std::get_if<BeginKeypressConditionalOpcode>(&cur_opcode.opcode)) {
859 /* Check for keypress. */ 891 // Check for keypress.
860 if ((cur_opcode.begin_keypress_cond.key_mask & kDown) != 892 if ((begin_keypress_cond->key_mask & kDown) != begin_keypress_cond->key_mask) {
861 cur_opcode.begin_keypress_cond.key_mask) { 893 // Keys not pressed. Skip conditional block.
862 /* Keys not pressed. Skip conditional block. */ 894 SkipConditionalBlock();
863 this->SkipConditionalBlock();
864 } 895 }
865 break; 896 } else if (auto perform_math_reg =
866 case CheatVmOpcodeType_PerformArithmeticRegister: { 897 std::get_if<PerformArithmeticRegisterOpcode>(&cur_opcode.opcode)) {
867 const u64 operand_1_value = 898 const u64 operand_1_value = registers[perform_math_reg->src_reg_1_index];
868 this->registers[cur_opcode.perform_math_reg.src_reg_1_index];
869 const u64 operand_2_value = 899 const u64 operand_2_value =
870 cur_opcode.perform_math_reg.has_immediate 900 perform_math_reg->has_immediate
871 ? GetVmInt(cur_opcode.perform_math_reg.value, 901 ? GetVmInt(perform_math_reg->value, perform_math_reg->bit_width)
872 cur_opcode.perform_math_reg.bit_width) 902 : registers[perform_math_reg->src_reg_2_index];
873 : this->registers[cur_opcode.perform_math_reg.src_reg_2_index];
874 903
875 u64 res_val = 0; 904 u64 res_val = 0;
876 /* Do requested math. */ 905 // Do requested math.
877 switch (cur_opcode.perform_math_reg.math_type) { 906 switch (perform_math_reg->math_type) {
878 case RegisterArithmeticType_Addition: 907 case RegisterArithmeticType::Addition:
879 res_val = operand_1_value + operand_2_value; 908 res_val = operand_1_value + operand_2_value;
880 break; 909 break;
881 case RegisterArithmeticType_Subtraction: 910 case RegisterArithmeticType::Subtraction:
882 res_val = operand_1_value - operand_2_value; 911 res_val = operand_1_value - operand_2_value;
883 break; 912 break;
884 case RegisterArithmeticType_Multiplication: 913 case RegisterArithmeticType::Multiplication:
885 res_val = operand_1_value * operand_2_value; 914 res_val = operand_1_value * operand_2_value;
886 break; 915 break;
887 case RegisterArithmeticType_LeftShift: 916 case RegisterArithmeticType::LeftShift:
888 res_val = operand_1_value << operand_2_value; 917 res_val = operand_1_value << operand_2_value;
889 break; 918 break;
890 case RegisterArithmeticType_RightShift: 919 case RegisterArithmeticType::RightShift:
891 res_val = operand_1_value >> operand_2_value; 920 res_val = operand_1_value >> operand_2_value;
892 break; 921 break;
893 case RegisterArithmeticType_LogicalAnd: 922 case RegisterArithmeticType::LogicalAnd:
894 res_val = operand_1_value & operand_2_value; 923 res_val = operand_1_value & operand_2_value;
895 break; 924 break;
896 case RegisterArithmeticType_LogicalOr: 925 case RegisterArithmeticType::LogicalOr:
897 res_val = operand_1_value | operand_2_value; 926 res_val = operand_1_value | operand_2_value;
898 break; 927 break;
899 case RegisterArithmeticType_LogicalNot: 928 case RegisterArithmeticType::LogicalNot:
900 res_val = ~operand_1_value; 929 res_val = ~operand_1_value;
901 break; 930 break;
902 case RegisterArithmeticType_LogicalXor: 931 case RegisterArithmeticType::LogicalXor:
903 res_val = operand_1_value ^ operand_2_value; 932 res_val = operand_1_value ^ operand_2_value;
904 break; 933 break;
905 case RegisterArithmeticType_None: 934 case RegisterArithmeticType::None:
906 res_val = operand_1_value; 935 res_val = operand_1_value;
907 break; 936 break;
908 } 937 }
909 938
910 /* Apply bit width. */ 939 // Apply bit width.
911 switch (cur_opcode.perform_math_reg.bit_width) { 940 switch (perform_math_reg->bit_width) {
912 case 1: 941 case 1:
913 res_val = static_cast<u8>(res_val); 942 res_val = static_cast<u8>(res_val);
914 break; 943 break;
@@ -923,282 +952,259 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
923 break; 952 break;
924 } 953 }
925 954
926 /* Save to register. */ 955 // Save to register.
927 this->registers[cur_opcode.perform_math_reg.dst_reg_index] = res_val; 956 registers[perform_math_reg->dst_reg_index] = res_val;
928 } break; 957 } else if (auto str_register =
929 case CheatVmOpcodeType_StoreRegisterToAddress: { 958 std::get_if<StoreRegisterToAddressOpcode>(&cur_opcode.opcode)) {
930 /* Calculate address. */ 959 // Calculate address.
931 u64 dst_value = this->registers[cur_opcode.str_register.str_reg_index]; 960 u64 dst_value = registers[str_register->str_reg_index];
932 u64 dst_address = this->registers[cur_opcode.str_register.addr_reg_index]; 961 u64 dst_address = registers[str_register->addr_reg_index];
933 switch (cur_opcode.str_register.ofs_type) { 962 switch (str_register->ofs_type) {
934 case StoreRegisterOffsetType_None: 963 case StoreRegisterOffsetType::None:
935 /* Nothing more to do */ 964 // Nothing more to do
936 break; 965 break;
937 case StoreRegisterOffsetType_Reg: 966 case StoreRegisterOffsetType::Reg:
938 dst_address += this->registers[cur_opcode.str_register.ofs_reg_index]; 967 dst_address += registers[str_register->ofs_reg_index];
939 break; 968 break;
940 case StoreRegisterOffsetType_Imm: 969 case StoreRegisterOffsetType::Imm:
941 dst_address += cur_opcode.str_register.rel_address; 970 dst_address += str_register->rel_address;
942 break; 971 break;
943 case StoreRegisterOffsetType_MemReg: 972 case StoreRegisterOffsetType::MemReg:
944 dst_address = 973 dst_address = GetCheatProcessAddress(metadata, str_register->mem_type,
945 GetCheatProcessAddress(metadata, cur_opcode.str_register.mem_type, 974 registers[str_register->addr_reg_index]);
946 this->registers[cur_opcode.str_register.addr_reg_index]);
947 break; 975 break;
948 case StoreRegisterOffsetType_MemImm: 976 case StoreRegisterOffsetType::MemImm:
949 dst_address = GetCheatProcessAddress(metadata, cur_opcode.str_register.mem_type, 977 dst_address = GetCheatProcessAddress(metadata, str_register->mem_type,
950 cur_opcode.str_register.rel_address); 978 str_register->rel_address);
951 break; 979 break;
952 case StoreRegisterOffsetType_MemImmReg: 980 case StoreRegisterOffsetType::MemImmReg:
953 dst_address = 981 dst_address = GetCheatProcessAddress(metadata, str_register->mem_type,
954 GetCheatProcessAddress(metadata, cur_opcode.str_register.mem_type, 982 registers[str_register->addr_reg_index] +
955 this->registers[cur_opcode.str_register.addr_reg_index] + 983 str_register->rel_address);
956 cur_opcode.str_register.rel_address);
957 break; 984 break;
958 } 985 }
959 986
960 /* Write value to memory. Write only on valid bitwidth. */ 987 // Write value to memory. Write only on valid bitwidth.
961 switch (cur_opcode.str_register.bit_width) { 988 switch (str_register->bit_width) {
962 case 1: 989 case 1:
963 case 2: 990 case 2:
964 case 4: 991 case 4:
965 case 8: 992 case 8:
966 callbacks->MemoryWrite(dst_address, &dst_value, cur_opcode.str_register.bit_width); 993 callbacks->MemoryWrite(dst_address, &dst_value, str_register->bit_width);
967 break; 994 break;
968 } 995 }
969 996
970 /* Increment register if relevant. */ 997 // Increment register if relevant.
971 if (cur_opcode.str_register.increment_reg) { 998 if (str_register->increment_reg) {
972 this->registers[cur_opcode.str_register.addr_reg_index] += 999 registers[str_register->addr_reg_index] += str_register->bit_width;
973 cur_opcode.str_register.bit_width;
974 } 1000 }
975 } break; 1001 } else if (auto begin_reg_cond =
976 case CheatVmOpcodeType_BeginRegisterConditionalBlock: { 1002 std::get_if<BeginRegisterConditionalOpcode>(&cur_opcode.opcode)) {
977 /* Get value from register. */ 1003 // Get value from register.
978 u64 src_value = 0; 1004 u64 src_value = 0;
979 switch (cur_opcode.begin_reg_cond.bit_width) { 1005 switch (begin_reg_cond->bit_width) {
980 case 1: 1006 case 1:
981 src_value = static_cast<u8>( 1007 src_value = static_cast<u8>(registers[begin_reg_cond->val_reg_index] & 0xFFul);
982 this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFul);
983 break; 1008 break;
984 case 2: 1009 case 2:
985 src_value = static_cast<u16>( 1010 src_value = static_cast<u16>(registers[begin_reg_cond->val_reg_index] & 0xFFFFul);
986 this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFul);
987 break; 1011 break;
988 case 4: 1012 case 4:
989 src_value = static_cast<u32>( 1013 src_value =
990 this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFFFFFul); 1014 static_cast<u32>(registers[begin_reg_cond->val_reg_index] & 0xFFFFFFFFul);
991 break; 1015 break;
992 case 8: 1016 case 8:
993 src_value = 1017 src_value = static_cast<u64>(registers[begin_reg_cond->val_reg_index] &
994 static_cast<u64>(this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 1018 0xFFFFFFFFFFFFFFFFul);
995 0xFFFFFFFFFFFFFFFFul);
996 break; 1019 break;
997 } 1020 }
998 1021
999 /* Read value from memory. */ 1022 // Read value from memory.
1000 u64 cond_value = 0; 1023 u64 cond_value = 0;
1001 if (cur_opcode.begin_reg_cond.comp_type == CompareRegisterValueType_StaticValue) { 1024 if (begin_reg_cond->comp_type == CompareRegisterValueType::StaticValue) {
1002 cond_value = 1025 cond_value = GetVmInt(begin_reg_cond->value, begin_reg_cond->bit_width);
1003 GetVmInt(cur_opcode.begin_reg_cond.value, cur_opcode.begin_reg_cond.bit_width); 1026 } else if (begin_reg_cond->comp_type == CompareRegisterValueType::OtherRegister) {
1004 } else if (cur_opcode.begin_reg_cond.comp_type == 1027 switch (begin_reg_cond->bit_width) {
1005 CompareRegisterValueType_OtherRegister) {
1006 switch (cur_opcode.begin_reg_cond.bit_width) {
1007 case 1: 1028 case 1:
1008 cond_value = static_cast<u8>( 1029 cond_value =
1009 this->registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFul); 1030 static_cast<u8>(registers[begin_reg_cond->other_reg_index] & 0xFFul);
1010 break; 1031 break;
1011 case 2: 1032 case 2:
1012 cond_value = static_cast<u16>( 1033 cond_value =
1013 this->registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFFFul); 1034 static_cast<u16>(registers[begin_reg_cond->other_reg_index] & 0xFFFFul);
1014 break; 1035 break;
1015 case 4: 1036 case 4:
1016 cond_value = static_cast<u32>( 1037 cond_value =
1017 this->registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFFFFFFFul); 1038 static_cast<u32>(registers[begin_reg_cond->other_reg_index] & 0xFFFFFFFFul);
1018 break; 1039 break;
1019 case 8: 1040 case 8:
1020 cond_value = static_cast<u64>( 1041 cond_value = static_cast<u64>(registers[begin_reg_cond->other_reg_index] &
1021 this->registers[cur_opcode.begin_reg_cond.other_reg_index] & 1042 0xFFFFFFFFFFFFFFFFul);
1022 0xFFFFFFFFFFFFFFFFul);
1023 break; 1043 break;
1024 } 1044 }
1025 } else { 1045 } else {
1026 u64 cond_address = 0; 1046 u64 cond_address = 0;
1027 switch (cur_opcode.begin_reg_cond.comp_type) { 1047 switch (begin_reg_cond->comp_type) {
1028 case CompareRegisterValueType_MemoryRelAddr: 1048 case CompareRegisterValueType::MemoryRelAddr:
1029 cond_address = 1049 cond_address = GetCheatProcessAddress(metadata, begin_reg_cond->mem_type,
1030 GetCheatProcessAddress(metadata, cur_opcode.begin_reg_cond.mem_type, 1050 begin_reg_cond->rel_address);
1031 cur_opcode.begin_reg_cond.rel_address);
1032 break; 1051 break;
1033 case CompareRegisterValueType_MemoryOfsReg: 1052 case CompareRegisterValueType::MemoryOfsReg:
1034 cond_address = GetCheatProcessAddress( 1053 cond_address = GetCheatProcessAddress(metadata, begin_reg_cond->mem_type,
1035 metadata, cur_opcode.begin_reg_cond.mem_type, 1054 registers[begin_reg_cond->ofs_reg_index]);
1036 this->registers[cur_opcode.begin_reg_cond.ofs_reg_index]);
1037 break; 1055 break;
1038 case CompareRegisterValueType_RegisterRelAddr: 1056 case CompareRegisterValueType::RegisterRelAddr:
1039 cond_address = this->registers[cur_opcode.begin_reg_cond.addr_reg_index] + 1057 cond_address =
1040 cur_opcode.begin_reg_cond.rel_address; 1058 registers[begin_reg_cond->addr_reg_index] + begin_reg_cond->rel_address;
1041 break; 1059 break;
1042 case CompareRegisterValueType_RegisterOfsReg: 1060 case CompareRegisterValueType::RegisterOfsReg:
1043 cond_address = this->registers[cur_opcode.begin_reg_cond.addr_reg_index] + 1061 cond_address = registers[begin_reg_cond->addr_reg_index] +
1044 this->registers[cur_opcode.begin_reg_cond.ofs_reg_index]; 1062 registers[begin_reg_cond->ofs_reg_index];
1045 break; 1063 break;
1046 default: 1064 default:
1047 break; 1065 break;
1048 } 1066 }
1049 switch (cur_opcode.begin_reg_cond.bit_width) { 1067 switch (begin_reg_cond->bit_width) {
1050 case 1: 1068 case 1:
1051 case 2: 1069 case 2:
1052 case 4: 1070 case 4:
1053 case 8: 1071 case 8:
1054 callbacks->MemoryRead(cond_address, &cond_value, 1072 callbacks->MemoryRead(cond_address, &cond_value, begin_reg_cond->bit_width);
1055 cur_opcode.begin_reg_cond.bit_width);
1056 break; 1073 break;
1057 } 1074 }
1058 } 1075 }
1059 1076
1060 /* Check against condition. */ 1077 // Check against condition.
1061 bool cond_met = false; 1078 bool cond_met = false;
1062 switch (cur_opcode.begin_reg_cond.cond_type) { 1079 switch (begin_reg_cond->cond_type) {
1063 case ConditionalComparisonType_GT: 1080 case ConditionalComparisonType::GT:
1064 cond_met = src_value > cond_value; 1081 cond_met = src_value > cond_value;
1065 break; 1082 break;
1066 case ConditionalComparisonType_GE: 1083 case ConditionalComparisonType::GE:
1067 cond_met = src_value >= cond_value; 1084 cond_met = src_value >= cond_value;
1068 break; 1085 break;
1069 case ConditionalComparisonType_LT: 1086 case ConditionalComparisonType::LT:
1070 cond_met = src_value < cond_value; 1087 cond_met = src_value < cond_value;
1071 break; 1088 break;
1072 case ConditionalComparisonType_LE: 1089 case ConditionalComparisonType::LE:
1073 cond_met = src_value <= cond_value; 1090 cond_met = src_value <= cond_value;
1074 break; 1091 break;
1075 case ConditionalComparisonType_EQ: 1092 case ConditionalComparisonType::EQ:
1076 cond_met = src_value == cond_value; 1093 cond_met = src_value == cond_value;
1077 break; 1094 break;
1078 case ConditionalComparisonType_NE: 1095 case ConditionalComparisonType::NE:
1079 cond_met = src_value != cond_value; 1096 cond_met = src_value != cond_value;
1080 break; 1097 break;
1081 } 1098 }
1082 1099
1083 /* Skip conditional block if condition not met. */ 1100 // Skip conditional block if condition not met.
1084 if (!cond_met) { 1101 if (!cond_met) {
1085 this->SkipConditionalBlock(); 1102 SkipConditionalBlock();
1086 } 1103 }
1087 } break; 1104 } else if (auto save_restore_reg =
1088 case CheatVmOpcodeType_SaveRestoreRegister: 1105 std::get_if<SaveRestoreRegisterOpcode>(&cur_opcode.opcode)) {
1089 /* Save or restore a register. */ 1106 // Save or restore a register.
1090 switch (cur_opcode.save_restore_reg.op_type) { 1107 switch (save_restore_reg->op_type) {
1091 case SaveRestoreRegisterOpType_ClearRegs: 1108 case SaveRestoreRegisterOpType::ClearRegs:
1092 this->registers[cur_opcode.save_restore_reg.dst_index] = 0ul; 1109 registers[save_restore_reg->dst_index] = 0ul;
1093 break; 1110 break;
1094 case SaveRestoreRegisterOpType_ClearSaved: 1111 case SaveRestoreRegisterOpType::ClearSaved:
1095 this->saved_values[cur_opcode.save_restore_reg.dst_index] = 0ul; 1112 saved_values[save_restore_reg->dst_index] = 0ul;
1096 break; 1113 break;
1097 case SaveRestoreRegisterOpType_Save: 1114 case SaveRestoreRegisterOpType::Save:
1098 this->saved_values[cur_opcode.save_restore_reg.dst_index] = 1115 saved_values[save_restore_reg->dst_index] = registers[save_restore_reg->src_index];
1099 this->registers[cur_opcode.save_restore_reg.src_index];
1100 break; 1116 break;
1101 case SaveRestoreRegisterOpType_Restore: 1117 case SaveRestoreRegisterOpType::Restore:
1102 default: 1118 default:
1103 this->registers[cur_opcode.save_restore_reg.dst_index] = 1119 registers[save_restore_reg->dst_index] = saved_values[save_restore_reg->src_index];
1104 this->saved_values[cur_opcode.save_restore_reg.src_index];
1105 break; 1120 break;
1106 } 1121 }
1107 break; 1122 } else if (auto save_restore_regmask =
1108 case CheatVmOpcodeType_SaveRestoreRegisterMask: 1123 std::get_if<SaveRestoreRegisterMaskOpcode>(&cur_opcode.opcode)) {
1109 /* Save or restore register mask. */ 1124 // Save or restore register mask.
1110 u64* src; 1125 u64* src;
1111 u64* dst; 1126 u64* dst;
1112 switch (cur_opcode.save_restore_regmask.op_type) { 1127 switch (save_restore_regmask->op_type) {
1113 case SaveRestoreRegisterOpType_ClearSaved: 1128 case SaveRestoreRegisterOpType::ClearSaved:
1114 case SaveRestoreRegisterOpType_Save: 1129 case SaveRestoreRegisterOpType::Save:
1115 src = this->registers.data(); 1130 src = registers.data();
1116 dst = this->saved_values.data(); 1131 dst = saved_values.data();
1117 break; 1132 break;
1118 case SaveRestoreRegisterOpType_ClearRegs: 1133 case SaveRestoreRegisterOpType::ClearRegs:
1119 case SaveRestoreRegisterOpType_Restore: 1134 case SaveRestoreRegisterOpType::Restore:
1120 default: 1135 default:
1121 src = this->registers.data(); 1136 src = registers.data();
1122 dst = this->saved_values.data(); 1137 dst = saved_values.data();
1123 break; 1138 break;
1124 } 1139 }
1125 for (size_t i = 0; i < NumRegisters; i++) { 1140 for (std::size_t i = 0; i < NumRegisters; i++) {
1126 if (cur_opcode.save_restore_regmask.should_operate[i]) { 1141 if (save_restore_regmask->should_operate[i]) {
1127 switch (cur_opcode.save_restore_regmask.op_type) { 1142 switch (save_restore_regmask->op_type) {
1128 case SaveRestoreRegisterOpType_ClearSaved: 1143 case SaveRestoreRegisterOpType::ClearSaved:
1129 case SaveRestoreRegisterOpType_ClearRegs: 1144 case SaveRestoreRegisterOpType::ClearRegs:
1130 dst[i] = 0ul; 1145 dst[i] = 0ul;
1131 break; 1146 break;
1132 case SaveRestoreRegisterOpType_Save: 1147 case SaveRestoreRegisterOpType::Save:
1133 case SaveRestoreRegisterOpType_Restore: 1148 case SaveRestoreRegisterOpType::Restore:
1134 default: 1149 default:
1135 dst[i] = src[i]; 1150 dst[i] = src[i];
1136 break; 1151 break;
1137 } 1152 }
1138 } 1153 }
1139 } 1154 }
1140 break; 1155 } else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) {
1141 case CheatVmOpcodeType_DebugLog: { 1156 // Read value from memory.
1142 /* Read value from memory. */
1143 u64 log_value = 0; 1157 u64 log_value = 0;
1144 if (cur_opcode.debug_log.val_type == DebugLogValueType_RegisterValue) { 1158 if (debug_log->val_type == DebugLogValueType::RegisterValue) {
1145 switch (cur_opcode.debug_log.bit_width) { 1159 switch (debug_log->bit_width) {
1146 case 1: 1160 case 1:
1147 log_value = static_cast<u8>( 1161 log_value = static_cast<u8>(registers[debug_log->val_reg_index] & 0xFFul);
1148 this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFul);
1149 break; 1162 break;
1150 case 2: 1163 case 2:
1151 log_value = static_cast<u16>( 1164 log_value = static_cast<u16>(registers[debug_log->val_reg_index] & 0xFFFFul);
1152 this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFFFul);
1153 break; 1165 break;
1154 case 4: 1166 case 4:
1155 log_value = static_cast<u32>( 1167 log_value =
1156 this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFFFFFFFul); 1168 static_cast<u32>(registers[debug_log->val_reg_index] & 0xFFFFFFFFul);
1157 break; 1169 break;
1158 case 8: 1170 case 8:
1159 log_value = static_cast<u64>( 1171 log_value = static_cast<u64>(registers[debug_log->val_reg_index] &
1160 this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFFFFFFFFFFFFFFFul); 1172 0xFFFFFFFFFFFFFFFFul);
1161 break; 1173 break;
1162 } 1174 }
1163 } else { 1175 } else {
1164 u64 val_address = 0; 1176 u64 val_address = 0;
1165 switch (cur_opcode.debug_log.val_type) { 1177 switch (debug_log->val_type) {
1166 case DebugLogValueType_MemoryRelAddr: 1178 case DebugLogValueType::MemoryRelAddr:
1167 val_address = GetCheatProcessAddress(metadata, cur_opcode.debug_log.mem_type, 1179 val_address = GetCheatProcessAddress(metadata, debug_log->mem_type,
1168 cur_opcode.debug_log.rel_address); 1180 debug_log->rel_address);
1169 break; 1181 break;
1170 case DebugLogValueType_MemoryOfsReg: 1182 case DebugLogValueType::MemoryOfsReg:
1171 val_address = 1183 val_address = GetCheatProcessAddress(metadata, debug_log->mem_type,
1172 GetCheatProcessAddress(metadata, cur_opcode.debug_log.mem_type, 1184 registers[debug_log->ofs_reg_index]);
1173 this->registers[cur_opcode.debug_log.ofs_reg_index]);
1174 break; 1185 break;
1175 case DebugLogValueType_RegisterRelAddr: 1186 case DebugLogValueType::RegisterRelAddr:
1176 val_address = this->registers[cur_opcode.debug_log.addr_reg_index] + 1187 val_address = registers[debug_log->addr_reg_index] + debug_log->rel_address;
1177 cur_opcode.debug_log.rel_address;
1178 break; 1188 break;
1179 case DebugLogValueType_RegisterOfsReg: 1189 case DebugLogValueType::RegisterOfsReg:
1180 val_address = this->registers[cur_opcode.debug_log.addr_reg_index] + 1190 val_address =
1181 this->registers[cur_opcode.debug_log.ofs_reg_index]; 1191 registers[debug_log->addr_reg_index] + registers[debug_log->ofs_reg_index];
1182 break; 1192 break;
1183 default: 1193 default:
1184 break; 1194 break;
1185 } 1195 }
1186 switch (cur_opcode.debug_log.bit_width) { 1196 switch (debug_log->bit_width) {
1187 case 1: 1197 case 1:
1188 case 2: 1198 case 2:
1189 case 4: 1199 case 4:
1190 case 8: 1200 case 8:
1191 callbacks->MemoryRead(val_address, &log_value, cur_opcode.debug_log.bit_width); 1201 callbacks->MemoryRead(val_address, &log_value, debug_log->bit_width);
1192 break; 1202 break;
1193 } 1203 }
1194 } 1204 }
1195 1205
1196 /* Log value. */ 1206 // Log value.
1197 this->DebugLog(cur_opcode.debug_log.log_id, log_value); 1207 DebugLog(debug_log->log_id, log_value);
1198 } break;
1199 default:
1200 /* By default, we do a no-op. */
1201 break;
1202 } 1208 }
1203 } 1209 }
1204} 1210}
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 @@
24 24
25#pragma once 25#pragma once
26 26
27#include <variant>
27#include <vector> 28#include <vector>
28#include <fmt/printf.h> 29#include <fmt/printf.h>
29#include "common/common_types.h" 30#include "common/common_types.h"
@@ -31,100 +32,100 @@
31 32
32namespace Memory { 33namespace Memory {
33 34
34enum CheatVmOpcodeType : u32 { 35enum class CheatVmOpcodeType : u32 {
35 CheatVmOpcodeType_StoreStatic = 0, 36 StoreStatic = 0,
36 CheatVmOpcodeType_BeginConditionalBlock = 1, 37 BeginConditionalBlock = 1,
37 CheatVmOpcodeType_EndConditionalBlock = 2, 38 EndConditionalBlock = 2,
38 CheatVmOpcodeType_ControlLoop = 3, 39 ControlLoop = 3,
39 CheatVmOpcodeType_LoadRegisterStatic = 4, 40 LoadRegisterStatic = 4,
40 CheatVmOpcodeType_LoadRegisterMemory = 5, 41 LoadRegisterMemory = 5,
41 CheatVmOpcodeType_StoreStaticToAddress = 6, 42 StoreStaticToAddress = 6,
42 CheatVmOpcodeType_PerformArithmeticStatic = 7, 43 PerformArithmeticStatic = 7,
43 CheatVmOpcodeType_BeginKeypressConditionalBlock = 8, 44 BeginKeypressConditionalBlock = 8,
44 45
45 /* These are not implemented by Gateway's VM. */ 46 // These are not implemented by Gateway's VM.
46 CheatVmOpcodeType_PerformArithmeticRegister = 9, 47 PerformArithmeticRegister = 9,
47 CheatVmOpcodeType_StoreRegisterToAddress = 10, 48 StoreRegisterToAddress = 10,
48 CheatVmOpcodeType_Reserved11 = 11, 49 Reserved11 = 11,
49 50
50 /* This is a meta entry, and not a real opcode. */ 51 // This is a meta entry, and not a real opcode.
51 /* This is to facilitate multi-nybble instruction decoding. */ 52 // This is to facilitate multi-nybble instruction decoding.
52 CheatVmOpcodeType_ExtendedWidth = 12, 53 ExtendedWidth = 12,
53 54
54 /* Extended width opcodes. */ 55 // Extended width opcodes.
55 CheatVmOpcodeType_BeginRegisterConditionalBlock = 0xC0, 56 BeginRegisterConditionalBlock = 0xC0,
56 CheatVmOpcodeType_SaveRestoreRegister = 0xC1, 57 SaveRestoreRegister = 0xC1,
57 CheatVmOpcodeType_SaveRestoreRegisterMask = 0xC2, 58 SaveRestoreRegisterMask = 0xC2,
58 59
59 /* This is a meta entry, and not a real opcode. */ 60 // This is a meta entry, and not a real opcode.
60 /* This is to facilitate multi-nybble instruction decoding. */ 61 // This is to facilitate multi-nybble instruction decoding.
61 CheatVmOpcodeType_DoubleExtendedWidth = 0xF0, 62 DoubleExtendedWidth = 0xF0,
62 63
63 /* Double-extended width opcodes. */ 64 // Double-extended width opcodes.
64 CheatVmOpcodeType_DebugLog = 0xFFF, 65 DebugLog = 0xFFF,
65}; 66};
66 67
67enum MemoryAccessType : u32 { 68enum class MemoryAccessType : u32 {
68 MemoryAccessType_MainNso = 0, 69 MainNso = 0,
69 MemoryAccessType_Heap = 1, 70 Heap = 1,
70}; 71};
71 72
72enum ConditionalComparisonType : u32 { 73enum class ConditionalComparisonType : u32 {
73 ConditionalComparisonType_GT = 1, 74 GT = 1,
74 ConditionalComparisonType_GE = 2, 75 GE = 2,
75 ConditionalComparisonType_LT = 3, 76 LT = 3,
76 ConditionalComparisonType_LE = 4, 77 LE = 4,
77 ConditionalComparisonType_EQ = 5, 78 EQ = 5,
78 ConditionalComparisonType_NE = 6, 79 NE = 6,
79}; 80};
80 81
81enum RegisterArithmeticType : u32 { 82enum class RegisterArithmeticType : u32 {
82 RegisterArithmeticType_Addition = 0, 83 Addition = 0,
83 RegisterArithmeticType_Subtraction = 1, 84 Subtraction = 1,
84 RegisterArithmeticType_Multiplication = 2, 85 Multiplication = 2,
85 RegisterArithmeticType_LeftShift = 3, 86 LeftShift = 3,
86 RegisterArithmeticType_RightShift = 4, 87 RightShift = 4,
87 88
88 /* These are not supported by Gateway's VM. */ 89 // These are not supported by Gateway's VM.
89 RegisterArithmeticType_LogicalAnd = 5, 90 LogicalAnd = 5,
90 RegisterArithmeticType_LogicalOr = 6, 91 LogicalOr = 6,
91 RegisterArithmeticType_LogicalNot = 7, 92 LogicalNot = 7,
92 RegisterArithmeticType_LogicalXor = 8, 93 LogicalXor = 8,
93 94
94 RegisterArithmeticType_None = 9, 95 None = 9,
95}; 96};
96 97
97enum StoreRegisterOffsetType : u32 { 98enum class StoreRegisterOffsetType : u32 {
98 StoreRegisterOffsetType_None = 0, 99 None = 0,
99 StoreRegisterOffsetType_Reg = 1, 100 Reg = 1,
100 StoreRegisterOffsetType_Imm = 2, 101 Imm = 2,
101 StoreRegisterOffsetType_MemReg = 3, 102 MemReg = 3,
102 StoreRegisterOffsetType_MemImm = 4, 103 MemImm = 4,
103 StoreRegisterOffsetType_MemImmReg = 5, 104 MemImmReg = 5,
104}; 105};
105 106
106enum CompareRegisterValueType : u32 { 107enum class CompareRegisterValueType : u32 {
107 CompareRegisterValueType_MemoryRelAddr = 0, 108 MemoryRelAddr = 0,
108 CompareRegisterValueType_MemoryOfsReg = 1, 109 MemoryOfsReg = 1,
109 CompareRegisterValueType_RegisterRelAddr = 2, 110 RegisterRelAddr = 2,
110 CompareRegisterValueType_RegisterOfsReg = 3, 111 RegisterOfsReg = 3,
111 CompareRegisterValueType_StaticValue = 4, 112 StaticValue = 4,
112 CompareRegisterValueType_OtherRegister = 5, 113 OtherRegister = 5,
113}; 114};
114 115
115enum SaveRestoreRegisterOpType : u32 { 116enum class SaveRestoreRegisterOpType : u32 {
116 SaveRestoreRegisterOpType_Restore = 0, 117 Restore = 0,
117 SaveRestoreRegisterOpType_Save = 1, 118 Save = 1,
118 SaveRestoreRegisterOpType_ClearSaved = 2, 119 ClearSaved = 2,
119 SaveRestoreRegisterOpType_ClearRegs = 3, 120 ClearRegs = 3,
120}; 121};
121 122
122enum DebugLogValueType : u32 { 123enum class DebugLogValueType : u32 {
123 DebugLogValueType_MemoryRelAddr = 0, 124 MemoryRelAddr = 0,
124 DebugLogValueType_MemoryOfsReg = 1, 125 MemoryOfsReg = 1,
125 DebugLogValueType_RegisterRelAddr = 2, 126 RegisterRelAddr = 2,
126 DebugLogValueType_RegisterOfsReg = 3, 127 RegisterOfsReg = 3,
127 DebugLogValueType_RegisterValue = 4, 128 RegisterValue = 4,
128}; 129};
129 130
130union VmInt { 131union VmInt {
@@ -247,26 +248,19 @@ struct DebugLogOpcode {
247 u64 rel_address; 248 u64 rel_address;
248}; 249};
249 250
250struct CheatVmOpcode { 251struct UnrecognizedInstruction {
251 CheatVmOpcodeType opcode; 252 CheatVmOpcodeType opcode;
253};
254
255struct CheatVmOpcode {
252 bool begin_conditional_block; 256 bool begin_conditional_block;
253 union { 257 std::variant<StoreStaticOpcode, BeginConditionalOpcode, EndConditionalOpcode, ControlLoopOpcode,
254 StoreStaticOpcode store_static; 258 LoadRegisterStaticOpcode, LoadRegisterMemoryOpcode, StoreStaticToAddressOpcode,
255 BeginConditionalOpcode begin_cond; 259 PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
256 EndConditionalOpcode end_cond; 260 PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
257 ControlLoopOpcode ctrl_loop; 261 BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
258 LoadRegisterStaticOpcode ldr_static; 262 SaveRestoreRegisterMaskOpcode, DebugLogOpcode, UnrecognizedInstruction>
259 LoadRegisterMemoryOpcode ldr_memory; 263 opcode;
260 StoreStaticToAddressOpcode str_static;
261 PerformArithmeticStaticOpcode perform_math_static;
262 BeginKeypressConditionalOpcode begin_keypress_cond;
263 PerformArithmeticRegisterOpcode perform_math_reg;
264 StoreRegisterToAddressOpcode str_register;
265 BeginRegisterConditionalOpcode begin_reg_cond;
266 SaveRestoreRegisterOpcode save_restore_reg;
267 SaveRestoreRegisterMaskOpcode save_restore_regmask;
268 DebugLogOpcode debug_log;
269 };
270}; 264};
271 265
272class DmntCheatVm { 266class DmntCheatVm {
@@ -285,50 +279,43 @@ public:
285 virtual void CommandLog(std::string_view data) = 0; 279 virtual void CommandLog(std::string_view data) = 0;
286 }; 280 };
287 281
288 constexpr static size_t MaximumProgramOpcodeCount = 0x400; 282 static constexpr std::size_t MaximumProgramOpcodeCount = 0x400;
289 constexpr static size_t NumRegisters = 0x10; 283 static constexpr std::size_t NumRegisters = 0x10;
284
285 explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks);
286 ~DmntCheatVm();
287
288 std::size_t GetProgramSize() const {
289 return this->num_opcodes;
290 }
291
292 bool LoadProgram(const std::vector<CheatEntry>& cheats);
293 void Execute(const CheatProcessMetadata& metadata);
290 294
291private: 295private:
292 std::unique_ptr<Callbacks> callbacks; 296 std::unique_ptr<Callbacks> callbacks;
293 297
294 size_t num_opcodes = 0; 298 std::size_t num_opcodes = 0;
295 size_t instruction_ptr = 0; 299 std::size_t instruction_ptr = 0;
296 size_t condition_depth = 0; 300 std::size_t condition_depth = 0;
297 bool decode_success = false; 301 bool decode_success = false;
298 std::array<u32, MaximumProgramOpcodeCount> program{}; 302 std::array<u32, MaximumProgramOpcodeCount> program{};
299 std::array<u64, NumRegisters> registers{}; 303 std::array<u64, NumRegisters> registers{};
300 std::array<u64, NumRegisters> saved_values{}; 304 std::array<u64, NumRegisters> saved_values{};
301 std::array<size_t, NumRegisters> loop_tops{}; 305 std::array<std::size_t, NumRegisters> loop_tops{};
302 306
303private:
304 bool DecodeNextOpcode(CheatVmOpcode& out); 307 bool DecodeNextOpcode(CheatVmOpcode& out);
305 void SkipConditionalBlock(); 308 void SkipConditionalBlock();
306 void ResetState(); 309 void ResetState();
307 310
308 /* For implementing the DebugLog opcode. */ 311 // For implementing the DebugLog opcode.
309 void DebugLog(u32 log_id, u64 value); 312 void DebugLog(u32 log_id, u64 value);
310 313
311 /* For debugging. These will be IFDEF'd out normally. */
312 template <typename... Args>
313 void LogToDebugFile(const char* format, const Args&... args) {
314 callbacks->CommandLog(fmt::sprintf(format, args...));
315 }
316
317 void LogOpcode(const CheatVmOpcode& opcode); 314 void LogOpcode(const CheatVmOpcode& opcode);
318 315
319 static u64 GetVmInt(VmInt value, u32 bit_width); 316 static u64 GetVmInt(VmInt value, u32 bit_width);
320 static u64 GetCheatProcessAddress(const CheatProcessMetadata& metadata, 317 static u64 GetCheatProcessAddress(const CheatProcessMetadata& metadata,
321 MemoryAccessType mem_type, u64 rel_address); 318 MemoryAccessType mem_type, u64 rel_address);
322
323public:
324 DmntCheatVm(std::unique_ptr<Callbacks> callbacks) : callbacks(std::move(callbacks)) {}
325
326 size_t GetProgramSize() {
327 return this->num_opcodes;
328 }
329
330 bool LoadProgram(const std::vector<CheatEntry>& cheats);
331 void Execute(const CheatProcessMetadata& metadata);
332}; 319};
333 320
334}; // namespace Memory 321}; // namespace Memory