Skip to main content

asmkit/aarch64/
decoder.rs

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        // 0=b, 1=h, 2=s, 3=d, (4=q), 5=2b, 6=4b, 7=2h
140        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");