public static void Emit(byte[] instruction, CompilationContext context) { // 300R0000 VVVVVVVV // R: Register to use as loop counter. // V: Number of iterations to loop. // 310R0000 byte mode = instruction[StartOrEndIndex]; byte iterationRegisterIndex = instruction[IterationRegisterIndex]; switch (mode) { case LoopBegin: // Just start a new compilation block and parse the instruction itself at the end. context.BlockStack.Push(new OperationBlock(instruction)); return; case LoopEnd: break; default: throw new TamperCompilationException($"Invalid loop {mode} in Atmosphere cheat"); } // Use the loop begin instruction stored in the stack. instruction = context.CurrentBlock.BaseInstruction; CodeType codeType = InstructionHelper.GetCodeType(instruction); if (codeType != CodeType.StartEndLoop) { throw new TamperCompilationException($"Loop end does not match code type {codeType} in Atmosphere cheat"); } // Validate if the register in the beginning and end are the same. byte oldIterationRegisterIndex = instruction[IterationRegisterIndex]; if (iterationRegisterIndex != oldIterationRegisterIndex) { throw new TamperCompilationException($"The register used for the loop changed from {oldIterationRegisterIndex} to {iterationRegisterIndex} in Atmosphere cheat"); } Register iterationRegister = context.GetRegister(iterationRegisterIndex); ulong immediate = InstructionHelper.GetImmediate(instruction, IterationsImmediateIndex, IterationsImmediateSize); // Create a loop block with the current operations and nest it in the upper // block of the stack. ForBlock block = new ForBlock(immediate, iterationRegister, context.CurrentOperations); context.BlockStack.Pop(); context.CurrentOperations.Add(block); }
public static void Emit(byte[] instruction, CompilationContext context) { // 20000000 // Use the conditional begin instruction stored in the stack. instruction = context.CurrentBlock.BaseInstruction; CodeType codeType = InstructionHelper.GetCodeType(instruction); // Pop the current block of operations from the stack so control instructions // for the conditional can be emitted in the upper block. IEnumerable <IOperation> operations = context.CurrentOperations; context.BlockStack.Pop(); ICondition condition; switch (codeType) { case CodeType.BeginMemoryConditionalBlock: condition = MemoryConditional.Emit(instruction, context); break; case CodeType.BeginKeypressConditionalBlock: condition = KeyPressConditional.Emit(instruction, context); break; case CodeType.BeginRegisterConditionalBlock: condition = RegisterConditional.Emit(instruction, context); break; default: throw new TamperCompilationException($"Conditional end does not match code type {codeType} in Atmosphere cheat"); } // Create a conditional block with the current operations and nest it in the upper // block of the stack. IfBlock block = new IfBlock(condition, operations); context.CurrentOperations.Add(block); }
private static void Emit(byte[] instruction, CompilationContext context, IEnumerable <IOperation> operationsElse) { // 2X000000 // X: End type (0 = End, 1 = Else). byte terminationType = instruction[TerminationTypeIndex]; switch (terminationType) { case End: break; case Else: // Start a new operation block with the 'else' instruction to signal that there is the 'then' block just above it. context.BlockStack.Push(new OperationBlock(instruction)); return; default: throw new TamperCompilationException($"Unknown conditional termination type {terminationType}"); } // Use the conditional begin instruction stored in the stack. var upperInstruction = context.CurrentBlock.BaseInstruction; CodeType codeType = InstructionHelper.GetCodeType(upperInstruction); // Pop the current block of operations from the stack so control instructions // for the conditional can be emitted in the upper block. IEnumerable <IOperation> operations = context.CurrentOperations; context.BlockStack.Pop(); // If the else operations are already set, then the upper block must not be another end. if (operationsElse != null && codeType == CodeType.EndConditionalBlock) { throw new TamperCompilationException($"Expected an upper 'if' conditional instead of 'end conditional'"); } ICondition condition; switch (codeType) { case CodeType.BeginMemoryConditionalBlock: condition = MemoryConditional.Emit(upperInstruction, context); break; case CodeType.BeginKeypressConditionalBlock: condition = KeyPressConditional.Emit(upperInstruction, context); break; case CodeType.BeginRegisterConditionalBlock: condition = RegisterConditional.Emit(upperInstruction, context); break; case CodeType.EndConditionalBlock: terminationType = upperInstruction[TerminationTypeIndex]; // If there is an end instruction above then it must be an else. if (terminationType != Else) { throw new TamperCompilationException($"Expected an upper 'else' conditional instead of {terminationType}"); } // Re-run the Emit with the else operations set. Emit(instruction, context, operations); return; default: throw new TamperCompilationException($"Conditional end does not match code type {codeType} in Atmosphere cheat"); } // Create a conditional block with the current operations and nest it in the upper // block of the stack. IfBlock block = new IfBlock(condition, operations, operationsElse); context.CurrentOperations.Add(block); }