Explorar o código

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
VolcaEM %!s(int64=6) %!d(string=hai) anos
pai
achega
b608acd688
Modificáronse 2 ficheiros con 41 adicións e 1 borrados
  1. 28 0
      src/core/memory/dmnt_cheat_vm.cpp
  2. 13 1
      src/core/memory/dmnt_cheat_vm.h

+ 28 - 0
src/core/memory/dmnt_cheat_vm.cpp

@@ -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;

+ 13 - 1
src/core/memory/dmnt_cheat_vm.h

@@ -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);