private const byte Rsh = 4; // reg >>= rhs public static void Emit(byte[] instruction, CompilationContext context) { // 7T0RC000 VVVVVVVV // T: Width of arithmetic operation(1, 2, 4, or 8 bytes). // R: Register to apply arithmetic to. // C: Arithmetic operation to apply, see below. // V: Value to use for arithmetic operation. byte operationWidth = instruction[OperationWidthIndex]; Register register = context.GetRegister(instruction[DestinationRegisterIndex]); byte operation = instruction[OperationTypeIndex]; ulong immediate = InstructionHelper.GetImmediate(instruction, ValueImmediateIndex, ValueImmediateSize); Value <ulong> rightHandSideValue = new Value <ulong>(immediate); void Emit(Type operationType) { InstructionHelper.Emit(operationType, operationWidth, context, register, register, rightHandSideValue); } switch (operation) { case Add: Emit(typeof(OpAdd <>)); break; case Sub: Emit(typeof(OpSub <>)); break; case Mul: Emit(typeof(OpMul <>)); break; case Lsh: Emit(typeof(OpLsh <>)); break; case Rsh: Emit(typeof(OpRsh <>)); break; default: throw new TamperCompilationException($"Invalid arithmetic operation {operation} in Atmosphere cheat"); } }
public static void Emit(byte[] instruction, CompilationContext context) { // FFFTIX## // FFFTI0Ma aaaaaaaa // FFFTI1Mr // FFFTI2Ra aaaaaaaa // FFFTI3Rr // FFFTI4V0 // T: Width of memory write (1, 2, 4, or 8 bytes). // I: Log id. // X: Operand Type, see below. // M: Memory Type (operand types 0 and 1). // R: Address Register (operand types 2 and 3). // a: Relative Address (operand types 0 and 2). // r: Offset Register (operand types 1 and 3). // V: Value Register (operand type 4). byte operationWidth = instruction[OperationWidthIndex]; byte logId = instruction[LogIdIndex]; byte operandType = instruction[OperandTypeIndex]; byte registerOrMemoryRegion = instruction[RegisterOrMemoryRegionIndex]; byte offsetRegisterIndex = instruction[OffsetRegisterOrImmediateIndex]; ulong immediate; Register addressRegister; Register offsetRegister; IOperand sourceOperand; switch (operandType) { case MemoryRegionWithOffsetImmediate: // *(?x + #a) immediate = InstructionHelper.GetImmediate(instruction, OffsetRegisterOrImmediateIndex, OffsetImmediateSize); sourceOperand = MemoryHelper.EmitPointer((MemoryRegion)registerOrMemoryRegion, immediate, context); break; case MemoryRegionWithOffsetRegister: // *(?x + $r) offsetRegister = context.GetRegister(offsetRegisterIndex); sourceOperand = MemoryHelper.EmitPointer((MemoryRegion)registerOrMemoryRegion, offsetRegister, context); break; case AddressRegisterWithOffsetImmediate: // *($R + #a) addressRegister = context.GetRegister(registerOrMemoryRegion); immediate = InstructionHelper.GetImmediate(instruction, OffsetRegisterOrImmediateIndex, OffsetImmediateSize); sourceOperand = MemoryHelper.EmitPointer(addressRegister, immediate, context); break; case AddressRegisterWithOffsetRegister: // *($R + $r) addressRegister = context.GetRegister(registerOrMemoryRegion); offsetRegister = context.GetRegister(offsetRegisterIndex); sourceOperand = MemoryHelper.EmitPointer(addressRegister, offsetRegister, context); break; case ValueRegister: // $V sourceOperand = context.GetRegister(registerOrMemoryRegion); break; default: throw new TamperCompilationException($"Invalid operand type {operandType} in Atmosphere cheat"); } InstructionHelper.Emit(typeof(OpLog <>), operationWidth, context, logId, sourceOperand); }
private const byte Mov = 9; // lhs (discards right-hand operand) public static void Emit(byte[] instruction, CompilationContext context) { // 9TCRS0s0 // T: Width of arithmetic operation(1, 2, 4, or 8 bytes). // C: Arithmetic operation to apply, see below. // R: Register to store result in. // S: Register to use as left - hand operand. // s: Register to use as right - hand operand. // 9TCRS100 VVVVVVVV (VVVVVVVV) // T: Width of arithmetic operation(1, 2, 4, or 8 bytes). // C: Arithmetic operation to apply, see below. // R: Register to store result in. // S: Register to use as left - hand operand. // V: Value to use as right - hand operand. byte operationWidth = instruction[OperationWidthIndex]; byte operation = instruction[OperationTypeIndex]; Register destinationRegister = context.GetRegister(instruction[DestinationRegisterIndex]); Register leftHandSideRegister = context.GetRegister(instruction[LeftHandSideRegisterIndex]); byte rightHandSideIsImmediate = instruction[UseImmediateAsRhsIndex]; IOperand rightHandSideOperand; switch (rightHandSideIsImmediate) { case 0: // Use a register as right-hand side. rightHandSideOperand = context.GetRegister(instruction[RightHandSideRegisterIndex]); break; case 1: // Use an immediate as right-hand side. int immediateSize = operationWidth <= 4 ? RightHandSideImmediate8 : RightHandSideImmediate16; ulong immediate = InstructionHelper.GetImmediate(instruction, RightHandSideImmediateIndex, immediateSize); rightHandSideOperand = new Value <ulong>(immediate); break; default: throw new TamperCompilationException($"Invalid right-hand side switch {rightHandSideIsImmediate} in Atmosphere cheat"); } void Emit(Type operationType, IOperand rhs = null) { List <IOperand> operandList = new List <IOperand>(); operandList.Add(destinationRegister); operandList.Add(leftHandSideRegister); if (rhs != null) { operandList.Add(rhs); } InstructionHelper.Emit(operationType, operationWidth, context, operandList.ToArray()); } switch (operation) { case Add: Emit(typeof(OpAdd <>), rightHandSideOperand); break; case Sub: Emit(typeof(OpSub <>), rightHandSideOperand); break; case Mul: Emit(typeof(OpMul <>), rightHandSideOperand); break; case Lsh: Emit(typeof(OpLsh <>), rightHandSideOperand); break; case Rsh: Emit(typeof(OpRsh <>), rightHandSideOperand); break; case And: Emit(typeof(OpAnd <>), rightHandSideOperand); break; case Or: Emit(typeof(OpOr <>), rightHandSideOperand); break; case Not: Emit(typeof(OpNot <>)); break; case Xor: Emit(typeof(OpXor <>), rightHandSideOperand); break; case Mov: Emit(typeof(OpMov <>)); break; default: throw new TamperCompilationException($"Invalid arithmetic operation {operation} in Atmosphere cheat"); } }