mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-06-03 16:18:51 -04:00
Add extensions to dmnt cheat virtual machine (#2479)
* dmnt_extension * update type 8 extension * clearify that bit 27 does not correspond to a button * update cheat.md with new code type 0xC4 * implement code type 0xC4 * Add type 1 extension * remove C0Tcr6Ma aaaaaaaa VVVVVVVV (VVVVVVVV) * Type 9 extension for floating point math * updated according to review
This commit is contained in:
parent
9f8d17b9e6
commit
4e99a5e08d
3 changed files with 171 additions and 10 deletions
|
@ -108,6 +108,8 @@ namespace ams::dmnt::cheat::impl {
|
|||
this->LogToDebugFile("Bit Width: %x\n", opcode->begin_cond.bit_width);
|
||||
this->LogToDebugFile("Mem Type: %x\n", opcode->begin_cond.mem_type);
|
||||
this->LogToDebugFile("Cond Type: %x\n", opcode->begin_cond.cond_type);
|
||||
this->LogToDebugFile("Inc Ofs reg: %d\n", opcode->begin_cond.include_ofs_reg);
|
||||
this->LogToDebugFile("Ofs Reg Idx: %x\n", opcode->begin_cond.ofs_reg_index);
|
||||
this->LogToDebugFile("Rel Addr: %lx\n", opcode->begin_cond.rel_address);
|
||||
this->LogToDebugFile("Value: %lx\n", opcode->begin_cond.value.bit64);
|
||||
break;
|
||||
|
@ -158,6 +160,11 @@ namespace ams::dmnt::cheat::impl {
|
|||
this->LogToDebugFile("Opcode: Begin Keypress Conditional\n");
|
||||
this->LogToDebugFile("Key Mask: %x\n", opcode->begin_keypress_cond.key_mask);
|
||||
break;
|
||||
case CheatVmOpcodeType_BeginExtendedKeypressConditionalBlock:
|
||||
this->LogToDebugFile("Opcode: Begin Extended Keypress Conditional\n");
|
||||
this->LogToDebugFile("Key Mask: %x\n", opcode->begin_ext_keypress_cond.key_mask);
|
||||
this->LogToDebugFile("Auto Repeat: %d\n", opcode->begin_ext_keypress_cond.auto_repeat);
|
||||
break;
|
||||
case CheatVmOpcodeType_PerformArithmeticRegister:
|
||||
this->LogToDebugFile("Opcode: Perform Register Arithmetic\n");
|
||||
this->LogToDebugFile("Bit Width: %x\n", opcode->perform_math_reg.bit_width);
|
||||
|
@ -358,6 +365,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
switch (opcode.opcode) {
|
||||
case CheatVmOpcodeType_BeginConditionalBlock:
|
||||
case CheatVmOpcodeType_BeginKeypressConditionalBlock:
|
||||
case CheatVmOpcodeType_BeginExtendedKeypressConditionalBlock:
|
||||
case CheatVmOpcodeType_BeginRegisterConditionalBlock:
|
||||
opcode.begin_conditional_block = true;
|
||||
break;
|
||||
|
@ -387,6 +395,8 @@ namespace ams::dmnt::cheat::impl {
|
|||
opcode.begin_cond.bit_width = (first_dword >> 24) & 0xF;
|
||||
opcode.begin_cond.mem_type = (MemoryAccessType)((first_dword >> 20) & 0xF);
|
||||
opcode.begin_cond.cond_type = (ConditionalComparisonType)((first_dword >> 16) & 0xF);
|
||||
opcode.begin_cond.include_ofs_reg = ((first_dword >> 12) & 0xF) != 0;
|
||||
opcode.begin_cond.ofs_reg_index = ((first_dword >> 8) & 0xF);
|
||||
opcode.begin_cond.rel_address = ((u64)(first_dword & 0xFF) << 32ul) | ((u64)second_dword);
|
||||
opcode.begin_cond.value = GetNextVmInt(opcode.begin_cond.bit_width);
|
||||
}
|
||||
|
@ -427,7 +437,8 @@ namespace ams::dmnt::cheat::impl {
|
|||
opcode.ldr_memory.bit_width = (first_dword >> 24) & 0xF;
|
||||
opcode.ldr_memory.mem_type = (MemoryAccessType)((first_dword >> 20) & 0xF);
|
||||
opcode.ldr_memory.reg_index = ((first_dword >> 16) & 0xF);
|
||||
opcode.ldr_memory.load_from_reg = ((first_dword >> 12) & 0xF) != 0;
|
||||
opcode.ldr_memory.load_from_reg = ((first_dword >> 12) & 0xF);
|
||||
opcode.ldr_memory.offset_register = ((first_dword >> 8) & 0xF);
|
||||
opcode.ldr_memory.rel_address = ((u64)(first_dword & 0xFF) << 32ul) | ((u64)second_dword);
|
||||
}
|
||||
break;
|
||||
|
@ -460,6 +471,14 @@ namespace ams::dmnt::cheat::impl {
|
|||
opcode.begin_keypress_cond.key_mask = first_dword & 0x0FFFFFFF;
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_BeginExtendedKeypressConditionalBlock:
|
||||
{
|
||||
/* C4r00000 kkkkkkkk kkkkkkkk */
|
||||
/* Read additional words. */
|
||||
opcode.begin_ext_keypress_cond.key_mask = (u64)GetNextDword() << 32ul | (u64)GetNextDword();
|
||||
opcode.begin_ext_keypress_cond.auto_repeat = ((first_dword >> 20) & 0xF) != 0;
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_PerformArithmeticRegister:
|
||||
{
|
||||
/* 9TCRSIs0 (VVVVVVVV (VVVVVVVV)) */
|
||||
|
@ -734,6 +753,8 @@ namespace ams::dmnt::cheat::impl {
|
|||
return metadata->alias_extents.base + rel_address;
|
||||
case MemoryAccessType_Aslr:
|
||||
return metadata->aslr_extents.base + rel_address;
|
||||
case MemoryAccessType_NonRelative:
|
||||
return rel_address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -769,6 +790,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
return true;
|
||||
}
|
||||
|
||||
static u64 s_keyold = 0;
|
||||
void CheatVirtualMachine::Execute(const CheatProcessMetadata *metadata) {
|
||||
CheatVmOpcode cur_opcode;
|
||||
u64 kHeld = 0;
|
||||
|
@ -824,7 +846,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
case CheatVmOpcodeType_BeginConditionalBlock:
|
||||
{
|
||||
/* Read value from memory. */
|
||||
u64 src_address = GetCheatProcessAddress(metadata, cur_opcode.begin_cond.mem_type, cur_opcode.begin_cond.rel_address);
|
||||
u64 src_address = GetCheatProcessAddress(metadata, cur_opcode.begin_cond.mem_type, (cur_opcode.begin_cond.include_ofs_reg) ? m_registers[cur_opcode.begin_cond.ofs_reg_index] + cur_opcode.begin_cond.rel_address : cur_opcode.begin_cond.rel_address);
|
||||
u64 src_value = 0;
|
||||
switch (cur_opcode.store_static.bit_width) {
|
||||
case 1:
|
||||
|
@ -896,8 +918,12 @@ namespace ams::dmnt::cheat::impl {
|
|||
{
|
||||
/* Choose source address. */
|
||||
u64 src_address;
|
||||
if (cur_opcode.ldr_memory.load_from_reg) {
|
||||
if (cur_opcode.ldr_memory.load_from_reg == 1) {
|
||||
src_address = m_registers[cur_opcode.ldr_memory.reg_index] + cur_opcode.ldr_memory.rel_address;
|
||||
} else if (cur_opcode.ldr_memory.load_from_reg == 2) {
|
||||
src_address = m_registers[cur_opcode.ldr_memory.offset_register] + cur_opcode.ldr_memory.rel_address;
|
||||
} else if (cur_opcode.ldr_memory.load_from_reg == 3) {
|
||||
src_address = GetCheatProcessAddress(metadata, cur_opcode.ldr_memory.mem_type, m_registers[cur_opcode.ldr_memory.offset_register] + cur_opcode.ldr_memory.rel_address);
|
||||
} else {
|
||||
src_address = GetCheatProcessAddress(metadata, cur_opcode.ldr_memory.mem_type, cur_opcode.ldr_memory.rel_address);
|
||||
}
|
||||
|
@ -982,6 +1008,18 @@ namespace ams::dmnt::cheat::impl {
|
|||
this->SkipConditionalBlock(true);
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_BeginExtendedKeypressConditionalBlock:
|
||||
/* Check for keypress. */
|
||||
if (!cur_opcode.begin_ext_keypress_cond.auto_repeat) {
|
||||
if ((cur_opcode.begin_ext_keypress_cond.key_mask & kHeld) != (cur_opcode.begin_ext_keypress_cond.key_mask) || (cur_opcode.begin_ext_keypress_cond.key_mask & s_keyold) == (cur_opcode.begin_ext_keypress_cond.key_mask)) {
|
||||
/* Keys not pressed. Skip conditional block. */
|
||||
this->SkipConditionalBlock(true);
|
||||
}
|
||||
} else if ((cur_opcode.begin_ext_keypress_cond.key_mask & kHeld) != cur_opcode.begin_ext_keypress_cond.key_mask) {
|
||||
/* Keys not pressed. Skip conditional block. */
|
||||
this->SkipConditionalBlock(true);
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_PerformArithmeticRegister:
|
||||
{
|
||||
const u64 operand_1_value = m_registers[cur_opcode.perform_math_reg.src_reg_1_index];
|
||||
|
@ -1022,6 +1060,34 @@ namespace ams::dmnt::cheat::impl {
|
|||
case RegisterArithmeticType_None:
|
||||
res_val = operand_1_value;
|
||||
break;
|
||||
case RegisterArithmeticType_FloatAddition:
|
||||
if (cur_opcode.perform_math_reg.bit_width == 4) {
|
||||
res_val = std::bit_cast<std::uint32_t>(std::bit_cast<float>(static_cast<uint32_t>(operand_1_value)) + std::bit_cast<float>(static_cast<uint32_t>(operand_2_value)));
|
||||
} else if (cur_opcode.perform_math_reg.bit_width == 8) {
|
||||
res_val = std::bit_cast<std::uint64_t>(std::bit_cast<double>(operand_1_value) + std::bit_cast<double>(operand_2_value));
|
||||
}
|
||||
break;
|
||||
case RegisterArithmeticType_FloatSubtraction:
|
||||
if (cur_opcode.perform_math_reg.bit_width == 4) {
|
||||
res_val = std::bit_cast<std::uint32_t>(std::bit_cast<float>(static_cast<uint32_t>(operand_1_value)) - std::bit_cast<float>(static_cast<uint32_t>(operand_2_value)));
|
||||
} else if (cur_opcode.perform_math_reg.bit_width == 8) {
|
||||
res_val = std::bit_cast<std::uint64_t>(std::bit_cast<double>(operand_1_value) - std::bit_cast<double>(operand_2_value));
|
||||
}
|
||||
break;
|
||||
case RegisterArithmeticType_FloatMultiplication:
|
||||
if (cur_opcode.perform_math_reg.bit_width == 4) {
|
||||
res_val = std::bit_cast<std::uint32_t>(std::bit_cast<float>(static_cast<uint32_t>(operand_1_value)) * std::bit_cast<float>(static_cast<uint32_t>(operand_2_value)));
|
||||
} else if (cur_opcode.perform_math_reg.bit_width == 8) {
|
||||
res_val = std::bit_cast<std::uint64_t>(std::bit_cast<double>(operand_1_value) * std::bit_cast<double>(operand_2_value));
|
||||
}
|
||||
break;
|
||||
case RegisterArithmeticType_FloatDivision:
|
||||
if (cur_opcode.perform_math_reg.bit_width == 4) {
|
||||
res_val = std::bit_cast<std::uint32_t>(std::bit_cast<float>(static_cast<uint32_t>(operand_1_value)) / std::bit_cast<float>(static_cast<uint32_t>(operand_2_value)));
|
||||
} else if (cur_opcode.perform_math_reg.bit_width == 8) {
|
||||
res_val = std::bit_cast<std::uint64_t>(std::bit_cast<double>(operand_1_value) / std::bit_cast<double>(operand_2_value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1304,6 +1370,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
break;
|
||||
}
|
||||
}
|
||||
s_keyold = kHeld;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
CheatVmOpcodeType_SaveRestoreRegister = 0xC1,
|
||||
CheatVmOpcodeType_SaveRestoreRegisterMask = 0xC2,
|
||||
CheatVmOpcodeType_ReadWriteStaticRegister = 0xC3,
|
||||
CheatVmOpcodeType_BeginExtendedKeypressConditionalBlock = 0xC4,
|
||||
|
||||
/* This is a meta entry, and not a real opcode. */
|
||||
/* This is to facilitate multi-nybble instruction decoding. */
|
||||
|
@ -59,6 +60,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
MemoryAccessType_Heap = 1,
|
||||
MemoryAccessType_Alias = 2,
|
||||
MemoryAccessType_Aslr = 3,
|
||||
MemoryAccessType_NonRelative = 4,
|
||||
};
|
||||
|
||||
enum ConditionalComparisonType : u32 {
|
||||
|
@ -84,6 +86,10 @@ namespace ams::dmnt::cheat::impl {
|
|||
RegisterArithmeticType_LogicalXor = 8,
|
||||
|
||||
RegisterArithmeticType_None = 9,
|
||||
RegisterArithmeticType_FloatAddition = 10,
|
||||
RegisterArithmeticType_FloatSubtraction = 11,
|
||||
RegisterArithmeticType_FloatMultiplication = 12,
|
||||
RegisterArithmeticType_FloatDivision = 13,
|
||||
};
|
||||
|
||||
enum StoreRegisterOffsetType : u32 {
|
||||
|
@ -138,6 +144,8 @@ namespace ams::dmnt::cheat::impl {
|
|||
u32 bit_width;
|
||||
MemoryAccessType mem_type;
|
||||
ConditionalComparisonType cond_type;
|
||||
bool include_ofs_reg;
|
||||
u32 ofs_reg_index;
|
||||
u64 rel_address;
|
||||
VmInt value;
|
||||
};
|
||||
|
@ -161,7 +169,8 @@ namespace ams::dmnt::cheat::impl {
|
|||
u32 bit_width;
|
||||
MemoryAccessType mem_type;
|
||||
u32 reg_index;
|
||||
bool load_from_reg;
|
||||
u8 load_from_reg;
|
||||
u8 offset_register;
|
||||
u64 rel_address;
|
||||
};
|
||||
|
||||
|
@ -185,6 +194,11 @@ namespace ams::dmnt::cheat::impl {
|
|||
u32 key_mask;
|
||||
};
|
||||
|
||||
struct BeginExtendedKeypressConditionalOpcode {
|
||||
u64 key_mask;
|
||||
bool auto_repeat;
|
||||
};
|
||||
|
||||
struct PerformArithmeticRegisterOpcode {
|
||||
u32 bit_width;
|
||||
RegisterArithmeticType math_type;
|
||||
|
@ -259,6 +273,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
StoreStaticToAddressOpcode str_static;
|
||||
PerformArithmeticStaticOpcode perform_math_static;
|
||||
BeginKeypressConditionalOpcode begin_keypress_cond;
|
||||
BeginExtendedKeypressConditionalOpcode begin_ext_keypress_cond;
|
||||
PerformArithmeticRegisterOpcode perform_math_reg;
|
||||
StoreRegisterToAddressOpcode str_register;
|
||||
BeginRegisterConditionalOpcode begin_reg_cond;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue