aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Decoders/DecoderHelper.cs
blob: 6fe4678f96611b14ff867ba702b010e5eab254a4 (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
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
using ARMeilleure.Common;

namespace ARMeilleure.Decoders
{
    static class DecoderHelper
    {
        static DecoderHelper()
        {
            Imm8ToFP32Table = BuildImm8ToFP32Table();
            Imm8ToFP64Table = BuildImm8ToFP64Table();
        }

        public static readonly uint[]  Imm8ToFP32Table;
        public static readonly ulong[] Imm8ToFP64Table;

        private static uint[] BuildImm8ToFP32Table()
        {
            uint[] tbl = new uint[256];

            for (int idx = 0; idx < 256; idx++)
            {
                tbl[idx] = ExpandImm8ToFP32((uint)idx);
            }

            return tbl;
        }

        private static ulong[] BuildImm8ToFP64Table()
        {
            ulong[] tbl = new ulong[256];

            for (int idx = 0; idx < 256; idx++)
            {
                tbl[idx] = ExpandImm8ToFP64((ulong)idx);
            }

            return tbl;
        }

        // abcdefgh -> aBbbbbbc defgh000 00000000 00000000 (B = ~b)
        private static uint ExpandImm8ToFP32(uint imm)
        {
            uint MoveBit(uint bits, int from, int to)
            {
                return ((bits >> from) & 1U) << to;
            }

            return MoveBit(imm, 7, 31) | MoveBit(~imm, 6, 30) |
                   MoveBit(imm, 6, 29) | MoveBit( imm, 6, 28) |
                   MoveBit(imm, 6, 27) | MoveBit( imm, 6, 26) |
                   MoveBit(imm, 6, 25) | MoveBit( imm, 5, 24) |
                   MoveBit(imm, 4, 23) | MoveBit( imm, 3, 22) |
                   MoveBit(imm, 2, 21) | MoveBit( imm, 1, 20) |
                   MoveBit(imm, 0, 19);
        }

        // abcdefgh -> aBbbbbbb bbcdefgh 00000000 00000000 00000000 00000000 00000000 00000000 (B = ~b)
        private static ulong ExpandImm8ToFP64(ulong imm)
        {
            ulong MoveBit(ulong bits, int from, int to)
            {
                return ((bits >> from) & 1UL) << to;
            }

            return MoveBit(imm, 7, 63) | MoveBit(~imm, 6, 62) |
                   MoveBit(imm, 6, 61) | MoveBit( imm, 6, 60) |
                   MoveBit(imm, 6, 59) | MoveBit( imm, 6, 58) |
                   MoveBit(imm, 6, 57) | MoveBit( imm, 6, 56) |
                   MoveBit(imm, 6, 55) | MoveBit( imm, 6, 54) |
                   MoveBit(imm, 5, 53) | MoveBit( imm, 4, 52) |
                   MoveBit(imm, 3, 51) | MoveBit( imm, 2, 50) |
                   MoveBit(imm, 1, 49) | MoveBit( imm, 0, 48);
        }

        public struct BitMask
        {
            public long WMask;
            public long TMask;
            public int  Pos;
            public int  Shift;
            public bool IsUndefined;

            public static BitMask Invalid => new BitMask { IsUndefined = true };
        }

        public static BitMask DecodeBitMask(int opCode, bool immediate)
        {
            int immS = (opCode >> 10) & 0x3f;
            int immR = (opCode >> 16) & 0x3f;

            int n  = (opCode >> 22) & 1;
            int sf = (opCode >> 31) & 1;

            int length = BitUtils.HighestBitSet((~immS & 0x3f) | (n << 6));

            if (length < 1 || (sf == 0 && n != 0))
            {
                return BitMask.Invalid;
            }

            int size = 1 << length;

            int levels = size - 1;

            int s = immS & levels;
            int r = immR & levels;

            if (immediate && s == levels)
            {
                return BitMask.Invalid;
            }

            long wMask = BitUtils.FillWithOnes(s + 1);
            long tMask = BitUtils.FillWithOnes(((s - r) & levels) + 1);

            if (r > 0)
            {
                wMask  = BitUtils.RotateRight(wMask, r, size);
                wMask &= BitUtils.FillWithOnes(size);
            }

            return new BitMask()
            {
                WMask = BitUtils.Replicate(wMask, size),
                TMask = BitUtils.Replicate(tMask, size),

                Pos   = immS,
                Shift = immR
            };
        }

        public static long DecodeImm24_2(int opCode)
        {
            return ((long)opCode << 40) >> 38;
        }

        public static long DecodeImm26_2(int opCode)
        {
            return ((long)opCode << 38) >> 36;
        }

        public static long DecodeImmS19_2(int opCode)
        {
            return (((long)opCode << 40) >> 43) & ~3;
        }

        public static long DecodeImmS14_2(int opCode)
        {
            return (((long)opCode << 45) >> 48) & ~3;
        }

        public static bool VectorArgumentsInvalid(bool q, params int[] args)
        {
            if (q) 
            {
                for (int i = 0; i < args.Length; i++)
                {
                    if ((args[i] & 1) == 1)
                    {
                        return true;
                    }
                }
            }
            return false;
        }
    }
}