mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
dmnt-cheat: Add register conditional vm instruction
This commit is contained in:
parent
e5ecd243f2
commit
5d79952bdd
2 changed files with 184 additions and 1 deletions
|
@ -144,6 +144,37 @@ void DmntCheatVm::LogOpcode(const CheatVmOpcode *opcode) {
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_BeginRegisterConditionalBlock:
|
||||
this->LogToDebugFile("Opcode: Begin Register Conditional\n");
|
||||
this->LogToDebugFile("Bit Width: %x\n", opcode->begin_reg_cond.bit_width);
|
||||
this->LogToDebugFile("V Reg Idx: %x\n", opcode->begin_reg_cond.val_reg_index);
|
||||
switch (opcode->begin_reg_cond.comp_type) {
|
||||
case CompareRegisterValueType_StaticValue:
|
||||
this->LogToDebugFile("Comp Type: Static Value\n");
|
||||
this->LogToDebugFile("Value: %lx\n", opcode->begin_reg_cond.value.bit64);
|
||||
break;
|
||||
case CompareRegisterValueType_MemoryRelAddr:
|
||||
this->LogToDebugFile("Comp Type: Memory Relative Address\n");
|
||||
this->LogToDebugFile("Mem Type: %x\n", opcode->begin_reg_cond.mem_type);
|
||||
this->LogToDebugFile("Rel Addr: %lx\n", opcode->begin_reg_cond.rel_address);
|
||||
break;
|
||||
case CompareRegisterValueType_MemoryOfsReg:
|
||||
this->LogToDebugFile("Comp Type: Memory Offset Register\n");
|
||||
this->LogToDebugFile("Mem Type: %x\n", opcode->begin_reg_cond.mem_type);
|
||||
this->LogToDebugFile("O Reg Idx: %x\n", opcode->begin_reg_cond.ofs_reg_index);
|
||||
break;
|
||||
case CompareRegisterValueType_RegisterRelAddr:
|
||||
this->LogToDebugFile("Comp Type: Register Relative Address\n");
|
||||
this->LogToDebugFile("A Reg Idx: %x\n", opcode->begin_reg_cond.addr_reg_index);
|
||||
this->LogToDebugFile("Rel Addr: %lx\n", opcode->begin_reg_cond.rel_address);
|
||||
break;
|
||||
case CompareRegisterValueType_RegisterOfsReg:
|
||||
this->LogToDebugFile("Comp Type: Register Offset Register\n");
|
||||
this->LogToDebugFile("A Reg Idx: %x\n", opcode->begin_reg_cond.addr_reg_index);
|
||||
this->LogToDebugFile("O Reg Idx: %x\n", opcode->begin_reg_cond.ofs_reg_index);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
this->LogToDebugFile("Unknown opcode: %x\n", opcode->opcode);
|
||||
break;
|
||||
|
@ -208,6 +239,7 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode *out) {
|
|||
switch (opcode.opcode) {
|
||||
case CheatVmOpcodeType_BeginConditionalBlock:
|
||||
case CheatVmOpcodeType_BeginKeypressConditionalBlock:
|
||||
case CheatVmOpcodeType_BeginRegisterConditionalBlock:
|
||||
opcode.begin_conditional_block = true;
|
||||
break;
|
||||
default:
|
||||
|
@ -356,6 +388,52 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode *out) {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_BeginRegisterConditionalBlock:
|
||||
{
|
||||
/* C0TcSX## */
|
||||
/* C0TcS0Ma aaaaaaaa */
|
||||
/* C0TcS1Mr */
|
||||
/* C0TcS2Ra aaaaaaaa */
|
||||
/* C0TcS3Rr */
|
||||
/* C0TcS400 VVVVVVVV (VVVVVVVV) */
|
||||
/* C0 = opcode 0xC0 */
|
||||
/* T = bit width */
|
||||
/* c = condition type. */
|
||||
/* S = source register. */
|
||||
/* X = value operand type, 0 = main/heap with relative offset, 1 = main/heap with offset register, */
|
||||
/* 1 = register with relative offset, 2 = register with offset register, 3 = static value. */
|
||||
/* M = memory type. */
|
||||
/* a = relative address. */
|
||||
/* r = offset register. */
|
||||
/* V = value */
|
||||
opcode.begin_reg_cond.bit_width = (first_dword >> 20) & 0xF;
|
||||
opcode.begin_reg_cond.cond_type = (ConditionalComparisonType)((first_dword >> 16) & 0xF);
|
||||
opcode.begin_reg_cond.val_reg_index = ((first_dword >> 12) & 0xF);
|
||||
opcode.begin_reg_cond.comp_type = (CompareRegisterValueType)((first_dword >> 8) & 0xF);
|
||||
|
||||
switch (opcode.begin_reg_cond.comp_type) {
|
||||
case CompareRegisterValueType_StaticValue:
|
||||
opcode.begin_reg_cond.value = GetNextVmInt(opcode.begin_reg_cond.bit_width);
|
||||
break;
|
||||
case CompareRegisterValueType_MemoryRelAddr:
|
||||
opcode.begin_reg_cond.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
|
||||
opcode.begin_reg_cond.rel_address = (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
|
||||
break;
|
||||
case CompareRegisterValueType_MemoryOfsReg:
|
||||
opcode.begin_reg_cond.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
|
||||
opcode.begin_reg_cond.ofs_reg_index = (first_dword & 0xF);
|
||||
break;
|
||||
case CompareRegisterValueType_RegisterRelAddr:
|
||||
opcode.begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF);
|
||||
opcode.begin_reg_cond.rel_address = (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
|
||||
break;
|
||||
case CompareRegisterValueType_RegisterOfsReg:
|
||||
opcode.begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF);
|
||||
opcode.begin_reg_cond.ofs_reg_index = (first_dword & 0xF);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_ExtendedWidth:
|
||||
default:
|
||||
/* Unrecognized instruction cannot be decoded. */
|
||||
|
@ -754,6 +832,86 @@ void DmntCheatVm::Execute(const CheatProcessMetadata *metadata) {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_BeginRegisterConditionalBlock:
|
||||
{
|
||||
/* Get value from register. */
|
||||
u64 src_value = 0;
|
||||
switch (cur_opcode.begin_reg_cond.bit_width) {
|
||||
case 1:
|
||||
src_value = static_cast<u8>(this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFul);
|
||||
break;
|
||||
case 2:
|
||||
src_value = static_cast<u16>(this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFul);
|
||||
break;
|
||||
case 4:
|
||||
src_value = static_cast<u32>(this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFFFFFul);
|
||||
break;
|
||||
case 8:
|
||||
src_value = static_cast<u64>(this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFFFFFFFFFFFFFul);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read value from memory. */
|
||||
u64 cond_value = 0;
|
||||
if (cur_opcode.begin_reg_cond.comp_type == CompareRegisterValueType_StaticValue) {
|
||||
cond_value = GetVmInt(cur_opcode.begin_reg_cond.value, cur_opcode.begin_reg_cond.bit_width);
|
||||
} else {
|
||||
u64 cond_address = 0;
|
||||
switch (cur_opcode.begin_reg_cond.comp_type) {
|
||||
case CompareRegisterValueType_MemoryRelAddr:
|
||||
cond_address = GetCheatProcessAddress(metadata, cur_opcode.begin_reg_cond.mem_type, cur_opcode.begin_reg_cond.rel_address);
|
||||
break;
|
||||
case CompareRegisterValueType_MemoryOfsReg:
|
||||
cond_address = GetCheatProcessAddress(metadata, cur_opcode.begin_reg_cond.mem_type, this->registers[cur_opcode.begin_reg_cond.ofs_reg_index]);
|
||||
break;
|
||||
case CompareRegisterValueType_RegisterRelAddr:
|
||||
cond_address = this->registers[cur_opcode.begin_reg_cond.addr_reg_index] + cur_opcode.begin_reg_cond.rel_address;
|
||||
break;
|
||||
case CompareRegisterValueType_RegisterOfsReg:
|
||||
cond_address = this->registers[cur_opcode.begin_reg_cond.addr_reg_index] + this->registers[cur_opcode.begin_reg_cond.ofs_reg_index];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (cur_opcode.begin_reg_cond.bit_width) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
DmntCheatManager::ReadCheatProcessMemoryForVm(cond_address, &cond_value, cur_opcode.begin_reg_cond.bit_width);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check against condition. */
|
||||
bool cond_met = false;
|
||||
switch (cur_opcode.begin_reg_cond.cond_type) {
|
||||
case ConditionalComparisonType_GT:
|
||||
cond_met = src_value > cond_value;
|
||||
break;
|
||||
case ConditionalComparisonType_GE:
|
||||
cond_met = src_value >= cond_value;
|
||||
break;
|
||||
case ConditionalComparisonType_LT:
|
||||
cond_met = src_value < cond_value;
|
||||
break;
|
||||
case ConditionalComparisonType_LE:
|
||||
cond_met = src_value <= cond_value;
|
||||
break;
|
||||
case ConditionalComparisonType_EQ:
|
||||
cond_met = src_value == cond_value;
|
||||
break;
|
||||
case ConditionalComparisonType_NE:
|
||||
cond_met = src_value != cond_value;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Skip conditional block if condition not met. */
|
||||
if (!cond_met) {
|
||||
this->SkipConditionalBlock();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* By default, we do a no-op. */
|
||||
break;
|
||||
|
|
|
@ -35,10 +35,14 @@ enum CheatVmOpcodeType : u32 {
|
|||
/* These are not implemented by Gateway's VM. */
|
||||
CheatVmOpcodeType_PerformArithmeticRegister = 9,
|
||||
CheatVmOpcodeType_StoreRegisterToAddress = 10,
|
||||
CheatVmOpcodeType_Reserved11 = 11,
|
||||
|
||||
/* This is a meta entry, and not a real opcode. */
|
||||
/* This is to facilitate multi-nybble instruction decoding in the future. */
|
||||
/* This is to facilitate multi-nybble instruction decoding. */
|
||||
CheatVmOpcodeType_ExtendedWidth = 12,
|
||||
|
||||
/* Extended width opcodes. */
|
||||
CheatVmOpcodeType_BeginRegisterConditionalBlock = 0xC0,
|
||||
};
|
||||
|
||||
enum MemoryAccessType : u32 {
|
||||
|
@ -77,6 +81,14 @@ enum StoreRegisterOffsetType : u32 {
|
|||
StoreRegisterOffsetType_Imm = 2,
|
||||
};
|
||||
|
||||
enum CompareRegisterValueType : u32 {
|
||||
CompareRegisterValueType_MemoryRelAddr = 0,
|
||||
CompareRegisterValueType_MemoryOfsReg = 1,
|
||||
CompareRegisterValueType_RegisterRelAddr = 2,
|
||||
CompareRegisterValueType_RegisterOfsReg = 3,
|
||||
CompareRegisterValueType_StaticValue = 4,
|
||||
};
|
||||
|
||||
union VmInt {
|
||||
u8 bit8;
|
||||
u16 bit16;
|
||||
|
@ -161,6 +173,18 @@ struct StoreRegisterToAddressOpcode {
|
|||
u64 rel_address;
|
||||
};
|
||||
|
||||
struct BeginRegisterConditionalOpcode {
|
||||
u32 bit_width;
|
||||
ConditionalComparisonType cond_type;
|
||||
u32 val_reg_index;
|
||||
CompareRegisterValueType comp_type;
|
||||
MemoryAccessType mem_type;
|
||||
u32 addr_reg_index;
|
||||
u32 ofs_reg_index;
|
||||
u64 rel_address;
|
||||
VmInt value;
|
||||
};
|
||||
|
||||
|
||||
struct CheatVmOpcode {
|
||||
CheatVmOpcodeType opcode;
|
||||
|
@ -177,6 +201,7 @@ struct CheatVmOpcode {
|
|||
BeginKeypressConditionalOpcode begin_keypress_cond;
|
||||
PerformArithmeticRegisterOpcode perform_math_reg;
|
||||
StoreRegisterToAddressOpcode str_register;
|
||||
BeginRegisterConditionalOpcode begin_reg_cond;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue