mirror of
https://gitlab.com/suyu-emu/suyu.git
synced 2024-03-15 23:15:44 +00:00
Merge pull request #12915 from german77/cheat
dmnt: cheats: Update cheat vm to latest version
This commit is contained in:
commit
74cc8721c7
|
@ -9,6 +9,7 @@
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/kernel/k_page_table.h"
|
#include "core/hle/kernel/k_page_table.h"
|
||||||
#include "core/hle/kernel/k_process.h"
|
#include "core/hle/kernel/k_process.h"
|
||||||
|
#include "core/hle/kernel/k_process_page_table.h"
|
||||||
#include "core/hle/service/hid/hid_server.h"
|
#include "core/hle/service/hid/hid_server.h"
|
||||||
#include "core/hle/service/sm/sm.h"
|
#include "core/hle/service/sm/sm.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
@ -46,12 +47,23 @@ StandardVmCallbacks::StandardVmCallbacks(System& system_, const CheatProcessMeta
|
||||||
|
|
||||||
StandardVmCallbacks::~StandardVmCallbacks() = default;
|
StandardVmCallbacks::~StandardVmCallbacks() = default;
|
||||||
|
|
||||||
void StandardVmCallbacks::MemoryRead(VAddr address, void* data, u64 size) {
|
void StandardVmCallbacks::MemoryReadUnsafe(VAddr address, void* data, u64 size) {
|
||||||
system.ApplicationMemory().ReadBlock(SanitizeAddress(address), data, size);
|
// Return zero on invalid address
|
||||||
|
if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) {
|
||||||
|
std::memset(data, 0, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
system.ApplicationMemory().ReadBlock(address, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StandardVmCallbacks::MemoryWrite(VAddr address, const void* data, u64 size) {
|
void StandardVmCallbacks::MemoryWriteUnsafe(VAddr address, const void* data, u64 size) {
|
||||||
system.ApplicationMemory().WriteBlock(SanitizeAddress(address), data, size);
|
// Skip invalid memory write address
|
||||||
|
if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
system.ApplicationMemory().WriteBlock(address, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 StandardVmCallbacks::HidKeysDown() {
|
u64 StandardVmCallbacks::HidKeysDown() {
|
||||||
|
@ -81,21 +93,25 @@ void StandardVmCallbacks::CommandLog(std::string_view data) {
|
||||||
data.back() == '\n' ? data.substr(0, data.size() - 1) : data);
|
data.back() == '\n' ? data.substr(0, data.size() - 1) : data);
|
||||||
}
|
}
|
||||||
|
|
||||||
VAddr StandardVmCallbacks::SanitizeAddress(VAddr in) const {
|
bool StandardVmCallbacks::IsAddressInRange(VAddr in) const {
|
||||||
if ((in < metadata.main_nso_extents.base ||
|
if ((in < metadata.main_nso_extents.base ||
|
||||||
in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) &&
|
in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) &&
|
||||||
(in < metadata.heap_extents.base ||
|
(in < metadata.heap_extents.base ||
|
||||||
in >= metadata.heap_extents.base + metadata.heap_extents.size)) {
|
in >= metadata.heap_extents.base + metadata.heap_extents.size) &&
|
||||||
LOG_ERROR(CheatEngine,
|
(in < metadata.alias_extents.base ||
|
||||||
|
in >= metadata.heap_extents.base + metadata.alias_extents.size) &&
|
||||||
|
(in < metadata.aslr_extents.base ||
|
||||||
|
in >= metadata.heap_extents.base + metadata.aslr_extents.size)) {
|
||||||
|
LOG_DEBUG(CheatEngine,
|
||||||
"Cheat attempting to access memory at invalid address={:016X}, if this "
|
"Cheat attempting to access memory at invalid address={:016X}, if this "
|
||||||
"persists, "
|
"persists, "
|
||||||
"the cheat may be incorrect. However, this may be normal early in execution if "
|
"the cheat may be incorrect. However, this may be normal early in execution if "
|
||||||
"the game has not properly set up yet.",
|
"the game has not properly set up yet.",
|
||||||
in);
|
in);
|
||||||
return 0; ///< Invalid addresses will hard crash
|
return false; ///< Invalid addresses will hard crash
|
||||||
}
|
}
|
||||||
|
|
||||||
return in;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CheatParser::~CheatParser() = default;
|
CheatParser::~CheatParser() = default;
|
||||||
|
@ -211,16 +227,14 @@ void CheatEngine::Initialize() {
|
||||||
.base = GetInteger(page_table.GetHeapRegionStart()),
|
.base = GetInteger(page_table.GetHeapRegionStart()),
|
||||||
.size = page_table.GetHeapRegionSize(),
|
.size = page_table.GetHeapRegionSize(),
|
||||||
};
|
};
|
||||||
|
metadata.aslr_extents = {
|
||||||
metadata.address_space_extents = {
|
|
||||||
.base = GetInteger(page_table.GetAddressSpaceStart()),
|
|
||||||
.size = page_table.GetAddressSpaceSize(),
|
|
||||||
};
|
|
||||||
|
|
||||||
metadata.alias_extents = {
|
|
||||||
.base = GetInteger(page_table.GetAliasCodeRegionStart()),
|
.base = GetInteger(page_table.GetAliasCodeRegionStart()),
|
||||||
.size = page_table.GetAliasCodeRegionSize(),
|
.size = page_table.GetAliasCodeRegionSize(),
|
||||||
};
|
};
|
||||||
|
metadata.alias_extents = {
|
||||||
|
.base = GetInteger(page_table.GetAliasRegionStart()),
|
||||||
|
.size = page_table.GetAliasRegionSize(),
|
||||||
|
};
|
||||||
|
|
||||||
is_pending_reload.exchange(true);
|
is_pending_reload.exchange(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,17 +27,17 @@ public:
|
||||||
StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_);
|
StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_);
|
||||||
~StandardVmCallbacks() override;
|
~StandardVmCallbacks() override;
|
||||||
|
|
||||||
void MemoryRead(VAddr address, void* data, u64 size) override;
|
void MemoryReadUnsafe(VAddr address, void* data, u64 size) override;
|
||||||
void MemoryWrite(VAddr address, const void* data, u64 size) override;
|
void MemoryWriteUnsafe(VAddr address, const void* data, u64 size) override;
|
||||||
u64 HidKeysDown() override;
|
u64 HidKeysDown() override;
|
||||||
void DebugLog(u8 id, u64 value) override;
|
void DebugLog(u8 id, u64 value) override;
|
||||||
void CommandLog(std::string_view data) override;
|
void CommandLog(std::string_view data) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VAddr SanitizeAddress(VAddr address) const;
|
bool IsAddressInRange(VAddr address) const;
|
||||||
|
|
||||||
const CheatProcessMetadata& metadata;
|
const CheatProcessMetadata& metadata;
|
||||||
System& system;
|
Core::System& system;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Intermediary class that parses a text file or other disk format for storing cheats into a
|
// Intermediary class that parses a text file or other disk format for storing cheats into a
|
||||||
|
|
|
@ -18,7 +18,7 @@ struct CheatProcessMetadata {
|
||||||
MemoryRegionExtents main_nso_extents{};
|
MemoryRegionExtents main_nso_extents{};
|
||||||
MemoryRegionExtents heap_extents{};
|
MemoryRegionExtents heap_extents{};
|
||||||
MemoryRegionExtents alias_extents{};
|
MemoryRegionExtents alias_extents{};
|
||||||
MemoryRegionExtents address_space_extents{};
|
MemoryRegionExtents aslr_extents{};
|
||||||
std::array<u8, 0x20> main_nso_build_id{};
|
std::array<u8, 0x20> main_nso_build_id{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -322,8 +322,9 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
|
||||||
} break;
|
} break;
|
||||||
case CheatVmOpcodeType::EndConditionalBlock: {
|
case CheatVmOpcodeType::EndConditionalBlock: {
|
||||||
// 20000000
|
// 20000000
|
||||||
// There's actually nothing left to process here!
|
opcode.opcode = EndConditionalOpcode{
|
||||||
opcode.opcode = EndConditionalOpcode{};
|
.is_else = ((first_dword >> 24) & 0xf) == 1,
|
||||||
|
};
|
||||||
} break;
|
} break;
|
||||||
case CheatVmOpcodeType::ControlLoop: {
|
case CheatVmOpcodeType::ControlLoop: {
|
||||||
// 300R0000 VVVVVVVV
|
// 300R0000 VVVVVVVV
|
||||||
|
@ -555,6 +556,18 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
|
||||||
.idx = first_dword & 0xF,
|
.idx = first_dword & 0xF,
|
||||||
};
|
};
|
||||||
} break;
|
} break;
|
||||||
|
case CheatVmOpcodeType::PauseProcess: {
|
||||||
|
/* FF0????? */
|
||||||
|
/* FF0 = opcode 0xFF0 */
|
||||||
|
/* Pauses the current process. */
|
||||||
|
opcode.opcode = PauseProcessOpcode{};
|
||||||
|
} break;
|
||||||
|
case CheatVmOpcodeType::ResumeProcess: {
|
||||||
|
/* FF0????? */
|
||||||
|
/* FF0 = opcode 0xFF0 */
|
||||||
|
/* Pauses the current process. */
|
||||||
|
opcode.opcode = ResumeProcessOpcode{};
|
||||||
|
} break;
|
||||||
case CheatVmOpcodeType::DebugLog: {
|
case CheatVmOpcodeType::DebugLog: {
|
||||||
// FFFTIX##
|
// FFFTIX##
|
||||||
// FFFTI0Ma aaaaaaaa
|
// FFFTI0Ma aaaaaaaa
|
||||||
|
@ -621,7 +634,7 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DmntCheatVm::SkipConditionalBlock() {
|
void DmntCheatVm::SkipConditionalBlock(bool is_if) {
|
||||||
if (condition_depth > 0) {
|
if (condition_depth > 0) {
|
||||||
// We want to continue until we're out of the current block.
|
// We want to continue until we're out of the current block.
|
||||||
const std::size_t desired_depth = condition_depth - 1;
|
const std::size_t desired_depth = condition_depth - 1;
|
||||||
|
@ -637,8 +650,12 @@ void DmntCheatVm::SkipConditionalBlock() {
|
||||||
// We also support nesting of conditional blocks, and Gateway does not.
|
// We also support nesting of conditional blocks, and Gateway does not.
|
||||||
if (skip_opcode.begin_conditional_block) {
|
if (skip_opcode.begin_conditional_block) {
|
||||||
condition_depth++;
|
condition_depth++;
|
||||||
} else if (std::holds_alternative<EndConditionalOpcode>(skip_opcode.opcode)) {
|
} else if (auto end_cond = std::get_if<EndConditionalOpcode>(&skip_opcode.opcode)) {
|
||||||
condition_depth--;
|
if (!end_cond->is_else) {
|
||||||
|
condition_depth--;
|
||||||
|
} else if (is_if && condition_depth - 1 == desired_depth) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -675,6 +692,10 @@ u64 DmntCheatVm::GetCheatProcessAddress(const CheatProcessMetadata& metadata,
|
||||||
return metadata.main_nso_extents.base + rel_address;
|
return metadata.main_nso_extents.base + rel_address;
|
||||||
case MemoryAccessType::Heap:
|
case MemoryAccessType::Heap:
|
||||||
return metadata.heap_extents.base + rel_address;
|
return metadata.heap_extents.base + rel_address;
|
||||||
|
case MemoryAccessType::Alias:
|
||||||
|
return metadata.alias_extents.base + rel_address;
|
||||||
|
case MemoryAccessType::Aslr:
|
||||||
|
return metadata.aslr_extents.base + rel_address;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,7 +703,6 @@ 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;
|
||||||
|
@ -753,7 +773,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||||
case 2:
|
case 2:
|
||||||
case 4:
|
case 4:
|
||||||
case 8:
|
case 8:
|
||||||
callbacks->MemoryWrite(dst_address, &dst_value, store_static->bit_width);
|
callbacks->MemoryWriteUnsafe(dst_address, &dst_value, store_static->bit_width);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (auto begin_cond = std::get_if<BeginConditionalOpcode>(&cur_opcode.opcode)) {
|
} else if (auto begin_cond = std::get_if<BeginConditionalOpcode>(&cur_opcode.opcode)) {
|
||||||
|
@ -766,7 +786,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||||
case 2:
|
case 2:
|
||||||
case 4:
|
case 4:
|
||||||
case 8:
|
case 8:
|
||||||
callbacks->MemoryRead(src_address, &src_value, begin_cond->bit_width);
|
callbacks->MemoryReadUnsafe(src_address, &src_value, begin_cond->bit_width);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Check against condition.
|
// Check against condition.
|
||||||
|
@ -794,13 +814,18 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||||
}
|
}
|
||||||
// Skip conditional block if condition not met.
|
// Skip conditional block if condition not met.
|
||||||
if (!cond_met) {
|
if (!cond_met) {
|
||||||
SkipConditionalBlock();
|
SkipConditionalBlock(true);
|
||||||
}
|
}
|
||||||
} else if (std::holds_alternative<EndConditionalOpcode>(cur_opcode.opcode)) {
|
} else if (auto end_cond = std::get_if<EndConditionalOpcode>(&cur_opcode.opcode)) {
|
||||||
// Decrement the condition depth.
|
if (end_cond->is_else) {
|
||||||
// We will assume, graciously, that mismatched conditional block ends are a nop.
|
/* Skip to the end of the conditional block. */
|
||||||
if (condition_depth > 0) {
|
this->SkipConditionalBlock(false);
|
||||||
condition_depth--;
|
} else {
|
||||||
|
/* Decrement the condition depth. */
|
||||||
|
/* We will assume, graciously, that mismatched conditional block ends are a nop. */
|
||||||
|
if (condition_depth > 0) {
|
||||||
|
condition_depth--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&cur_opcode.opcode)) {
|
} else if (auto ctrl_loop = std::get_if<ControlLoopOpcode>(&cur_opcode.opcode)) {
|
||||||
if (ctrl_loop->start_loop) {
|
if (ctrl_loop->start_loop) {
|
||||||
|
@ -832,8 +857,8 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||||
case 2:
|
case 2:
|
||||||
case 4:
|
case 4:
|
||||||
case 8:
|
case 8:
|
||||||
callbacks->MemoryRead(src_address, ®isters[ldr_memory->reg_index],
|
callbacks->MemoryReadUnsafe(src_address, ®isters[ldr_memory->reg_index],
|
||||||
ldr_memory->bit_width);
|
ldr_memory->bit_width);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (auto str_static = std::get_if<StoreStaticToAddressOpcode>(&cur_opcode.opcode)) {
|
} else if (auto str_static = std::get_if<StoreStaticToAddressOpcode>(&cur_opcode.opcode)) {
|
||||||
|
@ -849,7 +874,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||||
case 2:
|
case 2:
|
||||||
case 4:
|
case 4:
|
||||||
case 8:
|
case 8:
|
||||||
callbacks->MemoryWrite(dst_address, &dst_value, str_static->bit_width);
|
callbacks->MemoryWriteUnsafe(dst_address, &dst_value, str_static->bit_width);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Increment register if relevant.
|
// Increment register if relevant.
|
||||||
|
@ -908,7 +933,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||||
// Check for keypress.
|
// Check for keypress.
|
||||||
if ((begin_keypress_cond->key_mask & kDown) != begin_keypress_cond->key_mask) {
|
if ((begin_keypress_cond->key_mask & kDown) != begin_keypress_cond->key_mask) {
|
||||||
// Keys not pressed. Skip conditional block.
|
// Keys not pressed. Skip conditional block.
|
||||||
SkipConditionalBlock();
|
SkipConditionalBlock(true);
|
||||||
}
|
}
|
||||||
} else if (auto perform_math_reg =
|
} else if (auto perform_math_reg =
|
||||||
std::get_if<PerformArithmeticRegisterOpcode>(&cur_opcode.opcode)) {
|
std::get_if<PerformArithmeticRegisterOpcode>(&cur_opcode.opcode)) {
|
||||||
|
@ -1007,7 +1032,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||||
case 2:
|
case 2:
|
||||||
case 4:
|
case 4:
|
||||||
case 8:
|
case 8:
|
||||||
callbacks->MemoryWrite(dst_address, &dst_value, str_register->bit_width);
|
callbacks->MemoryWriteUnsafe(dst_address, &dst_value, str_register->bit_width);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1086,7 +1111,8 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||||
case 2:
|
case 2:
|
||||||
case 4:
|
case 4:
|
||||||
case 8:
|
case 8:
|
||||||
callbacks->MemoryRead(cond_address, &cond_value, begin_reg_cond->bit_width);
|
callbacks->MemoryReadUnsafe(cond_address, &cond_value,
|
||||||
|
begin_reg_cond->bit_width);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1116,7 +1142,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||||
|
|
||||||
// Skip conditional block if condition not met.
|
// Skip conditional block if condition not met.
|
||||||
if (!cond_met) {
|
if (!cond_met) {
|
||||||
SkipConditionalBlock();
|
SkipConditionalBlock(true);
|
||||||
}
|
}
|
||||||
} else if (auto save_restore_reg =
|
} else if (auto save_restore_reg =
|
||||||
std::get_if<SaveRestoreRegisterOpcode>(&cur_opcode.opcode)) {
|
std::get_if<SaveRestoreRegisterOpcode>(&cur_opcode.opcode)) {
|
||||||
|
@ -1178,6 +1204,10 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||||
// Store a register to a static register.
|
// Store a register to a static register.
|
||||||
static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx];
|
static_registers[rw_static_reg->static_idx] = registers[rw_static_reg->idx];
|
||||||
}
|
}
|
||||||
|
} else if (std::holds_alternative<PauseProcessOpcode>(cur_opcode.opcode)) {
|
||||||
|
// TODO: Pause cheat process
|
||||||
|
} else if (std::holds_alternative<ResumeProcessOpcode>(cur_opcode.opcode)) {
|
||||||
|
// TODO: Resume cheat process
|
||||||
} 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;
|
||||||
|
@ -1224,7 +1254,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
|
||||||
case 2:
|
case 2:
|
||||||
case 4:
|
case 4:
|
||||||
case 8:
|
case 8:
|
||||||
callbacks->MemoryRead(val_address, &log_value, debug_log->bit_width);
|
callbacks->MemoryReadUnsafe(val_address, &log_value, debug_log->bit_width);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,12 +42,16 @@ enum class CheatVmOpcodeType : u32 {
|
||||||
DoubleExtendedWidth = 0xF0,
|
DoubleExtendedWidth = 0xF0,
|
||||||
|
|
||||||
// Double-extended width opcodes.
|
// Double-extended width opcodes.
|
||||||
|
PauseProcess = 0xFF0,
|
||||||
|
ResumeProcess = 0xFF1,
|
||||||
DebugLog = 0xFFF,
|
DebugLog = 0xFFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class MemoryAccessType : u32 {
|
enum class MemoryAccessType : u32 {
|
||||||
MainNso = 0,
|
MainNso = 0,
|
||||||
Heap = 1,
|
Heap = 1,
|
||||||
|
Alias = 2,
|
||||||
|
Aslr = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ConditionalComparisonType : u32 {
|
enum class ConditionalComparisonType : u32 {
|
||||||
|
@ -131,7 +135,9 @@ struct BeginConditionalOpcode {
|
||||||
VmInt value{};
|
VmInt value{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EndConditionalOpcode {};
|
struct EndConditionalOpcode {
|
||||||
|
bool is_else;
|
||||||
|
};
|
||||||
|
|
||||||
struct ControlLoopOpcode {
|
struct ControlLoopOpcode {
|
||||||
bool start_loop{};
|
bool start_loop{};
|
||||||
|
@ -222,6 +228,10 @@ struct ReadWriteStaticRegisterOpcode {
|
||||||
u32 idx{};
|
u32 idx{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PauseProcessOpcode {};
|
||||||
|
|
||||||
|
struct ResumeProcessOpcode {};
|
||||||
|
|
||||||
struct DebugLogOpcode {
|
struct DebugLogOpcode {
|
||||||
u32 bit_width{};
|
u32 bit_width{};
|
||||||
u32 log_id{};
|
u32 log_id{};
|
||||||
|
@ -244,8 +254,8 @@ struct CheatVmOpcode {
|
||||||
PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
|
PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
|
||||||
PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
|
PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
|
||||||
BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
|
BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
|
||||||
SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, DebugLogOpcode,
|
SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, PauseProcessOpcode,
|
||||||
UnrecognizedInstruction>
|
ResumeProcessOpcode, DebugLogOpcode, UnrecognizedInstruction>
|
||||||
opcode{};
|
opcode{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -256,8 +266,8 @@ public:
|
||||||
public:
|
public:
|
||||||
virtual ~Callbacks();
|
virtual ~Callbacks();
|
||||||
|
|
||||||
virtual void MemoryRead(VAddr address, void* data, u64 size) = 0;
|
virtual void MemoryReadUnsafe(VAddr address, void* data, u64 size) = 0;
|
||||||
virtual void MemoryWrite(VAddr address, const void* data, u64 size) = 0;
|
virtual void MemoryWriteUnsafe(VAddr address, const void* data, u64 size) = 0;
|
||||||
|
|
||||||
virtual u64 HidKeysDown() = 0;
|
virtual u64 HidKeysDown() = 0;
|
||||||
|
|
||||||
|
@ -296,7 +306,7 @@ private:
|
||||||
std::array<std::size_t, NumRegisters> loop_tops{};
|
std::array<std::size_t, NumRegisters> loop_tops{};
|
||||||
|
|
||||||
bool DecodeNextOpcode(CheatVmOpcode& out);
|
bool DecodeNextOpcode(CheatVmOpcode& out);
|
||||||
void SkipConditionalBlock();
|
void SkipConditionalBlock(bool is_if);
|
||||||
void ResetState();
|
void ResetState();
|
||||||
|
|
||||||
// For implementing the DebugLog opcode.
|
// For implementing the DebugLog opcode.
|
||||||
|
|
Loading…
Reference in a new issue