dmnt_cheat_vm.cpp 55 KB

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