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( |             callbacks->CommandLog( | ||||||
|                 fmt::format("Act[{:02X}]:   {:d}", i, save_restore_regmask->should_operate[i])); |                 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)) { |     } else if (auto debug_log = std::get_if<DebugLogOpcode>(&opcode.opcode)) { | ||||||
|         callbacks->CommandLog("Opcode: Debug Log"); |         callbacks->CommandLog("Opcode: Debug Log"); | ||||||
|         callbacks->CommandLog(fmt::format("Bit Width: {:X}", debug_log->bit_width)); |         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; |         opcode.opcode = save_restore_regmask; | ||||||
|     } break; |     } 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: { |     case CheatVmOpcodeType::DebugLog: { | ||||||
|         DebugLogOpcode debug_log{}; |         DebugLogOpcode debug_log{}; | ||||||
|         // FFFTIX## |         // FFFTIX## | ||||||
| @@ -667,6 +686,7 @@ void DmntCheatVm::ResetState() { | |||||||
|     registers.fill(0); |     registers.fill(0); | ||||||
|     saved_values.fill(0); |     saved_values.fill(0); | ||||||
|     loop_tops.fill(0); |     loop_tops.fill(0); | ||||||
|  |     static_registers.fill(0); | ||||||
|     instruction_ptr = 0; |     instruction_ptr = 0; | ||||||
|     condition_depth = 0; |     condition_depth = 0; | ||||||
|     decode_success = true; |     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)) { |         } else if (auto debug_log = std::get_if<DebugLogOpcode>(&cur_opcode.opcode)) { | ||||||
|             // Read value from memory. |             // Read value from memory. | ||||||
|             u64 log_value = 0; |             u64 log_value = 0; | ||||||
|   | |||||||
| @@ -56,6 +56,7 @@ enum class CheatVmOpcodeType : u32 { | |||||||
|     BeginRegisterConditionalBlock = 0xC0, |     BeginRegisterConditionalBlock = 0xC0, | ||||||
|     SaveRestoreRegister = 0xC1, |     SaveRestoreRegister = 0xC1, | ||||||
|     SaveRestoreRegisterMask = 0xC2, |     SaveRestoreRegisterMask = 0xC2, | ||||||
|  |     ReadWriteStaticRegister = 0xC3, | ||||||
|  |  | ||||||
|     // This is a meta entry, and not a real opcode. |     // This is a meta entry, and not a real opcode. | ||||||
|     // This is to facilitate multi-nybble instruction decoding. |     // This is to facilitate multi-nybble instruction decoding. | ||||||
| @@ -237,6 +238,11 @@ struct SaveRestoreRegisterMaskOpcode { | |||||||
|     std::array<bool, 0x10> should_operate{}; |     std::array<bool, 0x10> should_operate{}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | struct ReadWriteStaticRegisterOpcode { | ||||||
|  |     u32 static_idx{}; | ||||||
|  |     u32 idx{}; | ||||||
|  | }; | ||||||
|  |  | ||||||
| struct DebugLogOpcode { | struct DebugLogOpcode { | ||||||
|     u32 bit_width{}; |     u32 bit_width{}; | ||||||
|     u32 log_id{}; |     u32 log_id{}; | ||||||
| @@ -259,7 +265,8 @@ struct CheatVmOpcode { | |||||||
|                  PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode, |                  PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode, | ||||||
|                  PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode, |                  PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode, | ||||||
|                  BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode, |                  BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode, | ||||||
|                  SaveRestoreRegisterMaskOpcode, DebugLogOpcode, UnrecognizedInstruction> |                  SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, DebugLogOpcode, | ||||||
|  |                  UnrecognizedInstruction> | ||||||
|         opcode{}; |         opcode{}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -281,6 +288,10 @@ public: | |||||||
|  |  | ||||||
|     static constexpr std::size_t MaximumProgramOpcodeCount = 0x400; |     static constexpr std::size_t MaximumProgramOpcodeCount = 0x400; | ||||||
|     static constexpr std::size_t NumRegisters = 0x10; |     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); |     explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks); | ||||||
|     ~DmntCheatVm(); |     ~DmntCheatVm(); | ||||||
| @@ -302,6 +313,7 @@ private: | |||||||
|     std::array<u32, MaximumProgramOpcodeCount> program{}; |     std::array<u32, MaximumProgramOpcodeCount> program{}; | ||||||
|     std::array<u64, NumRegisters> registers{}; |     std::array<u64, NumRegisters> registers{}; | ||||||
|     std::array<u64, NumRegisters> saved_values{}; |     std::array<u64, NumRegisters> saved_values{}; | ||||||
|  |     std::array<u64, NumStaticRegisters> static_registers{}; | ||||||
|     std::array<std::size_t, NumRegisters> loop_tops{}; |     std::array<std::size_t, NumRegisters> loop_tops{}; | ||||||
|  |  | ||||||
|     bool DecodeNextOpcode(CheatVmOpcode& out); |     bool DecodeNextOpcode(CheatVmOpcode& out); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user