aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/Instructions/InstEmitAlu32.cs
blob: 2ebb8073850f14009a7d946390e4016e2353cd7a (plain)
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
using ChocolArm64.Decoders;
using ChocolArm64.State;
using ChocolArm64.Translation;
using System.Reflection.Emit;

using static ChocolArm64.Instructions.InstEmit32Helper;
using static ChocolArm64.Instructions.InstEmitAluHelper;

namespace ChocolArm64.Instructions
{
    static partial class InstEmit32
    {
        public static void Add(ILEmitterCtx context)
        {
            IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;

            EmitAluLoadOpers(context, setCarry: false);

            context.Emit(OpCodes.Add);

            if (op.SetFlags)
            {
                context.EmitZnFlagCheck();

                EmitAddsCCheck(context);
                EmitAddsVCheck(context);
            }

            EmitAluStore(context);
        }

        public static void Mov(ILEmitterCtx context)
        {
            IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;

            EmitAluLoadOper2(context);

            if (op.SetFlags)
            {
                context.EmitZnFlagCheck();
            }

            EmitAluStore(context);
        }

        public static void Sub(ILEmitterCtx context)
        {
            IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;

            EmitAluLoadOpers(context, setCarry: false);

            context.Emit(OpCodes.Sub);

            if (op.SetFlags)
            {
                context.EmitZnFlagCheck();

                EmitSubsCCheck(context);
                EmitSubsVCheck(context);
            }

            EmitAluStore(context);
        }

        private static void EmitAluStore(ILEmitterCtx context)
        {
            IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;

            if (op.Rd == RegisterAlias.Aarch32Pc)
            {
                if (op.SetFlags)
                {
                    //TODO: Load SPSR etc.

                    context.EmitLdflg((int)PState.TBit);

                    ILLabel lblThumb = new ILLabel();
                    ILLabel lblEnd   = new ILLabel();

                    context.Emit(OpCodes.Brtrue_S, lblThumb);

                    context.EmitLdc_I4(~3);

                    context.Emit(OpCodes.Br_S, lblEnd);

                    context.MarkLabel(lblThumb);

                    context.EmitLdc_I4(~1);

                    context.MarkLabel(lblEnd);

                    context.Emit(OpCodes.And);
                    context.Emit(OpCodes.Conv_U8);
                    context.Emit(OpCodes.Ret);
                }
                else
                {
                    EmitAluWritePc(context);
                }
            }
            else
            {
                context.EmitStint(GetRegisterAlias(context.Mode, op.Rd));
            }
        }

        private static void EmitAluWritePc(ILEmitterCtx context)
        {
            if (IsThumb(context.CurrOp))
            {
                context.EmitLdc_I4(~1);

                context.Emit(OpCodes.And);
                context.Emit(OpCodes.Conv_U8);
                context.Emit(OpCodes.Ret);
            }
            else
            {
                EmitBxWritePc(context);
            }
        }
    }
}