aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.HLE/HOS/Tamper/CodeEmitters/SaveOrRestoreRegister.cs
blob: 59cbdb0037cb6def94d3b9d0dfbd5e99472c19f1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Tamper.Operations;

namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters
{
    /// <summary>
    /// Code type 0xC1 performs saving or restoring of registers.
    /// NOTE: Registers are saved and restored to a different set of registers than the ones used
    /// for the other opcodes (Save Registers).
    /// </summary>
    class SaveOrRestoreRegister
    {
        private const int DestinationRegisterIndex = 3;
        private const int SourceRegisterIndex = 5;
        private const int OperationTypeIndex = 6;

        private const int RestoreRegister = 0;
        private const int SaveRegister = 1;
        private const int ClearSavedValue = 2;
        private const int ClearRegister = 3;

        public static void Emit(byte[] instruction, CompilationContext context)
        {
            // C10D0Sx0
            // D: Destination index.
            // S: Source index.
            // x: Operand Type, see below.

            byte destinationRegIndex = instruction[DestinationRegisterIndex];
            byte sourceRegIndex = instruction[SourceRegisterIndex];
            byte operationType = instruction[OperationTypeIndex];
            Impl(operationType, destinationRegIndex, sourceRegIndex, context);
        }

        public static void Impl(byte operationType, byte destinationRegIndex, byte sourceRegIndex, CompilationContext context)
        {
            IOperand destinationOperand;
            IOperand sourceOperand;

            switch (operationType)
            {
                case RestoreRegister:
                    destinationOperand = context.GetRegister(destinationRegIndex);
                    sourceOperand = context.GetSavedRegister(sourceRegIndex);
                    break;
                case SaveRegister:
                    destinationOperand = context.GetSavedRegister(destinationRegIndex);
                    sourceOperand = context.GetRegister(sourceRegIndex);
                    break;
                case ClearSavedValue:
                    destinationOperand = new Value<ulong>(0);
                    sourceOperand = context.GetSavedRegister(sourceRegIndex);
                    break;
                case ClearRegister:
                    destinationOperand = new Value<ulong>(0);
                    sourceOperand = context.GetRegister(sourceRegIndex);
                    break;
                default:
                    throw new TamperCompilationException($"Invalid register operation type {operationType} in Atmosphere cheat");
            }

            context.CurrentOperations.Add(new OpMov<ulong>(destinationOperand, sourceOperand));
        }
    }
}