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 {
176 imm64: 0
177 }
178 }
179 }
180}
181
182pub union Imm {
183 imm64: u64,
184 float8: f64,
185}
186
187pub fn classify(inst: u32) -> InstKind {
188 InstKind::try_from(classify_impl(inst) as u16).unwrap()
189}
190
191fn ctz(v: u32) -> u32 {
192 v.trailing_zeros() as _
193}
194
195fn clz(v: u32, sz: usize) -> u32 {
196 if v != 0 {
197 v.leading_zeros() + sz as u32 - 32
198 } else {
199 sz as _
200 }
201}
202
203fn sext(imm: i32, bits: usize) -> i32 {
204 let sign = 1 << (bits - 1);
205 if imm & sign != 0 {
206 ((imm ^ sign) - sign) as _
207 } else {
208 imm as _
209 }
210}
211
212fn immlogical(sf: u32, n: u32, immr: u32, imms: u32) -> u32 {
213 if (n == 0) && (imms == 0x3f) {
214 return 0;
215 }
216
217 let len = 31 - (imms.count_ones() as u32);
218 let levels = (1 << len) - 1;
219 let s = imms & levels;
220 let r = immr & levels;
221 let esize = 1 << len;
222 let mut welem = ((1 << (s + 1)) - 1) as u64;
223
224 if r != 0 {
225 welem = (welem >> r) | (welem << (esize - r));
226 }
227
228 if esize < 64 {
229 welem &= ((1 << esize) - 1) as u64;
230 }
231
232 let mut wmask = 0 as u64;
233 for i in (0..(!sf as u32 * 32)).step_by(esize as usize) {
234 wmask |= welem << i;
235 }
236
237 wmask as u32
238}
239
240fn opreggp(idx: u32, sf: u32) -> Op {
241 Op {
242 op_type: OpType::RegGp,
243 value: OpValue::Reg(idx as u8),
244 detail: OpDetail::Gp { sf: sf != 0 },
245 }
246}
247
248fn opreggpinc(idx: u32) -> Op {
249 Op {
250 op_type: OpType::RegGpInc,
251 value: OpValue::Reg(idx as u8),
252 detail: OpDetail::Gp { sf: true },
253 }
254}
255
256fn opreggpsp(idx: u32, sf: u32) -> Op {
257 Op {
258 op_type: if idx != 31 {
259 OpType::RegGp
260 } else {
261 OpType::RegSp
262 },
263 value: OpValue::Reg(idx as u8),
264 detail: OpDetail::Gp { sf: sf != 0 },
265 }
266}
267
268fn opreggpmaysp(maysp: u32, idx: u32, sf: u32) -> Op {
269 if idx < 31 || maysp == 0 {
270 Op {
271 op_type: OpType::RegGp,
272 value: OpValue::Reg(idx as u8),
273 detail: OpDetail::Gp { sf: sf != 0 },
274 }
275 } else {
276 Op {
277 op_type: OpType::RegSp,
278 value: OpValue::Reg(idx as u8),
279 detail: OpDetail::Gp { sf: sf != 0 },
280 }
281 }
282}
283
284fn opreggpprf(isprf: u32, idx: u32, sf: u32) -> Op {
285 Op {
286 op_type: if isprf!= 0 { OpType::Prfop } else { OpType::RegGp },
287 value: OpValue::Reg(idx as u8),
288 detail: OpDetail::Gp { sf: sf!= 0 },
289 }
290
291}
292
293fn opreggpext(idx: u32, sf: u32, ext: u32, shift: u32) -> Op {
294 Op {
295 op_type: OpType::RegGpExt,
296 value: OpValue::Reg(idx as u8),
297 detail: OpDetail::GpPExt {
298 sf: sf!= 0,
299 ext: Ext::try_from(ext as u8).unwrap(),
300 shift: shift as u8,
301 },
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}
314
315fn opregvec(idx: u32, esize: u32, q: u32) -> Op {
316 Op {
317 op_type: OpType::RegVec,
318 value: OpValue::Reg(idx as u8),
319 detail: OpDetail::Vec {
320 va: VectorArrangement::try_from(((esize as u8) << 1) + q as u8).unwrap(),
321 },
322 }
323
324}
325
326fn opregvidx(idx: u32, esize: u32, elem: u32) -> Op {
327 Op {
328 op_type: OpType::RegVidx,
329 value: OpValue::Reg(idx as u8),
330 detail: OpDetail::Vidx {
331 esize: esize as u8,
332 elem: elem as u8,
333 },
334 }
335
336}
337
338fn opregvtbl(idx: u32, esize: u32, q: u32, cnt: u32) -> Op {
339 Op {
340 op_type: OpType::RegVtbl,
341 value: OpValue::Reg(idx as u8),
342 detail: OpDetail::Vtbl {
343 va: VectorArrangement::try_from(((esize as u8) << 1) + q as u8).unwrap(),
344 cnt: cnt as u8,
345 },
346 }
347
348}
349
350fn opregvtblidx(idx: u32, esize: u32, elem: u32, cnt: u32) -> Op {
351 Op {
352 op_type: OpType::RegVtblIdx,
353 value: OpValue::Reg(idx as u8),
354 detail: OpDetail::VtblIdx {
355 esize: esize as u8,
356 elem: elem as u8,
357 cnt: cnt as u8,
358 },
359 }
360}
361
362pub fn opmemuoff(idx: u32, off: u32) -> Op {
363 Op {
364 op_type: OpType::MemUoff,
365 value: OpValue::Reg(idx as u8),
366 detail: OpDetail::Uimm16(off as _),
367 }
368}
369
370pub fn opmemsoff(idx: u32, off: i32) -> Op {
371 Op {
372 op_type: OpType::MemSoff,
373 value: OpValue::Reg(idx as u8),
374 detail: OpDetail::Simm16(off as _),
375 }
376}
377
378pub fn opmemsoffpre(idx: u32, off: i32) -> Op {
379 Op {
380 op_type: OpType::MemSoffPre,
381 value: OpValue::Reg(idx as u8),
382 detail: OpDetail::Simm16(off as _),
383 }
384}
385
386pub fn opmemsoffpost(idx: u32, off: i32) -> Op {
387 Op {
388 op_type: OpType::MemSoffPost,
389 value: OpValue::Reg(idx as u8),
390 detail: OpDetail::Simm16(off as _),
391 }
392}
393
394pub fn opmemreg(idx: u32, offreg: u32, ext: u32, scale: u32, shift: u32) -> Op {
395 Op {
396 op_type: OpType::MemReg,
397 value: OpValue::Reg(idx as u8),
398 detail: OpDetail::MemReg {
399 sc: scale,
400 ext: Ext::try_from(ext as u8).unwrap(),
401 shift: shift as u8,
402 offreg: offreg as u8,
403 },
404 }
405}
406
407pub fn opmemregsimdpost(idx: u32, offreg: u32, constoff: u32) -> Op {
408 if offreg == 31 {
409 opmemsoffpost(idx, constoff as _)
410 } else {
411 Op {
412 op_type: OpType::MemRegPost,
413 value: OpValue::Reg(idx as u8),
414 detail: OpDetail::MemReg {
415 sc: 0,
416 ext: Ext::Uxtx,
417 shift: 0,
418 offreg: offreg as u8,
419 },
420 }
421 }
422}
423
424pub fn opmeminc(idx: u32) -> Op {
425 Op {
426 op_type: OpType::MemInc,
427 value: OpValue::Reg(idx as u8),
428 detail: OpDetail::Uimm16(0),
429 }
430}
431
432pub fn opimmsmall(imm6: u32) -> Op {
433 Op {
434 op_type: OpType::ImmSmall,
435 value: OpValue::ImmShift {
436 mask: false,
437 shift: 0,
438 },
439 detail: OpDetail::Uimm16(imm6 as u16),
440 }
441}
442
443pub fn opsimm(imm: i32) -> Op {
444 Op {
445 op_type: OpType::Simm,
446 value: OpValue::ImmShift {
447 mask: false,
448 shift: 0,
449 },
450 detail: OpDetail::Simm16(imm as _),
451 }
452}
453
454pub fn opuimm(imm: u32) -> Op {
455 Op {
456 op_type: OpType::Uimm,
457 value: OpValue::ImmShift {
458 mask: false,
459 shift: 0,
460 },
461 detail: OpDetail::Uimm16(imm as _),
462 }
463}
464
465pub fn opuimmshift(imm: u32, msl: u32, shift: u32) -> Op {
466 Op {
467 op_type: OpType::UimmShift,
468 value: OpValue::ImmShift {
469 mask: msl != 0,
470 shift: shift as u8,
471 },
472 detail: OpDetail::Uimm16(imm as _),
473 }
474}
475
476pub fn opreladdr(ddi: &mut Inst, imm: i32) -> Op {
477 ddi.imm = Imm {
478 imm64: imm as i32 as i64 as u64,
479 };
480 Op {
481 op_type: OpType::ImmLarge,
482 value: OpValue::ImmShift {
483 mask: false,
484 shift: 0,
485 },
486 detail: OpDetail::Uimm16(0),
487 }
488}
489
490pub fn opimmlogical(ddi: &mut Inst, sf: u32, n: u32, immr: u32, imms: u32) -> Op {
491 ddi.imm = Imm {
492 imm64: immlogical(sf, n, immr, imms) as u64,
493 };
494 Op {
495 op_type: OpType::ImmLarge,
496 value: OpValue::ImmShift {
497 mask: false,
498 shift: 0,
499 },
500 detail: OpDetail::Uimm16(sf as u16),
501 }
502}
503
504pub fn opimmsimdmask(ddi: &mut Inst, imm8: u32) -> Op {
505 let mut res = 0u64;
506 for i in 0..8 {
507 if (imm8 & (1 << i)) != 0 {
508 res |= 0xff << (i * 8);
509 }
510 }
511 ddi.imm = Imm { imm64: res };
512 Op {
513 op_type: OpType::ImmLarge,
514 value: OpValue::ImmShift {
515 mask: false,
516 shift: 0,
517 },
518 detail: OpDetail::Uimm16(1),
519 }
520}
521
522pub fn opimmfloatzero(ddi: &mut Inst) -> Op {
523 ddi.imm = Imm { float8: 0.0 };
524 Op {
525 op_type: OpType::ImmFloat,
526 value: OpValue::ImmShift {
527 mask: false,
528 shift: 0,
529 },
530 detail: OpDetail::Uimm16(0x100),
531 }
532}
533
534pub fn opimmfloat(ddi: &mut Inst, imm8: u32) -> Op {
535 let res = (imm8 as u32 & 0x80) << 24
536 | if (imm8 & 0x40) != 0 {
537 0x3e000000
538 } else {
539 0x40000000
540 }
541 | ((imm8 & 0x3f) as u32) << 19;
542 ddi.imm = Imm {
543 float8: f64::from_bits(res as u64),
544 };
545 Op {
546 op_type: OpType::ImmFloat,
547 value: OpValue::ImmShift {
548 mask: false,
549 shift: 0,
550 },
551 detail: OpDetail::Uimm16(imm8 as u16),
552 }
553}
554
555pub fn opsysreg(reg: u32) -> Op {
556 Op {
557 op_type: OpType::Sysreg,
558 value: OpValue::ImmShift {
559 mask: false,
560 shift: 0,
561 },
562 detail: OpDetail::Sysreg(reg as u16),
563 }
564}
565
566pub fn opcond(cond: u32) -> Op {
567 Op {
568 op_type: OpType::Cond,
569 value: OpValue::ImmShift {
570 mask: false,
571 shift: 0,
572 },
573 detail: OpDetail::Cond(Cond::try_from(cond as u8).unwrap()),
574 }
575}
576
577include!("classifier.rs");