aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/Instruction/AInstEmitSystem.cs
blob: a365398ff7c402f5deb17f7554a0fc038730250c (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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
using ChocolArm64.Decoder;
using ChocolArm64.State;
using ChocolArm64.Translation;
using System;
using System.Reflection;
using System.Reflection.Emit;

namespace ChocolArm64.Instruction
{
    static partial class AInstEmit
    {
        public static void Hint(AILEmitterCtx Context)
        {
            //Execute as no-op.
        }

        public static void Isb(AILEmitterCtx Context)
        {
            //Execute as no-op.
        }

        public static void Mrs(AILEmitterCtx Context)
        {
            AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp;

            Context.EmitLdarg(ATranslatedSub.StateArgIdx);

            string PropName;

            switch (GetPackedId(Op))
            {
                case 0b11_011_0000_0000_001: PropName = nameof(AThreadState.CtrEl0);    break;
                case 0b11_011_0000_0000_111: PropName = nameof(AThreadState.DczidEl0);  break;
                case 0b11_011_0100_0100_000: PropName = nameof(AThreadState.Fpcr);      break;
                case 0b11_011_0100_0100_001: PropName = nameof(AThreadState.Fpsr);      break;
                case 0b11_011_1101_0000_010: PropName = nameof(AThreadState.TpidrEl0);  break;
                case 0b11_011_1101_0000_011: PropName = nameof(AThreadState.Tpidr);     break;
                case 0b11_011_1110_0000_000: PropName = nameof(AThreadState.CntfrqEl0); break;
                case 0b11_011_1110_0000_001: PropName = nameof(AThreadState.CntpctEl0); break;

                default: throw new NotImplementedException($"Unknown MRS at {Op.Position:x16}");
            }

            Context.EmitCallPropGet(typeof(AThreadState), PropName);

            PropertyInfo PropInfo = typeof(AThreadState).GetProperty(PropName);

            if (PropInfo.PropertyType != typeof(long) &&
                PropInfo.PropertyType != typeof(ulong))
            {
                Context.Emit(OpCodes.Conv_U8);
            }

            Context.EmitStintzr(Op.Rt);
        }

        public static void Msr(AILEmitterCtx Context)
        {
            AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp;

            Context.EmitLdarg(ATranslatedSub.StateArgIdx);
            Context.EmitLdintzr(Op.Rt);

            string PropName;

            switch (GetPackedId(Op))
            {
                case 0b11_011_0100_0100_000: PropName = nameof(AThreadState.Fpcr);     break;
                case 0b11_011_0100_0100_001: PropName = nameof(AThreadState.Fpsr);     break;
                case 0b11_011_1101_0000_010: PropName = nameof(AThreadState.TpidrEl0); break;

                default: throw new NotImplementedException($"Unknown MSR at {Op.Position:x16}");
            }

            PropertyInfo PropInfo = typeof(AThreadState).GetProperty(PropName);

            if (PropInfo.PropertyType != typeof(long) &&
                PropInfo.PropertyType != typeof(ulong))
            {
                Context.Emit(OpCodes.Conv_U4);
            }

            Context.EmitCallPropSet(typeof(AThreadState), PropName);
        }

        public static void Nop(AILEmitterCtx Context)
        {
            //Do nothing.
        }

        public static void Sys(AILEmitterCtx Context)
        {
            //This instruction is used to do some operations on the CPU like cache invalidation,
            //address translation and the like.
            //We treat it as no-op here since we don't have any cache being emulated anyway.
            AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp;

            switch (GetPackedId(Op))
            {
                case 0b11_011_0111_0100_001:
                {
                    //DC ZVA
                    for (int Offs = 0; Offs < (4 << AThreadState.DczSizeLog2); Offs += 8)
                    {
                        Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
                        Context.EmitLdintzr(Op.Rt);
                        Context.EmitLdc_I(Offs);

                        Context.Emit(OpCodes.Add);

                        Context.EmitLdc_I8(0);

                        AInstEmitMemoryHelper.EmitWriteCall(Context, 3);
                    }

                    break;
                }

                //No-op
                case 0b11_011_0111_1110_001: //DC CIVAC
                    break;
            }
        }

        private static int GetPackedId(AOpCodeSystem Op)
        {
            int Id;

            Id  = Op.Op2 << 0;
            Id |= Op.CRm << 3;
            Id |= Op.CRn << 7;
            Id |= Op.Op1 << 11;
            Id |= Op.Op0 << 14;

            return Id;
        }
    }
}