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");