1#![allow(unused_parens)]
2use super::opcodes::*;
3use derive_more::TryFrom;
4
5#[derive(Copy, Clone, PartialEq, Eq, Debug, TryFrom)]
6#[repr(u8)]
7#[try_from(repr)]
8pub enum Cond {
9 EQ = 0x0,
10 NE = 0x1,
11
12 HS = 0x2,
13
14 LO = 0x3,
15 MI = 0x4,
16 PL = 0x5,
17 VS = 0x6,
18 VC = 0x7,
19 HI = 0x8,
20 LS = 0x9,
21 GE = 0xa,
22 LT = 0xb,
23 GT = 0xc,
24 LE = 0xd,
25 AL = 0xe,
26 NV = 0xf,
27}
28
29impl Cond {
30 pub const CS: Cond = Cond::HS;
31 pub const CC: Cond = Cond::LO;
32}
33
34#[derive(Copy, Clone, PartialEq, Eq, TryFrom, Debug)]
35#[repr(u8)]
36#[try_from(repr)]
37pub enum Ext {
38 Uxtb = 0,
39 Uxth = 1,
40 Uxtw = 2,
41 Uxtx = 3,
42 Sxtb = 4,
43 Sxth = 5,
44 Sxtw = 6,
45 Sxtx = 7,
46 Lsl = 8,
47 Lsr = 9,
48 Asr = 10,
49 Ror = 11,
50}
51
52#[derive(Copy, Clone, PartialEq, Eq, TryFrom, Debug)]
53#[repr(u8)]
54#[try_from(repr)]
55pub enum VectorArrangement {
56 Va8b = 0,
57 Va16b = 1,
58 Va4h = 2,
59 Va8h = 3,
60 Va2s = 4,
61 Va4s = 5,
62 Va1d = 6,
63 Va2d = 7,
64 Va2h = 8,
65 Va1q = 9,
66}
67#[derive(Copy, Clone, PartialEq, Eq, TryFrom, Debug)]
68#[repr(u8)]
69#[try_from(repr)]
70pub enum OpType {
71 None = 0,
72 RegGp,
73 RegGpInc,
74 RegGpExt,
75 RegSp,
76 RegFp,
77 RegVec,
78 RegVtbl,
79 RegVidx,
80 RegVtblIdx,
81 MemUoff,
82 MemSoff,
83 MemSoffPre,
84 MemSoffPost,
85 MemReg,
86 MemRegPost,
87 MemInc,
88 Cond,
89 Prfop,
90 Sysreg,
91 ImmSmall,
92 Simm,
93 Uimm,
94 UimmShift,
95 ImmLarge,
96 ImmFloat,
97}
98
99#[derive(Copy, Clone, PartialEq, Eq, Debug)]
100pub struct Op {
101 op_type: OpType,
102 value: OpValue,
103 detail: OpDetail,
104}
105#[derive(Copy, Clone, PartialEq, Eq, Debug)]
106pub enum OpValue {
107 Reg(u8),
108 Prfop(u8),
109 ImmShift { mask: bool, shift: u8 },
110}
111
112impl Default for Op {
113 fn default() -> Self {
114 Self {
115 op_type: OpType::None,
116 value: OpValue::Reg(0),
117 detail: OpDetail::Gp { sf: false },
118 }
119 }
120}
121
122#[derive(Copy, Clone, PartialEq, Eq, Debug)]
123pub enum OpDetail {
124 Gp {
125 sf: bool,
126 },
127 GpPExt {
128 sf: bool,
129 ext: Ext,
130 shift: u8,
131 },
132 Fp {
133 size: u8,
134 },
135 Vec {
136 va: VectorArrangement,
137 },
138 Vidx {
139 esize: u8,
141 elem: u8,
142 },
143 Vtbl {
144 va: VectorArrangement,
145 cnt: u8,
146 },
147 VtblIdx {
148 esize: u8,
149 elem: u8,
150 cnt: u8,
151 },
152 MemReg {
153 sc: u32,
154 ext: Ext,
155 shift: u8,
156 offreg: u8,
157 },
158 Sysreg(u16),
159 Uimm16(u16),
160 Simm16(i16),
161 Cond(Cond),
162}
163
164pub struct Inst {
165 pub mnem: InstKind,
166 pub ops: [Op; 5],
167 pub imm: Imm,
168}
169
170impl Default for Inst {
171 fn default() -> Self {
172 Self {
173 mnem: InstKind::Unknown,
174 ops: [Op::default(); 5],
175 imm: Imm { imm64: 0 },
176 }
177 }
178}
179
180pub union Imm {
181 imm64: u64,
182 float8: f64,
183}
184
185pub fn classify(inst: u32) -> InstKind {
186 InstKind::try_from(classify_impl(inst) as u16).unwrap()
187}
188
189fn ctz(v: u32) -> u32 {
190 v.trailing_zeros() as _
191}
192
193fn clz(v: u32, sz: usize) -> u32 {
194 if v != 0 {
195 v.leading_zeros() + sz as u32 - 32
196 } else {
197 sz as _
198 }
199}
200
201fn sext(imm: i32, bits: usize) -> i32 {
202 let sign = 1 << (bits - 1);
203 if imm & sign != 0 {
204 ((imm ^ sign) - sign) as _
205 } else {
206 imm as _
207 }
208}
209
210fn immlogical(sf: u32, n: u32, immr: u32, imms: u32) -> u32 {
211 if (n == 0) && (imms == 0x3f) {
212 return 0;
213 }
214
215 let len = 31 - (imms.count_ones() as u32);
216 let levels = (1 << len) - 1;
217 let s = imms & levels;
218 let r = immr & levels;
219 let esize = 1 << len;
220 let mut welem = ((1 << (s + 1)) - 1) as u64;
221
222 if r != 0 {
223 welem = (welem >> r) | (welem << (esize - r));
224 }
225
226 if esize < 64 {
227 welem &= ((1 << esize) - 1) as u64;
228 }
229
230 let mut wmask = 0 as u64;
231 for i in (0..(!sf as u32 * 32)).step_by(esize as usize) {
232 wmask |= welem << i;
233 }
234
235 wmask as u32
236}
237
238fn opreggp(idx: u32, sf: u32) -> Op {
239 Op {
240 op_type: OpType::RegGp,
241 value: OpValue::Reg(idx as u8),
242 detail: OpDetail::Gp { sf: sf != 0 },
243 }
244}
245
246fn opreggpinc(idx: u32) -> Op {
247 Op {
248 op_type: OpType::RegGpInc,
249 value: OpValue::Reg(idx as u8),
250 detail: OpDetail::Gp { sf: true },
251 }
252}
253
254fn opreggpsp(idx: u32, sf: u32) -> Op {
255 Op {
256 op_type: if idx != 31 {
257 OpType::RegGp
258 } else {
259 OpType::RegSp
260 },
261 value: OpValue::Reg(idx as u8),
262 detail: OpDetail::Gp { sf: sf != 0 },
263 }
264}
265
266fn opreggpmaysp(maysp: u32, idx: u32, sf: u32) -> Op {
267 if idx < 31 || maysp == 0 {
268 Op {
269 op_type: OpType::RegGp,
270 value: OpValue::Reg(idx as u8),
271 detail: OpDetail::Gp { sf: sf != 0 },
272 }
273 } else {
274 Op {
275 op_type: OpType::RegSp,
276 value: OpValue::Reg(idx as u8),
277 detail: OpDetail::Gp { sf: sf != 0 },
278 }
279 }
280}
281
282fn opreggpprf(isprf: u32, idx: u32, sf: u32) -> Op {
283 Op {
284 op_type: if isprf != 0 {
285 OpType::Prfop
286 } else {
287 OpType::RegGp
288 },
289 value: OpValue::Reg(idx as u8),
290 detail: OpDetail::Gp { sf: sf != 0 },
291 }
292}
293
294fn opreggpext(idx: u32, sf: u32, ext: u32, shift: u32) -> Op {
295 Op {
296 op_type: OpType::RegGpExt,
297 value: OpValue::Reg(idx as u8),
298 detail: OpDetail::GpPExt {
299 sf: sf != 0,
300 ext: Ext::try_from(ext as u8).unwrap(),
301 shift: shift as u8,
302 },
303 }
304}
305
306fn opregfp(idx: u32, size: u32) -> Op {
307 Op {
308 op_type: OpType::RegFp,
309 value: OpValue::Reg(idx as u8),
310 detail: OpDetail::Fp { size: size as u8 },
311 }
312}
313
314fn opregvec(idx: u32, esize: u32, q: u32) -> Op {
315 Op {
316 op_type: OpType::RegVec,
317 value: OpValue::Reg(idx as u8),
318 detail: OpDetail::Vec {
319 va: VectorArrangement::try_from(((esize as u8) << 1) + q as u8).unwrap(),
320 },
321 }
322}
323
324fn opregvidx(idx: u32, esize: u32, elem: u32) -> Op {
325 Op {
326 op_type: OpType::RegVidx,
327 value: OpValue::Reg(idx as u8),
328 detail: OpDetail::Vidx {
329 esize: esize as u8,
330 elem: elem as u8,
331 },
332 }
333}
334
335fn opregvtbl(idx: u32, esize: u32, q: u32, cnt: u32) -> Op {
336 Op {
337 op_type: OpType::RegVtbl,
338 value: OpValue::Reg(idx as u8),
339 detail: OpDetail::Vtbl {
340 va: VectorArrangement::try_from(((esize as u8) << 1) + q as u8).unwrap(),
341 cnt: cnt as u8,
342 },
343 }
344}
345
346fn opregvtblidx(idx: u32, esize: u32, elem: u32, cnt: u32) -> Op {
347 Op {
348 op_type: OpType::RegVtblIdx,
349 value: OpValue::Reg(idx as u8),
350 detail: OpDetail::VtblIdx {
351 esize: esize as u8,
352 elem: elem as u8,
353 cnt: cnt as u8,
354 },
355 }
356}
357
358pub fn opmemuoff(idx: u32, off: u32) -> Op {
359 Op {
360 op_type: OpType::MemUoff,
361 value: OpValue::Reg(idx as u8),
362 detail: OpDetail::Uimm16(off as _),
363 }
364}
365
366pub fn opmemsoff(idx: u32, off: i32) -> Op {
367 Op {
368 op_type: OpType::MemSoff,
369 value: OpValue::Reg(idx as u8),
370 detail: OpDetail::Simm16(off as _),
371 }
372}
373
374pub fn opmemsoffpre(idx: u32, off: i32) -> Op {
375 Op {
376 op_type: OpType::MemSoffPre,
377 value: OpValue::Reg(idx as u8),
378 detail: OpDetail::Simm16(off as _),
379 }
380}
381
382pub fn opmemsoffpost(idx: u32, off: i32) -> Op {
383 Op {
384 op_type: OpType::MemSoffPost,
385 value: OpValue::Reg(idx as u8),
386 detail: OpDetail::Simm16(off as _),
387 }
388}
389
390pub fn opmemreg(idx: u32, offreg: u32, ext: u32, scale: u32, shift: u32) -> Op {
391 Op {
392 op_type: OpType::MemReg,
393 value: OpValue::Reg(idx as u8),
394 detail: OpDetail::MemReg {
395 sc: scale,
396 ext: Ext::try_from(ext as u8).unwrap(),
397 shift: shift as u8,
398 offreg: offreg as u8,
399 },
400 }
401}
402
403pub fn opmemregsimdpost(idx: u32, offreg: u32, constoff: u32) -> Op {
404 if offreg == 31 {
405 opmemsoffpost(idx, constoff as _)
406 } else {
407 Op {
408 op_type: OpType::MemRegPost,
409 value: OpValue::Reg(idx as u8),
410 detail: OpDetail::MemReg {
411 sc: 0,
412 ext: Ext::Uxtx,
413 shift: 0,
414 offreg: offreg as u8,
415 },
416 }
417 }
418}
419
420pub fn opmeminc(idx: u32) -> Op {
421 Op {
422 op_type: OpType::MemInc,
423 value: OpValue::Reg(idx as u8),
424 detail: OpDetail::Uimm16(0),
425 }
426}
427
428pub fn opimmsmall(imm6: u32) -> Op {
429 Op {
430 op_type: OpType::ImmSmall,
431 value: OpValue::ImmShift {
432 mask: false,
433 shift: 0,
434 },
435 detail: OpDetail::Uimm16(imm6 as u16),
436 }
437}
438
439pub fn opsimm(imm: i32) -> Op {
440 Op {
441 op_type: OpType::Simm,
442 value: OpValue::ImmShift {
443 mask: false,
444 shift: 0,
445 },
446 detail: OpDetail::Simm16(imm as _),
447 }
448}
449
450pub fn opuimm(imm: u32) -> Op {
451 Op {
452 op_type: OpType::Uimm,
453 value: OpValue::ImmShift {
454 mask: false,
455 shift: 0,
456 },
457 detail: OpDetail::Uimm16(imm as _),
458 }
459}
460
461pub fn opuimmshift(imm: u32, msl: u32, shift: u32) -> Op {
462 Op {
463 op_type: OpType::UimmShift,
464 value: OpValue::ImmShift {
465 mask: msl != 0,
466 shift: shift as u8,
467 },
468 detail: OpDetail::Uimm16(imm as _),
469 }
470}
471
472pub fn opreladdr(ddi: &mut Inst, imm: i32) -> Op {
473 ddi.imm = Imm {
474 imm64: imm as i32 as i64 as u64,
475 };
476 Op {
477 op_type: OpType::ImmLarge,
478 value: OpValue::ImmShift {
479 mask: false,
480 shift: 0,
481 },
482 detail: OpDetail::Uimm16(0),
483 }
484}
485
486pub fn opimmlogical(ddi: &mut Inst, sf: u32, n: u32, immr: u32, imms: u32) -> Op {
487 ddi.imm = Imm {
488 imm64: immlogical(sf, n, immr, imms) as u64,
489 };
490 Op {
491 op_type: OpType::ImmLarge,
492 value: OpValue::ImmShift {
493 mask: false,
494 shift: 0,
495 },
496 detail: OpDetail::Uimm16(sf as u16),
497 }
498}
499
500pub fn opimmsimdmask(ddi: &mut Inst, imm8: u32) -> Op {
501 let mut res = 0u64;
502 for i in 0..8 {
503 if (imm8 & (1 << i)) != 0 {
504 res |= 0xff << (i * 8);
505 }
506 }
507 ddi.imm = Imm { imm64: res };
508 Op {
509 op_type: OpType::ImmLarge,
510 value: OpValue::ImmShift {
511 mask: false,
512 shift: 0,
513 },
514 detail: OpDetail::Uimm16(1),
515 }
516}
517
518pub fn opimmfloatzero(ddi: &mut Inst) -> Op {
519 ddi.imm = Imm { float8: 0.0 };
520 Op {
521 op_type: OpType::ImmFloat,
522 value: OpValue::ImmShift {
523 mask: false,
524 shift: 0,
525 },
526 detail: OpDetail::Uimm16(0x100),
527 }
528}
529
530pub fn opimmfloat(ddi: &mut Inst, imm8: u32) -> Op {
531 let res = (imm8 as u32 & 0x80) << 24
532 | if (imm8 & 0x40) != 0 {
533 0x3e000000
534 } else {
535 0x40000000
536 }
537 | ((imm8 & 0x3f) as u32) << 19;
538 ddi.imm = Imm {
539 float8: f64::from_bits(res as u64),
540 };
541 Op {
542 op_type: OpType::ImmFloat,
543 value: OpValue::ImmShift {
544 mask: false,
545 shift: 0,
546 },
547 detail: OpDetail::Uimm16(imm8 as u16),
548 }
549}
550
551pub fn opsysreg(reg: u32) -> Op {
552 Op {
553 op_type: OpType::Sysreg,
554 value: OpValue::ImmShift {
555 mask: false,
556 shift: 0,
557 },
558 detail: OpDetail::Sysreg(reg as u16),
559 }
560}
561
562pub fn opcond(cond: u32) -> Op {
563 Op {
564 op_type: OpType::Cond,
565 value: OpValue::ImmShift {
566 mask: false,
567 shift: 0,
568 },
569 detail: OpDetail::Cond(Cond::try_from(cond as u8).unwrap()),
570 }
571}
572
573include!("classifier.rs");