riscv_dis/
lib.rs

1// TODO list
2// op-imm shift amounts
3// clean up the compressed stuff (esp MISC-ALU)
4// finish transition to from_instr32 from 'new'
5// make the various component structs smaller (8 bit IntReg/FloatReg etc.)
6
7use std::borrow::Cow;
8use std::fmt;
9use std::fmt::Debug;
10use std::marker::PhantomData;
11use std::mem;
12
13use byteorder::{ByteOrder, LittleEndian};
14
15#[derive(Copy, Clone, Debug, Eq, PartialEq)]
16pub enum Error {
17    TooShort,
18    UnhandledLength,
19    Unaligned,
20    InvalidOpcode,
21    InvalidSubop,
22    BadRegister,
23}
24
25pub type DisResult<T> = Result<T, Error>;
26
27#[derive(Copy, Clone, Debug)]
28pub enum Op<D: RiscVDisassembler> {
29    //
30    // RV32I
31    //
32
33    // LOAD
34    Load(LoadTypeInst<D>),
35
36    // MISC-MEM
37    Fence(ITypeIntInst<D>),
38    FenceI(ITypeIntInst<D>),
39
40    // OP-IMM
41    AddI(ITypeIntInst<D>),
42    SltI(ITypeIntInst<D>),
43    SltIU(ITypeIntInst<D>),
44    XorI(ITypeIntInst<D>),
45    OrI(ITypeIntInst<D>),
46    AndI(ITypeIntInst<D>),
47    SllI(ITypeIntInst<D>),
48    SrlI(ITypeIntInst<D>),
49    SraI(ITypeIntInst<D>),
50
51    // AUIPC
52    Auipc(UTypeInst<D>),
53
54    // STORE
55    Store(StoreTypeInst<D>),
56
57    // OP
58    Add(RTypeIntInst<D>),
59    Sll(RTypeIntInst<D>),
60    Slt(RTypeIntInst<D>),
61    SltU(RTypeIntInst<D>),
62    Xor(RTypeIntInst<D>),
63    Srl(RTypeIntInst<D>),
64    Or(RTypeIntInst<D>),
65    And(RTypeIntInst<D>),
66    Sub(RTypeIntInst<D>),
67    Sra(RTypeIntInst<D>),
68
69    // LUI
70    Lui(UTypeInst<D>),
71
72    // BRANCH
73    Beq(BTypeInst<D>),
74    Bne(BTypeInst<D>),
75    Blt(BTypeInst<D>),
76    Bge(BTypeInst<D>),
77    BltU(BTypeInst<D>),
78    BgeU(BTypeInst<D>),
79
80    // JALR
81    Jalr(ITypeIntInst<D>),
82
83    // JAL
84    Jal(JTypeInst<D>),
85
86    // SYSTEM
87    Ecall,
88    Ebreak,
89    Csrrw(CsrTypeInst<D>),
90    Csrrs(CsrTypeInst<D>),
91    Csrrc(CsrTypeInst<D>),
92    CsrrwI(CsrITypeInst<D>),
93    CsrrsI(CsrITypeInst<D>),
94    CsrrcI(CsrITypeInst<D>),
95
96    Uret,
97    Sret,
98    Mret,
99    Wfi,
100    SfenceVm(RTypeIntInst<D>),
101    SfenceVma(RTypeIntInst<D>),
102
103    //
104    // RV64I
105    //
106
107    // OP-IMM-32
108    AddIW(ITypeIntInst<D>),
109    SllIW(ITypeIntInst<D>),
110    SrlIW(ITypeIntInst<D>),
111    SraIW(ITypeIntInst<D>),
112
113    // OP-32
114    AddW(RTypeIntInst<D>),
115    SllW(RTypeIntInst<D>),
116    SrlW(RTypeIntInst<D>),
117    SubW(RTypeIntInst<D>),
118    SraW(RTypeIntInst<D>),
119
120    //
121    // RV32M
122    //
123
124    // OP
125    Mul(RTypeIntInst<D>),
126    MulH(RTypeIntInst<D>),
127    MulHSU(RTypeIntInst<D>),
128    MulHU(RTypeIntInst<D>),
129    Div(RTypeIntInst<D>),
130    DivU(RTypeIntInst<D>),
131    Rem(RTypeIntInst<D>),
132    RemU(RTypeIntInst<D>),
133
134    //
135    // RV64M
136    //
137
138    // OP-32
139    MulW(RTypeIntInst<D>),
140    DivW(RTypeIntInst<D>),
141    DivUW(RTypeIntInst<D>),
142    RemW(RTypeIntInst<D>),
143    RemUW(RTypeIntInst<D>),
144
145    //
146    // RV32A
147    //
148
149    // AMO
150    Lr(AtomicInst<D>),
151    Sc(AtomicInst<D>),
152    AmoSwap(AtomicInst<D>),
153    AmoAdd(AtomicInst<D>),
154    AmoXor(AtomicInst<D>),
155    AmoAnd(AtomicInst<D>),
156    AmoOr(AtomicInst<D>),
157    AmoMin(AtomicInst<D>),
158    AmoMax(AtomicInst<D>),
159    AmoMinU(AtomicInst<D>),
160    AmoMaxU(AtomicInst<D>),
161
162    //
163    // RV32F
164    //
165    LoadFp(FpMemInst<D>),
166    StoreFp(FpMemInst<D>),
167    Fmadd(FpMAddInst<D>),
168    Fmsub(FpMAddInst<D>),
169    Fnmsub(FpMAddInst<D>),
170    Fnmadd(FpMAddInst<D>),
171    Fadd(RTypeFloatRoundInst<D>),
172    Fsub(RTypeFloatRoundInst<D>),
173    Fmul(RTypeFloatRoundInst<D>),
174    Fdiv(RTypeFloatRoundInst<D>),
175    Fsqrt(RTypeFloatRoundInst<D>),
176    Fsgnj(RTypeFloatInst<D>),
177    Fsgnjn(RTypeFloatInst<D>),
178    Fsgnjx(RTypeFloatInst<D>),
179    Fmin(RTypeFloatInst<D>),
180    Fmax(RTypeFloatInst<D>),
181    Fle(RTypeFloatCmpInst<D>),
182    Flt(RTypeFloatCmpInst<D>),
183    Feq(RTypeFloatCmpInst<D>),
184    Fcvt(FpCvtInst<D>),
185    FcvtToInt(FpCvtToIntInst<D>),
186    FcvtFromInt(FpCvtFromIntInst<D>),
187    FmvToInt(FpMvToIntInst<D>),
188    FmvFromInt(FpMvFromIntInst<D>),
189    Fclass(FpClassInst<D>),
190}
191
192pub trait Register {
193    fn new(id: u32) -> Self;
194
195    fn id(&self) -> u32;
196    fn valid(&self) -> bool;
197}
198
199#[derive(Copy, Clone, Debug, PartialEq, Eq)]
200pub enum RoundMode {
201    RoundNearestEven,
202    RoundTowardZero,
203    RoundDown,
204    RoundUp,
205    RoundMaxMagnitude,
206    Dynamic,
207}
208
209#[derive(Copy, Clone, Debug, Eq, PartialEq)]
210pub struct IntReg<D: RiscVDisassembler> {
211    reg_id: u8,
212    _dis: PhantomData<D>,
213}
214
215impl<D: RiscVDisassembler> Register for IntReg<D> {
216    #[inline(always)]
217    fn new(id: u32) -> Self {
218        let ret = Self {
219            reg_id: id as u8,
220            _dis: PhantomData,
221        };
222
223        debug_assert!(ret.valid());
224
225        ret
226    }
227
228    #[inline(always)]
229    fn id(&self) -> u32 {
230        self.reg_id as u32
231    }
232
233    #[inline(always)]
234    fn valid(&self) -> bool {
235        (self.reg_id as u32) < <D::RegFile as RegFile>::int_reg_count()
236    }
237}
238
239#[derive(Copy, Clone, Debug, Eq, PartialEq)]
240pub struct FloatReg<D: RiscVDisassembler> {
241    reg_id: u8,
242    _dis: PhantomData<D>,
243}
244
245impl<D: RiscVDisassembler> Register for FloatReg<D> {
246    #[inline(always)]
247    fn new(id: u32) -> Self {
248        let ret = Self {
249            reg_id: id as u8,
250            _dis: PhantomData,
251        };
252
253        debug_assert!(ret.valid());
254
255        ret
256    }
257
258    #[inline(always)]
259    fn id(&self) -> u32 {
260        self.reg_id as u32
261    }
262
263    #[inline(always)]
264    fn valid(&self) -> bool {
265        (self.reg_id as u32) < <D::RegFile as RegFile>::int_reg_count()
266    }
267}
268
269pub trait IntRegType: Sized {
270    #[inline(always)]
271    fn width() -> usize {
272        mem::size_of::<Self>()
273    }
274}
275
276pub trait FloatRegType: Sized {
277    #[inline(always)]
278    fn width() -> usize {
279        mem::size_of::<Self>()
280    }
281
282    #[inline(always)]
283    fn present() -> bool {
284        mem::size_of::<Self>() != 0
285    }
286}
287
288impl IntRegType for u32 {}
289impl IntRegType for u64 {}
290impl FloatRegType for () {}
291impl FloatRegType for f32 {}
292impl FloatRegType for f64 {}
293
294pub trait RegFile: Debug + Sized + Copy + Clone + Send + Sync + 'static {
295    type Int: IntRegType;
296    type Float: FloatRegType;
297
298    #[inline(always)]
299    fn int_reg_count() -> u32 {
300        32
301    }
302}
303
304#[derive(Copy, Clone, Debug)]
305pub struct Rv32IRegs;
306impl RegFile for Rv32IRegs {
307    type Int = u32;
308    type Float = ();
309}
310
311#[derive(Copy, Clone, Debug)]
312pub struct Rv32ERegs;
313impl RegFile for Rv32ERegs {
314    type Int = u32;
315    type Float = ();
316
317    #[inline(always)]
318    fn int_reg_count() -> u32 {
319        16
320    }
321}
322
323#[derive(Copy, Clone, Debug)]
324pub struct Rv32GRegs;
325impl RegFile for Rv32GRegs {
326    type Int = u32;
327    type Float = f64;
328}
329
330#[derive(Copy, Clone, Debug)]
331pub struct Rv64GRegs;
332impl RegFile for Rv64GRegs {
333    type Int = u64;
334    type Float = f64;
335}
336
337pub enum Operand<D: RiscVDisassembler> {
338    R(IntReg<D>),
339    F(FloatReg<D>),
340    I(i32),
341    M(i32, IntReg<D>), // reg + displacement
342    RM(RoundMode),
343}
344
345impl<D: RiscVDisassembler> fmt::Display for Operand<D> {
346    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
347        match *self {
348            Operand::R(r) => write!(f, "x{}", r.id()),
349            Operand::F(r) => write!(f, "f{}", r.id()),
350            Operand::I(i) => match i {
351                -0x80000..=-1 => write!(f, "-{:x}", -i),
352                _ => write!(f, "{:x}", i),
353            },
354            Operand::M(i, r) => {
355                if i < 0 {
356                    write!(f, "-{:x}(x{})", -i, r.id())
357                } else {
358                    write!(f, "{:x}(x{})", i, r.id())
359                }
360            }
361            Operand::RM(r) => write!(f, "{}", r.name()),
362        }
363    }
364}
365
366#[derive(Copy, Clone, Debug)]
367struct Instr32(u32);
368impl Instr32 {
369    #[inline(always)]
370    fn extract_bits(self, start_bit: u32, width: u32) -> u32 {
371        self.0.wrapping_shr(start_bit) & 1u32.wrapping_shl(width).wrapping_sub(1)
372    }
373
374    #[inline(always)]
375    fn opcode(self) -> u32 {
376        self.extract_bits(0, 7)
377    }
378
379    #[inline(always)]
380    fn rd(self) -> u32 {
381        self.extract_bits(7, 5)
382    }
383
384    #[inline(always)]
385    fn rs1(self) -> u32 {
386        self.extract_bits(15, 5)
387    }
388
389    #[inline(always)]
390    fn rs2(self) -> u32 {
391        self.extract_bits(20, 5)
392    }
393
394    #[inline(always)]
395    fn rs3(self) -> u32 {
396        self.extract_bits(27, 5)
397    }
398
399    #[inline(always)]
400    fn funct3(self) -> u32 {
401        self.extract_bits(12, 3)
402    }
403
404    #[inline(always)]
405    fn funct7(self) -> u32 {
406        self.extract_bits(25, 7)
407    }
408
409    #[inline(always)]
410    fn rm(self) -> u32 {
411        self.extract_bits(12, 3)
412    }
413
414    #[inline(always)]
415    fn fsize(self) -> u32 {
416        self.extract_bits(25, 2)
417    }
418
419    #[inline(always)]
420    fn fop(self) -> u32 {
421        self.extract_bits(27, 5)
422    }
423
424    #[inline(always)]
425    fn i_imm(self) -> i32 {
426        (self.0 as i32) >> 20
427    }
428
429    #[inline(always)]
430    fn s_imm(self) -> i32 {
431        (((self.0 as i32) >> 20) & !0x1f) | self.extract_bits(7, 5) as i32
432    }
433
434    #[inline(always)]
435    fn b_imm(self) -> i32 {
436        let b_imm = self.s_imm();
437        (b_imm & !0x801) | ((b_imm & 1) << 11)
438    }
439
440    #[inline(always)]
441    fn u_imm(self) -> i32 {
442        (self.0 & !0xfff) as i32
443    }
444
445    #[inline(always)]
446    fn j_imm(self) -> i32 {
447        let mut j_imm = (((self.0 as i32) >> 11) as u32) & 0xfff00000;
448        j_imm |= 0x000ff000 & self.0;
449        j_imm |= self.extract_bits(20, 11);
450        ((j_imm & !0x801) | ((j_imm & 1) << 11)) as i32
451    }
452}
453
454impl RoundMode {
455    fn from_bits(bits: u32) -> DisResult<RoundMode> {
456        match bits {
457            0b000 => Ok(RoundMode::RoundNearestEven),
458            0b001 => Ok(RoundMode::RoundTowardZero),
459            0b010 => Ok(RoundMode::RoundDown),
460            0b011 => Ok(RoundMode::RoundUp),
461            0b100 => Ok(RoundMode::RoundMaxMagnitude),
462            0b111 => Ok(RoundMode::Dynamic),
463            _ => Err(Error::InvalidSubop),
464        }
465    }
466
467    pub fn name(&self) -> &'static str {
468        match self {
469            RoundMode::RoundNearestEven => "rne",
470            RoundMode::RoundTowardZero => "rtz",
471            RoundMode::RoundDown => "rdn",
472            RoundMode::RoundUp => "rup",
473            RoundMode::RoundMaxMagnitude => "rmm",
474            RoundMode::Dynamic => "dyn",
475        }
476    }
477
478    pub fn all() -> &'static [RoundMode] {
479        &[
480            RoundMode::RoundNearestEven,
481            RoundMode::RoundTowardZero,
482            RoundMode::RoundDown,
483            RoundMode::RoundUp,
484            RoundMode::RoundMaxMagnitude,
485            RoundMode::Dynamic,
486        ]
487    }
488}
489
490#[derive(Copy, Clone, Debug)]
491pub struct LoadTypeInst<D: RiscVDisassembler> {
492    width: u8,
493    zx: bool,
494    rd: IntReg<D>,
495    rs1: IntReg<D>,
496    imm: i16,
497    _dis: PhantomData<D>,
498}
499
500impl<D: RiscVDisassembler> LoadTypeInst<D> {
501    #[inline(always)]
502    fn new(width: usize, zx: bool, rd: IntReg<D>, rs1: IntReg<D>, imm: i32) -> DisResult<Self> {
503        if width + zx as usize > <D::RegFile as RegFile>::Int::width() {
504            return Err(Error::InvalidSubop);
505        } else if !rd.valid() || !rs1.valid() {
506            return Err(Error::BadRegister);
507        }
508
509        Ok(Self {
510            width: width as u8,
511            zx,
512            rd,
513            rs1,
514            imm: imm as i16,
515            _dis: PhantomData,
516        })
517    }
518
519    #[inline(always)]
520    fn from_instr32(inst: Instr32) -> DisResult<Self> {
521        let width = 1u32.wrapping_shl(inst.extract_bits(12, 2)) as u8;
522        let zx = inst.extract_bits(14, 1) == 1;
523        let rd = IntReg::new(inst.rd());
524        let rs1 = IntReg::new(inst.rs1());
525
526        if width as usize + zx as usize > <D::RegFile as RegFile>::Int::width() {
527            return Err(Error::InvalidSubop);
528        } else if !rd.valid() || !rs1.valid() {
529            return Err(Error::BadRegister);
530        }
531
532        Ok(Self {
533            width,
534            zx,
535            rd,
536            rs1,
537            imm: inst.i_imm() as i16,
538            _dis: PhantomData,
539        })
540    }
541
542    #[inline(always)]
543    pub fn width(&self) -> usize {
544        self.width as usize
545    }
546
547    #[inline(always)]
548    pub fn zx(&self) -> bool {
549        self.zx
550    }
551
552    #[inline(always)]
553    pub fn rd(&self) -> IntReg<D> {
554        self.rd
555    }
556
557    #[inline(always)]
558    pub fn rs1(&self) -> IntReg<D> {
559        self.rs1
560    }
561
562    #[inline(always)]
563    pub fn imm(&self) -> i32 {
564        self.imm as i32
565    }
566}
567
568#[derive(Copy, Clone, Debug)]
569pub struct StoreTypeInst<D: RiscVDisassembler> {
570    width: u8,
571    rs1: IntReg<D>,
572    rs2: IntReg<D>,
573    imm: i16,
574    _dis: PhantomData<D>,
575}
576
577impl<D: RiscVDisassembler> StoreTypeInst<D> {
578    #[inline(always)]
579    fn new(width: usize, rs2: IntReg<D>, rs1: IntReg<D>, imm: i32) -> DisResult<Self> {
580        if width > <D::RegFile as RegFile>::Int::width() {
581            return Err(Error::InvalidSubop);
582        } else if !rs1.valid() || !rs2.valid() {
583            return Err(Error::BadRegister);
584        }
585
586        Ok(Self {
587            width: width as u8,
588            rs1,
589            rs2,
590            imm: imm as i16,
591            _dis: PhantomData,
592        })
593    }
594
595    #[inline(always)]
596    fn from_instr32(inst: Instr32) -> DisResult<Self> {
597        let width = 1u32.wrapping_shl(inst.extract_bits(12, 3)) as u8;
598        let rs1 = IntReg::new(inst.rs1());
599        let rs2 = IntReg::new(inst.rs2());
600
601        if width as usize > <D::RegFile as RegFile>::Int::width() {
602            return Err(Error::InvalidSubop);
603        } else if !rs1.valid() || !rs2.valid() {
604            return Err(Error::BadRegister);
605        }
606
607        Ok(Self {
608            width,
609            rs1,
610            rs2,
611            imm: inst.s_imm() as i16,
612            _dis: PhantomData,
613        })
614    }
615
616    #[inline(always)]
617    pub fn width(&self) -> usize {
618        self.width as usize
619    }
620
621    #[inline(always)]
622    pub fn rs1(&self) -> IntReg<D> {
623        self.rs1
624    }
625
626    #[inline(always)]
627    pub fn rs2(&self) -> IntReg<D> {
628        self.rs2
629    }
630
631    #[inline(always)]
632    pub fn imm(&self) -> i32 {
633        self.imm as i32
634    }
635}
636
637#[derive(Copy, Clone, Debug)]
638pub struct ITypeInst<Rd, Rs1>
639where
640    Rd: Register,
641    Rs1: Register,
642{
643    inst: Instr32,
644    _rd: PhantomData<Rd>,
645    _rs1: PhantomData<Rs1>,
646}
647
648pub type ITypeIntInst<D> = ITypeInst<IntReg<D>, IntReg<D>>;
649
650impl<Rd, Rs1> ITypeInst<Rd, Rs1>
651where
652    Rd: Register,
653    Rs1: Register,
654{
655    #[inline(always)]
656    fn new(inst: Instr32) -> DisResult<Self> {
657        let ret = Self {
658            inst,
659            _rd: PhantomData,
660            _rs1: PhantomData,
661        };
662
663        if !ret.rd().valid() || !ret.rs1().valid() {
664            return Err(Error::BadRegister);
665        }
666
667        Ok(ret)
668    }
669
670    #[inline(always)]
671    fn from_ops(rd: Rd, rs1: Rs1, imm: i32) -> Self {
672        let imm = imm as u32;
673        let raw: u32 = (imm << 20) | (rd.id() << 7) | (rs1.id() << 15);
674
675        Self {
676            inst: Instr32(raw),
677            _rd: PhantomData,
678            _rs1: PhantomData,
679        }
680    }
681
682    #[inline(always)]
683    pub fn rd(&self) -> Rd {
684        Rd::new(self.inst.rd())
685    }
686
687    #[inline(always)]
688    pub fn rs1(&self) -> Rs1 {
689        Rs1::new(self.inst.rs1())
690    }
691
692    #[inline(always)]
693    pub fn imm(&self) -> i32 {
694        self.inst.i_imm()
695    }
696}
697
698#[derive(Copy, Clone, Debug)]
699pub struct CsrITypeInst<D: RiscVDisassembler> {
700    inst: Instr32,
701    _dis: PhantomData<D>,
702}
703
704impl<D: RiscVDisassembler> CsrITypeInst<D> {
705    #[inline(always)]
706    fn new(inst: Instr32) -> DisResult<Self> {
707        let ret = Self {
708            inst,
709            _dis: PhantomData,
710        };
711
712        if !ret.rd().valid() {
713            return Err(Error::BadRegister);
714        }
715
716        Ok(ret)
717    }
718
719    #[inline(always)]
720    pub fn rd(&self) -> IntReg<D> {
721        IntReg::new(self.inst.rd())
722    }
723
724    #[inline(always)]
725    pub fn imm(&self) -> u32 {
726        self.inst.rs1()
727    }
728
729    #[inline(always)]
730    pub fn csr(&self) -> u32 {
731        self.inst.i_imm() as u32 & 0xfff
732    }
733}
734
735#[derive(Copy, Clone, Debug)]
736pub struct CsrTypeInst<D: RiscVDisassembler> {
737    inst: Instr32,
738    _dis: PhantomData<D>,
739    _rs1: PhantomData<IntReg<D>>,
740}
741
742impl<D: RiscVDisassembler> CsrTypeInst<D> {
743    #[inline(always)]
744    fn new(inst: Instr32) -> DisResult<Self> {
745        let ret = Self {
746            inst,
747            _dis: PhantomData,
748            _rs1: PhantomData,
749        };
750
751        if !ret.rd().valid() || !ret.rs1().valid() {
752            return Err(Error::BadRegister);
753        }
754
755        Ok(ret)
756    }
757
758    #[inline(always)]
759    pub fn rd(&self) -> IntReg<D> {
760        IntReg::new(self.inst.rd())
761    }
762
763    #[inline(always)]
764    pub fn rs1(&self) -> IntReg<D> {
765        IntReg::new(self.inst.rs1())
766    }
767
768    #[inline(always)]
769    pub fn csr(&self) -> u32 {
770        self.inst.i_imm() as u32 & 0xfff
771    }
772}
773
774#[derive(Copy, Clone, Debug)]
775pub struct RTypeInst<Rd, Rs1, Rs2>
776where
777    Rd: Register,
778    Rs1: Register,
779    Rs2: Register,
780{
781    inst: Instr32,
782    _rd: PhantomData<Rd>,
783    _rs1: PhantomData<Rs1>,
784    _rs2: PhantomData<Rs2>,
785}
786
787pub type RTypeIntInst<D> = RTypeInst<IntReg<D>, IntReg<D>, IntReg<D>>;
788
789impl<Rd, Rs1, Rs2> RTypeInst<Rd, Rs1, Rs2>
790where
791    Rd: Register,
792    Rs1: Register,
793    Rs2: Register,
794{
795    #[inline(always)]
796    fn new(inst: Instr32) -> DisResult<Self> {
797        let ret = Self {
798            inst,
799            _rd: PhantomData,
800            _rs1: PhantomData,
801            _rs2: PhantomData,
802        };
803
804        if !ret.rd().valid() || !ret.rs1().valid() || !ret.rs2().valid() {
805            return Err(Error::BadRegister);
806        }
807
808        Ok(ret)
809    }
810
811    #[inline(always)]
812    fn from_ops(rd: Rd, rs1: Rs1, rs2: Rs2) -> Self {
813        let raw: u32 = (rd.id() << 7) | (rs1.id() << 15) | (rs2.id() << 20);
814
815        Self {
816            inst: Instr32(raw),
817            _rd: PhantomData,
818            _rs1: PhantomData,
819            _rs2: PhantomData,
820        }
821    }
822
823    #[inline(always)]
824    pub fn rd(&self) -> Rd {
825        Rd::new(self.inst.rd())
826    }
827
828    #[inline(always)]
829    pub fn rs1(&self) -> Rs1 {
830        Rs1::new(self.inst.rs1())
831    }
832
833    #[inline(always)]
834    pub fn rs2(&self) -> Rs2 {
835        Rs2::new(self.inst.rs2())
836    }
837}
838
839#[derive(Copy, Clone, Debug)]
840pub struct RTypeFloatInst<D: RiscVDisassembler> {
841    width: u8,
842    rd: FloatReg<D>,
843    rs1: FloatReg<D>,
844    rs2: FloatReg<D>,
845}
846
847impl<D: RiscVDisassembler> RTypeFloatInst<D> {
848    #[inline(always)]
849    fn from_instr32(inst: Instr32) -> DisResult<Self> {
850        let width = match inst.fsize() {
851            0b00 => 4,
852            0b01 => 8,
853            0b11 => 16,
854            _ => return Err(Error::InvalidSubop),
855        };
856
857        if width > <D::RegFile as RegFile>::Float::width() {
858            return Err(Error::InvalidSubop);
859        }
860
861        let rd = FloatReg::new(inst.rd());
862        let rs1 = FloatReg::new(inst.rs1());
863        let rs2 = FloatReg::new(inst.rs2());
864
865        if !rd.valid() || !rs1.valid() || !rs2.valid() {
866            return Err(Error::BadRegister);
867        }
868
869        Ok(Self {
870            width: width as u8,
871            rd,
872            rs1,
873            rs2,
874        })
875    }
876
877    #[inline(always)]
878    pub fn width(&self) -> u8 {
879        self.width
880    }
881
882    #[inline(always)]
883    pub fn rd(&self) -> FloatReg<D> {
884        self.rd
885    }
886
887    #[inline(always)]
888    pub fn rs1(&self) -> FloatReg<D> {
889        self.rs1
890    }
891
892    #[inline(always)]
893    pub fn rs2(&self) -> FloatReg<D> {
894        self.rs2
895    }
896}
897
898#[derive(Copy, Clone, Debug)]
899pub struct RTypeFloatCmpInst<D: RiscVDisassembler> {
900    width: u8,
901    rd: IntReg<D>,
902    rs1: FloatReg<D>,
903    rs2: FloatReg<D>,
904}
905
906impl<D: RiscVDisassembler> RTypeFloatCmpInst<D> {
907    #[inline(always)]
908    fn from_instr32(inst: Instr32) -> DisResult<Self> {
909        let width = match inst.fsize() {
910            0b00 => 4,
911            0b01 => 8,
912            0b11 => 16,
913            _ => return Err(Error::InvalidSubop),
914        };
915
916        if width > <D::RegFile as RegFile>::Float::width() {
917            return Err(Error::InvalidSubop);
918        }
919
920        let rd = IntReg::new(inst.rd());
921        let rs1 = FloatReg::new(inst.rs1());
922        let rs2 = FloatReg::new(inst.rs2());
923
924        if !rd.valid() || !rs1.valid() || !rs2.valid() {
925            return Err(Error::BadRegister);
926        }
927
928        Ok(Self {
929            width: width as u8,
930            rd,
931            rs1,
932            rs2,
933        })
934    }
935
936    #[inline(always)]
937    pub fn width(&self) -> u8 {
938        self.width
939    }
940
941    #[inline(always)]
942    pub fn rd(&self) -> IntReg<D> {
943        self.rd
944    }
945
946    #[inline(always)]
947    pub fn rs1(&self) -> FloatReg<D> {
948        self.rs1
949    }
950
951    #[inline(always)]
952    pub fn rs2(&self) -> FloatReg<D> {
953        self.rs2
954    }
955}
956
957#[derive(Copy, Clone, Debug)]
958pub struct RTypeFloatRoundInst<D: RiscVDisassembler> {
959    width: u8,
960    rd: FloatReg<D>,
961    rs1: FloatReg<D>,
962    rs2: FloatReg<D>,
963    rm: RoundMode,
964}
965
966impl<D: RiscVDisassembler> RTypeFloatRoundInst<D> {
967    #[inline(always)]
968    fn from_instr32(inst: Instr32) -> DisResult<Self> {
969        let width = match inst.fsize() {
970            0b00 => 4,
971            0b01 => 8,
972            0b11 => 16,
973            _ => return Err(Error::InvalidSubop),
974        };
975
976        if width > <D::RegFile as RegFile>::Float::width() {
977            return Err(Error::InvalidSubop);
978        }
979
980        let rd = FloatReg::new(inst.rd());
981        let rs1 = FloatReg::new(inst.rs1());
982        let rs2 = FloatReg::new(inst.rs2());
983        let rm = RoundMode::from_bits(inst.rm())?;
984
985        if !rd.valid() || !rs1.valid() || !rs2.valid() {
986            return Err(Error::BadRegister);
987        }
988
989        Ok(Self {
990            width: width as u8,
991            rd,
992            rs1,
993            rs2,
994            rm,
995        })
996    }
997
998    #[inline(always)]
999    pub fn width(&self) -> u8 {
1000        self.width
1001    }
1002
1003    #[inline(always)]
1004    pub fn rd(&self) -> FloatReg<D> {
1005        self.rd
1006    }
1007
1008    #[inline(always)]
1009    pub fn rs1(&self) -> FloatReg<D> {
1010        self.rs1
1011    }
1012
1013    #[inline(always)]
1014    pub fn rs2(&self) -> FloatReg<D> {
1015        self.rs2
1016    }
1017
1018    #[inline(always)]
1019    pub fn rm(&self) -> RoundMode {
1020        self.rm
1021    }
1022}
1023
1024#[derive(Copy, Clone, Debug)]
1025pub struct BTypeInst<D: RiscVDisassembler> {
1026    rs1: IntReg<D>,
1027    rs2: IntReg<D>,
1028    imm: i16,
1029    _dis: PhantomData<D>,
1030}
1031
1032impl<D: RiscVDisassembler> BTypeInst<D> {
1033    #[inline(always)]
1034    fn new(rs1: IntReg<D>, rs2: IntReg<D>, imm: i32) -> DisResult<Self> {
1035        if !rs1.valid() || !rs2.valid() {
1036            return Err(Error::BadRegister);
1037        }
1038
1039        Ok(Self {
1040            rs1,
1041            rs2,
1042            imm: imm as i16,
1043            _dis: PhantomData,
1044        })
1045    }
1046
1047    #[inline(always)]
1048    fn from_instr32(inst: Instr32) -> DisResult<Self> {
1049        let rs1 = IntReg::new(inst.rs1());
1050        let rs2 = IntReg::new(inst.rs2());
1051
1052        if !rs1.valid() || !rs2.valid() {
1053            return Err(Error::BadRegister);
1054        }
1055
1056        Ok(Self {
1057            rs1,
1058            rs2,
1059            imm: inst.b_imm() as i16,
1060            _dis: PhantomData,
1061        })
1062    }
1063
1064    #[inline(always)]
1065    pub fn rs1(&self) -> IntReg<D> {
1066        self.rs1
1067    }
1068
1069    #[inline(always)]
1070    pub fn rs2(&self) -> IntReg<D> {
1071        self.rs2
1072    }
1073
1074    #[inline(always)]
1075    pub fn imm(&self) -> i32 {
1076        self.imm as i32
1077    }
1078}
1079
1080#[derive(Copy, Clone, Debug)]
1081pub struct UTypeInst<D: RiscVDisassembler> {
1082    rd: IntReg<D>,
1083    imm: i32,
1084    _dis: PhantomData<D>,
1085}
1086
1087impl<D: RiscVDisassembler> UTypeInst<D> {
1088    #[inline(always)]
1089    fn new(rd: IntReg<D>, imm: i32) -> DisResult<Self> {
1090        if !rd.valid() {
1091            return Err(Error::BadRegister);
1092        }
1093
1094        Ok(Self {
1095            rd,
1096            imm,
1097            _dis: PhantomData,
1098        })
1099    }
1100
1101    #[inline(always)]
1102    fn from_instr32(inst: Instr32) -> DisResult<Self> {
1103        let rd = IntReg::new(inst.rd());
1104
1105        if !rd.valid() {
1106            return Err(Error::BadRegister);
1107        }
1108
1109        Ok(Self {
1110            rd,
1111            imm: inst.u_imm(),
1112            _dis: PhantomData,
1113        })
1114    }
1115
1116    #[inline(always)]
1117    pub fn rd(&self) -> IntReg<D> {
1118        self.rd
1119    }
1120
1121    #[inline(always)]
1122    pub fn imm(&self) -> i32 {
1123        self.imm
1124    }
1125}
1126
1127#[derive(Copy, Clone, Debug)]
1128pub struct JTypeInst<D: RiscVDisassembler> {
1129    rd: IntReg<D>,
1130    imm: i32,
1131    _dis: PhantomData<D>,
1132}
1133
1134impl<D: RiscVDisassembler> JTypeInst<D> {
1135    #[inline(always)]
1136    fn new(rd: IntReg<D>, imm: i32) -> DisResult<Self> {
1137        if !rd.valid() {
1138            return Err(Error::BadRegister);
1139        }
1140
1141        Ok(Self {
1142            rd,
1143            imm,
1144            _dis: PhantomData,
1145        })
1146    }
1147
1148    #[inline(always)]
1149    fn from_instr32(inst: Instr32) -> DisResult<Self> {
1150        let rd = IntReg::new(inst.rd());
1151
1152        if !rd.valid() {
1153            return Err(Error::BadRegister);
1154        }
1155
1156        Ok(Self {
1157            rd,
1158            imm: inst.j_imm(),
1159            _dis: PhantomData,
1160        })
1161    }
1162
1163    #[inline(always)]
1164    pub fn rd(&self) -> IntReg<D> {
1165        self.rd
1166    }
1167
1168    #[inline(always)]
1169    pub fn imm(&self) -> i32 {
1170        self.imm
1171    }
1172}
1173
1174#[derive(Copy, Clone, Debug)]
1175pub struct AtomicInst<D: RiscVDisassembler> {
1176    inst: Instr32,
1177    _dis: PhantomData<D>,
1178}
1179
1180impl<D: RiscVDisassembler> AtomicInst<D> {
1181    #[inline(always)]
1182    fn new(inst: Instr32) -> DisResult<Self> {
1183        let ret = Self {
1184            inst,
1185            _dis: PhantomData,
1186        };
1187
1188        let width = ret.width();
1189
1190        if width < 4 || width > <D::RegFile as RegFile>::Int::width() {
1191            return Err(Error::InvalidSubop);
1192        } else if !ret.rd().valid() || !ret.rs1().valid() || !ret.rs2().valid() {
1193            return Err(Error::BadRegister);
1194        }
1195
1196        Ok(ret)
1197    }
1198
1199    #[inline(always)]
1200    pub fn rd(&self) -> IntReg<D> {
1201        IntReg::new(self.inst.rd())
1202    }
1203
1204    #[inline(always)]
1205    pub fn rs1(&self) -> IntReg<D> {
1206        IntReg::new(self.inst.rs1())
1207    }
1208
1209    #[inline(always)]
1210    pub fn rs2(&self) -> IntReg<D> {
1211        IntReg::new(self.inst.rs2())
1212    }
1213
1214    #[inline(always)]
1215    pub fn width(&self) -> usize {
1216        1usize.wrapping_shl(self.inst.funct3())
1217    }
1218
1219    #[inline(always)]
1220    pub fn aq(&self) -> bool {
1221        self.inst.extract_bits(26, 1) != 0
1222    }
1223
1224    #[inline(always)]
1225    pub fn rl(&self) -> bool {
1226        self.inst.extract_bits(25, 1) != 0
1227    }
1228}
1229
1230#[derive(Copy, Clone, Debug)]
1231pub struct FpMemInst<D: RiscVDisassembler> {
1232    width: u8,
1233    fr: FloatReg<D>,
1234    rs1: IntReg<D>,
1235    imm: i16,
1236    _dis: PhantomData<D>,
1237}
1238
1239impl<D: RiscVDisassembler> FpMemInst<D> {
1240    #[inline(always)]
1241    fn new(width: usize, fr: FloatReg<D>, rs1: IntReg<D>, imm: i32) -> DisResult<Self> {
1242        if width > <D::RegFile as RegFile>::Float::width() {
1243            return Err(Error::InvalidSubop);
1244        } else if !fr.valid() || !rs1.valid() {
1245            return Err(Error::BadRegister);
1246        }
1247
1248        Ok(Self {
1249            width: width as u8,
1250            fr,
1251            rs1,
1252            imm: imm as i16,
1253            _dis: PhantomData,
1254        })
1255    }
1256
1257    #[inline(always)]
1258    pub fn width(&self) -> usize {
1259        self.width as usize
1260    }
1261
1262    #[inline(always)]
1263    pub fn fr(&self) -> FloatReg<D> {
1264        self.fr
1265    }
1266
1267    #[inline(always)]
1268    pub fn rs1(&self) -> IntReg<D> {
1269        self.rs1
1270    }
1271
1272    #[inline(always)]
1273    pub fn imm(&self) -> i32 {
1274        self.imm as i32
1275    }
1276}
1277
1278#[derive(Copy, Clone, Debug)]
1279pub struct FpMAddInst<D: RiscVDisassembler> {
1280    width: u8,
1281    rd: FloatReg<D>,
1282    rs1: FloatReg<D>,
1283    rs2: FloatReg<D>,
1284    rs3: FloatReg<D>,
1285    rm: RoundMode,
1286    _dis: PhantomData<D>,
1287}
1288
1289impl<D: RiscVDisassembler> FpMAddInst<D> {
1290    #[inline(always)]
1291    fn from_instr32(inst: Instr32) -> DisResult<Self> {
1292        let width = match inst.fsize() {
1293            0b00 => 4,
1294            0b01 => 8,
1295            0b11 => 16,
1296            _ => return Err(Error::InvalidSubop),
1297        };
1298
1299        if width > <D::RegFile as RegFile>::Float::width() {
1300            return Err(Error::InvalidSubop);
1301        }
1302
1303        let rd = FloatReg::new(inst.rd());
1304        let rs1 = FloatReg::new(inst.rs1());
1305        let rs2 = FloatReg::new(inst.rs2());
1306        let rs3 = FloatReg::new(inst.rs3());
1307        let rm = RoundMode::from_bits(inst.rm())?;
1308
1309        if !rd.valid() || !rs1.valid() || !rs2.valid() || !rs3.valid() {
1310            return Err(Error::BadRegister);
1311        }
1312
1313        Ok(Self {
1314            width: width as u8,
1315            rd,
1316            rs1,
1317            rs2,
1318            rs3,
1319            rm,
1320            _dis: PhantomData,
1321        })
1322    }
1323
1324    #[inline(always)]
1325    pub fn width(&self) -> u8 {
1326        self.width
1327    }
1328
1329    #[inline(always)]
1330    pub fn rd(&self) -> FloatReg<D> {
1331        self.rd
1332    }
1333
1334    #[inline(always)]
1335    pub fn rs1(&self) -> FloatReg<D> {
1336        self.rs1
1337    }
1338
1339    #[inline(always)]
1340    pub fn rs2(&self) -> FloatReg<D> {
1341        self.rs2
1342    }
1343
1344    #[inline(always)]
1345    pub fn rs3(&self) -> FloatReg<D> {
1346        self.rs3
1347    }
1348
1349    #[inline(always)]
1350    pub fn rm(&self) -> RoundMode {
1351        self.rm
1352    }
1353}
1354
1355#[derive(Copy, Clone, Debug)]
1356pub struct FpCvtInst<D: RiscVDisassembler> {
1357    rd_width: u8,
1358    rs1_width: u8,
1359    rd: FloatReg<D>,
1360    rs1: FloatReg<D>,
1361    rm: RoundMode,
1362    _dis: PhantomData<D>,
1363}
1364
1365impl<D: RiscVDisassembler> FpCvtInst<D> {
1366    #[inline(always)]
1367    fn new(
1368        rd: FloatReg<D>,
1369        rd_width: u8,
1370        rs1: FloatReg<D>,
1371        rs1_width: u8,
1372        rm: RoundMode,
1373    ) -> DisResult<Self> {
1374        Ok(Self {
1375            rd_width,
1376            rs1_width,
1377            rd,
1378            rs1,
1379            rm,
1380            _dis: PhantomData,
1381        })
1382    }
1383
1384    #[inline(always)]
1385    pub fn rd_width(&self) -> u8 {
1386        self.rd_width
1387    }
1388
1389    #[inline(always)]
1390    pub fn rs1_width(&self) -> u8 {
1391        self.rs1_width
1392    }
1393
1394    #[inline(always)]
1395    pub fn rd(&self) -> FloatReg<D> {
1396        self.rd
1397    }
1398
1399    #[inline(always)]
1400    pub fn rs1(&self) -> FloatReg<D> {
1401        self.rs1
1402    }
1403
1404    #[inline(always)]
1405    pub fn rm(&self) -> RoundMode {
1406        self.rm
1407    }
1408}
1409
1410#[derive(Copy, Clone, Debug)]
1411pub struct FpCvtToIntInst<D: RiscVDisassembler> {
1412    rd_width: u8,
1413    rs1_width: u8,
1414    zx: bool,
1415    rd: IntReg<D>,
1416    rs1: FloatReg<D>,
1417    rm: RoundMode,
1418    _dis: PhantomData<D>,
1419}
1420
1421impl<D: RiscVDisassembler> FpCvtToIntInst<D> {
1422    #[inline(always)]
1423    fn new(
1424        rd: IntReg<D>,
1425        rd_width: u8,
1426        zx: bool,
1427        rs1: FloatReg<D>,
1428        rs1_width: u8,
1429        rm: RoundMode,
1430    ) -> DisResult<Self> {
1431        Ok(Self {
1432            rd_width,
1433            rs1_width,
1434            zx,
1435            rd,
1436            rs1,
1437            rm,
1438            _dis: PhantomData,
1439        })
1440    }
1441
1442    #[inline(always)]
1443    pub fn rd_width(&self) -> u8 {
1444        self.rd_width
1445    }
1446
1447    #[inline(always)]
1448    pub fn rs1_width(&self) -> u8 {
1449        self.rs1_width
1450    }
1451
1452    #[inline(always)]
1453    pub fn zx(&self) -> bool {
1454        self.zx
1455    }
1456
1457    #[inline(always)]
1458    pub fn rd(&self) -> IntReg<D> {
1459        self.rd
1460    }
1461
1462    #[inline(always)]
1463    pub fn rs1(&self) -> FloatReg<D> {
1464        self.rs1
1465    }
1466
1467    #[inline(always)]
1468    pub fn rm(&self) -> RoundMode {
1469        self.rm
1470    }
1471}
1472
1473#[derive(Copy, Clone, Debug)]
1474pub struct FpCvtFromIntInst<D: RiscVDisassembler> {
1475    rd_width: u8,
1476    rs1_width: u8,
1477    zx: bool,
1478    rd: FloatReg<D>,
1479    rs1: IntReg<D>,
1480    rm: RoundMode,
1481    _dis: PhantomData<D>,
1482}
1483
1484impl<D: RiscVDisassembler> FpCvtFromIntInst<D> {
1485    #[inline(always)]
1486    fn new(
1487        rd: FloatReg<D>,
1488        rd_width: u8,
1489        rs1: IntReg<D>,
1490        rs1_width: u8,
1491        zx: bool,
1492        rm: RoundMode,
1493    ) -> DisResult<Self> {
1494        Ok(Self {
1495            rd_width,
1496            rs1_width,
1497            zx,
1498            rd,
1499            rs1,
1500            rm,
1501            _dis: PhantomData,
1502        })
1503    }
1504
1505    #[inline(always)]
1506    pub fn rd_width(&self) -> u8 {
1507        self.rd_width
1508    }
1509
1510    #[inline(always)]
1511    pub fn rs1_width(&self) -> u8 {
1512        self.rs1_width
1513    }
1514
1515    #[inline(always)]
1516    pub fn zx(&self) -> bool {
1517        self.zx
1518    }
1519
1520    #[inline(always)]
1521    pub fn rd(&self) -> FloatReg<D> {
1522        self.rd
1523    }
1524
1525    #[inline(always)]
1526    pub fn rs1(&self) -> IntReg<D> {
1527        self.rs1
1528    }
1529
1530    #[inline(always)]
1531    pub fn rm(&self) -> RoundMode {
1532        self.rm
1533    }
1534}
1535
1536#[derive(Copy, Clone, Debug)]
1537pub struct FpMvToIntInst<D: RiscVDisassembler> {
1538    width: u8,
1539    rd: IntReg<D>,
1540    rs1: FloatReg<D>,
1541    _dis: PhantomData<D>,
1542}
1543
1544impl<D: RiscVDisassembler> FpMvToIntInst<D> {
1545    #[inline(always)]
1546    fn from_instr32(inst: Instr32) -> DisResult<Self> {
1547        let width = match inst.fsize() {
1548            0b00 => 4,
1549            0b01 => 8,
1550            0b11 => 16,
1551            _ => return Err(Error::InvalidSubop),
1552        };
1553
1554        if width > <D::RegFile as RegFile>::Float::width()
1555            || width > <D::RegFile as RegFile>::Int::width()
1556        {
1557            return Err(Error::InvalidSubop);
1558        }
1559
1560        let rd = IntReg::new(inst.rd());
1561        let rs1 = FloatReg::new(inst.rs1());
1562
1563        if !rd.valid() || !rs1.valid() {
1564            return Err(Error::BadRegister);
1565        }
1566
1567        Ok(Self {
1568            width: width as u8,
1569            rd,
1570            rs1,
1571            _dis: PhantomData,
1572        })
1573    }
1574
1575    #[inline(always)]
1576    pub fn width(&self) -> u8 {
1577        self.width
1578    }
1579
1580    #[inline(always)]
1581    pub fn rd(&self) -> IntReg<D> {
1582        self.rd
1583    }
1584
1585    #[inline(always)]
1586    pub fn rs1(&self) -> FloatReg<D> {
1587        self.rs1
1588    }
1589}
1590
1591#[derive(Copy, Clone, Debug)]
1592pub struct FpMvFromIntInst<D: RiscVDisassembler> {
1593    width: u8,
1594    rd: FloatReg<D>,
1595    rs1: IntReg<D>,
1596    _dis: PhantomData<D>,
1597}
1598
1599impl<D: RiscVDisassembler> FpMvFromIntInst<D> {
1600    #[inline(always)]
1601    fn from_instr32(inst: Instr32) -> DisResult<Self> {
1602        let width = match inst.fsize() {
1603            0b00 => 4,
1604            0b01 => 8,
1605            0b11 => 16,
1606            _ => return Err(Error::InvalidSubop),
1607        };
1608
1609        if width > <D::RegFile as RegFile>::Float::width()
1610            || width > <D::RegFile as RegFile>::Int::width()
1611        {
1612            return Err(Error::InvalidSubop);
1613        }
1614
1615        let rd = FloatReg::new(inst.rd());
1616        let rs1 = IntReg::new(inst.rs1());
1617
1618        if !rd.valid() || !rs1.valid() {
1619            return Err(Error::BadRegister);
1620        }
1621
1622        Ok(Self {
1623            width: width as u8,
1624            rd,
1625            rs1,
1626            _dis: PhantomData,
1627        })
1628    }
1629
1630    #[inline(always)]
1631    pub fn width(&self) -> u8 {
1632        self.width
1633    }
1634
1635    #[inline(always)]
1636    pub fn rd(&self) -> FloatReg<D> {
1637        self.rd
1638    }
1639
1640    #[inline(always)]
1641    pub fn rs1(&self) -> IntReg<D> {
1642        self.rs1
1643    }
1644}
1645
1646#[derive(Copy, Clone, Debug)]
1647pub struct FpClassInst<D: RiscVDisassembler> {
1648    width: u8,
1649    rd: IntReg<D>,
1650    rs1: FloatReg<D>,
1651    _dis: PhantomData<D>,
1652}
1653
1654impl<D: RiscVDisassembler> FpClassInst<D> {
1655    #[inline(always)]
1656    fn from_instr32(inst: Instr32) -> DisResult<Self> {
1657        let width = match inst.fsize() {
1658            0b00 => 4,
1659            0b01 => 8,
1660            0b11 => 16,
1661            _ => return Err(Error::InvalidSubop),
1662        };
1663
1664        if width > <D::RegFile as RegFile>::Float::width() {
1665            return Err(Error::InvalidSubop);
1666        }
1667
1668        let rd = IntReg::new(inst.rd());
1669        let rs1 = FloatReg::new(inst.rs1());
1670
1671        if !rd.valid() || !rs1.valid() {
1672            return Err(Error::BadRegister);
1673        }
1674
1675        Ok(Self {
1676            width: width as u8,
1677            rd,
1678            rs1,
1679            _dis: PhantomData,
1680        })
1681    }
1682
1683    #[inline(always)]
1684    pub fn width(&self) -> u8 {
1685        self.width
1686    }
1687
1688    #[inline(always)]
1689    pub fn rd(&self) -> IntReg<D> {
1690        self.rd
1691    }
1692
1693    #[inline(always)]
1694    pub fn rs1(&self) -> FloatReg<D> {
1695        self.rs1
1696    }
1697}
1698
1699#[derive(Copy, Clone, Debug)]
1700pub struct Instr16(u16);
1701impl Instr16 {
1702    #[inline(always)]
1703    fn extract_bits(self, start_bit: u32, width: u32) -> u16 {
1704        self.0.wrapping_shr(start_bit) & 1u16.wrapping_shl(width).wrapping_sub(1)
1705    }
1706
1707    #[inline(always)]
1708    fn sp_load_imm(self, size: usize) -> i32 {
1709        let size = size as u32 >> 3;
1710        let start = 4 + size;
1711
1712        let res = (self.extract_bits(start, 3 - size) << (2 + size))
1713            | (self.extract_bits(2, 2 + size) << 6);
1714
1715        (res | (self.extract_bits(12, 1) << 5)) as i32
1716    }
1717
1718    #[inline(always)]
1719    fn mem_imm(self, size: usize) -> i32 {
1720        let upper = self.extract_bits(10, 3) << 3;
1721
1722        let res = match size {
1723            4 => upper | self.extract_bits(6, 1) << 2 | self.extract_bits(5, 1) << 6,
1724            8 => upper | self.extract_bits(5, 2) << 6,
1725            _ => unimplemented!(),
1726        };
1727
1728        res as i32
1729    }
1730
1731    #[inline(always)]
1732    fn sp_store_imm(self, size: usize) -> i32 {
1733        let size = size as u32 >> 3;
1734        let start = 9 + size;
1735
1736        ((self.extract_bits(start, 4 - size) << (2 + size)) | (self.extract_bits(7, 2 + size) << 6))
1737            as i32
1738    }
1739
1740    #[inline(always)]
1741    fn cb_imm(self) -> i32 {
1742        let mut imm = self.extract_bits(2, 1) << 5;
1743        imm |= self.extract_bits(3, 2) << 1;
1744        imm |= self.extract_bits(5, 2) << 6;
1745        imm |= self.extract_bits(10, 2) << 3;
1746
1747        if self.extract_bits(12, 1) != 0 {
1748            imm |= !0xff;
1749        }
1750
1751        imm as i16 as i32
1752    }
1753
1754    #[inline(always)]
1755    fn cj_imm(self) -> i32 {
1756        let mut imm = self.extract_bits(2, 1) << 5;
1757        imm |= self.extract_bits(3, 3) << 1;
1758        imm |= self.extract_bits(6, 1) << 7;
1759        imm |= self.extract_bits(7, 1) << 6;
1760        imm |= self.extract_bits(8, 1) << 10;
1761        imm |= self.extract_bits(9, 2) << 8;
1762        imm |= self.extract_bits(11, 1) << 4;
1763
1764        if self.extract_bits(12, 1) != 0 {
1765            imm |= !0x7ff;
1766        }
1767
1768        imm as i16 as i32
1769    }
1770}
1771
1772pub enum Instr<D: RiscVDisassembler> {
1773    Rv16(Op<D>),
1774    Rv32(Op<D>),
1775}
1776
1777impl<D: RiscVDisassembler> Instr<D> {
1778    pub fn mnem(&self) -> Mnem<'_, D> {
1779        Mnem(self)
1780    }
1781
1782    pub fn operands(&self) -> Vec<Operand<D>> {
1783        let mut ops = Vec::new();
1784
1785        match *self {
1786            //Instr::Rv16(..) => {}
1787            Instr::Rv32(ref op) | Instr::Rv16(ref op) => match *op {
1788                Op::Load(ref l) => {
1789                    ops.push(Operand::R(l.rd()));
1790                    ops.push(Operand::M(l.imm(), l.rs1()));
1791                }
1792                Op::Store(ref s) => {
1793                    ops.push(Operand::R(s.rs2()));
1794                    ops.push(Operand::M(s.imm(), s.rs1()));
1795                }
1796                Op::Fence(ref i)
1797                | Op::FenceI(ref i)
1798                | Op::AddI(ref i)
1799                | Op::SltI(ref i)
1800                | Op::SltIU(ref i)
1801                | Op::XorI(ref i)
1802                | Op::OrI(ref i)
1803                | Op::AndI(ref i)
1804                | Op::SllI(ref i)
1805                | Op::SrlI(ref i)
1806                | Op::SraI(ref i)
1807                | Op::AddIW(ref i)
1808                | Op::SllIW(ref i)
1809                | Op::SrlIW(ref i)
1810                | Op::SraIW(ref i) => {
1811                    ops.push(Operand::R(i.rd()));
1812                    ops.push(Operand::R(i.rs1()));
1813                    ops.push(Operand::I(i.imm()));
1814                }
1815                Op::Auipc(ref u) | Op::Lui(ref u) => {
1816                    ops.push(Operand::R(u.rd()));
1817                    ops.push(Operand::I(u.imm()));
1818                }
1819                Op::Add(ref r)
1820                | Op::Sll(ref r)
1821                | Op::Slt(ref r)
1822                | Op::SltU(ref r)
1823                | Op::Xor(ref r)
1824                | Op::Srl(ref r)
1825                | Op::Or(ref r)
1826                | Op::And(ref r)
1827                | Op::Sub(ref r)
1828                | Op::Sra(ref r)
1829                | Op::AddW(ref r)
1830                | Op::SllW(ref r)
1831                | Op::SrlW(ref r)
1832                | Op::SubW(ref r)
1833                | Op::SraW(ref r)
1834                | Op::Mul(ref r)
1835                | Op::MulH(ref r)
1836                | Op::MulHSU(ref r)
1837                | Op::MulHU(ref r)
1838                | Op::Div(ref r)
1839                | Op::DivU(ref r)
1840                | Op::Rem(ref r)
1841                | Op::RemU(ref r)
1842                | Op::MulW(ref r)
1843                | Op::DivW(ref r)
1844                | Op::DivUW(ref r)
1845                | Op::RemW(ref r)
1846                | Op::RemUW(ref r) => {
1847                    ops.push(Operand::R(r.rd()));
1848                    ops.push(Operand::R(r.rs1()));
1849                    ops.push(Operand::R(r.rs2()));
1850                }
1851                Op::Beq(ref b)
1852                | Op::Bne(ref b)
1853                | Op::Blt(ref b)
1854                | Op::Bge(ref b)
1855                | Op::BltU(ref b)
1856                | Op::BgeU(ref b) => {
1857                    ops.push(Operand::R(b.rs1()));
1858                    ops.push(Operand::R(b.rs2()));
1859                    ops.push(Operand::I(b.imm()));
1860                }
1861                Op::Jalr(ref i) => {
1862                    ops.push(Operand::R(i.rd()));
1863                    ops.push(Operand::R(i.rs1()));
1864                    ops.push(Operand::I(i.imm()));
1865                }
1866                Op::Jal(ref j) => {
1867                    ops.push(Operand::R(j.rd()));
1868                    ops.push(Operand::I(j.imm()));
1869                }
1870                Op::SfenceVm(ref _r) => {}
1871                Op::SfenceVma(ref r) => {
1872                    ops.push(Operand::R(r.rs1()));
1873                    ops.push(Operand::R(r.rs2()));
1874                }
1875                Op::Csrrw(ref i) | Op::Csrrs(ref i) | Op::Csrrc(ref i) => {
1876                    ops.push(Operand::R(i.rd()));
1877                    ops.push(Operand::I(i.csr() as i32));
1878                    ops.push(Operand::R(i.rs1()));
1879                }
1880                Op::CsrrwI(ref i) | Op::CsrrsI(ref i) | Op::CsrrcI(ref i) => {
1881                    ops.push(Operand::R(i.rd()));
1882                    ops.push(Operand::I(i.csr() as i32));
1883                    ops.push(Operand::I(i.imm() as i32));
1884                }
1885                Op::Ecall | Op::Ebreak | Op::Uret | Op::Sret | Op::Mret | Op::Wfi => {}
1886                Op::Lr(ref a)
1887                | Op::Sc(ref a)
1888                | Op::AmoSwap(ref a)
1889                | Op::AmoAdd(ref a)
1890                | Op::AmoXor(ref a)
1891                | Op::AmoAnd(ref a)
1892                | Op::AmoOr(ref a)
1893                | Op::AmoMin(ref a)
1894                | Op::AmoMax(ref a)
1895                | Op::AmoMinU(ref a)
1896                | Op::AmoMaxU(ref a) => {
1897                    ops.push(Operand::R(a.rd()));
1898
1899                    if let Op::Lr(..) = *op {
1900                    } else {
1901                        ops.push(Operand::R(a.rs2()));
1902                    }
1903
1904                    ops.push(Operand::M(0, a.rs1()));
1905                }
1906                Op::LoadFp(ref m) | Op::StoreFp(ref m) => {
1907                    ops.push(Operand::F(m.fr()));
1908                    ops.push(Operand::M(m.imm(), m.rs1()));
1909                }
1910                Op::Fmadd(ref f) | Op::Fmsub(ref f) | Op::Fnmadd(ref f) | Op::Fnmsub(ref f) => {
1911                    ops.push(Operand::F(f.rd()));
1912                    ops.push(Operand::F(f.rs1()));
1913                    ops.push(Operand::F(f.rs2()));
1914                    ops.push(Operand::F(f.rs3()));
1915                    if f.rm() != RoundMode::Dynamic {
1916                        ops.push(Operand::RM(f.rm()));
1917                    }
1918                }
1919                Op::Fadd(ref f) | Op::Fsub(ref f) | Op::Fmul(ref f) | Op::Fdiv(ref f) => {
1920                    ops.push(Operand::F(f.rd()));
1921                    ops.push(Operand::F(f.rs1()));
1922                    ops.push(Operand::F(f.rs2()));
1923                    if f.rm() != RoundMode::Dynamic {
1924                        ops.push(Operand::RM(f.rm()));
1925                    }
1926                }
1927                Op::Fsqrt(ref f) => {
1928                    ops.push(Operand::F(f.rd()));
1929                    ops.push(Operand::F(f.rs1()));
1930                    if f.rm() != RoundMode::Dynamic {
1931                        ops.push(Operand::RM(f.rm()));
1932                    }
1933                }
1934                Op::Fsgnj(ref f)
1935                | Op::Fsgnjn(ref f)
1936                | Op::Fsgnjx(ref f)
1937                | Op::Fmin(ref f)
1938                | Op::Fmax(ref f) => {
1939                    ops.push(Operand::F(f.rd()));
1940                    ops.push(Operand::F(f.rs1()));
1941                    ops.push(Operand::F(f.rs2()));
1942                }
1943                Op::Fle(ref f) | Op::Flt(ref f) | Op::Feq(ref f) => {
1944                    ops.push(Operand::R(f.rd()));
1945                    ops.push(Operand::F(f.rs1()));
1946                    ops.push(Operand::F(f.rs2()));
1947                }
1948                Op::Fcvt(ref f) => {
1949                    ops.push(Operand::F(f.rd()));
1950                    ops.push(Operand::F(f.rs1()));
1951                    if f.rm() != RoundMode::Dynamic {
1952                        ops.push(Operand::RM(f.rm()));
1953                    }
1954                }
1955                Op::FcvtToInt(ref f) => {
1956                    ops.push(Operand::R(f.rd()));
1957                    ops.push(Operand::F(f.rs1()));
1958                    if f.rm() != RoundMode::Dynamic {
1959                        ops.push(Operand::RM(f.rm()));
1960                    }
1961                }
1962                Op::FcvtFromInt(ref f) => {
1963                    ops.push(Operand::F(f.rd()));
1964                    ops.push(Operand::R(f.rs1()));
1965                    if f.rm() != RoundMode::Dynamic {
1966                        ops.push(Operand::RM(f.rm()));
1967                    }
1968                }
1969                Op::FmvToInt(ref f) => {
1970                    ops.push(Operand::R(f.rd()));
1971                    ops.push(Operand::F(f.rs1()));
1972                }
1973                Op::FmvFromInt(ref f) => {
1974                    ops.push(Operand::F(f.rd()));
1975                    ops.push(Operand::R(f.rs1()));
1976                }
1977                Op::Fclass(ref f) => {
1978                    ops.push(Operand::R(f.rd()));
1979                    ops.push(Operand::F(f.rs1()));
1980                }
1981            },
1982        }
1983
1984        ops
1985    }
1986}
1987
1988pub struct Mnem<'a, D: RiscVDisassembler + 'a>(&'a Instr<D>);
1989impl<'a, D: RiscVDisassembler + 'a> Mnem<'a, D> {
1990    fn mnem(&self) -> &str {
1991        match self.0 {
1992            &Instr::Rv32(ref op) | &Instr::Rv16(ref op) => match *op {
1993                Op::Load(..) => "l",
1994                Op::Fence(..) => "fence",
1995                Op::FenceI(..) => "fence.i",
1996
1997                Op::AddI(..) => "addi",
1998                Op::SltI(..) => "slti",
1999                Op::SltIU(..) => "sltiu",
2000                Op::XorI(..) => "xori",
2001                Op::OrI(..) => "ori",
2002                Op::AndI(..) => "andi",
2003                Op::SllI(..) => "slli",
2004                Op::SrlI(..) => "srli",
2005                Op::SraI(..) => "srai",
2006
2007                Op::Auipc(..) => "auipc",
2008
2009                Op::AddIW(..) => "addiw",
2010                Op::SllIW(..) => "slliw",
2011                Op::SrlIW(..) => "srliw",
2012                Op::SraIW(..) => "sraiw",
2013
2014                Op::Store(..) => "s",
2015
2016                Op::Lr(..) => "lr",
2017                Op::Sc(..) => "sc",
2018                Op::AmoSwap(..) => "amoswap",
2019                Op::AmoAdd(..) => "amoadd",
2020                Op::AmoXor(..) => "amoxor",
2021                Op::AmoAnd(..) => "amoand",
2022                Op::AmoOr(..) => "amoor",
2023                Op::AmoMin(..) => "amoamin",
2024                Op::AmoMax(..) => "amoamax",
2025                Op::AmoMinU(..) => "amoaminu",
2026                Op::AmoMaxU(..) => "amoamaxu",
2027
2028                Op::Add(..) => "add",
2029                Op::Sll(..) => "sll",
2030                Op::Slt(..) => "slt",
2031                Op::SltU(..) => "sltu",
2032                Op::Xor(..) => "xor",
2033                Op::Srl(..) => "srl",
2034                Op::Or(..) => "or",
2035                Op::And(..) => "and",
2036                Op::Sub(..) => "sub",
2037                Op::Sra(..) => "sra",
2038
2039                Op::Mul(..) => "mul",
2040                Op::MulH(..) => "mulh",
2041                Op::MulHSU(..) => "mulhsu",
2042                Op::MulHU(..) => "mulhu",
2043                Op::Div(..) => "div",
2044                Op::DivU(..) => "divu",
2045                Op::Rem(..) => "rem",
2046                Op::RemU(..) => "remu",
2047
2048                Op::Lui(..) => "lui",
2049
2050                Op::AddW(..) => "addw",
2051                Op::SllW(..) => "sllw",
2052                Op::SrlW(..) => "srlw",
2053                Op::SubW(..) => "subw",
2054                Op::SraW(..) => "sraw",
2055
2056                Op::MulW(..) => "mulw",
2057                Op::DivW(..) => "divw",
2058                Op::DivUW(..) => "divuw",
2059                Op::RemW(..) => "remw",
2060                Op::RemUW(..) => "remuw",
2061
2062                Op::Beq(..) => "beq",
2063                Op::Bne(..) => "bne",
2064                Op::Blt(..) => "blt",
2065                Op::Bge(..) => "bge",
2066                Op::BltU(..) => "bltu",
2067                Op::BgeU(..) => "bgeu",
2068
2069                Op::Jalr(..) => "jalr",
2070                Op::Jal(..) => "jal",
2071
2072                Op::Ecall => "ecall",
2073                Op::Ebreak => "ebreak",
2074
2075                Op::Uret => "uret",
2076                Op::Sret => "sret",
2077                Op::Mret => "mret",
2078
2079                Op::Wfi => "wfi",
2080
2081                Op::SfenceVm(..) => "sfence.vm",
2082                Op::SfenceVma(..) => "sfence.vma",
2083
2084                Op::Csrrw(..) => "csrrw",
2085                Op::Csrrs(..) => "csrrs",
2086                Op::Csrrc(..) => "csrrc",
2087
2088                Op::CsrrwI(..) => "csrrwi",
2089                Op::CsrrsI(..) => "csrrsi",
2090                Op::CsrrcI(..) => "csrrci",
2091
2092                Op::LoadFp(..) => "fl",
2093                Op::StoreFp(..) => "fs",
2094
2095                Op::Fmadd(..) => "fmadd",
2096                Op::Fmsub(..) => "fmsub",
2097                Op::Fnmadd(..) => "fnmadd",
2098                Op::Fnmsub(..) => "fnmsub",
2099                Op::Fadd(..) => "fadd",
2100                Op::Fsub(..) => "fsub",
2101                Op::Fmul(..) => "fmul",
2102                Op::Fdiv(..) => "fdiv",
2103                Op::Fsqrt(..) => "fsqrt",
2104                Op::Fsgnj(..) => "fsgnj",
2105                Op::Fsgnjn(..) => "fsgnjn",
2106                Op::Fsgnjx(..) => "fsgnjx",
2107                Op::Fmin(..) => "fmin",
2108                Op::Fmax(..) => "fmax",
2109                Op::Fle(..) => "fle",
2110                Op::Flt(..) => "flt",
2111                Op::Feq(..) => "feq",
2112                Op::Fcvt(..) | Op::FcvtToInt(..) | Op::FcvtFromInt(..) => "fcvt",
2113                Op::FmvToInt(..) | Op::FmvFromInt(..) => "fmv",
2114                Op::Fclass(..) => "fclass",
2115            },
2116        }
2117    }
2118
2119    fn suffix(&self) -> Option<Cow<'_, str>> {
2120        match self.0 {
2121            // &Instr::Rv16(_) => None,
2122            &Instr::Rv32(ref op) | &Instr::Rv16(ref op) => match *op {
2123                Op::Load(ref l) => {
2124                    let zx = if l.zx() { "u" } else { "" };
2125                    let width = match l.width() {
2126                        1 => "b",
2127                        2 => "h",
2128                        4 => "w",
2129                        8 => "d",
2130                        _ => unreachable!(),
2131                    };
2132
2133                    Some(format!("{}{}", width, zx).into())
2134                }
2135                Op::Store(ref s) => Some(
2136                    match s.width() {
2137                        1 => "b",
2138                        2 => "h",
2139                        4 => "w",
2140                        8 => "d",
2141                        _ => unreachable!(),
2142                    }
2143                    .into(),
2144                ),
2145                Op::Lr(ref a)
2146                | Op::Sc(ref a)
2147                | Op::AmoSwap(ref a)
2148                | Op::AmoAdd(ref a)
2149                | Op::AmoXor(ref a)
2150                | Op::AmoAnd(ref a)
2151                | Op::AmoOr(ref a)
2152                | Op::AmoMin(ref a)
2153                | Op::AmoMax(ref a)
2154                | Op::AmoMinU(ref a)
2155                | Op::AmoMaxU(ref a) => {
2156                    let width = match a.width() {
2157                        4 => ".w",
2158                        8 => ".d",
2159                        _ => unreachable!(),
2160                    };
2161                    let aq = if a.aq() { ".aq" } else { "" };
2162                    let rl = if a.rl() { ".rl" } else { "" };
2163
2164                    Some(format!("{}{}{}", width, aq, rl).into())
2165                }
2166                Op::LoadFp(ref m) | Op::StoreFp(ref m) => {
2167                    let suf = match m.width() {
2168                        4 => "w",
2169                        8 => "d",
2170                        16 => "q",
2171                        _ => unreachable!(),
2172                    };
2173
2174                    Some(suf.into())
2175                }
2176                Op::Fmadd(ref f) | Op::Fmsub(ref f) | Op::Fnmadd(ref f) | Op::Fnmsub(ref f) => {
2177                    let suf = match f.width() {
2178                        4 => ".s",
2179                        8 => ".d",
2180                        16 => ".q",
2181                        _ => unreachable!(),
2182                    };
2183
2184                    Some(suf.into())
2185                }
2186                Op::Fadd(ref f) | Op::Fsub(ref f) | Op::Fmul(ref f) | Op::Fdiv(ref f) => {
2187                    let suf = match f.width() {
2188                        4 => ".s",
2189                        8 => ".d",
2190                        16 => ".q",
2191                        _ => unreachable!(),
2192                    };
2193
2194                    Some(suf.into())
2195                }
2196                Op::Fsgnj(ref f)
2197                | Op::Fsgnjn(ref f)
2198                | Op::Fsgnjx(ref f)
2199                | Op::Fmin(ref f)
2200                | Op::Fmax(ref f) => {
2201                    let suf = match f.width() {
2202                        4 => ".s",
2203                        8 => ".d",
2204                        16 => ".q",
2205                        _ => unreachable!(),
2206                    };
2207
2208                    Some(suf.into())
2209                }
2210                Op::Fle(ref f) | Op::Flt(ref f) | Op::Feq(ref f) => {
2211                    let suf = match f.width() {
2212                        4 => ".s",
2213                        8 => ".d",
2214                        16 => ".q",
2215                        _ => unreachable!(),
2216                    };
2217
2218                    Some(suf.into())
2219                }
2220                Op::Fcvt(ref f) => {
2221                    let rd_suf = match f.rd_width() {
2222                        4 => ".s",
2223                        8 => ".d",
2224                        16 => ".q",
2225                        _ => unreachable!(),
2226                    };
2227                    let rs1_suf = match f.rs1_width() {
2228                        4 => ".s",
2229                        8 => ".d",
2230                        16 => ".q",
2231                        _ => unreachable!(),
2232                    };
2233
2234                    Some(format!("{}{}", rd_suf, rs1_suf).into())
2235                }
2236                Op::FcvtToInt(ref f) => {
2237                    let rd_suf = match f.rd_width() {
2238                        4 => ".w",
2239                        8 => ".l",
2240                        _ => unreachable!(),
2241                    };
2242                    let zx_suf = if f.zx() { "u" } else { "" };
2243                    let rs1_suf = match f.rs1_width() {
2244                        4 => ".s",
2245                        8 => ".d",
2246                        16 => ".q",
2247                        _ => unreachable!(),
2248                    };
2249
2250                    Some(format!("{}{}{}", rd_suf, zx_suf, rs1_suf).into())
2251                }
2252                Op::FcvtFromInt(ref f) => {
2253                    let rd_suf = match f.rs1_width() {
2254                        4 => ".s",
2255                        8 => ".d",
2256                        16 => ".q",
2257                        _ => unreachable!(),
2258                    };
2259                    let rs1_suf = match f.rd_width() {
2260                        4 => ".w",
2261                        8 => ".l",
2262                        _ => unreachable!(),
2263                    };
2264                    let zx_suf = if f.zx() { "u" } else { "" };
2265
2266                    Some(format!("{}{}{}", rd_suf, rs1_suf, zx_suf).into())
2267                }
2268                Op::FmvToInt(ref f) => {
2269                    let suf = match f.width() {
2270                        4 => ".x.w",
2271                        8 => ".x.d",
2272                        _ => unreachable!(),
2273                    };
2274
2275                    Some(suf.into())
2276                }
2277                Op::FmvFromInt(ref f) => {
2278                    let suf = match f.width() {
2279                        4 => ".w.x",
2280                        8 => ".d.x",
2281                        _ => unreachable!(),
2282                    };
2283
2284                    Some(suf.into())
2285                }
2286                Op::Fclass(ref f) => {
2287                    let suf = match f.width() {
2288                        4 => ".s",
2289                        8 => ".d",
2290                        16 => ".q",
2291                        _ => unreachable!(),
2292                    };
2293
2294                    Some(suf.into())
2295                }
2296                _ => None,
2297            },
2298        }
2299    }
2300}
2301
2302impl<D: RiscVDisassembler> fmt::Display for Mnem<'_, D> {
2303    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2304        match (self.mnem(), self.suffix()) {
2305            (m, None) => f.pad(m),
2306            (m, Some(s)) => {
2307                let s = format!("{}{}", m, s);
2308                f.pad(&s)
2309            }
2310        }
2311    }
2312}
2313
2314pub trait StandardExtension {
2315    fn supported() -> bool;
2316}
2317
2318pub struct ExtensionNotImplemented;
2319impl StandardExtension for ExtensionNotImplemented {
2320    #[inline(always)]
2321    fn supported() -> bool {
2322        false
2323    }
2324}
2325
2326pub struct ExtensionSupported;
2327impl StandardExtension for ExtensionSupported {
2328    #[inline(always)]
2329    fn supported() -> bool {
2330        true
2331    }
2332}
2333
2334pub trait RiscVDisassembler: 'static + Debug + Sized + Copy + Clone + Send + Sync {
2335    type RegFile: RegFile;
2336    type MulDivExtension: StandardExtension;
2337    type AtomicExtension: StandardExtension;
2338    type CompressedExtension: StandardExtension;
2339
2340    fn decode(addr: u64, bytes: &[u8]) -> DisResult<Instr<Self>> {
2341        use Error::*;
2342
2343        let required_alignment: u64 = if Self::CompressedExtension::supported() {
2344            2
2345        } else {
2346            4
2347        };
2348
2349        if addr & required_alignment.wrapping_sub(1) != 0
2350            || bytes.len() < required_alignment as usize
2351        {
2352            return Err(Unaligned);
2353        }
2354
2355        let parcel = LittleEndian::read_u16(bytes);
2356
2357        let inst_len = match parcel {
2358            p if (p & 0b11) != 0b11 => 2,
2359            p if (p & 0b11111) != 0b11111 => 4,
2360            _ => {
2361                return Err(UnhandledLength);
2362            }
2363        };
2364
2365        match inst_len {
2366            2 if bytes.len() >= 2 && Self::CompressedExtension::supported() => {
2367                let inst = Instr16(parcel);
2368
2369                // top 3 bits and bottom 2 bits make up
2370                // the bulk of the opcode map
2371                // see: Table 12.3 RVC Opcode Map RISCV spec 2.2
2372                let opcode = (parcel >> 11 & !3) | (parcel & 3);
2373                let int_width = <Self::RegFile as RegFile>::Int::width();
2374                let float_width = <Self::RegFile as RegFile>::Float::width();
2375
2376                let decoded = match opcode {
2377                    0b000_00 if parcel != 0 => {
2378                        // ADDI4SPN
2379                        let rd = 8 + inst.extract_bits(2, 3) as u32;
2380                        let mut imm = inst.extract_bits(5, 1) << 3;
2381                        imm |= inst.extract_bits(6, 1) << 2;
2382                        imm |= inst.extract_bits(7, 4) << 6;
2383                        imm |= inst.extract_bits(11, 2) << 4;
2384
2385                        if imm == 0 {
2386                            return Err(InvalidSubop);
2387                        }
2388
2389                        Op::AddI(ITypeInst::from_ops(
2390                            IntReg::new(rd),
2391                            IntReg::new(2),
2392                            imm as i32,
2393                        ))
2394                    }
2395                    0b000_01 => {
2396                        // ADDI
2397                        let rd = inst.extract_bits(7, 5) as u32;
2398                        let mut imm = inst.extract_bits(2, 5) as u32;
2399
2400                        // sign extend the 6 bit immediate value
2401                        if inst.extract_bits(12, 1) == 1 {
2402                            imm |= !0x1f;
2403                        }
2404
2405                        Op::AddI(ITypeInst::from_ops(
2406                            IntReg::new(rd),
2407                            IntReg::new(rd),
2408                            imm as i32,
2409                        ))
2410                    }
2411                    // shift amounts >= 32 are prohibited for Rv32 (reserved for NSE)
2412                    0b000_10 if int_width >= 8 || inst.extract_bits(12, 1) == 0 => {
2413                        // SLLI
2414                        // TODO merge shamt extraction
2415                        let shamt =
2416                            (inst.extract_bits(12, 1) << 5 | inst.extract_bits(2, 5)) as u32;
2417                        let rd = inst.extract_bits(7, 5) as u32;
2418
2419                        // TODO Rv128 shamt of 0 == 64
2420
2421                        Op::SllI(ITypeInst::from_ops(
2422                            IntReg::new(rd),
2423                            IntReg::new(rd),
2424                            shamt as i32,
2425                        ))
2426                    }
2427
2428                    //0b001_00 if int_width == 16 => unimplemented!("LQ"),
2429                    0b001_00 if float_width >= 8 => {
2430                        // FLD
2431                        let rd = FloatReg::new(8 + inst.extract_bits(2, 3) as u32);
2432                        let rs1 = IntReg::new(8 + inst.extract_bits(7, 3) as u32);
2433
2434                        let imm = inst.mem_imm(8);
2435                        Op::LoadFp(FpMemInst::new(8, rd, rs1, imm)?)
2436                    }
2437                    0b001_01 if int_width == 4 => {
2438                        // JAL
2439                        Op::Jal(JTypeInst::new(IntReg::new(1), inst.cj_imm())?)
2440                    }
2441                    0b001_01 => {
2442                        // ADDIW
2443                        let rd = inst.extract_bits(7, 5) as u32;
2444                        let mut imm = inst.extract_bits(2, 5) as u32;
2445
2446                        // TODO rd == zero valid?
2447                        // sign extend the 6 bit immediate value
2448                        if inst.extract_bits(12, 1) == 1 {
2449                            imm |= !0x1f;
2450                        }
2451
2452                        Op::AddIW(ITypeInst::from_ops(
2453                            IntReg::new(rd),
2454                            IntReg::new(rd),
2455                            imm as i32,
2456                        ))
2457                    }
2458                    //0b001_10 if int_width == 16 => unimplemented!("LQSP"),
2459                    0b001_10 if float_width >= 8 => {
2460                        // FLDSP
2461                        let rd = FloatReg::new(inst.extract_bits(7, 5) as u32);
2462                        let imm = inst.sp_load_imm(8);
2463
2464                        Op::LoadFp(FpMemInst::new(8, rd, IntReg::new(2), imm)?)
2465                    }
2466
2467                    0b010_00 => {
2468                        // LW
2469                        let rd = IntReg::new(8 + inst.extract_bits(2, 3) as u32);
2470                        let rs1 = IntReg::new(8 + inst.extract_bits(7, 3) as u32);
2471
2472                        let imm = inst.mem_imm(4);
2473                        Op::Load(LoadTypeInst::new(4, false, rd, rs1, imm)?)
2474                    }
2475                    0b010_01 => {
2476                        // LI
2477                        let rd = inst.extract_bits(7, 5) as u32;
2478
2479                        // TODO rd == 0 behavior
2480                        if rd == 0 {
2481                            return Err(InvalidSubop);
2482                        }
2483
2484                        // sign extend the 6 bit immediate value
2485                        let mut imm = inst.extract_bits(2, 5) as u32;
2486                        if inst.extract_bits(12, 1) == 1 {
2487                            imm |= !0x1f;
2488                        }
2489
2490                        Op::AddI(ITypeInst::from_ops(
2491                            IntReg::new(rd),
2492                            IntReg::new(0),
2493                            imm as i32,
2494                        ))
2495                    }
2496                    0b010_10 => {
2497                        // LWSP
2498                        let rd = IntReg::new(inst.extract_bits(7, 5) as u32);
2499                        let imm = inst.sp_load_imm(4);
2500
2501                        if rd.id() == 0 {
2502                            return Err(InvalidOpcode);
2503                        }
2504
2505                        Op::Load(LoadTypeInst::new(4, false, rd, IntReg::new(2), imm)?)
2506                    }
2507
2508                    0b011_00 if int_width >= 8 => {
2509                        // LD
2510                        let rd = IntReg::new(8 + inst.extract_bits(2, 3) as u32);
2511                        let rs1 = IntReg::new(8 + inst.extract_bits(7, 3) as u32);
2512
2513                        let imm = inst.mem_imm(8);
2514                        Op::Load(LoadTypeInst::new(8, false, rd, rs1, imm)?)
2515                    }
2516                    0b011_00 if float_width >= 4 => {
2517                        // FLW
2518                        let rd = FloatReg::new(8 + inst.extract_bits(2, 3) as u32);
2519                        let rs1 = IntReg::new(8 + inst.extract_bits(7, 3) as u32);
2520
2521                        let imm = inst.mem_imm(4);
2522                        Op::LoadFp(FpMemInst::new(4, rd, rs1, imm)?)
2523                    }
2524                    0b011_01 => {
2525                        // LUI/ADDI16SP
2526                        let rd = inst.extract_bits(7, 5) as u32;
2527
2528                        match rd {
2529                            0 => return Err(InvalidSubop),
2530                            2 => {
2531                                // ADDI16SP
2532                                let mut imm = inst.extract_bits(2, 1) << 5;
2533                                imm |= inst.extract_bits(3, 2) << 7;
2534                                imm |= inst.extract_bits(5, 1) << 6;
2535                                imm |= inst.extract_bits(6, 1) << 4;
2536
2537                                if inst.extract_bits(12, 1) == 1 {
2538                                    imm |= !0x1ff;
2539                                }
2540
2541                                if imm == 0 {
2542                                    return Err(InvalidSubop);
2543                                }
2544
2545                                Op::AddI(ITypeInst::from_ops(
2546                                    IntReg::new(2),
2547                                    IntReg::new(2),
2548                                    imm as i16 as i32,
2549                                ))
2550                            }
2551                            _ => {
2552                                // sign extend the 6 bit immediate value
2553                                let mut imm = inst.extract_bits(2, 5) as u32;
2554                                if inst.extract_bits(12, 1) == 1 {
2555                                    imm |= !0x1f;
2556                                }
2557
2558                                let imm = (imm as i32) << 12;
2559                                Op::Lui(UTypeInst::new(IntReg::new(rd), imm)?)
2560                            }
2561                        }
2562                    }
2563                    0b011_10 if int_width >= 8 => {
2564                        // LDSP
2565                        let rd = IntReg::new(inst.extract_bits(7, 5) as u32);
2566                        let imm = inst.sp_load_imm(8);
2567
2568                        if rd.id() == 0 {
2569                            return Err(InvalidOpcode);
2570                        }
2571
2572                        Op::Load(LoadTypeInst::new(8, false, rd, IntReg::new(2), imm)?)
2573                    }
2574                    0b011_10 if float_width >= 4 => {
2575                        // FLWSP
2576                        let rd = FloatReg::new(inst.extract_bits(7, 5) as u32);
2577                        let imm = inst.sp_load_imm(4);
2578
2579                        Op::LoadFp(FpMemInst::new(4, rd, IntReg::new(2), imm)?)
2580                    }
2581
2582                    // 0b100_00 RESERVED
2583                    0b100_01 => {
2584                        // MISC-ALU
2585                        let rd = 8 + inst.extract_bits(7, 3) as u32;
2586
2587                        // TODO merge shamt extraction
2588                        let shamt =
2589                            (inst.extract_bits(12, 1) << 5 | inst.extract_bits(2, 5)) as u32;
2590
2591                        let mut mask = inst.extract_bits(2, 5) as u32;
2592                        if inst.extract_bits(12, 1) == 1 {
2593                            mask |= !0x1f;
2594                        }
2595
2596                        // TODO is shamt 0 actually prohibited?
2597                        // TODO should not always check this...
2598                        //if shamt == 0 || (int_width == 4 && shamt >= 32) {
2599                        //    return Err(InvalidSubop);
2600                        //}
2601
2602                        match inst.extract_bits(10, 2) {
2603                            0 => Op::SrlI(ITypeInst::from_ops(
2604                                IntReg::new(rd),
2605                                IntReg::new(rd),
2606                                shamt as i32,
2607                            )), // SRLI
2608                            1 => Op::SraI(ITypeInst::from_ops(
2609                                IntReg::new(rd),
2610                                IntReg::new(rd),
2611                                shamt as i32,
2612                            )), // SRAI
2613                            2 => Op::AndI(ITypeInst::from_ops(
2614                                IntReg::new(rd),
2615                                IntReg::new(rd),
2616                                mask as i32,
2617                            )), // ANDI
2618                            3 => {
2619                                let op = inst.extract_bits(5, 2) | (inst.extract_bits(12, 1) << 2);
2620                                let rs2 = 8 + inst.extract_bits(2, 3) as u32;
2621                                let rtype = RTypeInst::from_ops(
2622                                    IntReg::new(rd),
2623                                    IntReg::new(rd),
2624                                    IntReg::new(rs2),
2625                                );
2626
2627                                match op {
2628                                    0 => Op::Sub(rtype),                    // SUB
2629                                    1 => Op::Xor(rtype),                    // XOR
2630                                    2 => Op::Or(rtype),                     // OR
2631                                    3 => Op::And(rtype),                    // AND
2632                                    4 if int_width >= 8 => Op::SubW(rtype), // SUBW
2633                                    5 if int_width >= 8 => Op::AddW(rtype), // ADDW
2634                                    _ => return Err(InvalidSubop),
2635                                }
2636                            }
2637                            _ => unreachable!(),
2638                        }
2639                    }
2640                    0b100_10 => {
2641                        // JALR/MV/ADD
2642                        let reg1 = inst.extract_bits(7, 5) as u32;
2643                        let reg2 = inst.extract_bits(2, 5) as u32;
2644                        let bit = inst.extract_bits(12, 1) as u32;
2645
2646                        match (bit, reg1, reg2) {
2647                            (link, rs1, 0) if rs1 != 0 => {
2648                                // JR, JALR
2649                                Op::Jalr(ITypeInst::from_ops(
2650                                    IntReg::new(link),
2651                                    IntReg::new(rs1),
2652                                    0,
2653                                ))
2654                            }
2655                            (0, rd, rs2) if rd != 0 && rs2 != 0 => {
2656                                // MV
2657                                Op::AddI(ITypeInst::from_ops(IntReg::new(rd), IntReg::new(rs2), 0))
2658                            }
2659                            (1, 0, 0) => Op::Ebreak,
2660                            (1, rd, rs2) if rs2 != 0 => {
2661                                // ADD
2662                                Op::Add(RTypeInst::from_ops(
2663                                    IntReg::new(rd),
2664                                    IntReg::new(rd),
2665                                    IntReg::new(rs2),
2666                                ))
2667                            }
2668                            _ => return Err(InvalidSubop),
2669                        }
2670                    }
2671
2672                    //0b101_00 if int_width == 16 => unimplemented!("SQ"),
2673                    0b101_00 if float_width >= 8 => {
2674                        // FSD
2675                        let rd = FloatReg::new(8 + inst.extract_bits(2, 3) as u32);
2676                        let rs1 = IntReg::new(8 + inst.extract_bits(7, 3) as u32);
2677
2678                        let imm = inst.mem_imm(8);
2679                        Op::StoreFp(FpMemInst::new(8, rd, rs1, imm)?)
2680                    }
2681                    0b101_01 => {
2682                        // J
2683                        Op::Jal(JTypeInst::new(IntReg::new(0), inst.cj_imm())?)
2684                    }
2685                    //0b101_10 if int_width == 16 => unimplemented!("SQSP"),
2686                    0b101_10 if float_width >= 8 => {
2687                        // FSDSP
2688                        let rd = FloatReg::new(inst.extract_bits(7, 5) as u32);
2689                        let imm = inst.sp_load_imm(8);
2690
2691                        Op::StoreFp(FpMemInst::new(8, rd, IntReg::new(2), imm)?)
2692                    }
2693
2694                    0b110_00 => {
2695                        // SW
2696                        let rs2 = IntReg::new(8 + inst.extract_bits(2, 3) as u32);
2697                        let rs1 = IntReg::new(8 + inst.extract_bits(7, 3) as u32);
2698
2699                        let imm = inst.mem_imm(4);
2700                        Op::Store(StoreTypeInst::new(4, rs2, rs1, imm)?)
2701                    }
2702                    0b110_01 => {
2703                        // BEQZ
2704                        let rs1 = IntReg::new(8 + inst.extract_bits(7, 3) as u32);
2705                        Op::Beq(BTypeInst::new(rs1, IntReg::new(0), inst.cb_imm())?)
2706                    }
2707                    0b110_10 => {
2708                        // SWSP
2709                        let rs2 = IntReg::new(inst.extract_bits(2, 5) as u32);
2710                        let imm = inst.sp_store_imm(4);
2711
2712                        Op::Store(StoreTypeInst::new(4, rs2, IntReg::new(2), imm)?)
2713                    }
2714
2715                    0b111_00 if int_width >= 8 => {
2716                        // SD
2717                        let rs2 = IntReg::new(8 + inst.extract_bits(2, 3) as u32);
2718                        let rs1 = IntReg::new(8 + inst.extract_bits(7, 3) as u32);
2719
2720                        let imm = inst.mem_imm(8);
2721                        Op::Store(StoreTypeInst::new(8, rs2, rs1, imm)?)
2722                    }
2723                    0b111_00 if float_width >= 4 => {
2724                        // FSW
2725                        let rd = FloatReg::new(8 + inst.extract_bits(2, 3) as u32);
2726                        let rs1 = IntReg::new(8 + inst.extract_bits(7, 3) as u32);
2727
2728                        let imm = inst.mem_imm(4);
2729                        Op::StoreFp(FpMemInst::new(4, rd, rs1, imm)?)
2730                    }
2731                    0b111_01 => {
2732                        // BNEZ
2733                        let rs1 = IntReg::new(8 + inst.extract_bits(7, 3) as u32);
2734                        Op::Bne(BTypeInst::new(rs1, IntReg::new(0), inst.cb_imm())?)
2735                    }
2736                    0b111_10 if int_width >= 8 => {
2737                        // SDSP
2738                        let rs2 = IntReg::new(inst.extract_bits(2, 5) as u32);
2739                        let imm = inst.sp_store_imm(8);
2740
2741                        Op::Store(StoreTypeInst::new(8, rs2, IntReg::new(2), imm)?)
2742                    }
2743                    0b111_10 if float_width >= 4 => {
2744                        // FSWSP
2745                        let rd = FloatReg::new(inst.extract_bits(7, 5) as u32);
2746                        let imm = inst.sp_load_imm(4);
2747
2748                        Op::StoreFp(FpMemInst::new(4, rd, IntReg::new(2), imm)?)
2749                    }
2750
2751                    _ => return Err(InvalidOpcode),
2752                };
2753
2754                Ok(Instr::Rv16(decoded))
2755            }
2756            4 if bytes.len() >= 4 => {
2757                let inst = LittleEndian::read_u32(bytes);
2758                let inst = Instr32(inst);
2759
2760                let int_width = <Self::RegFile as RegFile>::Int::width();
2761                let float_width = <Self::RegFile as RegFile>::Float::width();
2762
2763                let decoded = match inst.opcode() >> 2 {
2764                    0b00000 => Op::Load(LoadTypeInst::from_instr32(inst)?), // LOAD
2765                    0b00001 if float_width > 0 => {
2766                        // LOAD-FP
2767                        let width = 1usize.wrapping_shl(inst.funct3());
2768                        let fr = FloatReg::new(inst.rd());
2769                        let rs1 = IntReg::new(inst.rs1());
2770                        let imm = inst.i_imm();
2771
2772                        if width < 4 || width > float_width {
2773                            return Err(InvalidSubop);
2774                        }
2775
2776                        Op::LoadFp(FpMemInst::new(width, fr, rs1, imm)?)
2777                    }
2778                    // TODO CUSTOM_0
2779                    0b00011 => {
2780                        // MISC-MEM
2781                        let itype = ITypeInst::new(inst)?;
2782
2783                        match inst.funct3() {
2784                            0b000 => Op::Fence(itype),
2785                            0b001 => Op::FenceI(itype),
2786                            _ => return Err(InvalidSubop),
2787                        }
2788                    }
2789                    0b00100 => {
2790                        // OP-IMM
2791                        let mut itype = ITypeInst::new(inst)?;
2792                        match inst.funct3() {
2793                            0b000 => Op::AddI(itype),
2794                            0b010 => Op::SltI(itype),
2795                            0b011 => Op::SltIU(itype),
2796                            0b100 => Op::XorI(itype),
2797                            0b110 => Op::OrI(itype),
2798                            0b111 => Op::AndI(itype),
2799                            0b001 => Op::SllI(itype), // TODO shamt
2800                            0b101 => {
2801                                if inst.0 & 0x40000000 == 0 {
2802                                    Op::SrlI(itype)
2803                                } else {
2804                                    // pretty terrible hack, whatever
2805                                    itype.inst.0 &= !0x40000000;
2806                                    Op::SraI(itype)
2807                                }
2808                            }
2809                            _ => unreachable!(),
2810                        }
2811                    }
2812
2813                    0b00101 => Op::Auipc(UTypeInst::from_instr32(inst)?), // AUIPC
2814
2815                    0b00110 if int_width > 4 => {
2816                        // OP-IMM-32
2817                        let mut itype = ITypeInst::new(inst)?;
2818                        match inst.funct3() {
2819                            0b000 => Op::AddIW(itype),
2820                            0b001 => Op::SllIW(itype), // TODO shamt
2821                            0b101 => {
2822                                if inst.0 & 0x40000000 == 0 {
2823                                    Op::SrlIW(itype)
2824                                } else {
2825                                    // pretty terrible hack, whatever
2826                                    itype.inst.0 &= !0x40000000;
2827                                    Op::SraIW(itype)
2828                                }
2829                            }
2830                            _ => return Err(InvalidSubop),
2831                        }
2832                    }
2833
2834                    0b01000 => Op::Store(StoreTypeInst::from_instr32(inst)?), // STORE
2835                    0b01001 if float_width > 0 => {
2836                        // STORE-FP
2837                        let width = 1usize.wrapping_shl(inst.funct3());
2838                        let fr = FloatReg::new(inst.rs2());
2839                        let rs1 = IntReg::new(inst.rs1());
2840                        let imm = inst.s_imm();
2841
2842                        if width < 4 || width > float_width {
2843                            return Err(InvalidSubop);
2844                        }
2845
2846                        Op::StoreFp(FpMemInst::new(width, fr, rs1, imm)?)
2847                    }
2848                    // TODO CUSTOM_1
2849                    0b01011 if Self::AtomicExtension::supported() => {
2850                        // AMO
2851                        let atomic = AtomicInst::new(inst)?;
2852
2853                        // lower two bits represent aq/rl
2854                        match inst.funct7() >> 2 {
2855                            0b00010 if inst.rs2() == 0 => Op::Lr(atomic),
2856                            0b00011 => Op::Sc(atomic),
2857                            0b00001 => Op::AmoSwap(atomic),
2858                            0b00000 => Op::AmoAdd(atomic),
2859                            0b00100 => Op::AmoXor(atomic),
2860                            0b01100 => Op::AmoAnd(atomic),
2861                            0b01000 => Op::AmoOr(atomic),
2862                            0b10000 => Op::AmoMin(atomic),
2863                            0b10100 => Op::AmoMax(atomic),
2864                            0b11000 => Op::AmoMinU(atomic),
2865                            0b11100 => Op::AmoMaxU(atomic),
2866                            _ => return Err(InvalidSubop),
2867                        }
2868                    }
2869                    0b01100 => {
2870                        // OP
2871                        let rtype = RTypeIntInst::new(inst)?;
2872                        match inst.funct7() {
2873                            0b0000000 => match inst.funct3() {
2874                                0b000 => Op::Add(rtype),
2875                                0b001 => Op::Sll(rtype),
2876                                0b010 => Op::Slt(rtype),
2877                                0b011 => Op::SltU(rtype),
2878                                0b100 => Op::Xor(rtype),
2879                                0b101 => Op::Srl(rtype),
2880                                0b110 => Op::Or(rtype),
2881                                0b111 => Op::And(rtype),
2882                                _ => unreachable!(),
2883                            },
2884                            0b0100000 => match inst.funct3() {
2885                                0b000 => Op::Sub(rtype),
2886                                0b101 => Op::Sra(rtype),
2887                                _ => return Err(InvalidSubop),
2888                            },
2889                            0b0000001 if Self::MulDivExtension::supported() => {
2890                                match inst.funct3() {
2891                                    0b000 => Op::Mul(rtype),
2892                                    0b001 => Op::MulH(rtype),
2893                                    0b010 => Op::MulHSU(rtype),
2894                                    0b011 => Op::MulHU(rtype),
2895                                    0b100 => Op::Div(rtype),
2896                                    0b101 => Op::DivU(rtype),
2897                                    0b110 => Op::Rem(rtype),
2898                                    0b111 => Op::RemU(rtype),
2899                                    _ => unreachable!(),
2900                                }
2901                            }
2902                            _ => return Err(InvalidSubop),
2903                        }
2904                    }
2905                    0b01101 => Op::Lui(UTypeInst::from_instr32(inst)?), // LUI
2906                    0b01110 if int_width > 4 => {
2907                        // OP-32
2908                        let rtype = RTypeIntInst::new(inst)?;
2909                        match inst.funct7() {
2910                            0b0000000 => match inst.funct3() {
2911                                0b000 => Op::AddW(rtype),
2912                                0b001 => Op::SllW(rtype),
2913                                0b101 => Op::SrlW(rtype),
2914                                _ => return Err(InvalidSubop),
2915                            },
2916                            0b0100000 => match inst.funct3() {
2917                                0b000 => Op::SubW(rtype),
2918                                0b101 => Op::SraW(rtype),
2919                                _ => return Err(InvalidSubop),
2920                            },
2921                            0b0000001 if Self::MulDivExtension::supported() => {
2922                                match inst.funct3() {
2923                                    0b000 => Op::MulW(rtype),
2924                                    0b100 => Op::DivW(rtype),
2925                                    0b101 => Op::DivUW(rtype),
2926                                    0b110 => Op::RemW(rtype),
2927                                    0b111 => Op::RemUW(rtype),
2928                                    _ => return Err(InvalidSubop),
2929                                }
2930                            }
2931                            _ => return Err(InvalidSubop),
2932                        }
2933                    }
2934                    0b10000 if float_width > 0 => Op::Fmadd(FpMAddInst::from_instr32(inst)?), // MADD
2935                    0b10001 if float_width > 0 => Op::Fmsub(FpMAddInst::from_instr32(inst)?), // MSUB
2936                    0b10010 if float_width > 0 => Op::Fnmsub(FpMAddInst::from_instr32(inst)?), // NMSUB
2937                    0b10011 if float_width > 0 => Op::Fnmadd(FpMAddInst::from_instr32(inst)?), // NMADD
2938                    0b10100 if float_width > 0 => {
2939                        // OP-FP
2940                        match inst.fop() {
2941                            0b00000 => Op::Fadd(RTypeFloatRoundInst::from_instr32(inst)?),
2942                            0b00001 => Op::Fsub(RTypeFloatRoundInst::from_instr32(inst)?),
2943                            0b00010 => Op::Fmul(RTypeFloatRoundInst::from_instr32(inst)?),
2944                            0b00011 => Op::Fdiv(RTypeFloatRoundInst::from_instr32(inst)?),
2945                            0b00100 => match inst.funct3() {
2946                                0b000 => Op::Fsgnj(RTypeFloatInst::from_instr32(inst)?),
2947                                0b001 => Op::Fsgnjn(RTypeFloatInst::from_instr32(inst)?),
2948                                0b010 => Op::Fsgnjx(RTypeFloatInst::from_instr32(inst)?),
2949                                _ => return Err(InvalidSubop),
2950                            },
2951                            0b00101 => match inst.funct3() {
2952                                0b000 => Op::Fmin(RTypeFloatInst::from_instr32(inst)?),
2953                                0b001 => Op::Fmax(RTypeFloatInst::from_instr32(inst)?),
2954                                _ => return Err(InvalidSubop),
2955                            },
2956                            0b01000 => {
2957                                let rd_width = match inst.fsize() {
2958                                    0b00 => 4,
2959                                    0b01 => 8,
2960                                    0b11 => 16,
2961                                    _ => return Err(InvalidSubop),
2962                                };
2963                                let rs1_width = match inst.rs2() {
2964                                    0b00000 => 4,
2965                                    0b00001 => 8,
2966                                    0b00011 => 16,
2967                                    _ => return Err(InvalidSubop),
2968                                };
2969
2970                                if rd_width > float_width
2971                                    || rs1_width > float_width
2972                                    || rd_width == rs1_width
2973                                {
2974                                    return Err(InvalidSubop);
2975                                }
2976
2977                                let rd = FloatReg::new(inst.rd());
2978                                let rs1 = FloatReg::new(inst.rs1());
2979                                let rm = RoundMode::from_bits(inst.rm())?;
2980
2981                                Op::Fcvt(FpCvtInst::new(
2982                                    rd,
2983                                    rd_width as u8,
2984                                    rs1,
2985                                    rs1_width as u8,
2986                                    rm,
2987                                )?)
2988                            }
2989                            0b10100 => match inst.funct3() {
2990                                0b000 => Op::Fle(RTypeFloatCmpInst::from_instr32(inst)?),
2991                                0b001 => Op::Flt(RTypeFloatCmpInst::from_instr32(inst)?),
2992                                0b010 => Op::Feq(RTypeFloatCmpInst::from_instr32(inst)?),
2993                                _ => return Err(InvalidSubop),
2994                            },
2995                            0b01011 if inst.rs2() == 0 => {
2996                                Op::Fsqrt(RTypeFloatRoundInst::from_instr32(inst)?)
2997                            }
2998                            0b11000 => {
2999                                let rs1_width = match inst.fsize() {
3000                                    0b00 => 4,
3001                                    0b01 => 8,
3002                                    0b11 => 16,
3003                                    _ => return Err(InvalidSubop),
3004                                };
3005
3006                                if rs1_width > float_width {
3007                                    return Err(InvalidSubop);
3008                                }
3009
3010                                let rd = IntReg::new(inst.rd());
3011                                let rs1 = FloatReg::new(inst.rs1());
3012                                let rm = RoundMode::from_bits(inst.rm())?;
3013
3014                                match inst.rs2() {
3015                                    0b00000 => Op::FcvtToInt(FpCvtToIntInst::new(
3016                                        rd,
3017                                        4,
3018                                        false,
3019                                        rs1,
3020                                        rs1_width as u8,
3021                                        rm,
3022                                    )?),
3023                                    0b00001 => Op::FcvtToInt(FpCvtToIntInst::new(
3024                                        rd,
3025                                        4,
3026                                        true,
3027                                        rs1,
3028                                        rs1_width as u8,
3029                                        rm,
3030                                    )?),
3031                                    0b00010 if int_width >= 8 => {
3032                                        Op::FcvtToInt(FpCvtToIntInst::new(
3033                                            rd,
3034                                            8,
3035                                            false,
3036                                            rs1,
3037                                            rs1_width as u8,
3038                                            rm,
3039                                        )?)
3040                                    }
3041                                    0b00011 if int_width >= 8 => Op::FcvtToInt(
3042                                        FpCvtToIntInst::new(rd, 8, true, rs1, rs1_width as u8, rm)?,
3043                                    ),
3044                                    _ => return Err(InvalidSubop),
3045                                }
3046                            }
3047                            0b11010 => {
3048                                let rd_width = match inst.fsize() {
3049                                    0b00 => 4,
3050                                    0b01 => 8,
3051                                    0b11 => 16,
3052                                    _ => return Err(InvalidSubop),
3053                                };
3054
3055                                if rd_width > float_width {
3056                                    return Err(InvalidSubop);
3057                                }
3058
3059                                let rd = FloatReg::new(inst.rd());
3060                                let rs1 = IntReg::new(inst.rs1());
3061                                let rm = RoundMode::from_bits(inst.rm())?;
3062
3063                                match inst.rs2() {
3064                                    0b00000 => Op::FcvtFromInt(FpCvtFromIntInst::new(
3065                                        rd,
3066                                        rd_width as u8,
3067                                        rs1,
3068                                        4,
3069                                        false,
3070                                        rm,
3071                                    )?),
3072                                    0b00001 => Op::FcvtFromInt(FpCvtFromIntInst::new(
3073                                        rd,
3074                                        rd_width as u8,
3075                                        rs1,
3076                                        4,
3077                                        true,
3078                                        rm,
3079                                    )?),
3080                                    0b00010 if int_width >= 8 => {
3081                                        Op::FcvtFromInt(FpCvtFromIntInst::new(
3082                                            rd,
3083                                            rd_width as u8,
3084                                            rs1,
3085                                            8,
3086                                            false,
3087                                            rm,
3088                                        )?)
3089                                    }
3090                                    0b00011 if int_width >= 8 => {
3091                                        Op::FcvtFromInt(FpCvtFromIntInst::new(
3092                                            rd,
3093                                            rd_width as u8,
3094                                            rs1,
3095                                            8,
3096                                            true,
3097                                            rm,
3098                                        )?)
3099                                    }
3100                                    _ => return Err(InvalidSubop),
3101                                }
3102                            }
3103                            0b11100 if inst.rs2() == 0 => match inst.funct3() {
3104                                0b000 => Op::FmvToInt(FpMvToIntInst::from_instr32(inst)?),
3105                                0b001 => Op::Fclass(FpClassInst::from_instr32(inst)?),
3106                                _ => return Err(InvalidSubop),
3107                            },
3108                            0b11110 if inst.rs2() == 0 && inst.funct3() == 0 => {
3109                                Op::FmvFromInt(FpMvFromIntInst::from_instr32(inst)?)
3110                            }
3111                            _ => return Err(InvalidSubop),
3112                        }
3113                    }
3114                    // TODO CUSTOM_2
3115                    0b11000 => {
3116                        // BRANCH
3117                        let btype = BTypeInst::from_instr32(inst)?;
3118                        match inst.funct3() {
3119                            0b000 => Op::Beq(btype),
3120                            0b001 => Op::Bne(btype),
3121                            0b100 => Op::Blt(btype),
3122                            0b101 => Op::Bge(btype),
3123                            0b110 => Op::BltU(btype),
3124                            0b111 => Op::BgeU(btype),
3125                            _ => return Err(InvalidSubop),
3126                        }
3127                    }
3128                    0b11001 if inst.funct3() == 0b000 => Op::Jalr(ITypeIntInst::new(inst)?), // JALR
3129                    0b11011 => Op::Jal(JTypeInst::from_instr32(inst)?),                      // JAL
3130                    0b11100 => {
3131                        // SYSTEM
3132                        match inst.funct3() {
3133                            0b000 => {
3134                                let funct12 = inst.0 >> 20;
3135
3136                                match funct12 {
3137                                    // Uses the low 5 bits to hold a register,
3138                                    // everything else treats this as an immediate
3139                                    // or ignores it
3140                                    f if (f & 0xfe0) == 0x120 => {
3141                                        Op::SfenceVma(RTypeIntInst::new(inst)?)
3142                                    }
3143                                    0x104 => Op::SfenceVm(RTypeIntInst::new(inst)?),
3144
3145                                    0x000 => Op::Ecall,
3146                                    0x001 => Op::Ebreak,
3147
3148                                    0x002 => Op::Uret,
3149                                    0x102 => Op::Sret,
3150                                    0x302 => Op::Mret,
3151
3152                                    0x105 => Op::Wfi,
3153                                    _ => return Err(InvalidSubop),
3154                                }
3155                            }
3156                            0b001 => Op::Csrrw(CsrTypeInst::new(inst)?),
3157                            0b010 => Op::Csrrs(CsrTypeInst::new(inst)?),
3158                            0b011 => Op::Csrrc(CsrTypeInst::new(inst)?),
3159                            0b101 => Op::CsrrwI(CsrITypeInst::new(inst)?),
3160                            0b110 => Op::CsrrsI(CsrITypeInst::new(inst)?),
3161                            0b111 => Op::CsrrcI(CsrITypeInst::new(inst)?),
3162                            _ => return Err(InvalidSubop),
3163                        }
3164                    }
3165
3166                    _ => return Err(InvalidOpcode),
3167                };
3168
3169                Ok(Instr::Rv32(decoded))
3170            }
3171            _ => Err(TooShort),
3172        }
3173    }
3174}
3175
3176#[derive(Copy, Clone, Debug)]
3177pub struct RiscVIMACDisassembler<RF: RegFile>(PhantomData<RF>);
3178
3179impl<RF: RegFile> RiscVDisassembler for RiscVIMACDisassembler<RF> {
3180    type RegFile = RF;
3181    type MulDivExtension = ExtensionSupported;
3182    type AtomicExtension = ExtensionSupported;
3183    type CompressedExtension = ExtensionSupported;
3184}