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:
parent
a0ee597b19
commit
b608acd688
|
@ -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