mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
dmnt: add theoretical 'else' support to cheat engine vm conditionals
This commit is contained in:
parent
389c3b6baa
commit
4cb4707f34
3 changed files with 32 additions and 18 deletions
|
@ -59,7 +59,7 @@ Code type 0x0 allows writing a static value to a memory address.
|
||||||
### Code Type 0x1: Begin Conditional Block
|
### Code Type 0x1: Begin Conditional Block
|
||||||
Code type 0x1 performs a comparison of the contents of memory to a static value.
|
Code type 0x1 performs a comparison of the contents of memory to a static value.
|
||||||
|
|
||||||
If the condition is not met, all instructions until the appropriate conditional block terminator are skipped.
|
If the condition is not met, all instructions until the appropriate End or Else conditional block terminator are skipped.
|
||||||
|
|
||||||
#### Encoding
|
#### Encoding
|
||||||
`1TMC00AA AAAAAAAA VVVVVVVV (VVVVVVVV)`
|
`1TMC00AA AAAAAAAA VVVVVVVV (VVVVVVVV)`
|
||||||
|
@ -83,8 +83,12 @@ If the condition is not met, all instructions until the appropriate conditional
|
||||||
### Code Type 0x2: End Conditional Block
|
### Code Type 0x2: End Conditional Block
|
||||||
Code type 0x2 marks the end of a conditional block (started by Code Type 0x1 or Code Type 0x8).
|
Code type 0x2 marks the end of a conditional block (started by Code Type 0x1 or Code Type 0x8).
|
||||||
|
|
||||||
|
When an Else is executed, all instructions until the appropriate End conditional block terminator are skipped.
|
||||||
|
|
||||||
#### Encoding
|
#### Encoding
|
||||||
`20000000`
|
`2X000000`
|
||||||
|
|
||||||
|
+ X: End type (0 = End, 1 = Else).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -387,8 +387,8 @@ namespace ams::dmnt::cheat::impl {
|
||||||
break;
|
break;
|
||||||
case CheatVmOpcodeType_EndConditionalBlock:
|
case CheatVmOpcodeType_EndConditionalBlock:
|
||||||
{
|
{
|
||||||
/* 20000000 */
|
/* 2X000000 */
|
||||||
/* There's actually nothing left to process here! */
|
opcode.end_cond.is_else = ((first_dword >> 28) & 0xF) == 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CheatVmOpcodeType_ControlLoop:
|
case CheatVmOpcodeType_ControlLoop:
|
||||||
|
@ -668,7 +668,7 @@ namespace ams::dmnt::cheat::impl {
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatVirtualMachine::SkipConditionalBlock() {
|
void CheatVirtualMachine::SkipConditionalBlock(bool is_if) {
|
||||||
if (this->condition_depth > 0) {
|
if (this->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 size_t desired_depth = this->condition_depth - 1;
|
const size_t desired_depth = this->condition_depth - 1;
|
||||||
|
@ -685,15 +685,18 @@ namespace ams::dmnt::cheat::impl {
|
||||||
if (skip_opcode.begin_conditional_block) {
|
if (skip_opcode.begin_conditional_block) {
|
||||||
this->condition_depth++;
|
this->condition_depth++;
|
||||||
} else if (skip_opcode.opcode == CheatVmOpcodeType_EndConditionalBlock) {
|
} else if (skip_opcode.opcode == CheatVmOpcodeType_EndConditionalBlock) {
|
||||||
this->condition_depth--;
|
if (!skip_opcode.end_cond.is_else) {
|
||||||
|
this->condition_depth--;
|
||||||
|
} else if (is_if && this->condition_depth - 1 == desired_depth) {
|
||||||
|
/* An if will continue to an else at the same depth. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Skipping, but this->condition_depth = 0. */
|
/* Skipping, but this->condition_depth = 0. */
|
||||||
/* This is an error condition. */
|
/* This is an error condition. */
|
||||||
/* However, I don't actually believe it is possible for this to happen. */
|
/* This could occur with a mismatched "else" opcode, for example. */
|
||||||
/* I guess we'll throw a fatal error here, so as to encourage me to fix the VM */
|
|
||||||
/* in the event that someone triggers it? I don't know how you'd do that. */
|
|
||||||
R_ABORT_UNLESS(ResultVirtualMachineInvalidConditionDepth());
|
R_ABORT_UNLESS(ResultVirtualMachineInvalidConditionDepth());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -850,15 +853,20 @@ namespace ams::dmnt::cheat::impl {
|
||||||
}
|
}
|
||||||
/* Skip conditional block if condition not met. */
|
/* Skip conditional block if condition not met. */
|
||||||
if (!cond_met) {
|
if (!cond_met) {
|
||||||
this->SkipConditionalBlock();
|
this->SkipConditionalBlock(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CheatVmOpcodeType_EndConditionalBlock:
|
case CheatVmOpcodeType_EndConditionalBlock:
|
||||||
/* Decrement the condition depth. */
|
if (cur_opcode.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 (this->condition_depth > 0) {
|
this->SkipConditionalBlock(false);
|
||||||
this->condition_depth--;
|
} else {
|
||||||
|
/* Decrement the condition depth. */
|
||||||
|
/* We will assume, graciously, that mismatched conditional block ends are a nop. */
|
||||||
|
if (this->condition_depth > 0) {
|
||||||
|
this->condition_depth--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CheatVmOpcodeType_ControlLoop:
|
case CheatVmOpcodeType_ControlLoop:
|
||||||
|
@ -965,7 +973,7 @@ namespace ams::dmnt::cheat::impl {
|
||||||
/* Check for keypress. */
|
/* Check for keypress. */
|
||||||
if ((cur_opcode.begin_keypress_cond.key_mask & kHeld) != cur_opcode.begin_keypress_cond.key_mask) {
|
if ((cur_opcode.begin_keypress_cond.key_mask & kHeld) != cur_opcode.begin_keypress_cond.key_mask) {
|
||||||
/* Keys not pressed. Skip conditional block. */
|
/* Keys not pressed. Skip conditional block. */
|
||||||
this->SkipConditionalBlock();
|
this->SkipConditionalBlock(true);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CheatVmOpcodeType_PerformArithmeticRegister:
|
case CheatVmOpcodeType_PerformArithmeticRegister:
|
||||||
|
@ -1164,7 +1172,7 @@ namespace ams::dmnt::cheat::impl {
|
||||||
|
|
||||||
/* Skip conditional block if condition not met. */
|
/* Skip conditional block if condition not met. */
|
||||||
if (!cond_met) {
|
if (!cond_met) {
|
||||||
this->SkipConditionalBlock();
|
this->SkipConditionalBlock(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -142,7 +142,9 @@ namespace ams::dmnt::cheat::impl {
|
||||||
VmInt value;
|
VmInt value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EndConditionalOpcode {};
|
struct EndConditionalOpcode {
|
||||||
|
bool is_else;
|
||||||
|
};
|
||||||
|
|
||||||
struct ControlLoopOpcode {
|
struct ControlLoopOpcode {
|
||||||
bool start_loop;
|
bool start_loop;
|
||||||
|
@ -286,7 +288,7 @@ namespace ams::dmnt::cheat::impl {
|
||||||
size_t loop_tops[NumRegisters] = {0};
|
size_t loop_tops[NumRegisters] = {0};
|
||||||
private:
|
private:
|
||||||
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