• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SamboyCoding / Disarm / 10668496526

02 Sep 2024 01:55PM UTC coverage: 44.746% (+0.6%) from 44.151%
10668496526

push

github

SamboyCoding
Implemented some more families:

- Add/subtract imm (with tags)
- Data processing (register, 1-source)
- Add/subtract with carry
- Rotate right into flags
- Evaluate into flags
- Floating point conversion to/from fixed point

689 of 2012 branches covered (34.24%)

Branch coverage included in aggregate %.

86 of 183 new or added lines in 3 files covered. (46.99%)

3 existing lines in 2 files now uncovered.

1551 of 2994 relevant lines covered (51.8%)

102.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

53.62
/Disarm/InternalDisassembly/Arm64DataProcessingRegister.cs
1
namespace Disarm.InternalDisassembly;
2

3
internal static class Arm64DataProcessingRegister
4
{
5
    public static Arm64Instruction Disassemble(uint instruction)
6
    {
7
        var op0 = instruction.TestBit(30); //Bit 30
249✔
8
        var op1 = instruction.TestBit(28); //Bit 28
249✔
9
        //25-27 must be 101
10
        var op2 = (instruction >> 21) & 0b1111; //Bits 21-24
249✔
11
        var op3 = (instruction >> 10) & 0b11_1111; //Bits 10-15
249✔
12

13
        if (op2 == 0b0110 && op1)
249✔
14
            return op0
8✔
15
                ? DataProcessing1Source(instruction)
8✔
16
                : DataProcessing2Source(instruction);
8✔
17

18
        if (!op1)
241✔
19
        {
20
            if (op2 >> 3 == 0)
224✔
21
                return LogicalShiftedRegister(instruction);
210✔
22
            
23
            if((op2 & 0b1001) == 0b1000)
14✔
24
                return AddSubtractShiftedRegister(instruction);
7✔
25
            
26
            return AddSubtractExtendedRegister(instruction);
7✔
27
        }
28

29
        return op2 switch
17✔
30
        {
17✔
31
            0b0000 when op3 == 0 => AddSubtractWithCarry(instruction),
16!
32
            0b0000 when op3 is 0b100001 or 0b000001 => RotateRightIntoFlags(instruction),
×
33
            0b0000 when (op3 & 0b1111) == 0b0010 => EvaluateIntoFlags(instruction),
×
34
            0b0010 when op3.TestBit(1) => ConditionalCompare(instruction, false),
1!
35
            0b0010 => ConditionalCompare(instruction, true),
1✔
36
            0b0100 => ConditionalSelect(instruction),
1✔
37
            _ => DataProcessing3Source(instruction)
7✔
38
        };
17✔
39
    }
40

41
    private static Arm64Instruction DataProcessing1Source(uint instruction)
42
    {
43
        var sf = instruction.TestBit(31);
7✔
44
        var sFlag = instruction.TestBit(29);
7✔
45
        var opcode = (instruction >> 10) & 0b11_1111;
7✔
46
        var opcode2 = (instruction >> 16) & 0b1_1111;
7✔
47
        var rn = (int)(instruction >> 5) & 0b1_1111;
7✔
48
        var rd = (int)instruction & 0b1_1111;
7✔
49
        
50
        if(sFlag)
7!
NEW
51
            throw new Arm64UndefinedInstructionException("DataProcessing1Source: S flag set");
×
52
        
53
        if(opcode.TestBit(6))
7!
NEW
54
            throw new Arm64UndefinedInstructionException("DataProcessing1Source: top bit of opcode set");
×
55
        
56
        if(opcode2 > 1)
7!
NEW
57
            throw new Arm64UndefinedInstructionException("DataProcessing1Source: opcode2 > 1");
×
58

59
        if (opcode2 == 1)
7!
60
        {
61
            //FEAT_PAUTH stuff. Not implemented in disarm, yet.
62
            //But also literally not defined if sf == 0
63
            
NEW
64
            if(!sf)
×
NEW
65
                throw new Arm64UndefinedInstructionException("DataProcessing1Source: opcode2 == 1 and sf == 0");
×
66
            
NEW
67
            return new()
×
NEW
68
            {
×
NEW
69
                Mnemonic = Arm64Mnemonic.UNIMPLEMENTED,
×
NEW
70
                MnemonicCategory = Arm64MnemonicCategory.PointerAuthentication,
×
NEW
71
            };
×
72
        }
73
        
74
        if(opcode > 0b00_0101)
7!
75
            //Anything above this is FEAT_PAUTH stuff, so not defined if that's not set.
NEW
76
            throw new Arm64UndefinedInstructionException($"DataProcessing1Source: opcode > 0b00_0101: {opcode:X} when opcode2 == 0");
×
77
        
78
        var baseReg = sf ? Arm64Register.X0 : Arm64Register.W0; //sf == 1 means 64-bit variant
7✔
79

80
        var mnemonic = opcode switch
7!
81
        {
7✔
82
            0b00_0000 => Arm64Mnemonic.RBIT,
1✔
83
            0b00_0001 => Arm64Mnemonic.REV16,
1✔
84
            0b00_0010 when !sf => Arm64Mnemonic.REV,
3✔
85
            0b00_0010 => Arm64Mnemonic.REV32,
1✔
86
            //This would be REV64 but on a 32-bit register, which is invalid
7✔
87
            0b00_0011 when !sf => throw new Arm64UndefinedInstructionException("DataProcessing1Source: opcode == 0b00_0011 and sf == 0"),
1!
88
            0b00_0011 => Arm64Mnemonic.REV,
1✔
89
            0b00_0100 => Arm64Mnemonic.CLZ,
1✔
90
            0b00_0101 => Arm64Mnemonic.CLS,
1✔
91
        };
7✔
92
        
93
        return new()
7✔
94
        {
7✔
95
            Mnemonic = mnemonic,
7✔
96
            MnemonicCategory = Arm64MnemonicCategory.GeneralDataProcessing,
7✔
97
            Op0Kind = Arm64OperandKind.Register,
7✔
98
            Op1Kind = Arm64OperandKind.Register,
7✔
99
            Op0Reg = baseReg + rd,
7✔
100
            Op1Reg = baseReg + rn,
7✔
101
        };
7✔
102
    }
103

104
    private static Arm64Instruction DataProcessing2Source(uint instruction)
105
    {
106
        var sf = instruction.TestBit(31);
1✔
107
        var sFlag = instruction.TestBit(29);
1✔
108
        var rm = (int)(instruction >> 16) & 0b1_1111;
1✔
109
        var opcode = (int)(instruction >> 10) & 0b11_1111;
1✔
110
        var rn = (int)(instruction >> 5) & 0b1_1111;
1✔
111
        var rd = (int)instruction & 0b1_1111;
1✔
112
        
113
        if(opcode == 1 || (opcode >> 5) == 1 || (opcode >> 3) == 0b011)
1!
114
            throw new Arm64UndefinedInstructionException($"Invalid opcode for DataProcessing2Source: {opcode:X}");
×
115
        
116
        if(!sf && opcode == 0)
1!
117
            throw new Arm64UndefinedInstructionException($"Invalid opcode for DataProcessing2Source: {opcode:X} when sf = 0");
×
118
        
119
        //Just going to implement what exists and fall-through to the undefined exception
120

121
        if (!sf && !sFlag)
1!
122
        {
123
            var mnemonic = opcode switch
1!
124
            {
1✔
125
                0b000010 => Arm64Mnemonic.UDIV,
×
126
                0b000011 => Arm64Mnemonic.SDIV,
1✔
127
                0b001000 => Arm64Mnemonic.LSLV,
×
128
                0b001001 => Arm64Mnemonic.LSRV,
×
129
                0b001010 => Arm64Mnemonic.ASRV,
×
130
                0b001011 => Arm64Mnemonic.RORV,
×
131
                0b010000 => Arm64Mnemonic.CRC32B,
×
132
                0b010001 => Arm64Mnemonic.CRC32H,
×
133
                0b010010 => Arm64Mnemonic.CRC32W,
×
134
                0b010100 => Arm64Mnemonic.CRC32CB,
×
135
                0b010101 => Arm64Mnemonic.CRC32CH,
×
136
                0b010110 => Arm64Mnemonic.CRC32CW,
×
137
                _ => throw new Arm64UndefinedInstructionException($"DataProcessing2Source: opcode {opcode:X} with sf == S == 0")
×
138
            };
1✔
139

140
            return new()
1✔
141
            {
1✔
142
                Mnemonic = mnemonic,
1✔
143
                Op0Kind = Arm64OperandKind.Register,
1✔
144
                Op1Kind = Arm64OperandKind.Register,
1✔
145
                Op2Kind = Arm64OperandKind.Register,
1✔
146
                Op0Reg = Arm64Register.W0 + rd,
1✔
147
                Op1Reg = Arm64Register.W0 + rn,
1✔
148
                Op2Reg = Arm64Register.W0 + rm,
1✔
149
                MnemonicCategory = Arm64MnemonicCategory.Math,
1✔
150
            };
1✔
151
        }
152

153
        if (sf && sFlag)
×
154
        {
155
            if(opcode != 0)
×
156
                throw new Arm64UndefinedInstructionException("DataProcessing2Source: opcode != 0 when sf == S == 1");
×
157

158
            return new()
×
159
            {
×
160
                Mnemonic = Arm64Mnemonic.SUBPS,
×
161
                Op0Kind = Arm64OperandKind.Register,
×
162
                Op1Kind = Arm64OperandKind.Register,
×
163
                Op2Kind = Arm64OperandKind.Register,
×
164
                Op0Reg = Arm64Register.X0 + rd,
×
165
                Op1Reg = Arm64Register.X0 + rn,
×
166
                Op2Reg = Arm64Register.X0 + rm,
×
167
                MnemonicCategory = Arm64MnemonicCategory.MemoryTagging,
×
168
            };
×
169
        }
170
        
171
        //sf but no S
172

173
        var mnemonic2 = opcode switch
×
174
        {
×
175
            0b000000 => Arm64Mnemonic.SUBP,
×
176
            0b000010 => Arm64Mnemonic.UDIV,
×
177
            0b000011 => Arm64Mnemonic.SDIV,
×
178
            0b000100 => Arm64Mnemonic.IRG,
×
179
            0b000101 => Arm64Mnemonic.GMI,
×
180
            0b001000 => Arm64Mnemonic.LSLV,
×
181
            0b001001 => Arm64Mnemonic.LSRV,
×
182
            0b001010 => Arm64Mnemonic.ASRV,
×
183
            0b001011 => Arm64Mnemonic.RORV,
×
184
            0b001100 => Arm64Mnemonic.PACGA,
×
185
            0b010011 => Arm64Mnemonic.CRC32X,
×
186
            0b010111 => Arm64Mnemonic.CRC32CX,
×
187
            _ => throw new Arm64UndefinedInstructionException($"DataProcessing2Source: opcode {opcode:X} with sf == 1 and S == 0")
×
188
        };
×
189

190
        var category = mnemonic2 switch
×
191
        {
×
192
            Arm64Mnemonic.IRG or Arm64Mnemonic.GMI or Arm64Mnemonic.SUBP => Arm64MnemonicCategory.MemoryTagging,
×
193
            Arm64Mnemonic.PACGA => Arm64MnemonicCategory.PointerAuthentication,
×
194
            _ => Arm64MnemonicCategory.Math,
×
195
        };
×
196

197
        return new()
×
198
        {
×
199
            Mnemonic = mnemonic2,
×
200
            Op0Kind = Arm64OperandKind.Register,
×
201
            Op1Kind = Arm64OperandKind.Register,
×
202
            Op2Kind = Arm64OperandKind.Register,
×
203
            Op0Reg = Arm64Register.X0 + rd,
×
204
            Op1Reg = Arm64Register.X0 + rn,
×
205
            Op2Reg = Arm64Register.X0 + rm,
×
206
            MnemonicCategory = category,
×
207
        };
×
208
    }
209

210
    private static Arm64Instruction LogicalShiftedRegister(uint instruction)
211
    {
212
        var is64Bit = instruction.TestBit(31); //sf flag
210✔
213
        var opc = (instruction >> 29) & 0b11;
210✔
214
        var shift = (instruction >> 22) & 0b11;
215
        var negateFlag = instruction.TestBit(21); //N flag - defines if the result is negated
210✔
216
        var rm = (int) (instruction >> 16) & 0b1_1111;
210✔
217
        var imm6 = (instruction >> 10) & 0b11_1111;
210✔
218
        var rn = (int) (instruction >> 5) & 0b1_1111;
210✔
219
        var rd = (int) instruction & 0b1_1111;
210✔
220
        
221
        if(!is64Bit && imm6.TestBit(5))
210!
222
            throw new Arm64UndefinedInstructionException("LogicalShiftedRegister: imm6 bit 5 set and sf = 0");
×
223

224
        var opcode = opc switch
210!
225
        {
210✔
226
            0b00 when negateFlag => Arm64Mnemonic.BIC,
×
227
            0b00 => Arm64Mnemonic.AND,
×
228
            0b01 when negateFlag => Arm64Mnemonic.ORN,
210!
229
            0b01 => Arm64Mnemonic.ORR,
210✔
230
            0b10 when negateFlag => Arm64Mnemonic.EON,
×
231
            0b10 => Arm64Mnemonic.EOR,
×
232
            0b11 when negateFlag => Arm64Mnemonic.BICS,
×
233
            0b11 => Arm64Mnemonic.ANDS,
×
234
            _ => throw new("LogicalShiftedRegister: impossible opc")
×
235
        };
210✔
236

237
        var baseReg = is64Bit ? Arm64Register.X0 : Arm64Register.W0;
210✔
238
        var regD = baseReg + rd;
210✔
239
        var regN = baseReg + rn;
210✔
240
        var regM = baseReg + rm;
210✔
241

242

243
        return new()
210✔
244
        {
210✔
245
            Mnemonic = opcode,
210✔
246
            Op0Kind = Arm64OperandKind.Register,
210✔
247
            Op1Kind = Arm64OperandKind.Register,
210✔
248
            Op2Kind = Arm64OperandKind.Register,
210✔
249
            Op3Kind = Arm64OperandKind.Immediate,
210✔
250
            Op0Reg = regD,
210✔
251
            Op1Reg = regN,
210✔
252
            Op2Reg = regM,
210✔
253
            Op3Imm = imm6,
210✔
254
            MnemonicCategory = Arm64MnemonicCategory.Math
210✔
255
        };
210✔
256
    }
257
    
258
    private static Arm64Instruction AddSubtractShiftedRegister(uint instruction)
259
    {
260
        var is64Bit = instruction.TestBit(31);
7✔
261
        var isSubtract = instruction.TestBit(30);
7✔
262
        var setFlags = instruction.TestBit(29);
7✔
263
        var shift = (Arm64ShiftType) ((instruction >> 22) & 0b11);
7✔
264
        var rm = (int) (instruction >> 16) & 0b1_1111;
7✔
265
        var shiftAmount = (instruction >> 10) & 0b11_1111;
7✔
266
        var rn = (int) (instruction >> 5) & 0b1_1111;
7✔
267
        var rd = (int) instruction & 0b1_1111;
7✔
268
        
269
        var mnemonic = isSubtract
7!
270
            ? setFlags ? Arm64Mnemonic.SUBS : Arm64Mnemonic.SUB
7✔
271
            : setFlags ? Arm64Mnemonic.ADDS : Arm64Mnemonic.ADD;
7✔
272
        
273
        var baseReg = is64Bit ? Arm64Register.X0 : Arm64Register.W0;
7!
274
        var regD = baseReg + rd;
7✔
275
        var regN = baseReg + rn;
7✔
276
        var regM = baseReg + rm;
7✔
277

278
        if (shift == Arm64ShiftType.ROR)
7!
279
            throw new Arm64UndefinedInstructionException("Add/Subtract Shifted Register: Shift type ROR is reserved");
×
280

281
        return new()
7!
282
        {
7✔
283
            Mnemonic = mnemonic,
7✔
284
            Op0Kind = Arm64OperandKind.Register,
7✔
285
            Op1Kind = Arm64OperandKind.Register,
7✔
286
            Op2Kind = Arm64OperandKind.Register,
7✔
287
            Op3Kind = shiftAmount == 0 ? Arm64OperandKind.None : Arm64OperandKind.Immediate,
7✔
288
            Op0Reg = regD,
7✔
289
            Op1Reg = regN,
7✔
290
            Op2Reg = regM,
7✔
291
            Op3Imm = shiftAmount,
7✔
292
            FinalOpShiftType = shiftAmount == 0 ? Arm64ShiftType.NONE : shift,
7✔
293
            MnemonicCategory = Arm64MnemonicCategory.Math
7✔
294
        };
7✔
295
    }
296
    
297
    private static Arm64Instruction AddSubtractExtendedRegister(uint instruction)
298
    {
299
        var is64Bit = instruction.TestBit(31);
7✔
300
        var isSubtract = instruction.TestBit(30);
7✔
301
        var setFlags = instruction.TestBit(29);
7✔
302
        var opt = (instruction >> 22) & 0b11;
7✔
303
        var rm = (int) (instruction >> 16) & 0b1_1111;
7✔
304
        var extendType = (Arm64ExtendType) ((instruction >> 13) & 0b111);
7✔
305
        var shift = (instruction >> 10) & 0b111;
7✔
306
        var rn = (int) (instruction >> 5) & 0b1_1111;
7✔
307
        var rd = (int) instruction & 0b1_1111;
7✔
308
        
309
        if(opt != 0)
7!
310
            throw new Arm64UndefinedInstructionException("AddSubtractExtendedRegister: opt != 0");
×
311
        
312
        if(shift > 4)
7!
313
            throw new Arm64UndefinedInstructionException($"AddSubtractExtendedRegister: Shift > 4");
×
314
        
315
        var mnemonic = isSubtract
7!
316
            ? setFlags ? Arm64Mnemonic.SUBS : Arm64Mnemonic.SUB
7✔
317
            : setFlags ? Arm64Mnemonic.ADDS : Arm64Mnemonic.ADD;
7✔
318
        
319
        var baseReg = is64Bit ? Arm64Register.X0 : Arm64Register.W0;
7!
320
        var secondBaseReg = is64Bit
7!
321
            ? extendType is Arm64ExtendType.UXTX or Arm64ExtendType.SXTX ? Arm64Register.X0 : Arm64Register.W0
7✔
322
            : Arm64Register.W0;
7✔
323

324
        var regD = baseReg + rd;
7✔
325
        var regN = baseReg + rn;
7✔
326
        var regM = secondBaseReg + rm;
7✔
327

328
        return new()
7!
329
        {
7✔
330
            Mnemonic = mnemonic,
7✔
331
            Op0Kind = Arm64OperandKind.Register,
7✔
332
            Op1Kind = Arm64OperandKind.Register,
7✔
333
            Op2Kind = Arm64OperandKind.Register,
7✔
334
            Op3Kind = shift != 0 ? Arm64OperandKind.Immediate : Arm64OperandKind.None,
7✔
335
            Op0Reg = regD,
7✔
336
            Op1Reg = regN,
7✔
337
            Op2Reg = regM,
7✔
338
            Op3Imm = shift,
7✔
339
            FinalOpExtendType = extendType,
7✔
340
            MnemonicCategory = Arm64MnemonicCategory.Math
7✔
341
        };
7✔
342
    }
343
    
344
    private static Arm64Instruction AddSubtractWithCarry(uint instruction)
345
    {
346
        var sf = instruction.TestBit(31);
8✔
347
        var op = instruction.TestBit(30);
8✔
348
        var sFlag = instruction.TestBit(29);
8✔
349
        var rm = (int) (instruction >> 16) & 0b1_1111;
8✔
350
        var rn = (int) (instruction >> 5) & 0b1_1111;
8✔
351
        var rd = (int) instruction & 0b1_1111;
8✔
352
        
353
        var mnemonic = op 
8✔
354
            ? sFlag ? Arm64Mnemonic.SBCS : Arm64Mnemonic.SBC
8✔
355
            : sFlag ? Arm64Mnemonic.ADCS : Arm64Mnemonic.ADC;
8✔
356
        
357
        var baseReg = sf ? Arm64Register.X0 : Arm64Register.W0;
8✔
358
        
359
        var regM = baseReg + rm;
8✔
360
        var regN = baseReg + rn;
8✔
361
        var regD = baseReg + rd;
8✔
362

363
        return new()
8✔
364
        {
8✔
365
            Mnemonic = mnemonic,
8✔
366
            MnemonicCategory = Arm64MnemonicCategory.Math,
8✔
367
            Op0Kind = Arm64OperandKind.Register,
8✔
368
            Op1Kind = Arm64OperandKind.Register,
8✔
369
            Op2Kind = Arm64OperandKind.Register,
8✔
370
            Op0Reg = regD,
8✔
371
            Op1Reg = regN,
8✔
372
            Op2Reg = regM,
8✔
373
        };
8✔
374
    }
375
    
376
    private static Arm64Instruction RotateRightIntoFlags(uint instruction)
377
    {
NEW
378
        var sf = instruction.TestBit(31);
×
NEW
379
        var op = instruction.TestBit(30);
×
NEW
380
        var sFlag = instruction.TestBit(29);
×
NEW
381
        var imm6 = (instruction >> 15) & 0b11_1111;
×
NEW
382
        var rn = (int) (instruction >> 5) & 0b1_1111;
×
NEW
383
        var o2 = instruction.TestBit(4);
×
NEW
384
        var mask = instruction & 0b1111;
×
385
        
NEW
386
        if(!sf)
×
NEW
387
            throw new Arm64UndefinedInstructionException("RotateRightIntoFlags: sf == 0");
×
388
        
NEW
389
        if(op)
×
NEW
390
            throw new Arm64UndefinedInstructionException("RotateRightIntoFlags: op == 1");
×
391
        
NEW
392
        if(!sFlag)
×
NEW
393
            throw new Arm64UndefinedInstructionException("RotateRightIntoFlags: S == 0");
×
394
        
NEW
395
        if(o2)
×
NEW
396
            throw new Arm64UndefinedInstructionException("RotateRightIntoFlags: o2 == 1");
×
397
        
398
        //The ONLY valid encoding is sf, no op, S, no o2, which is RMIF
399
        //This entire block is FEAT_FlagM stuff but it's trivial to implement so.
400
        
NEW
401
        var regN = Arm64Register.X0 + rn;
×
402
        
403
        return new()
×
404
        {
×
NEW
405
            Mnemonic = Arm64Mnemonic.RMIF,
×
406
            MnemonicCategory = Arm64MnemonicCategory.FlagMath, 
×
NEW
407
            Op0Kind = Arm64OperandKind.Register,
×
NEW
408
            Op1Kind = Arm64OperandKind.Immediate,
×
NEW
409
            Op2Kind = Arm64OperandKind.Immediate,
×
NEW
410
            Op0Reg = regN,
×
NEW
411
            Op1Imm = imm6,
×
NEW
412
            Op2Imm = mask,
×
UNCOV
413
        };
×
414
    }
415
    
416
    private static Arm64Instruction EvaluateIntoFlags(uint instruction)
417
    {
NEW
418
        var sf = instruction.TestBit(31);
×
NEW
419
        var op = instruction.TestBit(30);
×
NEW
420
        var sFlag = instruction.TestBit(29);
×
NEW
421
        var opcode2 = (instruction >> 15) & 0b11_1111;
×
NEW
422
        var sz = instruction.TestBit(14);
×
NEW
423
        var rn = (int) (instruction >> 5) & 0b1_1111;
×
NEW
424
        var o3 = instruction.TestBit(4);
×
NEW
425
        var mask = instruction & 0b1111;
×
426
        
427
        //Only valid encoding is no sf, no op, S set, opcode2 == 0, o3 clear, mask == 0b1101
428
        //Again this is FEAT_FlagM stuff but trivial to implement
NEW
429
        if(sf)
×
NEW
430
            throw new Arm64UndefinedInstructionException("EvaluateIntoFlags: sf == 1");
×
431
        
NEW
432
        if(op)
×
NEW
433
            throw new Arm64UndefinedInstructionException("EvaluateIntoFlags: op == 1");
×
434
        
NEW
435
        if(!sFlag)
×
NEW
436
            throw new Arm64UndefinedInstructionException("EvaluateIntoFlags: S == 0");
×
437
        
NEW
438
        if(opcode2 != 0)
×
NEW
439
            throw new Arm64UndefinedInstructionException("EvaluateIntoFlags: opcode2 != 0");
×
440
        
NEW
441
        if(o3)
×
NEW
442
            throw new Arm64UndefinedInstructionException("EvaluateIntoFlags: o3 == 1");
×
443
        
NEW
444
        if(mask != 0b1101)
×
NEW
445
            throw new Arm64UndefinedInstructionException("EvaluateIntoFlags: mask != 0b1101");
×
446
        
NEW
447
        var regN = Arm64Register.W0 + rn;
×
NEW
448
        var mnemonic = sz ? Arm64Mnemonic.SETF16 : Arm64Mnemonic.SETF8;
×
449
        
450
        return new()
×
451
        {
×
NEW
452
            Mnemonic = mnemonic,
×
453
            MnemonicCategory = Arm64MnemonicCategory.FlagMath,
×
NEW
454
            Op0Kind = Arm64OperandKind.Register,
×
NEW
455
            Op0Reg = regN,
×
UNCOV
456
        };
×
457
    }
458

459
    private static Arm64Instruction ConditionalCompare(uint instruction, bool secondOpIsReg)
460
    {
461
        var is64Bit = instruction.TestBit(31);
1✔
462
        var op = instruction.TestBit(30);
1✔
463
        var sFlag = instruction.TestBit(29);
1✔
464
        var imm5 = (instruction >> 16) & 0b1_1111;
1✔
465
        var cond = (Arm64ConditionCode) ((instruction >> 12) & 0b1111);
1✔
466
        var o2 = instruction.TestBit(10);
1✔
467
        var rn = (int) (instruction >> 5) & 0b1_1111;
1✔
468
        var o3 = instruction.TestBit(4);
1✔
469
        var nzcv = instruction & 0b1111;
1✔
470
        
471
        if(!sFlag)
1!
472
            throw new Arm64UndefinedInstructionException("ConditionalCompareImmediate: sFlag == 0");
×
473
        
474
        if(o2 || o3)
1!
475
            throw new Arm64UndefinedInstructionException("ConditionalCompareImmediate: o2 or o3 is set");
×
476
        
477
        var mnemonic = op ? Arm64Mnemonic.CCMP : Arm64Mnemonic.CCMN;
1!
478
        var baseReg = is64Bit ? Arm64Register.X0 : Arm64Register.W0;
1!
479
        
480
        return new()
1!
481
        {
1✔
482
            Mnemonic = mnemonic,
1✔
483
            Op0Kind = Arm64OperandKind.Register,
1✔
484
            Op1Kind = secondOpIsReg ? Arm64OperandKind.Register : Arm64OperandKind.Immediate,
1✔
485
            Op2Kind = Arm64OperandKind.Immediate,
1✔
486
            Op0Reg = baseReg + rn,
1✔
487
            Op1Imm = secondOpIsReg ? 0 : imm5,
1✔
488
            Op1Reg = secondOpIsReg ? baseReg + (int)imm5 : Arm64Register.INVALID,
1✔
489
            Op2Imm = nzcv,
1✔
490
            FinalOpConditionCode = cond,
1✔
491
            MnemonicCategory = Arm64MnemonicCategory.Comparison
1✔
492
        };
1✔
493
    }
494
    
495
    private static Arm64Instruction ConditionalSelect(uint instruction)
496
    {
497
        var is64Bit = instruction.TestBit(31);
1✔
498
        var isInvert = instruction.TestBit(30);
1✔
499
        var setFlags = instruction.TestBit(29);
1✔
500
        var rm = (int) (instruction >> 16) & 0b1_1111;
1✔
501
        var cond = (Arm64ConditionCode) ((instruction >> 12) & 0b1111);
1✔
502
        var op2 = (instruction >> 10) & 0b11;
1✔
503
        var rn = (int) (instruction >> 5) & 0b1_1111;
1✔
504
        var rd = (int) instruction & 0b1_1111;
1✔
505
        
506
        if(setFlags)
1!
507
            throw new Arm64UndefinedInstructionException("ConditionalSelect: S flag set");
×
508
        
509
        if(op2 > 1)
1!
510
            throw new Arm64UndefinedInstructionException("ConditionalSelect: op2 > 1");
×
511

512
        var mnemonic = isInvert switch
1!
513
        {
1✔
514
            false when op2 == 0 => Arm64Mnemonic.CSEL,
1!
515
            false => Arm64Mnemonic.CSINC,
1✔
516
            true when op2 == 0 => Arm64Mnemonic.CSINV,
×
517
            true => Arm64Mnemonic.CSNEG,
×
518
        };
1✔
519
        
520
        var baseReg = is64Bit ? Arm64Register.X0 : Arm64Register.W0;
1!
521
        
522
        var regD = baseReg + rd;
1✔
523
        var regN = baseReg + rn;
1✔
524
        var regM = baseReg + rm;
1✔
525
        
526
        return new()
1✔
527
        {
1✔
528
            Mnemonic = mnemonic,
1✔
529
            Op0Kind = Arm64OperandKind.Register,
1✔
530
            Op1Kind = Arm64OperandKind.Register,
1✔
531
            Op2Kind = Arm64OperandKind.Register,
1✔
532
            Op3Kind = Arm64OperandKind.None,
1✔
533
            Op0Reg = regD,
1✔
534
            Op1Reg = regN,
1✔
535
            Op2Reg = regM,
1✔
536
            FinalOpConditionCode = cond,
1✔
537
            MnemonicCategory = Arm64MnemonicCategory.Comparison,
1✔
538
        };
1✔
539
    }
540
    
541
    private static Arm64Instruction DataProcessing3Source(uint instruction)
542
    {
543
        var is64Bit = instruction.TestBit(31);
7✔
544
        var op54 = (instruction >> 29) & 0b11;
7✔
545
        var op31 = (instruction >> 21) & 0b111;
7✔
546
        var rm = (int) (instruction >> 16) & 0b1_1111;
7✔
547
        var o0 = instruction.TestBit(15);
7✔
548
        var ra = (int) (instruction >> 10) & 0b1_1111;
7✔
549
        var rn = (int) (instruction >> 5) & 0b1_1111;
7✔
550
        var rd = (int) instruction & 0b1_1111;
7✔
551
        
552
        if(op54 != 0)
7!
553
            throw new Arm64UndefinedInstructionException("DataProcessing3Source: op54 != 0");
×
554

555
        var mnemonic = op31 switch
7!
556
        {
7✔
557
            0b000 when o0 => Arm64Mnemonic.MSUB,
7!
558
            0b000 => Arm64Mnemonic.MADD,
7✔
559
            0b001 when !is64Bit => throw new Arm64UndefinedInstructionException("DataProcessing3Source: op31 == 0b001 && sf == 0"),
×
560
            0b001 when o0 =>  Arm64Mnemonic.SMSUBL,
×
561
            0b001 => Arm64Mnemonic.SMADDL,
×
562
            0b010 when !o0 && is64Bit => Arm64Mnemonic.SMULH,
×
563
            0b101 when o0 && is64Bit => Arm64Mnemonic.UMSUBL,
×
564
            0b101 when !o0 && is64Bit => Arm64Mnemonic.UMADDL,
×
565
            0b110 when o0 && is64Bit => Arm64Mnemonic.UMULH,
×
566
            _ => throw new Arm64UndefinedInstructionException($"DataProcessing3Source: unallocated operand combination: op31 = {op31} o0 = {o0} sf = {(is64Bit ? 1 : 0)}")
×
567
        };
7✔
568
        
569
        var baseReg = is64Bit ? Arm64Register.X0 : Arm64Register.W0;
7!
570
        
571
        var regM = baseReg + rm;
7✔
572
        var regN = baseReg + rn;
7✔
573
        var regD = baseReg + rd;
7✔
574
        var regA = baseReg + ra;
7✔
575

576
        return new()
7✔
577
        {
7✔
578
            Mnemonic = mnemonic,
7✔
579
            Op0Kind = Arm64OperandKind.Register,
7✔
580
            Op1Kind = Arm64OperandKind.Register,
7✔
581
            Op2Kind = Arm64OperandKind.Register,
7✔
582
            Op3Kind = Arm64OperandKind.Register,
7✔
583
            Op0Reg = regD,
7✔
584
            Op1Reg = regN,
7✔
585
            Op2Reg = regM,
7✔
586
            Op3Reg = regA,
7✔
587
            MnemonicCategory = Arm64MnemonicCategory.Math,
7✔
588
        };
7✔
589
    }
590
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc