public static void Emit(byte[] instruction, CompilationContext context)
        {
            // 6T0RIor0 VVVVVVVV VVVVVVVV
            // T: Width of memory write(1, 2, 4, or 8 bytes).
            // R: Register used as base memory address.
            // I: Increment register flag(0 = do not increment R, 1 = increment R by T).
            // o: Offset register enable flag(0 = do not add r to address, 1 = add r to address).
            // r: Register used as offset when o is 1.
            // V: Value to write to memory.

            byte          operationWidth           = instruction[OperationWidthIndex];
            Register      sourceRegister           = context.GetRegister(instruction[AddressRegisterIndex]);
            byte          incrementAddressRegister = instruction[IncrementAddressRegisterIndex];
            byte          useOffsetRegister        = instruction[UseOffsetRegisterIndex];
            ulong         immediate  = InstructionHelper.GetImmediate(instruction, ValueImmediateIndex, ValueImmediateSize);
            Value <ulong> storeValue = new Value <ulong>(immediate);

            Pointer destinationMemory;

            switch (useOffsetRegister)
            {
            case 0:
                // Don't offset the address register by another register.
                destinationMemory = MemoryHelper.EmitPointer(sourceRegister, context);
                break;

            case 1:
                // Replace the source address by the sum of the base and offset registers.
                Register offsetRegister = context.GetRegister(instruction[OffsetRegisterIndex]);
                destinationMemory = MemoryHelper.EmitPointer(sourceRegister, offsetRegister, context);
                break;

            default:
                throw new TamperCompilationException($"Invalid offset mode {useOffsetRegister} in Atmosphere cheat");
            }

            InstructionHelper.EmitMov(operationWidth, context, destinationMemory, storeValue);

            switch (incrementAddressRegister)
            {
            case 0:
                // Don't increment the address register by operationWidth.
                break;

            case 1:
                // Increment the address register by operationWidth.
                IOperand increment = new Value <ulong>(operationWidth);
                context.CurrentOperations.Add(new OpAdd <ulong>(sourceRegister, sourceRegister, increment));
                break;

            default:
                throw new TamperCompilationException($"Invalid increment mode {incrementAddressRegister} in Atmosphere cheat");
            }
        }
        public static void Emit(byte[] instruction, CompilationContext context)
        {
            // 5TMR00AA AAAAAAAA
            // T: Width of memory read (1, 2, 4, or 8 bytes).
            // M: Memory region to write to (0 = Main NSO, 1 = Heap).
            // R: Register to load value into.
            // A: Immediate offset to use from memory region base.

            // 5TMR10AA AAAAAAAA
            // T: Width of memory read(1, 2, 4, or 8 bytes).
            // M: Ignored.
            // R: Register to use as base address and to load value into.
            // A: Immediate offset to use from register R.

            byte         operationWidth              = instruction[OperationWidthIndex];
            MemoryRegion memoryRegion                = (MemoryRegion)instruction[MemoryRegionIndex];
            Register     destinationRegister         = context.GetRegister(instruction[DestinationRegisterIndex]);
            byte         useDestinationAsSourceIndex = instruction[UseDestinationAsSourceIndex];
            ulong        address = InstructionHelper.GetImmediate(instruction, OffsetImmediateIndex, OffsetImmediateSize);

            Pointer sourceMemory;

            switch (useDestinationAsSourceIndex)
            {
            case 0:
                // Don't use the source register as an additional address offset.
                sourceMemory = MemoryHelper.EmitPointer(memoryRegion, address, context);
                break;

            case 1:
                // Use the source register as the base address.
                sourceMemory = MemoryHelper.EmitPointer(destinationRegister, address, context);
                break;

            default:
                throw new TamperCompilationException($"Invalid source mode {useDestinationAsSourceIndex} in Atmosphere cheat");
            }

            InstructionHelper.EmitMov(operationWidth, context, destinationRegister, sourceMemory);
        }
