dmnt: add theoretical 'else' support to cheat engine vm conditionals

This commit is contained in:
Michael Scire 2021-07-21 19:36:46 -07:00
parent 389c3b6baa
commit 4cb4707f34
3 changed files with 32 additions and 18 deletions

View file

@ -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 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
`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 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
`20000000`
`2X000000`
+ X: End type (0 = End, 1 = Else).
---

View file

@ -387,8 +387,8 @@ namespace ams::dmnt::cheat::impl {
break;
case CheatVmOpcodeType_EndConditionalBlock:
{
/* 20000000 */
/* There's actually nothing left to process here! */
/* 2X000000 */
opcode.end_cond.is_else = ((first_dword >> 28) & 0xF) == 1;
}
break;
case CheatVmOpcodeType_ControlLoop:
@ -668,7 +668,7 @@ namespace ams::dmnt::cheat::impl {
return valid;
}
void CheatVirtualMachine::SkipConditionalBlock() {
void CheatVirtualMachine::SkipConditionalBlock(bool is_if) {
if (this->condition_depth > 0) {
/* We want to continue until we're out of the current block. */
const size_t desired_depth = this->condition_depth - 1;
@ -685,15 +685,18 @@ namespace ams::dmnt::cheat::impl {
if (skip_opcode.begin_conditional_block) {
this->condition_depth++;
} 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 {
/* Skipping, but this->condition_depth = 0. */
/* This is an error condition. */
/* However, I don't actually believe it is possible for this to happen. */
/* 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. */
/* This could occur with a mismatched "else" opcode, for example. */
R_ABORT_UNLESS(ResultVirtualMachineInvalidConditionDepth());
}
}
@ -850,15 +853,20 @@ namespace ams::dmnt::cheat::impl {
}
/* Skip conditional block if condition not met. */
if (!cond_met) {
this->SkipConditionalBlock();
this->SkipConditionalBlock(true);
}
}
break;
case CheatVmOpcodeType_EndConditionalBlock:
/* Decrement the condition depth. */
/* We will assume, graciously, that mismatched conditional block ends are a nop. */
if (this->condition_depth > 0) {
this->condition_depth--;
if (cur_opcode.end_cond.is_else) {
/* Skip to the end of the conditional block. */
this->SkipConditionalBlock(false);
} 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;
case CheatVmOpcodeType_ControlLoop:
@ -965,7 +973,7 @@ namespace ams::dmnt::cheat::impl {
/* Check for keypress. */
if ((cur_opcode.begin_keypress_cond.key_mask & kHeld) != cur_opcode.begin_keypress_cond.key_mask) {
/* Keys not pressed. Skip conditional block. */
this->SkipConditionalBlock();
this->SkipConditionalBlock(true);
}
break;
case CheatVmOpcodeType_PerformArithmeticRegister:
@ -1164,7 +1172,7 @@ namespace ams::dmnt::cheat::impl {
/* Skip conditional block if condition not met. */
if (!cond_met) {
this->SkipConditionalBlock();
this->SkipConditionalBlock(true);
}
}
break;

View file

@ -142,7 +142,9 @@ namespace ams::dmnt::cheat::impl {
VmInt value;
};
struct EndConditionalOpcode {};
struct EndConditionalOpcode {
bool is_else;
};
struct ControlLoopOpcode {
bool start_loop;
@ -286,7 +288,7 @@ namespace ams::dmnt::cheat::impl {
size_t loop_tops[NumRegisters] = {0};
private:
bool DecodeNextOpcode(CheatVmOpcode *out);
void SkipConditionalBlock();
void SkipConditionalBlock(bool is_if);
void ResetState();
/* For implementing the DebugLog opcode. */