diff --git a/stratosphere/dmnt/source/dmnt_cheat_vm.cpp b/stratosphere/dmnt/source/dmnt_cheat_vm.cpp index cc1c3820f..162e60c33 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_vm.cpp +++ b/stratosphere/dmnt/source/dmnt_cheat_vm.cpp @@ -194,6 +194,13 @@ void DmntCheatVm::LogOpcode(const CheatVmOpcode *opcode) { this->LogToDebugFile("Src Idx: %x\n", opcode->save_restore_reg.src_index); this->LogToDebugFile("Is Save: %d\n", opcode->save_restore_reg.is_save); break; + case CheatVmOpcodeType_SaveRestoreRegisterMask: + this->LogToDebugFile("Opcode: Save or Restore Register Mask\n"); + this->LogToDebugFile("Is Save: %d\n", opcode->save_restore_regmask.is_save); + for (size_t i = 0; i < NumRegisters; i++) { + this->LogToDebugFile("Act[%02x]: %d\n", i, opcode->save_restore_regmask.should_save_or_restore[i]); + } + break; default: this->LogToDebugFile("Unknown opcode: %x\n", opcode->opcode); break; @@ -481,6 +488,18 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode *out) { opcode.save_restore_reg.is_save = ((first_dword >> 4) & 0xF) != 0; } break; + case CheatVmOpcodeType_SaveRestoreRegisterMask: + { + /* C2x0XXXX */ + /* C2 = opcode 0xC2 */ + /* x = 1 if saving, 0 if restoring. */ + /* X = 16-bit bitmask, bit i --> save or restore register i. */ + opcode.save_restore_regmask.is_save = ((first_dword >> 20) & 0xF) != 0; + for (size_t i = 0; i < NumRegisters; i++) { + opcode.save_restore_regmask.should_save_or_restore[i] = (first_dword & (1u << i)) != 0; + } + } + break; case CheatVmOpcodeType_ExtendedWidth: default: /* Unrecognized instruction cannot be decoded. */ @@ -996,6 +1015,23 @@ void DmntCheatVm::Execute(const CheatProcessMetadata *metadata) { this->registers[cur_opcode.save_restore_reg.dst_index] = this->saved_values[cur_opcode.save_restore_reg.src_index]; } break; + case CheatVmOpcodeType_SaveRestoreRegisterMask: + /* Save or restore register mask. */ + u64 *src; + u64 *dst; + if (cur_opcode.save_restore_regmask.is_save) { + src = this->registers; + dst = this->saved_values; + } else { + src = this->registers; + dst = this->saved_values; + } + for (size_t i = 0; i < NumRegisters; i++) { + if (cur_opcode.save_restore_regmask.should_save_or_restore[i]) { + dst[i] = src[i]; + } + } + break; default: /* By default, we do a no-op. */ break; diff --git a/stratosphere/dmnt/source/dmnt_cheat_vm.hpp b/stratosphere/dmnt/source/dmnt_cheat_vm.hpp index 5689f8fd8..4ab1b1511 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_vm.hpp +++ b/stratosphere/dmnt/source/dmnt_cheat_vm.hpp @@ -44,6 +44,7 @@ enum CheatVmOpcodeType : u32 { /* Extended width opcodes. */ CheatVmOpcodeType_BeginRegisterConditionalBlock = 0xC0, CheatVmOpcodeType_SaveRestoreRegister = 0xC1, + CheatVmOpcodeType_SaveRestoreRegisterMask = 0xC2, }; enum MemoryAccessType : u32 { @@ -198,6 +199,11 @@ struct SaveRestoreRegisterOpcode { bool is_save; }; +struct SaveRestoreRegisterMaskOpcode { + bool is_save; + bool should_save_or_restore[0x10]; +}; + struct CheatVmOpcode { CheatVmOpcodeType opcode; bool begin_conditional_block; @@ -215,6 +221,7 @@ struct CheatVmOpcode { StoreRegisterToAddressOpcode str_register; BeginRegisterConditionalOpcode begin_reg_cond; SaveRestoreRegisterOpcode save_restore_reg; + SaveRestoreRegisterMaskOpcode save_restore_regmask; }; };