dmnt_cheat_vm: Implement opcode 0xC3 (ReadWriteStaticRegister)
This was based on Atmosphére's DMNT Cheat VM: - https://github.com/Atmosphere-NX/Atmosphere/blob/master/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_vm.hpp - https://github.com/Atmosphere-NX/Atmosphere/blob/master/stratosphere/dmnt/source/cheat/impl/dmnt_cheat_vm.cpp From Atmosphére's documentation: "Code type 0xC3 reads or writes a static register with a given register" There are now only two remaining opcodes to implement (PauseProcess and BreakProcess) This is untested because I don't have any experience in testing cheats on yuzu
This commit is contained in:
		| @@ -190,6 +190,15 @@ void DmntCheatVm::LogOpcode(const CheatVmOpcode& opcode) { | ||||
|             callbacks->CommandLog( | ||||
|                 fmt::format("Act[{:02X}]:   {:d}", i, save_restore_regmask->should_operate[i])); | ||||
|         } | ||||
|     } else if (auto rw_static_reg = std::get_if<ReadWriteStaticRegisterOpcode>(&opcode.opcode)) { | ||||
|         callbacks->CommandLog("Opcode: Read/Write Static Register"); | ||||
|         if (rw_static_reg->static_idx < NumReadableStaticRegisters) { | ||||
|             callbacks->CommandLog("Op Type: ReadStaticRegister"); | ||||
|         } else { | ||||
|             callbacks->CommandLog("Op Type: WriteStaticRegister"); | ||||
|         } | ||||
|         callbacks->CommandLog(fmt::format("Reg Idx   {:X}", rw_static_reg->idx)); | ||||
|         callbacks->CommandLog(fmt::format("Stc Idx   {:X}", rw_static_reg->static_idx)); | ||||
|     } else if (auto debug_log = std::get_if<DebugLogOpcode>(&opcode.opcode)) { | ||||
|         callbacks->CommandLog("Opcode: Debug Log"); | ||||
|         callbacks->CommandLog(fmt::format("Bit Width: {:X}", debug_log->bit_width)); | ||||
| @@ -544,6 +553,16 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) { | ||||
|         } | ||||
|         opcode.opcode = save_restore_regmask; | ||||
|     } break; | ||||
|     case CheatVmOpcodeType::ReadWriteStaticRegister: { | ||||
|         ReadWriteStaticRegisterOpcode rw_static_reg{}; | ||||
|         // C3000XXx | ||||
|         // C3 = opcode 0xC3. | ||||
|         // XX = static register index. | ||||
|         // x  = register index. | ||||
|         rw_static_reg.static_idx = ((first_dword >> 4) & 0xFF); | ||||
|         rw_static_reg.idx = (first_dword & 0xF); | ||||
|         opcode.opcode = rw_static_reg; | ||||
|     } break; | ||||
|     case CheatVmOpcodeType::DebugLog: { | ||||
|         DebugLogOpcode debug_log{}; | ||||
|         // FFFTIX## | ||||
| @@ -667,6 +686,7 @@ void DmntCheatVm::ResetState() { | ||||
|     registers.fill(0); | ||||
|     saved_values.fill(0); | ||||
|     loop_tops.fill(0); | ||||
|     static_registers.fill(0); | ||||
|     instruction_ptr = 0; | ||||
|     condition_depth = 0; | ||||
|     decode_success = true; | ||||
| @@ -1153,6 +1173,14 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } else if (auto rw_static_reg = std::get_if<ReadWriteStaticRegisterOpcode>(&cur_opcode.opcode)) { | ||||
|             if (rw_static_reg->static_idx < NumReadableStaticRegisters) { | ||||
|                 // Load a register with a static register. | ||||
|                 registers[rw_static_reg->idx] = static_registers[rw_static_reg->static_idx]; | ||||
|             } else { | ||||
|                 // Store a register to a static register. | ||||
|                 static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx]; | ||||
|             } | ||||
|         } else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) { | ||||
|             // Read value from memory. | ||||
|             u64 log_value = 0; | ||||
|   | ||||
| @@ -56,6 +56,7 @@ enum class CheatVmOpcodeType : u32 { | ||||
|     BeginRegisterConditionalBlock = 0xC0, | ||||
|     SaveRestoreRegister = 0xC1, | ||||
|     SaveRestoreRegisterMask = 0xC2, | ||||
|     ReadWriteStaticRegister = 0xC3, | ||||
|  | ||||
|     // This is a meta entry, and not a real opcode. | ||||
|     // This is to facilitate multi-nybble instruction decoding. | ||||
| @@ -237,6 +238,11 @@ struct SaveRestoreRegisterMaskOpcode { | ||||
|     std::array<bool, 0x10> should_operate{}; | ||||
| }; | ||||
|  | ||||
| struct ReadWriteStaticRegisterOpcode { | ||||
|     u32 static_idx{}; | ||||
|     u32 idx{}; | ||||
| }; | ||||
|  | ||||
| struct DebugLogOpcode { | ||||
|     u32 bit_width{}; | ||||
|     u32 log_id{}; | ||||
| @@ -259,7 +265,8 @@ struct CheatVmOpcode { | ||||
|                  PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode, | ||||
|                  PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode, | ||||
|                  BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode, | ||||
|                  SaveRestoreRegisterMaskOpcode, DebugLogOpcode, UnrecognizedInstruction> | ||||
|                  SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, DebugLogOpcode, | ||||
|                  UnrecognizedInstruction> | ||||
|         opcode{}; | ||||
| }; | ||||
|  | ||||
| @@ -281,6 +288,10 @@ public: | ||||
|  | ||||
|     static constexpr std::size_t MaximumProgramOpcodeCount = 0x400; | ||||
|     static constexpr std::size_t NumRegisters = 0x10; | ||||
|     static constexpr std::size_t NumReadableStaticRegisters = 0x80; | ||||
|     static constexpr std::size_t NumWritableStaticRegisters = 0x80; | ||||
|     static constexpr std::size_t NumStaticRegisters = | ||||
|         NumReadableStaticRegisters + NumWritableStaticRegisters; | ||||
|  | ||||
|     explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks); | ||||
|     ~DmntCheatVm(); | ||||
| @@ -302,6 +313,7 @@ private: | ||||
|     std::array<u32, MaximumProgramOpcodeCount> program{}; | ||||
|     std::array<u64, NumRegisters> registers{}; | ||||
|     std::array<u64, NumRegisters> saved_values{}; | ||||
|     std::array<u64, NumStaticRegisters> static_registers{}; | ||||
|     std::array<std::size_t, NumRegisters> loop_tops{}; | ||||
|  | ||||
|     bool DecodeNextOpcode(CheatVmOpcode& out); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user