Beispiel #3
0
        public static void Emit(byte[] instruction, CompilationContext context)
        {
            // 0TMR00AA AAAAAAAA VVVVVVVV (VVVVVVVV)
            // T: Width of memory write(1, 2, 4, or 8 bytes).
            // M: Memory region to write to(0 = Main NSO, 1 = Heap).
            // R: Register to use as an offset from memory region base.
            // A: Immediate offset to use from memory region base.
            // V: Value to write.

            byte         operationWidth  = instruction[OperationWidthIndex];
            MemoryRegion memoryRegion    = (MemoryRegion)instruction[MemoryRegionIndex];
            Register     offsetRegister  = context.GetRegister(instruction[OffsetRegisterIndex]);
            ulong        offsetImmediate = InstructionHelper.GetImmediate(instruction, OffsetImmediateIndex, OffsetImmediateSize);

            Pointer dstMem = MemoryHelper.EmitPointer(memoryRegion, offsetRegister, offsetImmediate, context);

            int           valueImmediateSize = operationWidth <= 4 ? ValueImmediateSize8 : ValueImmediateSize16;
            ulong         valueImmediate     = InstructionHelper.GetImmediate(instruction, ValueImmediateIndex, valueImmediateSize);
            Value <ulong> storeValue         = new Value <ulong>(valueImmediate);

            InstructionHelper.EmitMov(operationWidth, context, dstMem, storeValue);
        }
        public static void Emit(byte[] instruction, CompilationContext context)
        {
            // ATSRIOxa (aaaaaaaa)
            // T: Width of memory write (1, 2, 4, or 8 bytes).
            // S: Register to write to memory.
            // R: Register to use as base address.
            // I: Increment register flag (0 = do not increment R, 1 = increment R by T).
            // O: Offset type, see below.
            // x: Register used as offset when O is 1, Memory type when O is 3, 4 or 5.
            // a: Value used as offset when O is 2, 4 or 5.

            byte     operationWidth           = instruction[OperationWidthIndex];
            Register sourceRegister           = context.GetRegister(instruction[SourceRegisterIndex]);
            Register addressRegister          = context.GetRegister(instruction[AddressRegisterIndex]);
            byte     incrementAddressRegister = instruction[IncrementAddressRegisterIndex];
            byte     offsetType             = instruction[AddressingTypeIndex];
            byte     registerOrMemoryRegion = instruction[RegisterOrMemoryRegionIndex];
            int      immediateSize          = instruction.Length <= 8 ? OffsetImmediateSize1 : OffsetImmediateSize9;
            ulong    immediate = InstructionHelper.GetImmediate(instruction, OffsetImmediateIndex, immediateSize);

            Pointer destinationMemory;

            switch (offsetType)
            {
            case AddressRegister:
                // *($R) = $S
                destinationMemory = MemoryHelper.EmitPointer(addressRegister, context);
                break;

            case AddressRegisterWithOffsetRegister:
                // *($R + $x) = $S
                Register offsetRegister = context.GetRegister(registerOrMemoryRegion);
                destinationMemory = MemoryHelper.EmitPointer(addressRegister, offsetRegister, context);
                break;

            case OffsetImmediate:
                // *(#a) = $S
                destinationMemory = MemoryHelper.EmitPointer(addressRegister, immediate, context);
                break;

            case MemoryRegionWithOffsetRegister:
                // *(?x + $R) = $S
                destinationMemory = MemoryHelper.EmitPointer((MemoryRegion)registerOrMemoryRegion, addressRegister, context);
                break;

            case MemoryRegionWithOffsetImmediate:
                // *(?x + #a) = $S
                destinationMemory = MemoryHelper.EmitPointer((MemoryRegion)registerOrMemoryRegion, immediate, context);
                break;

            case MemoryRegionWithOffsetRegisterAndImmediate:
                // *(?x + #a + $R) = $S
                destinationMemory = MemoryHelper.EmitPointer((MemoryRegion)registerOrMemoryRegion, addressRegister, immediate, context);
                break;

            default:
                throw new TamperCompilationException($"Invalid offset type {offsetType} in Atmosphere cheat");
            }

            InstructionHelper.EmitMov(operationWidth, context, destinationMemory, sourceRegister);

            switch (incrementAddressRegister)
            {
            case 0:
                // Don't increment the address register by operationWidth.
                break;

            case 1:
                // Increment the address register by operationWidth.
                IOperand increment = new Value <ulong>(operationWidth);
                context.CurrentOperations.Add(new OpAdd <ulong>(addressRegister, addressRegister, increment));
                break;

            default:
                throw new TamperCompilationException($"Invalid increment mode {incrementAddressRegister} in Atmosphere cheat");
            }
        }