riscv_codec/
instruction.rs

1use crate::immediates::{
2    BImmediate, CSR, CSRImmediate, JImmediate, SImmediate, Shamt, ShamtW, UImmediate,
3};
4use crate::register::{FRegister, IRegister};
5use crate::{immediates::IImmediate, opcode::Opcode};
6use alloc::borrow::ToOwned;
7use alloc::fmt::{Display, Formatter};
8use alloc::format;
9use alloc::string::String;
10
11#[derive(Debug, PartialEq, Clone, Copy)]
12pub enum RoundingMode {
13    /// round to nearest, ties to even
14    RNE = 0b000,
15    /// round towards zero
16    RTZ = 0b001,
17    /// round down
18    RDN = 0b010,
19    /// round up
20    RUP = 0b011,
21    /// round to nearest, ties to max magnitude
22    RMM = 0b100,
23    /// use rounding mode in fcsr
24    DYN = 0b111,
25}
26
27impl Display for RoundingMode {
28    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), alloc::fmt::Error> {
29        match self {
30            RoundingMode::RNE => write!(f, "rne"),
31            RoundingMode::RTZ => write!(f, "rtz"),
32            RoundingMode::RDN => write!(f, "rdn"),
33            RoundingMode::RUP => write!(f, "rup"),
34            RoundingMode::RMM => write!(f, "rmm"),
35            RoundingMode::DYN => write!(f, "dyn"),
36        }
37    }
38}
39
40impl RoundingMode {
41    pub fn from_int(x: u32) -> Result<RoundingMode, String> {
42        match x {
43            0b000 => Ok(RoundingMode::RNE),
44            0b001 => Ok(RoundingMode::RTZ),
45            0b010 => Ok(RoundingMode::RDN),
46            0b011 => Ok(RoundingMode::RUP),
47            0b100 => Ok(RoundingMode::RMM),
48            0b111 => Ok(RoundingMode::DYN),
49            _ => Err("attempted to create invalid rounding mode".to_owned()),
50        }
51    }
52    pub fn from_str(x: &str) -> Result<RoundingMode, String> {
53        match x {
54            "rne" => Ok(RoundingMode::RNE),
55            "rtz" => Ok(RoundingMode::RTZ),
56            "rdn" => Ok(RoundingMode::RDN),
57            "rup" => Ok(RoundingMode::RUP),
58            "rmm" => Ok(RoundingMode::RMM),
59            "dyn" => Ok(RoundingMode::DYN),
60            _ => Err("attempted to create invalid rounding mode".to_owned()),
61        }
62    }
63
64    pub fn to_u32(self) -> u32 {
65        return (self as u32) << 12;
66    }
67}
68
69#[derive(Debug, PartialEq)]
70pub enum Instruction {
71    //
72    // Instructions from RV32I
73    //
74    /// Load upper immediate
75    Lui {
76        dest: IRegister,
77        imm: UImmediate,
78    },
79    /// Add upper immediate to PC
80    Auipc {
81        dest: IRegister,
82        imm: UImmediate,
83    },
84    /// Jump and Link
85    Jal {
86        dest: IRegister,
87        offset: JImmediate,
88    },
89    /// Jump and Link Register
90    Jalr {
91        dest: IRegister,
92        base: IRegister,
93        offset: IImmediate,
94    },
95    Beq {
96        src1: IRegister,
97        src2: IRegister,
98        offset: BImmediate,
99    },
100    Bne {
101        src1: IRegister,
102        src2: IRegister,
103        offset: BImmediate,
104    },
105    Blt {
106        src1: IRegister,
107        src2: IRegister,
108        offset: BImmediate,
109    },
110    Bge {
111        src1: IRegister,
112        src2: IRegister,
113        offset: BImmediate,
114    },
115    Bltu {
116        src1: IRegister,
117        src2: IRegister,
118        offset: BImmediate,
119    },
120    Bgeu {
121        src1: IRegister,
122        src2: IRegister,
123        offset: BImmediate,
124    },
125    /// Load Byte
126    Lb {
127        dest: IRegister,
128        base: IRegister,
129        offset: IImmediate,
130    },
131    /// Load Halfword
132    Lh {
133        dest: IRegister,
134        base: IRegister,
135        offset: IImmediate,
136    },
137    /// Load Word
138    Lw {
139        dest: IRegister,
140        base: IRegister,
141        offset: IImmediate,
142    },
143    /// Load Byte Unsigned
144    Lbu {
145        dest: IRegister,
146        base: IRegister,
147        offset: IImmediate,
148    },
149    /// Load Halfword Unsigned
150    Lhu {
151        dest: IRegister,
152        base: IRegister,
153        offset: IImmediate,
154    },
155    /// Store Byte
156    Sb {
157        src: IRegister,
158        base: IRegister,
159        offset: SImmediate,
160    },
161    /// Store Halfword
162    Sh {
163        src: IRegister,
164        base: IRegister,
165        offset: SImmediate,
166    },
167    /// Store Word
168    Sw {
169        src: IRegister,
170        base: IRegister,
171        offset: SImmediate,
172    },
173    Addi {
174        dest: IRegister,
175        src: IRegister,
176        imm: IImmediate,
177    },
178    Slti {
179        dest: IRegister,
180        src: IRegister,
181        imm: IImmediate,
182    },
183    Sltiu {
184        dest: IRegister,
185        src: IRegister,
186        imm: IImmediate,
187    },
188    Xori {
189        dest: IRegister,
190        src: IRegister,
191        imm: IImmediate,
192    },
193    Ori {
194        dest: IRegister,
195        src: IRegister,
196        imm: IImmediate,
197    },
198    Andi {
199        dest: IRegister,
200        src: IRegister,
201        imm: IImmediate,
202    },
203    /// Left Shift Immediate
204    Slli {
205        dest: IRegister,
206        src: IRegister,
207        shamt: Shamt,
208    },
209    /// Logical Right Shift Immediate
210    Srli {
211        dest: IRegister,
212        src: IRegister,
213        shamt: Shamt,
214    },
215    /// Arithmetic Right Shift Immediate
216    Srai {
217        dest: IRegister,
218        src: IRegister,
219        shamt: Shamt,
220    },
221    Add {
222        dest: IRegister,
223        src1: IRegister,
224        src2: IRegister,
225    },
226    Sub {
227        dest: IRegister,
228        src1: IRegister,
229        src2: IRegister,
230    },
231    /// Left Shift
232    Sll {
233        dest: IRegister,
234        src1: IRegister,
235        src2: IRegister,
236    },
237    Slt {
238        dest: IRegister,
239        src1: IRegister,
240        src2: IRegister,
241    },
242    Sltu {
243        dest: IRegister,
244        src1: IRegister,
245        src2: IRegister,
246    },
247    Xor {
248        dest: IRegister,
249        src1: IRegister,
250        src2: IRegister,
251    },
252    /// Logical Right Shift Immediate
253    Srl {
254        dest: IRegister,
255        src1: IRegister,
256        src2: IRegister,
257    },
258    /// Arithmetic Right Shift Immediate
259    Sra {
260        dest: IRegister,
261        src1: IRegister,
262        src2: IRegister,
263    },
264    Or {
265        dest: IRegister,
266        src1: IRegister,
267        src2: IRegister,
268    },
269    And {
270        dest: IRegister,
271        src1: IRegister,
272        src2: IRegister,
273    },
274    Fence {
275        rd: IRegister,
276        rs1: IRegister,
277        ops: u8,
278        fm: u8,
279    },
280    Ecall,
281    Ebreak,
282    //
283    // Instructions Added In RV64I
284    //
285    /// Load Word Unsigned
286    Lwu {
287        dest: IRegister,
288        base: IRegister,
289        offset: IImmediate,
290    },
291    /// Load Doubleword
292    Ld {
293        dest: IRegister,
294        base: IRegister,
295        offset: IImmediate,
296    },
297    /// Store Doubleword
298    Sd {
299        src: IRegister,
300        base: IRegister,
301        offset: SImmediate,
302    },
303    /// Add Immediate (word)
304    Addiw {
305        dest: IRegister,
306        src: IRegister,
307        imm: IImmediate,
308    },
309    /// Left Shift Immediate (word)
310    Slliw {
311        dest: IRegister,
312        src: IRegister,
313        shamt: ShamtW,
314    },
315    /// Logical Right Shift Immediate (word)
316    Srliw {
317        dest: IRegister,
318        src: IRegister,
319        shamt: ShamtW,
320    },
321    /// Arithmetic Right Shift Immediate (word)
322    Sraiw {
323        dest: IRegister,
324        src: IRegister,
325        shamt: ShamtW,
326    },
327    /// Add (word)
328    Addw {
329        dest: IRegister,
330        src1: IRegister,
331        src2: IRegister,
332    },
333    /// Subtract (word)
334    Subw {
335        dest: IRegister,
336        src1: IRegister,
337        src2: IRegister,
338    },
339    /// Left Shift (word)
340    Sllw {
341        dest: IRegister,
342        src1: IRegister,
343        src2: IRegister,
344    },
345    /// Logical Right Shift (word)
346    Srlw {
347        dest: IRegister,
348        src1: IRegister,
349        src2: IRegister,
350    },
351    /// Arithmetic Right Shift (word)
352    Sraw {
353        dest: IRegister,
354        src1: IRegister,
355        src2: IRegister,
356    },
357    //
358    // Instructions In M Extension
359    //
360    /// Multiply
361    Mul {
362        dest: IRegister,
363        src1: IRegister,
364        src2: IRegister,
365    },
366    /// Multiply (High bits)
367    Mulh {
368        dest: IRegister,
369        src1: IRegister,
370        src2: IRegister,
371    },
372    /// Multiply Signed-Unsigned (High bits)
373    Mulhsu {
374        dest: IRegister,
375        src1: IRegister,
376        src2: IRegister,
377    },
378    /// Multiply Unsigned (High)
379    Mulhu {
380        dest: IRegister,
381        src1: IRegister,
382        src2: IRegister,
383    },
384    /// Divide
385    Div {
386        dest: IRegister,
387        src1: IRegister,
388        src2: IRegister,
389    },
390    /// Divide (Unsigned)
391    Divu {
392        dest: IRegister,
393        src1: IRegister,
394        src2: IRegister,
395    },
396    /// Remainder
397    Rem {
398        dest: IRegister,
399        src1: IRegister,
400        src2: IRegister,
401    },
402    /// Remainder (Unsigned)
403    Remu {
404        dest: IRegister,
405        src1: IRegister,
406        src2: IRegister,
407    },
408    /// Multiply Word
409    Mulw {
410        dest: IRegister,
411        src1: IRegister,
412        src2: IRegister,
413    },
414    /// Divide Word
415    Divw {
416        dest: IRegister,
417        src1: IRegister,
418        src2: IRegister,
419    },
420    /// Divide Unsigned Word
421    Divuw {
422        dest: IRegister,
423        src1: IRegister,
424        src2: IRegister,
425    },
426    /// Remainder Word
427    Remw {
428        dest: IRegister,
429        src1: IRegister,
430        src2: IRegister,
431    },
432    /// Remainder Unsigned Word
433    Remuw {
434        dest: IRegister,
435        src1: IRegister,
436        src2: IRegister,
437    },
438    //
439    // Instructions In A Extension
440    //
441    /// Load Reserved Word
442    // rd, rs1, ac, rl
443    LrW {
444        dest: IRegister,
445        addr: IRegister,
446        aq: bool,
447        rl: bool,
448    },
449    ScW {
450        dest: IRegister,
451        addr: IRegister,
452        src: IRegister,
453        aq: bool,
454        rl: bool,
455    },
456    AmoswapW {
457        dest: IRegister,
458        addr: IRegister,
459        src: IRegister,
460        aq: bool,
461        rl: bool,
462    },
463    AmoaddW {
464        dest: IRegister,
465        addr: IRegister,
466        src: IRegister,
467        aq: bool,
468        rl: bool,
469    },
470    AmoxorW {
471        dest: IRegister,
472        addr: IRegister,
473        src: IRegister,
474        aq: bool,
475        rl: bool,
476    },
477    AmoandW {
478        dest: IRegister,
479        addr: IRegister,
480        src: IRegister,
481        aq: bool,
482        rl: bool,
483    },
484    AmoorW {
485        dest: IRegister,
486        addr: IRegister,
487        src: IRegister,
488        aq: bool,
489        rl: bool,
490    },
491    AmominW {
492        dest: IRegister,
493        addr: IRegister,
494        src: IRegister,
495        aq: bool,
496        rl: bool,
497    },
498    AmomaxW {
499        dest: IRegister,
500        addr: IRegister,
501        src: IRegister,
502        aq: bool,
503        rl: bool,
504    },
505    AmominuW {
506        dest: IRegister,
507        addr: IRegister,
508        src: IRegister,
509        aq: bool,
510        rl: bool,
511    },
512    AmomaxuW {
513        dest: IRegister,
514        addr: IRegister,
515        src: IRegister,
516        aq: bool,
517        rl: bool,
518    },
519    //
520    LrD {
521        dest: IRegister,
522        addr: IRegister,
523        aq: bool,
524        rl: bool,
525    },
526    ScD {
527        dest: IRegister,
528        addr: IRegister,
529        src: IRegister,
530        aq: bool,
531        rl: bool,
532    },
533    AmoswapD {
534        dest: IRegister,
535        addr: IRegister,
536        src: IRegister,
537        aq: bool,
538        rl: bool,
539    },
540    AmoaddD {
541        dest: IRegister,
542        addr: IRegister,
543        src: IRegister,
544        aq: bool,
545        rl: bool,
546    },
547    AmoxorD {
548        dest: IRegister,
549        addr: IRegister,
550        src: IRegister,
551        aq: bool,
552        rl: bool,
553    },
554    AmoandD {
555        dest: IRegister,
556        addr: IRegister,
557        src: IRegister,
558        aq: bool,
559        rl: bool,
560    },
561    AmoorD {
562        dest: IRegister,
563        addr: IRegister,
564        src: IRegister,
565        aq: bool,
566        rl: bool,
567    },
568    AmominD {
569        dest: IRegister,
570        addr: IRegister,
571        src: IRegister,
572        aq: bool,
573        rl: bool,
574    },
575    AmomaxD {
576        dest: IRegister,
577        addr: IRegister,
578        src: IRegister,
579        aq: bool,
580        rl: bool,
581    },
582    AmominuD {
583        dest: IRegister,
584        addr: IRegister,
585        src: IRegister,
586        aq: bool,
587        rl: bool,
588    },
589    AmomaxuD {
590        dest: IRegister,
591        addr: IRegister,
592        src: IRegister,
593        aq: bool,
594        rl: bool,
595    },
596    //
597    // Instructions in F Extension
598    //
599    Flw {
600        dest: FRegister,
601        base: IRegister,
602        offset: IImmediate,
603    },
604    Fsw {
605        base: IRegister,
606        src: FRegister,
607        offset: SImmediate,
608    },
609    FmaddS {
610        dest: FRegister,
611        src1: FRegister,
612        src2: FRegister,
613        src3: FRegister,
614        rm: RoundingMode,
615    },
616    FmsubS {
617        dest: FRegister,
618        src1: FRegister,
619        src2: FRegister,
620        src3: FRegister,
621        rm: RoundingMode,
622    },
623    FnmsubS {
624        dest: FRegister,
625        src1: FRegister,
626        src2: FRegister,
627        src3: FRegister,
628        rm: RoundingMode,
629    },
630    FnmaddS {
631        dest: FRegister,
632        src1: FRegister,
633        src2: FRegister,
634        src3: FRegister,
635        rm: RoundingMode,
636    },
637    FaddS {
638        dest: FRegister,
639        src1: FRegister,
640        src2: FRegister,
641        rm: RoundingMode,
642    },
643    FsubS {
644        dest: FRegister,
645        src1: FRegister,
646        src2: FRegister,
647        rm: RoundingMode,
648    },
649    FmulS {
650        dest: FRegister,
651        src1: FRegister,
652        src2: FRegister,
653        rm: RoundingMode,
654    },
655    FdivS {
656        dest: FRegister,
657        src1: FRegister,
658        src2: FRegister,
659        rm: RoundingMode,
660    },
661    FsqrtS {
662        dest: FRegister,
663        src: FRegister,
664        rm: RoundingMode,
665    },
666    FsgnjS {
667        dest: FRegister,
668        src1: FRegister,
669        src2: FRegister,
670    },
671    FsgnjnS {
672        dest: FRegister,
673        src1: FRegister,
674        src2: FRegister,
675    },
676    FsgnjxS {
677        dest: FRegister,
678        src1: FRegister,
679        src2: FRegister,
680    },
681    FminS {
682        dest: FRegister,
683        src1: FRegister,
684        src2: FRegister,
685    },
686    FmaxS {
687        dest: FRegister,
688        src1: FRegister,
689        src2: FRegister,
690    },
691    FcvtWS {
692        dest: IRegister,
693        src: FRegister,
694        rm: RoundingMode,
695    },
696    FcvtWuS {
697        dest: IRegister,
698        src: FRegister,
699        rm: RoundingMode,
700    },
701    FmvXW {
702        dest: IRegister,
703        src: FRegister,
704    },
705    FeqS {
706        dest: IRegister,
707        src1: FRegister,
708        src2: FRegister,
709    },
710    FltS {
711        dest: IRegister,
712        src1: FRegister,
713        src2: FRegister,
714    },
715    FleS {
716        dest: IRegister,
717        src1: FRegister,
718        src2: FRegister,
719    },
720    FclassS {
721        dest: IRegister,
722        src: FRegister,
723    },
724    FcvtSW {
725        dest: FRegister,
726        src: IRegister,
727        rm: RoundingMode,
728    },
729    FcvtSWu {
730        dest: FRegister,
731        src: IRegister,
732        rm: RoundingMode,
733    },
734    FmvWX {
735        dest: FRegister,
736        src: IRegister,
737    },
738    //
739    // Instructions in F Extension (RV64)
740    //
741    FcvtLS {
742        dest: IRegister,
743        src: FRegister,
744        rm: RoundingMode,
745    },
746    FcvtLuS {
747        dest: IRegister,
748        src: FRegister,
749        rm: RoundingMode,
750    },
751    FcvtSL {
752        dest: FRegister,
753        src: IRegister,
754        rm: RoundingMode,
755    },
756    FcvtSLu {
757        dest: FRegister,
758        src: IRegister,
759        rm: RoundingMode,
760    },
761    //
762    // Instructions in Zicsr Extension
763    //
764    Csrrw {
765        dest: IRegister,
766        src: IRegister,
767        csr: CSR,
768    },
769    Csrrs {
770        dest: IRegister,
771        src: IRegister,
772        csr: CSR,
773    },
774    Csrrc {
775        dest: IRegister,
776        src: IRegister,
777        csr: CSR,
778    },
779    Csrrwi {
780        dest: IRegister,
781        imm: CSRImmediate,
782        csr: CSR,
783    },
784    Csrrsi {
785        dest: IRegister,
786        imm: CSRImmediate,
787        csr: CSR,
788    },
789    Csrrci {
790        dest: IRegister,
791        imm: CSRImmediate,
792        csr: CSR,
793    },
794    //
795    // Instructions in Zifencei Extension
796    //
797    FenceI,
798    //
799    // Instructions in D Extension
800    //
801    Fld {
802        dest: FRegister,
803        base: IRegister,
804        offset: IImmediate,
805    },
806    Fsd {
807        src: FRegister,
808        base: IRegister,
809        offset: SImmediate,
810    },
811    FmaddD {
812        dest: FRegister,
813        src1: FRegister,
814        src2: FRegister,
815        src3: FRegister,
816        rm: RoundingMode,
817    },
818    FmsubD {
819        dest: FRegister,
820        src1: FRegister,
821        src2: FRegister,
822        src3: FRegister,
823        rm: RoundingMode,
824    },
825    FnmaddD {
826        dest: FRegister,
827        src1: FRegister,
828        src2: FRegister,
829        src3: FRegister,
830        rm: RoundingMode,
831    },
832    FnmsubD {
833        dest: FRegister,
834        src1: FRegister,
835        src2: FRegister,
836        src3: FRegister,
837        rm: RoundingMode,
838    },
839    FaddD {
840        dest: FRegister,
841        src1: FRegister,
842        src2: FRegister,
843        rm: RoundingMode,
844    },
845    FsubD {
846        dest: FRegister,
847        src1: FRegister,
848        src2: FRegister,
849        rm: RoundingMode,
850    },
851    FmulD {
852        dest: FRegister,
853        src1: FRegister,
854        src2: FRegister,
855        rm: RoundingMode,
856    },
857    FdivD {
858        dest: FRegister,
859        src1: FRegister,
860        src2: FRegister,
861        rm: RoundingMode,
862    },
863    FsqrtD {
864        dest: FRegister,
865        src: FRegister,
866        rm: RoundingMode,
867    },
868    FsgnjD {
869        dest: FRegister,
870        src1: FRegister,
871        src2: FRegister,
872    },
873    FsgnjnD {
874        dest: FRegister,
875        src1: FRegister,
876        src2: FRegister,
877    },
878    FsgnjxD {
879        dest: FRegister,
880        src1: FRegister,
881        src2: FRegister,
882    },
883    FminD {
884        dest: FRegister,
885        src1: FRegister,
886        src2: FRegister,
887    },
888    FmaxD {
889        dest: FRegister,
890        src1: FRegister,
891        src2: FRegister,
892    },
893    FcvtSD {
894        dest: FRegister,
895        src: FRegister,
896        rm: RoundingMode,
897    },
898    FcvtDS {
899        dest: FRegister,
900        src: FRegister,
901        rm: RoundingMode,
902    },
903    FeqD {
904        dest: IRegister,
905        src1: FRegister,
906        src2: FRegister,
907    },
908    FltD {
909        dest: IRegister,
910        src1: FRegister,
911        src2: FRegister,
912    },
913    FleD {
914        dest: IRegister,
915        src1: FRegister,
916        src2: FRegister,
917    },
918    FclassD {
919        dest: IRegister,
920        src1: FRegister,
921    },
922    FcvtWD {
923        dest: IRegister,
924        src1: FRegister,
925        rm: RoundingMode,
926    },
927    FcvtWuD {
928        dest: IRegister,
929        src1: FRegister,
930        rm: RoundingMode,
931    },
932    FcvtDW {
933        dest: FRegister,
934        src1: IRegister,
935        rm: RoundingMode,
936    },
937    FcvtDWu {
938        dest: FRegister,
939        src1: IRegister,
940        rm: RoundingMode,
941    },
942    FcvtLD {
943        dest: IRegister,
944        src1: FRegister,
945        rm: RoundingMode,
946    },
947    FcvtLuD {
948        dest: IRegister,
949        src1: FRegister,
950        rm: RoundingMode,
951    },
952    FmvXD {
953        dest: IRegister,
954        src: FRegister,
955    },
956    FcvtDL {
957        dest: FRegister,
958        src: IRegister,
959        rm: RoundingMode,
960    },
961    FcvtDLu {
962        dest: FRegister,
963        src: IRegister,
964        rm: RoundingMode,
965    },
966    FmvDX {
967        dest: FRegister,
968        src: IRegister,
969    },
970}
971
972fn aq_rl_suffix(aq: &bool, rl: &bool) -> &'static str {
973    match (aq, rl) {
974        (true, true) => ".aqrl",
975        (true, false) => ".aq",
976        (false, true) => ".rl",
977        (false, false) => "",
978    }
979}
980
981/// puts the aquire bit in the correct location
982fn aqb(aq: bool) -> u32 {
983    if aq { 1 << 26 } else { 0 }
984}
985
986/// puts the release bit in the correct location
987fn rlb(rl: bool) -> u32 {
988    if rl { 1 << 25 } else { 0 }
989}
990
991impl Display for Instruction {
992    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), alloc::fmt::Error> {
993        match self {
994            Instruction::Lui { dest, imm } => write!(f, "lui {dest},{imm}"),
995            Instruction::Auipc { dest, imm } => write!(f, "auipc {dest},{imm}"),
996            Instruction::Jal { dest, offset } => write!(f, "jal {dest},{offset}"),
997            Instruction::Jalr { dest, base, offset } => write!(f, "jalr {dest},{offset}({base})"),
998            Instruction::Beq { src1, src2, offset } => write!(f, "beq {src1},{src2},{offset}"),
999            Instruction::Bne { src1, src2, offset } => write!(f, "bne {src1},{src2},{offset}"),
1000            Instruction::Blt { src1, src2, offset } => write!(f, "blt {src1},{src2},{offset}"),
1001            Instruction::Bge { src1, src2, offset } => write!(f, "bge {src1},{src2},{offset}"),
1002            Instruction::Bltu { src1, src2, offset } => write!(f, "bltu {src1},{src2},{offset}"),
1003            Instruction::Bgeu { src1, src2, offset } => write!(f, "bgeu {src1},{src2},{offset}"),
1004            Instruction::Lb { dest, base, offset } => write!(f, "lb {dest},{offset}({base})"),
1005            Instruction::Lh { dest, base, offset } => write!(f, "lh {dest},{offset}({base})"),
1006            Instruction::Lw { dest, base, offset } => write!(f, "lw {dest},{offset}({base})"),
1007            Instruction::Lbu { dest, base, offset } => write!(f, "lbu {dest},{offset}({base})"),
1008            Instruction::Lhu { dest, base, offset } => write!(f, "lhu {dest},{offset}({base})"),
1009            Instruction::Sb { src, base, offset } => write!(f, "sb {src},{offset}({base})"),
1010            Instruction::Sh { src, base, offset } => write!(f, "sh {src},{offset}({base})"),
1011            Instruction::Sw { src, base, offset } => write!(f, "sw {src},{offset}({base})"),
1012            Instruction::Addi { dest, src, imm } => write!(f, "addi {dest},{src},{imm}"),
1013            Instruction::Slti { dest, src, imm } => write!(f, "slti {dest},{src},{imm}"),
1014            Instruction::Sltiu { dest, src, imm } => write!(f, "sltiu {dest},{src},{imm}"),
1015            Instruction::Xori { dest, src, imm } => write!(f, "xori {dest},{src},{imm}"),
1016            Instruction::Ori { dest, src, imm } => write!(f, "ori {dest},{src},{imm}"),
1017            Instruction::Andi { dest, src, imm } => write!(f, "andi {dest},{src},{imm}"),
1018            Instruction::Slli { dest, src, shamt } => write!(f, "slli {dest},{src},{shamt}"),
1019            Instruction::Srli { dest, src, shamt } => write!(f, "srli {dest},{src},{shamt}"),
1020            Instruction::Srai { dest, src, shamt } => write!(f, "srai {dest},{src},{shamt}"),
1021            Instruction::Add { dest, src1, src2 } => write!(f, "add {dest},{src1},{src2}"),
1022            Instruction::Sub { dest, src1, src2 } => write!(f, "sub {dest},{src1},{src2}"),
1023            Instruction::Sll { dest, src1, src2 } => write!(f, "sll {dest},{src1},{src2}"),
1024            Instruction::Slt { dest, src1, src2 } => write!(f, "slt {dest},{src1},{src2}"),
1025            Instruction::Sltu { dest, src1, src2 } => write!(f, "sltu {dest},{src1},{src2}"),
1026            Instruction::Xor { dest, src1, src2 } => write!(f, "xor {dest},{src1},{src2}"),
1027            Instruction::Srl { dest, src1, src2 } => write!(f, "srl {dest},{src1},{src2}"),
1028            Instruction::Sra { dest, src1, src2 } => write!(f, "sra {dest},{src1},{src2}"),
1029            Instruction::Or { dest, src1, src2 } => write!(f, "or {dest},{src1},{src2}"),
1030            Instruction::And { dest, src1, src2 } => write!(f, "and {dest},{src1},{src2}"),
1031            Instruction::Fence { .. } => write!(f, "{}", self.fmt_fence()),
1032            Instruction::Ecall => write!(f, "ecall"),
1033            Instruction::Ebreak => write!(f, "ebreak"),
1034            Instruction::Lwu { dest, base, offset } => write!(f, "lwu {dest},{offset}({base})"),
1035            Instruction::Ld { dest, base, offset } => write!(f, "ld {dest},{offset}({base})"),
1036            Instruction::Sd { src, base, offset } => write!(f, "sd {src},{offset}({base})"),
1037            Instruction::Addiw { dest, src, imm } => write!(f, "addiw {dest},{src},{imm}"),
1038            Instruction::Slliw { dest, src, shamt } => write!(f, "slliw {dest},{src},{shamt}"),
1039            Instruction::Srliw { dest, src, shamt } => write!(f, "srliw {dest},{src},{shamt}"),
1040            Instruction::Sraiw { dest, src, shamt } => write!(f, "sraiw {dest},{src},{shamt}"),
1041            Instruction::Addw { dest, src1, src2 } => write!(f, "addw {dest},{src1},{src2}"),
1042            Instruction::Subw { dest, src1, src2 } => write!(f, "subw {dest},{src1},{src2}"),
1043            Instruction::Sllw { dest, src1, src2 } => write!(f, "sllw {dest},{src1},{src2}"),
1044            Instruction::Srlw { dest, src1, src2 } => write!(f, "srlw {dest},{src1},{src2}"),
1045            Instruction::Sraw { dest, src1, src2 } => write!(f, "sraw {dest},{src1},{src2}"),
1046            Instruction::Mul { dest, src1, src2 } => write!(f, "mul {dest},{src1},{src2}"),
1047            Instruction::Mulh { dest, src1, src2 } => write!(f, "mulh {dest},{src1},{src2}"),
1048            Instruction::Mulhsu { dest, src1, src2 } => write!(f, "mulhsu {dest},{src1},{src2}"),
1049            Instruction::Mulhu { dest, src1, src2 } => write!(f, "mulhu {dest},{src1},{src2}"),
1050            Instruction::Div { dest, src1, src2 } => write!(f, "div {dest},{src1},{src2}"),
1051            Instruction::Divu { dest, src1, src2 } => write!(f, "divu {dest},{src1},{src2}"),
1052            Instruction::Rem { dest, src1, src2 } => write!(f, "rem {dest},{src1},{src2}"),
1053            Instruction::Remu { dest, src1, src2 } => write!(f, "remu {dest},{src1},{src2}"),
1054            Instruction::Mulw { dest, src1, src2 } => write!(f, "mulw {dest},{src1},{src2}"),
1055            Instruction::Divw { dest, src1, src2 } => write!(f, "divw {dest},{src1},{src2}"),
1056            Instruction::Divuw { dest, src1, src2 } => write!(f, "divuw {dest},{src1},{src2}"),
1057            Instruction::Remw { dest, src1, src2 } => write!(f, "remw {dest},{src1},{src2}"),
1058            Instruction::Remuw { dest, src1, src2 } => write!(f, "remuw {dest},{src1},{src2}"),
1059            Instruction::LrW { dest, addr, aq, rl } => {
1060                write!(f, "lr.w{} {dest},{addr}", aq_rl_suffix(aq, rl))
1061            }
1062            Instruction::ScW {
1063                dest,
1064                addr,
1065                src,
1066                aq,
1067                rl,
1068            } => {
1069                write!(f, "sc.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1070            }
1071            Instruction::AmoswapW {
1072                dest,
1073                addr,
1074                src,
1075                aq,
1076                rl,
1077            } => {
1078                write!(f, "amoswap.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1079            }
1080            Instruction::AmoaddW {
1081                dest,
1082                addr,
1083                src,
1084                aq,
1085                rl,
1086            } => {
1087                write!(f, "amoadd.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1088            }
1089            Instruction::AmoxorW {
1090                dest,
1091                addr,
1092                src,
1093                aq,
1094                rl,
1095            } => {
1096                write!(f, "amoxor.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1097            }
1098            Instruction::AmoandW {
1099                dest,
1100                addr,
1101                src,
1102                aq,
1103                rl,
1104            } => {
1105                write!(f, "amoand.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1106            }
1107            Instruction::AmoorW {
1108                dest,
1109                addr,
1110                src,
1111                aq,
1112                rl,
1113            } => {
1114                write!(f, "amoor.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1115            }
1116            Instruction::AmominW {
1117                dest,
1118                addr,
1119                src,
1120                aq,
1121                rl,
1122            } => {
1123                write!(f, "amomin.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1124            }
1125            Instruction::AmomaxW {
1126                dest,
1127                addr,
1128                src,
1129                aq,
1130                rl,
1131            } => {
1132                write!(f, "amomax.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1133            }
1134            Instruction::AmominuW {
1135                dest,
1136                addr,
1137                src,
1138                aq,
1139                rl,
1140            } => {
1141                write!(f, "amominu.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1142            }
1143            Instruction::AmomaxuW {
1144                dest,
1145                addr,
1146                src,
1147                aq,
1148                rl,
1149            } => {
1150                write!(f, "amomaxu.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1151            }
1152            Instruction::LrD { dest, addr, aq, rl } => {
1153                write!(f, "lr.d{} {dest},{addr}", aq_rl_suffix(aq, rl))
1154            }
1155            Instruction::ScD {
1156                dest,
1157                addr,
1158                src,
1159                aq,
1160                rl,
1161            } => {
1162                write!(f, "sc.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1163            }
1164            Instruction::AmoswapD {
1165                dest,
1166                addr,
1167                src,
1168                aq,
1169                rl,
1170            } => {
1171                write!(f, "amoswap.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1172            }
1173            Instruction::AmoaddD {
1174                dest,
1175                addr,
1176                src,
1177                aq,
1178                rl,
1179            } => {
1180                write!(f, "amoadd.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1181            }
1182            Instruction::AmoxorD {
1183                dest,
1184                addr,
1185                src,
1186                aq,
1187                rl,
1188            } => {
1189                write!(f, "amoxor.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1190            }
1191            Instruction::AmoandD {
1192                dest,
1193                addr,
1194                src,
1195                aq,
1196                rl,
1197            } => {
1198                write!(f, "amoand.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1199            }
1200            Instruction::AmoorD {
1201                dest,
1202                addr,
1203                src,
1204                aq,
1205                rl,
1206            } => {
1207                write!(f, "amoor.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1208            }
1209            Instruction::AmominD {
1210                dest,
1211                addr,
1212                src,
1213                aq,
1214                rl,
1215            } => {
1216                write!(f, "amomin.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1217            }
1218            Instruction::AmomaxD {
1219                dest,
1220                addr,
1221                src,
1222                aq,
1223                rl,
1224            } => {
1225                write!(f, "amomax.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1226            }
1227            Instruction::AmominuD {
1228                dest,
1229                addr,
1230                src,
1231                aq,
1232                rl,
1233            } => {
1234                write!(f, "amominu.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1235            }
1236            Instruction::AmomaxuD {
1237                dest,
1238                addr,
1239                src,
1240                aq,
1241                rl,
1242            } => {
1243                write!(f, "amomaxu.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1244            }
1245            Instruction::Flw { dest, base, offset } => write!(f, "flw {dest},{offset}({base})"),
1246            Instruction::Fsw { base, src, offset } => write!(f, "fsw {src},{offset}({base})"),
1247            Instruction::FmaddS {
1248                dest,
1249                src1,
1250                src2,
1251                src3,
1252                rm,
1253            } => {
1254                write!(f, "fmadd.s {dest},{src1},{src2},{src3},{rm}")
1255            }
1256            Instruction::FmsubS {
1257                dest,
1258                src1,
1259                src2,
1260                src3,
1261                rm,
1262            } => {
1263                write!(f, "fmsub.s {dest},{src1},{src2},{src3},{rm}")
1264            }
1265            Instruction::FnmsubS {
1266                dest,
1267                src1,
1268                src2,
1269                src3,
1270                rm,
1271            } => {
1272                write!(f, "fnmsub.s {dest},{src1},{src2},{src3},{rm}")
1273            }
1274            Instruction::FnmaddS {
1275                dest,
1276                src1,
1277                src2,
1278                src3,
1279                rm,
1280            } => {
1281                write!(f, "fnmadd.s {dest},{src1},{src2},{src3},{rm}")
1282            }
1283            Instruction::FaddS {
1284                dest,
1285                src1,
1286                src2,
1287                rm,
1288            } => write!(f, "fadd.s {dest},{src1},{src2},{rm}"),
1289            Instruction::FsubS {
1290                dest,
1291                src1,
1292                src2,
1293                rm,
1294            } => write!(f, "fsub.s {dest},{src1},{src2},{rm}"),
1295            Instruction::FmulS {
1296                dest,
1297                src1,
1298                src2,
1299                rm,
1300            } => write!(f, "fmul.s {dest},{src1},{src2},{rm}"),
1301            Instruction::FdivS {
1302                dest,
1303                src1,
1304                src2,
1305                rm,
1306            } => write!(f, "fdiv.s {dest},{src1},{src2},{rm}"),
1307            Instruction::FsqrtS { dest, src, rm } => write!(f, "fsqrt.s {dest},{src},{rm}"),
1308            Instruction::FsgnjS { dest, src1, src2 } => write!(f, "fsgnj.s {dest},{src1},{src2}"),
1309            Instruction::FsgnjnS { dest, src1, src2 } => write!(f, "fsgnjn.s {dest},{src1},{src2}"),
1310            Instruction::FsgnjxS { dest, src1, src2 } => write!(f, "fsgnjx.s {dest},{src1},{src2}"),
1311            Instruction::FminS { dest, src1, src2 } => write!(f, "fmin.s {dest},{src1},{src2}"),
1312            Instruction::FmaxS { dest, src1, src2 } => write!(f, "fmax.s {dest},{src1},{src2}"),
1313            Instruction::FcvtWS { dest, src, rm } => write!(f, "fcvt.w.s {dest},{src},{rm}"),
1314            Instruction::FcvtWuS { dest, src, rm } => write!(f, "fcvt.wu.s {dest},{src},{rm}"),
1315            Instruction::FmvXW { dest, src } => write!(f, "fmv.x.w {dest},{src}"),
1316            Instruction::FeqS { dest, src1, src2 } => write!(f, "feq.s {dest},{src1},{src2}"),
1317            Instruction::FltS { dest, src1, src2 } => write!(f, "flt.s {dest},{src1},{src2}"),
1318            Instruction::FleS { dest, src1, src2 } => write!(f, "fle.s {dest},{src1},{src2}"),
1319            Instruction::FclassS { dest, src } => write!(f, "fclass.s {dest},{src}"),
1320            Instruction::FcvtSW { dest, src, rm } => write!(f, "fcvt.s.w {dest},{src},{rm}"),
1321            Instruction::FcvtSWu { dest, src, rm } => write!(f, "fcvt.s.wu {dest},{src},{rm}"),
1322            Instruction::FmvWX { dest, src } => write!(f, "fmv.w.x {dest},{src}"),
1323            Instruction::FcvtLS { dest, src, rm } => write!(f, "fcvt.l.s {dest},{src},{rm}"),
1324            Instruction::FcvtLuS { dest, src, rm } => write!(f, "fcvt.lu.s {dest},{src},{rm}"),
1325            Instruction::FcvtSL { dest, src, rm } => write!(f, "fcvt.s.l {dest},{src},{rm}"),
1326            Instruction::FcvtSLu { dest, src, rm } => write!(f, "fcvt.s.lu {dest},{src},{rm}"),
1327            Instruction::Csrrw { dest, src, csr } => write!(f, "csrrw {dest},{csr},{src}"),
1328            Instruction::Csrrs { dest, src, csr } => write!(f, "csrrs {dest},{csr},{src}"),
1329            Instruction::Csrrc { dest, src, csr } => write!(f, "csrrc {dest},{csr},{src}"),
1330            Instruction::Csrrwi { dest, imm, csr } => write!(f, "csrrwi {dest},{csr},{imm}"),
1331            Instruction::Csrrsi { dest, imm, csr } => write!(f, "csrrsi {dest},{csr},{imm}"),
1332            Instruction::Csrrci { dest, imm, csr } => write!(f, "csrrci {dest},{csr},{imm}"),
1333            Instruction::FenceI => write!(f, "fence.i"),
1334            Instruction::Fld { dest, base, offset } => write!(f, "fld {dest},{offset}({base})"),
1335            Instruction::Fsd { src, base, offset } => write!(f, "fsd {src},{offset}({base})"),
1336            Instruction::FmaddD {
1337                dest,
1338                src1,
1339                src2,
1340                src3,
1341                rm,
1342            } => write!(f, "fmadd.d {dest},{src1},{src2},{src3},{rm}"),
1343            Instruction::FmsubD {
1344                dest,
1345                src1,
1346                src2,
1347                src3,
1348                rm,
1349            } => write!(f, "fmsub.d {dest},{src1},{src2},{src3},{rm}"),
1350            Instruction::FnmaddD {
1351                dest,
1352                src1,
1353                src2,
1354                src3,
1355                rm,
1356            } => write!(f, "fnmadd.d {dest},{src1},{src2},{src3},{rm}"),
1357            Instruction::FnmsubD {
1358                dest,
1359                src1,
1360                src2,
1361                src3,
1362                rm,
1363            } => write!(f, "fnmsub.d {dest},{src1},{src2},{src3},{rm}"),
1364            Instruction::FaddD {
1365                dest,
1366                src1,
1367                src2,
1368                rm,
1369            } => write!(f, "fadd.d {dest},{src1},{src2},{rm}"),
1370            Instruction::FsubD {
1371                dest,
1372                src1,
1373                src2,
1374                rm,
1375            } => write!(f, "fsub.d {dest},{src1},{src2},{rm}"),
1376            Instruction::FmulD {
1377                dest,
1378                src1,
1379                src2,
1380                rm,
1381            } => write!(f, "fmul.d {dest},{src1},{src2},{rm}"),
1382            Instruction::FdivD {
1383                dest,
1384                src1,
1385                src2,
1386                rm,
1387            } => write!(f, "fdiv.d {dest},{src1},{src2},{rm}"),
1388            Instruction::FsqrtD {
1389                dest,
1390                src: src1,
1391                rm,
1392            } => write!(f, "fsqrt.d {dest},{src1},{rm}"),
1393            Instruction::FsgnjD { dest, src1, src2 } => write!(f, "fsgnj.d {dest},{src1},{src2}"),
1394            Instruction::FsgnjnD { dest, src1, src2 } => write!(f, "fsgnjn.d {dest},{src1},{src2}"),
1395            Instruction::FsgnjxD { dest, src1, src2 } => write!(f, "fsgnjx.d {dest},{src1},{src2}"),
1396            Instruction::FminD { dest, src1, src2 } => write!(f, "fmin.d {dest},{src1},{src2}"),
1397            Instruction::FmaxD { dest, src1, src2 } => write!(f, "fmax.d {dest},{src1},{src2}"),
1398            Instruction::FcvtSD { dest, src, rm } => write!(f, "fcvt.s.d {dest},{src},{rm}"),
1399            Instruction::FcvtDS { dest, src, rm } => write!(f, "fcvt.d.s {dest},{src},{rm}"),
1400            Instruction::FeqD { dest, src1, src2 } => write!(f, "feq.d {dest},{src1},{src2}"),
1401            Instruction::FltD { dest, src1, src2 } => write!(f, "flt.d {dest},{src1},{src2}"),
1402            Instruction::FleD { dest, src1, src2 } => write!(f, "fle.d {dest},{src1},{src2}"),
1403            Instruction::FclassD { dest, src1 } => write!(f, "fclass.d {dest},{src1}"),
1404            Instruction::FcvtWD { dest, src1, rm } => write!(f, "fcvt.w.d {dest},{src1},{rm}"),
1405            Instruction::FcvtWuD { dest, src1, rm } => write!(f, "fcvt.wu.d {dest},{src1},{rm}"),
1406            Instruction::FcvtDW { dest, src1, rm } => write!(f, "fcvt.d.w {dest},{src1},{rm}"),
1407            Instruction::FcvtDWu { dest, src1, rm } => write!(f, "fcvt.d.wu {dest},{src1},{rm}"),
1408            Instruction::FcvtLD { dest, src1, rm } => write!(f, "fcvt.l.d {dest},{src1},{rm}"),
1409            Instruction::FcvtLuD { dest, src1, rm } => write!(f, "fcvt.lu.d {dest},{src1},{rm}"),
1410            Instruction::FmvXD { dest, src } => write!(f, "fmv.x.d {dest},{src}"),
1411            Instruction::FcvtDL {
1412                dest,
1413                src: src1,
1414                rm,
1415            } => write!(f, "fcvt.d.l {dest},{src1},{rm}"),
1416            Instruction::FcvtDLu {
1417                dest,
1418                src: src1,
1419                rm,
1420            } => write!(f, "fcvt.d.lu {dest},{src1},{rm}"),
1421            Instruction::FmvDX { dest, src } => write!(f, "fmv.d.x {dest},{src}"),
1422        }
1423    }
1424}
1425
1426impl Instruction {
1427    fn fmt_fence(&self) -> String {
1428        if let Instruction::Fence {
1429            rd: _,
1430            rs1: _,
1431            ops,
1432            fm,
1433        } = *self
1434        {
1435            let sw = if ops & 0b0000_0001 != 0 { "w" } else { "" };
1436            let sr = if ops & 0b0000_0010 != 0 { "r" } else { "" };
1437            let so = if ops & 0b0000_0100 != 0 { "o" } else { "" };
1438            let si = if ops & 0b0000_1000 != 0 { "i" } else { "" };
1439            let pw = if ops & 0b0001_0000 != 0 { "w" } else { "" };
1440            let pr = if ops & 0b0010_0000 != 0 { "r" } else { "" };
1441            let po = if ops & 0b0100_0000 != 0 { "o" } else { "" };
1442            let pi = if ops & 0b1000_0000 != 0 { "i" } else { "" };
1443            if fm == 0b1000 {
1444                format!("fence.tso {pi}{po}{pr}{pw},{si}{so}{sr}{sw}")
1445            } else {
1446                format!("fence {pi}{po}{pr}{pw},{si}{so}{sr}{sw}")
1447            }
1448        } else {
1449            unreachable!();
1450        }
1451    }
1452
1453    /// Constructs an `Instruction` from it's machine code representation.
1454    pub fn decode(instruction: u32) -> Result<Instruction, String> {
1455        let opcode = Opcode::from_int(instruction & 0b111_1111);
1456
1457        let func3 = (instruction >> 12) & 0b111;
1458        let func7 = (instruction >> 25) & 0b111_1111;
1459
1460        let rd = IRegister::from_int((instruction >> 7) & 0b1_1111);
1461        let rs1 = IRegister::from_int((instruction >> 15) & 0b1_1111);
1462        let rs2 = IRegister::from_int((instruction >> 20) & 0b1_1111);
1463
1464        let frd = FRegister::try_from((instruction >> 7) & 0b1_1111).unwrap();
1465        let frs1 = FRegister::try_from((instruction >> 15) & 0b1_1111).unwrap();
1466        let frs2 = FRegister::try_from((instruction >> 20) & 0b1_1111).unwrap();
1467        let frs3 = FRegister::try_from((instruction >> 27) & 0b1_1111).unwrap();
1468
1469        let i_immediate: IImmediate = IImmediate::from_u32(instruction);
1470
1471        let s_immediate: SImmediate = SImmediate::from_u32(instruction);
1472
1473        let u_immediate = UImmediate::from_u32(instruction);
1474
1475        let b_immediate = BImmediate::from_u32(instruction);
1476
1477        let shamt: Shamt = Shamt::from_u32(instruction);
1478
1479        let shamtw: ShamtW = ShamtW::from_u32(instruction);
1480
1481        // aq is bit 26, rl is bit 25
1482        let aq: bool = ((instruction >> 26) & 0b1) == 0b1;
1483        let rl: bool = ((instruction >> 25) & 0b1) == 0b1;
1484
1485        match opcode {
1486            Opcode::Load => match func3 {
1487                0b000 => Ok(Instruction::Lb {
1488                    dest: rd,
1489                    base: rs1,
1490                    offset: i_immediate,
1491                }),
1492                0b001 => Ok(Instruction::Lh {
1493                    dest: rd,
1494                    base: rs1,
1495                    offset: i_immediate,
1496                }),
1497                0b010 => Ok(Instruction::Lw {
1498                    dest: rd,
1499                    base: rs1,
1500                    offset: i_immediate,
1501                }),
1502                0b011 => Ok(Instruction::Ld {
1503                    dest: rd,
1504                    base: rs1,
1505                    offset: i_immediate,
1506                }),
1507                0b100 => Ok(Instruction::Lbu {
1508                    dest: rd,
1509                    base: rs1,
1510                    offset: i_immediate,
1511                }),
1512                0b101 => Ok(Instruction::Lhu {
1513                    dest: rd,
1514                    base: rs1,
1515                    offset: i_immediate,
1516                }),
1517                0b110 => Ok(Instruction::Lwu {
1518                    dest: rd,
1519                    base: rs1,
1520                    offset: i_immediate,
1521                }),
1522                0b111 => Err("Invalid load func3".to_owned()),
1523                _ => unreachable!(),
1524            },
1525            Opcode::Auipc => Ok(Instruction::Auipc {
1526                dest: rd,
1527                imm: u_immediate,
1528            }),
1529            Opcode::Store => match func3 {
1530                0b000 => Ok(Instruction::Sb {
1531                    src: rs2,
1532                    base: rs1,
1533                    offset: s_immediate,
1534                }),
1535                0b001 => Ok(Instruction::Sh {
1536                    src: rs2,
1537                    base: rs1,
1538                    offset: s_immediate,
1539                }),
1540                0b010 => Ok(Instruction::Sw {
1541                    src: rs2,
1542                    base: rs1,
1543                    offset: s_immediate,
1544                }),
1545                0b011 => Ok(Instruction::Sd {
1546                    src: rs2,
1547                    base: rs1,
1548                    offset: s_immediate,
1549                }),
1550                x => Err(format!("invalid store func3: {}", x)),
1551            },
1552            Opcode::Lui => Ok(Instruction::Lui {
1553                dest: rd,
1554                imm: u_immediate,
1555            }),
1556            Opcode::Op => match (func7, func3) {
1557                (0b000_0000, 0b000) => Ok(Instruction::Add {
1558                    dest: rd,
1559                    src1: rs1,
1560                    src2: rs2,
1561                }),
1562                (0b000_0000, 0b001) => Ok(Instruction::Sll {
1563                    dest: rd,
1564                    src1: rs1,
1565                    src2: rs2,
1566                }),
1567                (0b000_0000, 0b010) => Ok(Instruction::Slt {
1568                    dest: rd,
1569                    src1: rs1,
1570                    src2: rs2,
1571                }),
1572                (0b000_0000, 0b011) => Ok(Instruction::Sltu {
1573                    dest: rd,
1574                    src1: rs1,
1575                    src2: rs2,
1576                }),
1577                (0b000_0000, 0b100) => Ok(Instruction::Xor {
1578                    dest: rd,
1579                    src1: rs1,
1580                    src2: rs2,
1581                }),
1582                (0b000_0000, 0b101) => Ok(Instruction::Srl {
1583                    dest: rd,
1584                    src1: rs1,
1585                    src2: rs2,
1586                }),
1587                (0b000_0000, 0b110) => Ok(Instruction::Or {
1588                    dest: rd,
1589                    src1: rs1,
1590                    src2: rs2,
1591                }),
1592                (0b000_0000, 0b111) => Ok(Instruction::And {
1593                    dest: rd,
1594                    src1: rs1,
1595                    src2: rs2,
1596                }),
1597                (0b010_0000, 0b000) => Ok(Instruction::Sub {
1598                    dest: rd,
1599                    src1: rs1,
1600                    src2: rs2,
1601                }),
1602                (0b010_0000, 0b101) => Ok(Instruction::Sra {
1603                    dest: rd,
1604                    src1: rs1,
1605                    src2: rs2,
1606                }),
1607                (0b000_0001, 0b000) => Ok(Instruction::Mul {
1608                    dest: rd,
1609                    src1: rs1,
1610                    src2: rs2,
1611                }),
1612                (0b000_0001, 0b001) => Ok(Instruction::Mulh {
1613                    dest: rd,
1614                    src1: rs1,
1615                    src2: rs2,
1616                }),
1617                (0b000_0001, 0b010) => Ok(Instruction::Mulhsu {
1618                    dest: rd,
1619                    src1: rs1,
1620                    src2: rs2,
1621                }),
1622                (0b000_0001, 0b011) => Ok(Instruction::Mulhu {
1623                    dest: rd,
1624                    src1: rs1,
1625                    src2: rs2,
1626                }),
1627                (0b000_0001, 0b100) => Ok(Instruction::Div {
1628                    dest: rd,
1629                    src1: rs1,
1630                    src2: rs2,
1631                }),
1632                (0b000_0001, 0b101) => Ok(Instruction::Divu {
1633                    dest: rd,
1634                    src1: rs1,
1635                    src2: rs2,
1636                }),
1637                (0b000_0001, 0b110) => Ok(Instruction::Rem {
1638                    dest: rd,
1639                    src1: rs1,
1640                    src2: rs2,
1641                }),
1642                (0b000_0001, 0b111) => Ok(Instruction::Remu {
1643                    dest: rd,
1644                    src1: rs1,
1645                    src2: rs2,
1646                }),
1647                _ => Err(format!("unknown Op. func3: {}, func7: {}", func3, func7)),
1648            },
1649            Opcode::Op32 => match (func3, func7) {
1650                (0b000, 0b000_0000) => Ok(Instruction::Addw {
1651                    dest: rd,
1652                    src1: rs1,
1653                    src2: rs2,
1654                }),
1655                (0b000, 0b000_0001) => Ok(Instruction::Mulw {
1656                    dest: rd,
1657                    src1: rs1,
1658                    src2: rs2,
1659                }),
1660                (0b000, 0b010_0000) => Ok(Instruction::Subw {
1661                    dest: rd,
1662                    src1: rs1,
1663                    src2: rs2,
1664                }),
1665                (0b001, 0b000_0000) => Ok(Instruction::Sllw {
1666                    dest: rd,
1667                    src1: rs1,
1668                    src2: rs2,
1669                }),
1670                (0b100, 0b0000_001) => Ok(Instruction::Divw {
1671                    dest: rd,
1672                    src1: rs1,
1673                    src2: rs2,
1674                }),
1675                (0b101, 0b000_0000) => Ok(Instruction::Srlw {
1676                    dest: rd,
1677                    src1: rs1,
1678                    src2: rs2,
1679                }),
1680                (0b101, 0b000_0001) => Ok(Instruction::Divuw {
1681                    dest: rd,
1682                    src1: rs1,
1683                    src2: rs2,
1684                }),
1685                (0b101, 0b010_0000) => Ok(Instruction::Sraw {
1686                    dest: rd,
1687                    src1: rs1,
1688                    src2: rs2,
1689                }),
1690                (0b110, 0b000_0001) => Ok(Instruction::Remw {
1691                    dest: rd,
1692                    src1: rs1,
1693                    src2: rs2,
1694                }),
1695                (0b111, 0b000_0001) => Ok(Instruction::Remuw {
1696                    dest: rd,
1697                    src1: rs1,
1698                    src2: rs2,
1699                }),
1700                _ => Err(format!("unknown Op32. func3: {}, func7: {}", func3, func7)),
1701            },
1702            Opcode::OpImm => match func3 {
1703                0b000 => Ok(Instruction::Addi {
1704                    dest: rd,
1705                    src: rs1,
1706                    imm: i_immediate,
1707                }),
1708                // SLLi requires special handling because shamt uses the bottom bit of func7
1709                0b001 => match func7 | 0b1 {
1710                    0b000000_1 => Ok(Instruction::Slli {
1711                        dest: rd,
1712                        src: rs1,
1713                        shamt,
1714                    }),
1715                    _ => Err(format!("unknown OpImm. func3: {}, func7: {}", func3, func7)),
1716                },
1717                0b010 => Ok(Instruction::Slti {
1718                    dest: rd,
1719                    src: rs1,
1720                    imm: i_immediate,
1721                }),
1722                0b011 => Ok(Instruction::Sltiu {
1723                    dest: rd,
1724                    src: rs1,
1725                    imm: i_immediate,
1726                }),
1727                0b100 => Ok(Instruction::Xori {
1728                    dest: rd,
1729                    src: rs1,
1730                    imm: i_immediate,
1731                }),
1732                // SRLI SRAI require special handling because shamt uses the bottom bit of func7
1733                0b101 => match func7 | 0b1 {
1734                    0b000000_1 => Ok(Instruction::Srli {
1735                        dest: rd,
1736                        src: rs1,
1737                        shamt,
1738                    }),
1739                    0b010000_1 => Ok(Instruction::Srai {
1740                        dest: rd,
1741                        src: rs1,
1742                        shamt,
1743                    }),
1744                    _ => Err(format!("unknown OpImm. func3: {}, func7: {}", func3, func7)),
1745                },
1746                0b110 => Ok(Instruction::Ori {
1747                    dest: rd,
1748                    src: rs1,
1749                    imm: i_immediate,
1750                }),
1751                0b111 => Ok(Instruction::Andi {
1752                    dest: rd,
1753                    src: rs1,
1754                    imm: i_immediate,
1755                }),
1756                _ => Err(format!("unknown OpImm. func3: {}, func7: {}", func3, func7)),
1757            },
1758            Opcode::OpImm32 => match func3 {
1759                0b000 => Ok(Instruction::Addiw {
1760                    dest: rd,
1761                    src: rs1,
1762                    imm: i_immediate,
1763                }),
1764                0b001 => match func7 {
1765                    0b000_0000 => Ok(Instruction::Slliw {
1766                        dest: rd,
1767                        src: rs1,
1768                        shamt: shamtw,
1769                    }),
1770                    x => Err(format!("unknown OpImm32(001) func7: {}", x).to_owned()),
1771                },
1772                0b101 => match func7 {
1773                    0b000_0000 => Ok(Instruction::Srliw {
1774                        dest: rd,
1775                        src: rs1,
1776                        shamt: shamtw,
1777                    }),
1778                    0b010_0000 => Ok(Instruction::Sraiw {
1779                        dest: rd,
1780                        src: rs1,
1781                        shamt: shamtw,
1782                    }),
1783                    x => Err(format!("unknown OpImm32(101) func7: {}", x).to_owned()),
1784                },
1785                x => Err(format!("unkown OpImm32 func3: {}", x).to_owned()),
1786            },
1787            Opcode::Jalr => match func3 {
1788                0b000 => Ok(Instruction::Jalr {
1789                    dest: rd,
1790                    base: rs1,
1791                    offset: i_immediate,
1792                }),
1793                x => Err(format!("unknown Jalr func3: {}", x)),
1794            },
1795            Opcode::Jal => Ok(Instruction::Jal {
1796                dest: rd,
1797                offset: JImmediate::from_u32(instruction),
1798            }),
1799            Opcode::Branch => match func3 {
1800                0b000 => Ok(Instruction::Beq {
1801                    src1: rs1,
1802                    src2: rs2,
1803                    offset: b_immediate,
1804                }),
1805                0b001 => Ok(Instruction::Bne {
1806                    src1: rs1,
1807                    src2: rs2,
1808                    offset: b_immediate,
1809                }),
1810                0b100 => Ok(Instruction::Blt {
1811                    src1: rs1,
1812                    src2: rs2,
1813                    offset: b_immediate,
1814                }),
1815                0b101 => Ok(Instruction::Bge {
1816                    src1: rs1,
1817                    src2: rs2,
1818                    offset: b_immediate,
1819                }),
1820                0b110 => Ok(Instruction::Bltu {
1821                    src1: rs1,
1822                    src2: rs2,
1823                    offset: b_immediate,
1824                }),
1825                0b111 => Ok(Instruction::Bgeu {
1826                    src1: rs1,
1827                    src2: rs2,
1828                    offset: b_immediate,
1829                }),
1830                x => Err(format!("invalid branch func3: {x}").to_owned()),
1831            },
1832            Opcode::MiscMem => match func3 {
1833                0b000 => {
1834                    if rd != IRegister::Zero || rs1 != IRegister::Zero {
1835                        // technicially, we are supposed to ignore these fields
1836                        Err("reserved register fields not set to zero".to_owned())
1837                    } else {
1838                        let fm = ((instruction >> 28) & 0b1111) as u8;
1839                        if fm != 0 && fm != 0b1000 {
1840                            Err(format!("reserved fence FM: {fm}").to_owned())
1841                        } else if fm == 0b1000 && ((instruction >> 20) & 0xFF) != 0b0011_0011 {
1842                            Err("fence.tso must be rw,rw".to_owned())
1843                        } else {
1844                            Ok(Instruction::Fence {
1845                                rd,
1846                                rs1,
1847                                ops: ((instruction >> 20) & 0xFF) as u8,
1848                                fm: ((instruction >> 28) & 0b1111) as u8,
1849                            })
1850                        }
1851                    }
1852                }
1853                0b001 => {
1854                    if rd != IRegister::Zero || rs1 != IRegister::Zero {
1855                        // technicially, we are supposed to ignore these fields
1856                        Err("reserved register fields not set to zero".to_owned())
1857                    } else {
1858                        let func12 = instruction >> 20;
1859                        if func12 != 0 {
1860                            Err("reserved register fields not set to zero".to_owned())
1861                        } else {
1862                            Ok(Instruction::FenceI)
1863                        }
1864                    }
1865                }
1866                x => Err(format!("unknown fence func3: {x}")),
1867            },
1868            Opcode::AMO => match (func3, func7 >> 2) {
1869                (0b010, 0b00010) => {
1870                    if rs2 != IRegister::Zero {
1871                        Err("LR.W expects rs2 to be 0".to_owned())
1872                    } else {
1873                        Ok(Instruction::LrW {
1874                            dest: rd,
1875                            addr: rs1,
1876                            aq,
1877                            rl,
1878                        })
1879                    }
1880                }
1881                (0b011, 0b00010) => {
1882                    if rs2 != IRegister::Zero {
1883                        Err("LR.D expects rs2 to be 0".to_owned())
1884                    } else {
1885                        Ok(Instruction::LrD {
1886                            dest: rd,
1887                            addr: rs1,
1888                            aq,
1889                            rl,
1890                        })
1891                    }
1892                }
1893                (0b010, 0b00011) => Ok(Instruction::ScW {
1894                    dest: rd,
1895                    addr: rs1,
1896                    src: rs2,
1897                    aq,
1898                    rl,
1899                }),
1900                (0b011, 0b00011) => Ok(Instruction::ScD {
1901                    dest: rd,
1902                    addr: rs1,
1903                    src: rs2,
1904                    aq,
1905                    rl,
1906                }),
1907                (0b010, 0b00001) => Ok(Instruction::AmoswapW {
1908                    dest: rd,
1909                    addr: rs1,
1910                    src: rs2,
1911                    aq,
1912                    rl,
1913                }),
1914                (0b011, 0b00001) => Ok(Instruction::AmoswapD {
1915                    dest: rd,
1916                    addr: rs1,
1917                    src: rs2,
1918                    aq,
1919                    rl,
1920                }),
1921                (0b010, 0b00000) => Ok(Instruction::AmoaddW {
1922                    dest: rd,
1923                    addr: rs1,
1924                    src: rs2,
1925                    aq,
1926                    rl,
1927                }),
1928                (0b011, 0b00000) => Ok(Instruction::AmoaddD {
1929                    dest: rd,
1930                    addr: rs1,
1931                    src: rs2,
1932                    aq,
1933                    rl,
1934                }),
1935                (0b010, 0b00100) => Ok(Instruction::AmoxorW {
1936                    dest: rd,
1937                    addr: rs1,
1938                    src: rs2,
1939                    aq,
1940                    rl,
1941                }),
1942                (0b011, 0b00100) => Ok(Instruction::AmoxorD {
1943                    dest: rd,
1944                    addr: rs1,
1945                    src: rs2,
1946                    aq,
1947                    rl,
1948                }),
1949                (0b010, 0b01100) => Ok(Instruction::AmoandW {
1950                    dest: rd,
1951                    addr: rs1,
1952                    src: rs2,
1953                    aq,
1954                    rl,
1955                }),
1956                (0b011, 0b01100) => Ok(Instruction::AmoandD {
1957                    dest: rd,
1958                    addr: rs1,
1959                    src: rs2,
1960                    aq,
1961                    rl,
1962                }),
1963                (0b010, 0b01000) => Ok(Instruction::AmoorW {
1964                    dest: rd,
1965                    addr: rs1,
1966                    src: rs2,
1967                    aq,
1968                    rl,
1969                }),
1970                (0b011, 0b01000) => Ok(Instruction::AmoorD {
1971                    dest: rd,
1972                    addr: rs1,
1973                    src: rs2,
1974                    aq,
1975                    rl,
1976                }),
1977                (0b010, 0b10000) => Ok(Instruction::AmominW {
1978                    dest: rd,
1979                    addr: rs1,
1980                    src: rs2,
1981                    aq,
1982                    rl,
1983                }),
1984                (0b011, 0b10000) => Ok(Instruction::AmominD {
1985                    dest: rd,
1986                    addr: rs1,
1987                    src: rs2,
1988                    aq,
1989                    rl,
1990                }),
1991                (0b010, 0b10100) => Ok(Instruction::AmomaxW {
1992                    dest: rd,
1993                    addr: rs1,
1994                    src: rs2,
1995                    aq,
1996                    rl,
1997                }),
1998                (0b011, 0b10100) => Ok(Instruction::AmomaxD {
1999                    dest: rd,
2000                    addr: rs1,
2001                    src: rs2,
2002                    aq,
2003                    rl,
2004                }),
2005                (0b010, 0b11000) => Ok(Instruction::AmominuW {
2006                    dest: rd,
2007                    addr: rs1,
2008                    src: rs2,
2009                    aq,
2010                    rl,
2011                }),
2012                (0b011, 0b11000) => Ok(Instruction::AmominuD {
2013                    dest: rd,
2014                    addr: rs1,
2015                    src: rs2,
2016                    aq,
2017                    rl,
2018                }),
2019                (0b010, 0b11100) => Ok(Instruction::AmomaxuW {
2020                    dest: rd,
2021                    addr: rs1,
2022                    src: rs2,
2023                    aq,
2024                    rl,
2025                }),
2026                (0b011, 0b11100) => Ok(Instruction::AmomaxuD {
2027                    dest: rd,
2028                    addr: rs1,
2029                    src: rs2,
2030                    aq,
2031                    rl,
2032                }),
2033                _ => Err(format!("unknown AMO. func3: {func3}, func7: {func7}")),
2034            },
2035            Opcode::LoadFp => match func3 {
2036                0b010 => Ok(Instruction::Flw {
2037                    dest: frd,
2038                    base: rs1,
2039                    offset: i_immediate,
2040                }),
2041                0b011 => Ok(Instruction::Fld {
2042                    dest: frd,
2043                    base: rs1,
2044                    offset: i_immediate,
2045                }),
2046                _ => Err(format!("unknown func3: {func3} in opcode LoadFp")),
2047            },
2048            Opcode::StoreFp => match func3 {
2049                0b010 => Ok(Instruction::Fsw {
2050                    src: frs2,
2051                    base: rs1,
2052                    offset: s_immediate,
2053                }),
2054                0b011 => Ok(Instruction::Fsd {
2055                    src: frs2,
2056                    base: rs1,
2057                    offset: s_immediate,
2058                }),
2059                _ => Err(format!("unknown func3: {func3} in opcode StoreFp")),
2060            },
2061            Opcode::OpFp => match func7 {
2062                0b000_0000 => Ok(Instruction::FaddS {
2063                    dest: frd,
2064                    src1: frs1,
2065                    src2: frs2,
2066                    rm: RoundingMode::from_int(func3)?,
2067                }),
2068                0b000_0001 => Ok(Instruction::FaddD {
2069                    dest: frd,
2070                    src1: frs1,
2071                    src2: frs2,
2072                    rm: RoundingMode::from_int(func3)?,
2073                }),
2074                0b000_0100 => Ok(Instruction::FsubS {
2075                    dest: frd,
2076                    src1: frs1,
2077                    src2: frs2,
2078                    rm: RoundingMode::from_int(func3)?,
2079                }),
2080                0b000_0101 => Ok(Instruction::FsubD {
2081                    dest: frd,
2082                    src1: frs1,
2083                    src2: frs2,
2084                    rm: RoundingMode::from_int(func3)?,
2085                }),
2086                0b000_1000 => Ok(Instruction::FmulS {
2087                    dest: frd,
2088                    src1: frs1,
2089                    src2: frs2,
2090                    rm: RoundingMode::from_int(func3)?,
2091                }),
2092                0b000_1001 => Ok(Instruction::FmulD {
2093                    dest: frd,
2094                    src1: frs1,
2095                    src2: frs2,
2096                    rm: RoundingMode::from_int(func3)?,
2097                }),
2098                0b000_1100 => Ok(Instruction::FdivS {
2099                    dest: frd,
2100                    src1: frs1,
2101                    src2: frs2,
2102                    rm: RoundingMode::from_int(func3)?,
2103                }),
2104                0b000_1101 => Ok(Instruction::FdivD {
2105                    dest: frd,
2106                    src1: frs1,
2107                    src2: frs2,
2108                    rm: RoundingMode::from_int(func3)?,
2109                }),
2110                0b010_0000 => {
2111                    if instruction >> 20 & 0b11111 != 0b0_0001 {
2112                        Err("expected rs2=0b0_0001 in OpFp func7=0b010_0000".to_owned())
2113                    } else {
2114                        Ok(Instruction::FcvtSD {
2115                            dest: frd,
2116                            src: frs1,
2117                            rm: RoundingMode::from_int(func3)?,
2118                        })
2119                    }
2120                }
2121                0b010_0001 => {
2122                    if instruction >> 20 & 0b11111 != 0b0_0000 {
2123                        Err("expected rs2=0b0_0000 in OpFp func7=0b010_0001".to_owned())
2124                    } else {
2125                        Ok(Instruction::FcvtDS {
2126                            dest: frd,
2127                            src: frs1,
2128                            rm: RoundingMode::from_int(func3)?,
2129                        })
2130                    }
2131                }
2132                0b010_1100 => {
2133                    if instruction >> 20 & 0b11111 != 0b0_0000 {
2134                        Err("expected rs2=0b0_0000 in OpFp func7=0b010_1100".to_owned())
2135                    } else {
2136                        Ok(Instruction::FsqrtS {
2137                            dest: frd,
2138                            src: frs1,
2139                            rm: RoundingMode::from_int(func3)?,
2140                        })
2141                    }
2142                }
2143                0b010_1101 => {
2144                    if instruction >> 20 & 0b11111 != 0b0_0000 {
2145                        Err("expected rs2=0b0_0000 in OpFp func7=0b010_1101".to_owned())
2146                    } else {
2147                        Ok(Instruction::FsqrtD {
2148                            dest: frd,
2149                            src: frs1,
2150                            rm: RoundingMode::from_int(func3)?,
2151                        })
2152                    }
2153                },
2154                0b001_0000 => match func3 {
2155                    0b000 => Ok(Instruction::FsgnjS {
2156                        dest: frd,
2157                        src1: frs1,
2158                        src2: frs2,
2159                    }),
2160                    0b001 => Ok(Instruction::FsgnjnS {
2161                        dest: frd,
2162                        src1: frs1,
2163                        src2: frs2,
2164                    }),
2165                    0b010 => Ok(Instruction::FsgnjxS {
2166                        dest: frd,
2167                        src1: frs1,
2168                        src2: frs2,
2169                    }),
2170                    x => Err(format!("unknown OpFp func7=0b001_0000 func3: {}", x)),
2171                },
2172                0b001_0001 => match func3 {
2173                    0b000 => Ok(Instruction::FsgnjD {
2174                        dest: frd,
2175                        src1: frs1,
2176                        src2: frs2,
2177                    }),
2178                    0b001 => Ok(Instruction::FsgnjnD {
2179                        dest: frd,
2180                        src1: frs1,
2181                        src2: frs2,
2182                    }),
2183                    0b010 => Ok(Instruction::FsgnjxD {
2184                        dest: frd,
2185                        src1: frs1,
2186                        src2: frs2,
2187                    }),
2188                    x => Err(format!("unknown OpFp func7=0b001_0001 func3: {}", x)),
2189                },
2190                0b001_0100 => match func3 {
2191                    0b000 => Ok(Instruction::FminS {
2192                        dest: frd,
2193                        src1: frs1,
2194                        src2: frs2,
2195                    }),
2196                    0b001 => Ok(Instruction::FmaxS {
2197                        dest: frd,
2198                        src1: frs1,
2199                        src2: frs2,
2200                    }),
2201                    x => Err(format!("unknown OpFp func7=0b001_0100 func3: {}", x)),
2202                },
2203                0b001_0101 => match func3 {
2204                    0b000 => Ok(Instruction::FminD {
2205                        dest: frd,
2206                        src1: frs1,
2207                        src2: frs2,
2208                    }),
2209                    0b001 => Ok(Instruction::FmaxD {
2210                        dest: frd,
2211                        src1: frs1,
2212                        src2: frs2,
2213                    }),
2214                    x => Err(format!("unknown OpFp func7=0b001_0101 func3: {}", x)),
2215                },
2216                0b101_0000 => match func3 {
2217                    0b000 => Ok(Instruction::FleS {
2218                        dest: rd,
2219                        src1: frs1,
2220                        src2: frs2,
2221                    }),
2222                    0b001 => Ok(Instruction::FltS {
2223                        dest: rd,
2224                        src1: frs1,
2225                        src2: frs2,
2226                    }),
2227                    0b010 => Ok(Instruction::FeqS {
2228                        dest: rd,
2229                        src1: frs1,
2230                        src2: frs2,
2231                    }),
2232                    x => Err(format!("unknown OpFp func7=0b101_0000 func3: {}", x)),
2233                },
2234                0b101_0001 => match func3 {
2235                    0b000 => Ok(Instruction::FleD {
2236                        dest: rd,
2237                        src1: frs1,
2238                        src2: frs2,
2239                    }),
2240                    0b001 => Ok(Instruction::FltD {
2241                        dest: rd,
2242                        src1: frs1,
2243                        src2: frs2,
2244                    }),
2245                    0b010 => Ok(Instruction::FeqD {
2246                        dest: rd,
2247                        src1: frs1,
2248                        src2: frs2,
2249                    }),
2250                    x => Err(format!("unknown OpFp func7=0b101_0000 func3: {}", x)),
2251                },
2252                0b110_0000 => match (instruction >> 20) & 0b1_1111 {
2253                    0b0_0000 => Ok(Instruction::FcvtWS {
2254                        dest: rd,
2255                        src: frs1,
2256                        rm: RoundingMode::from_int(func3)?,
2257                    }),
2258                    0b0_0001 => Ok(Instruction::FcvtWuS {
2259                        dest: rd,
2260                        src: frs1,
2261                        rm: RoundingMode::from_int(func3)?,
2262                    }),
2263                    0b0_0010 => Ok(Instruction::FcvtLS {
2264                        dest: rd,
2265                        src: frs1,
2266                        rm: RoundingMode::from_int(func3)?,
2267                    }),
2268                    0b0_0011 => Ok(Instruction::FcvtLuS {
2269                        dest: rd,
2270                        src: frs1,
2271                        rm: RoundingMode::from_int(func3)?,
2272                    }),
2273                    x => Err(format!("unknown OpFp func7=0b001_0100 rs2: {}", x)),
2274                },
2275                0b110_0001 => match (instruction >> 20) & 0b1_1111 {
2276                    0b0_0000 => Ok(Instruction::FcvtWD {
2277                        dest: rd,
2278                        src1: frs1,
2279                        rm: RoundingMode::from_int(func3)?,
2280                    }),
2281                    0b0_0001 => Ok(Instruction::FcvtWuD {
2282                        dest: rd,
2283                        src1: frs1,
2284                        rm: RoundingMode::from_int(func3)?,
2285                    }),
2286                    0b0_0010 => Ok(Instruction::FcvtLD {
2287                        dest: rd,
2288                        src1: frs1,
2289                        rm: RoundingMode::from_int(func3)?,
2290                    }),
2291                    0b0_0011 => Ok(Instruction::FcvtLuD {
2292                        dest: rd,
2293                        src1: frs1,
2294                        rm: RoundingMode::from_int(func3)?,
2295                    }),
2296                    x => Err(format!("unknown OpFp func7=0b001_0100 rs2: {}", x)),
2297                },
2298                0b110_1000 => match (instruction >> 20) & 0b1_1111 {
2299                    0b0_0000 => Ok(Instruction::FcvtSW {
2300                        dest: frd,
2301                        src: rs1,
2302                        rm: RoundingMode::from_int(func3)?,
2303                    }),
2304                    0b0_0001 => Ok(Instruction::FcvtSWu {
2305                        dest: frd,
2306                        src: rs1,
2307                        rm: RoundingMode::from_int(func3)?,
2308                    }),
2309                    0b0_0010 => Ok(Instruction::FcvtSL {
2310                        dest: frd,
2311                        src: rs1,
2312                        rm: RoundingMode::from_int(func3)?,
2313                    }),
2314                    0b0_0011 => Ok(Instruction::FcvtSLu {
2315                        dest: frd,
2316                        src: rs1,
2317                        rm: RoundingMode::from_int(func3)?,
2318                    }),
2319                    x => Err(format!("unknown OpFp func7=0b001_0100 rs2: {}", x)),
2320                },
2321                0b110_1001 => match (instruction >> 20) & 0b1_1111 {
2322                    0b0_0000 => Ok(Instruction::FcvtDW {
2323                        dest: frd,
2324                        src1: rs1,
2325                        rm: RoundingMode::from_int(func3)?,
2326                    }),
2327                    0b0_0001 => Ok(Instruction::FcvtDWu {
2328                        dest: frd,
2329                        src1: rs1,
2330                        rm: RoundingMode::from_int(func3)?,
2331                    }),
2332                    0b0_0010 => Ok(Instruction::FcvtDL {
2333                        dest: frd,
2334                        src: rs1,
2335                        rm: RoundingMode::from_int(func3)?,
2336                    }),
2337                    0b0_0011 => Ok(Instruction::FcvtDLu {
2338                        dest: frd,
2339                        src: rs1,
2340                        rm: RoundingMode::from_int(func3)?,
2341                    }),
2342                    x => Err(format!("unknown OpFp func7=0b001_0101 rs2: {}", x)),
2343                },
2344                0b111_0000 => {
2345                    if (instruction >> 20) & 0b1_1111 == 0 {
2346                        if func3 == 0 {
2347                            Ok(Instruction::FmvXW {
2348                                dest: rd,
2349                                src: frs1,
2350                            })
2351                        } else if func3 == 1 {
2352                            Ok(Instruction::FclassS {
2353                                dest: rd,
2354                                src: frs1,
2355                            })
2356                        } else {
2357                            Err(format!(
2358                                "unknown OpFp func7=0b111_0000 rs2=0 func3: {}",
2359                                func3
2360                            ))
2361                        }
2362                    } else {
2363                        Err(format!(
2364                            "unknown OpFp func7=0b111_0000 unknown rs2: {} and func3: {}",
2365                            (instruction >> 20) & 0b1_1111,
2366                            func3
2367                        ))
2368                    }
2369                }
2370                0b111_0001 => {
2371                    if (instruction >> 20) & 0b1_1111 == 0 {
2372                        if func3 == 0 {
2373                            Ok(Instruction::FmvXD {
2374                                dest: rd,
2375                                src: frs1,
2376                            })
2377                        } else if func3 == 1 {
2378                            Ok(Instruction::FclassD {
2379                                dest: rd,
2380                                src1: frs1,
2381                            })
2382                        } else {
2383                            Err(format!(
2384                                "unknown OpFp func7=0b111_0001 rs2=0 func3: {}",
2385                                func3
2386                            ))
2387                        }
2388                    } else {
2389                        Err(format!(
2390                            "unknown OpFp func7=0b111_0001 unknown rs2: {} and func3: {}",
2391                            (instruction >> 20) & 0b1_1111,
2392                            func3
2393                        ))
2394                    }
2395                }
2396                0b111_1000 => {
2397                    if (instruction >> 20) & 0b1_1111 == 0 {
2398                        if func3 == 0 {
2399                            Ok(Instruction::FmvWX {
2400                                dest: frd,
2401                                src: rs1,
2402                            })
2403                        } else {
2404                            Err(format!(
2405                                "unknown OpFp func7=0b111_1000 rs2=0 func3: {}",
2406                                func3
2407                            ))
2408                        }
2409                    } else {
2410                        Err(format!(
2411                            "unknown OpFp func7=0b111_0000 unknown rs2: {} and func3: {}",
2412                            (instruction >> 20) & 0b1_1111,
2413                            func3
2414                        ))
2415                    }
2416                }
2417                0b111_1001 => {
2418                    if (instruction >> 20) & 0b1_1111 == 0 {
2419                        if func3 == 0 {
2420                            Ok(Instruction::FmvDX {
2421                                dest: frd,
2422                                src: rs1,
2423                            })
2424                        } else {
2425                            Err(format!(
2426                                "unknown OpFp func7=0b111_1001 rs2=0 func3: {}",
2427                                func3
2428                            ))
2429                        }
2430                    } else {
2431                        Err(format!(
2432                            "unknown OpFp func7=0b111_0001 unknown rs2: {} and func3: {}",
2433                            (instruction >> 20) & 0b1_1111,
2434                            func3
2435                        ))
2436                    }
2437                }
2438                x => Err(format!("Unknown OpFp func7: {x}")),
2439            },
2440            Opcode::Reserved => Err("instruction uses reserved opcode".to_owned()),
2441            Opcode::Madd => match func7 & 0b11 {
2442                0b00 => Ok(Instruction::FmaddS {
2443                    dest: frd,
2444                    src1: frs1,
2445                    src2: frs2,
2446                    src3: frs3,
2447                    rm: RoundingMode::from_int(func3)?,
2448                }),
2449                0b01 => Ok(Instruction::FmaddD {
2450                    dest: frd,
2451                    src1: frs1,
2452                    src2: frs2,
2453                    src3: frs3,
2454                    rm: RoundingMode::from_int(func3)?,
2455                }),
2456                _ => Err(format!(
2457                    "Fmadd unknown lower 2 bits of func7: {}",
2458                    func7 & 0b11
2459                )),
2460            },
2461            Opcode::Msub => match func7 & 0b11 {
2462                0b00 => Ok(Instruction::FmsubS {
2463                    dest: frd,
2464                    src1: frs1,
2465                    src2: frs2,
2466                    src3: frs3,
2467                    rm: RoundingMode::from_int(func3)?,
2468                }),
2469                0b01 => Ok(Instruction::FmsubD {
2470                    dest: frd,
2471                    src1: frs1,
2472                    src2: frs2,
2473                    src3: frs3,
2474                    rm: RoundingMode::from_int(func3)?,
2475                }),
2476                _ => Err(format!(
2477                    "Fmsub unknown lower 2 bits of func7: {}",
2478                    func7 & 0b11
2479                )),
2480            },
2481            Opcode::Nmsub => match func7 & 0b11 {
2482                0b00 => Ok(Instruction::FnmsubS {
2483                    dest: frd,
2484                    src1: frs1,
2485                    src2: frs2,
2486                    src3: frs3,
2487                    rm: RoundingMode::from_int(func3)?,
2488                }),
2489                0b01 => Ok(Instruction::FnmsubD {
2490                    dest: frd,
2491                    src1: frs1,
2492                    src2: frs2,
2493                    src3: frs3,
2494                    rm: RoundingMode::from_int(func3)?,
2495                }),
2496                _ => Err(format!(
2497                    "Fnmsub unknown lower 2 bits of func7: {}",
2498                    func7 & 0b11
2499                )),
2500            },
2501            Opcode::Nmadd => match func7 & 0b11 {
2502                0b00 => Ok(Instruction::FnmaddS {
2503                    dest: frd,
2504                    src1: frs1,
2505                    src2: frs2,
2506                    src3: frs3,
2507                    rm: RoundingMode::from_int(func3)?,
2508                }),
2509                0b01 => Ok(Instruction::FnmaddD {
2510                    dest: frd,
2511                    src1: frs1,
2512                    src2: frs2,
2513                    src3: frs3,
2514                    rm: RoundingMode::from_int(func3)?,
2515                }),
2516                _ => Err(format!(
2517                    "Fmadd unknown lower 2 bits of func7: {}",
2518                    func7 & 0b11
2519                )),
2520            },
2521            Opcode::System => match func3 {
2522                0b000 => Err("Reserved func3 in Opcode SYSTEM".to_owned()),
2523                0b001 => Ok(Instruction::Csrrw {
2524                    dest: rd,
2525                    src: rs1,
2526                    csr: CSR::from_u32(instruction),
2527                }),
2528                0b010 => Ok(Instruction::Csrrs {
2529                    dest: rd,
2530                    src: rs1,
2531                    csr: CSR::from_u32(instruction),
2532                }),
2533                0b011 => Ok(Instruction::Csrrc {
2534                    dest: rd,
2535                    src: rs1,
2536                    csr: CSR::from_u32(instruction),
2537                }),
2538                0b100 => Err("Reserved func3 in Opcode SYSTEM".to_owned()),
2539                0b101 => Ok(Instruction::Csrrwi {
2540                    dest: rd,
2541                    imm: CSRImmediate::from_u32(instruction),
2542                    csr: CSR::from_u32(instruction),
2543                }),
2544                0b110 => Ok(Instruction::Csrrsi {
2545                    dest: rd,
2546                    imm: CSRImmediate::from_u32(instruction),
2547                    csr: CSR::from_u32(instruction),
2548                }),
2549                0b111 => Ok(Instruction::Csrrci {
2550                    dest: rd,
2551                    imm: CSRImmediate::from_u32(instruction),
2552                    csr: CSR::from_u32(instruction),
2553                }),
2554                _ => unreachable!(),
2555            },
2556        }
2557    }
2558
2559    pub fn encode(instruction: &Instruction) -> u32 {
2560        match instruction {
2561            Instruction::Lui { dest, imm } => imm.to_u32() | dest.rd() | 0b0110111,
2562            Instruction::Auipc { dest, imm } => imm.to_u32() | dest.rd() | 0b0010111,
2563            Instruction::Jal { dest, offset } => offset.to_u32() | dest.rd() | 0b1101111,
2564            Instruction::Jalr { dest, base, offset } => {
2565                offset.to_u32() | base.rs1() | dest.rd() | 0b1100111
2566            }
2567            Instruction::Beq { src1, src2, offset } => {
2568                offset.to_u32() | src2.rs2() | src1.rs1() | 0b000 << 12 | 0b1100011
2569            }
2570            Instruction::Bne { src1, src2, offset } => {
2571                offset.to_u32() | src2.rs2() | src1.rs1() | 0b001 << 12 | 0b1100011
2572            }
2573            Instruction::Blt { src1, src2, offset } => {
2574                offset.to_u32() | src2.rs2() | src1.rs1() | 0b100 << 12 | 0b1100011
2575            }
2576            Instruction::Bge { src1, src2, offset } => {
2577                offset.to_u32() | src2.rs2() | src1.rs1() | 0b101 << 12 | 0b1100011
2578            }
2579            Instruction::Bltu { src1, src2, offset } => {
2580                offset.to_u32() | src2.rs2() | src1.rs1() | 0b110 << 12 | 0b1100011
2581            }
2582            Instruction::Bgeu { src1, src2, offset } => {
2583                offset.to_u32() | src2.rs2() | src1.rs1() | 0b111 << 12 | 0b1100011
2584            }
2585            Instruction::Lb { dest, base, offset } => {
2586                offset.to_u32() | base.rs1() | 0b000 << 12 | dest.rd() | 0b0000011
2587            }
2588            Instruction::Lh { dest, base, offset } => {
2589                offset.to_u32() | base.rs1() | 0b001 << 12 | dest.rd() | 0b0000011
2590            }
2591            Instruction::Lw { dest, base, offset } => {
2592                offset.to_u32() | base.rs1() | 0b010 << 12 | dest.rd() | 0b0000011
2593            }
2594            Instruction::Lbu { dest, base, offset } => {
2595                offset.to_u32() | base.rs1() | 0b100 << 12 | dest.rd() | 0b0000011
2596            }
2597            Instruction::Lhu { dest, base, offset } => {
2598                offset.to_u32() | base.rs1() | 0b101 << 12 | dest.rd() | 0b0000011
2599            }
2600            Instruction::Sb { src, base, offset } => {
2601                offset.to_u32() | src.rs2() | base.rs1() | 0b000 << 12 | 0b0100011
2602            }
2603            Instruction::Sh { src, base, offset } => {
2604                offset.to_u32() | src.rs2() | base.rs1() | 0b001 << 12 | 0b0100011
2605            }
2606            Instruction::Sw { src, base, offset } => {
2607                offset.to_u32() | src.rs2() | base.rs1() | 0b010 << 12 | 0b0100011
2608            }
2609            Instruction::Addi { dest, src, imm } => {
2610                imm.to_u32() | src.rs1() | 0b000 << 12 | dest.rd() | 0b0010011
2611            }
2612            Instruction::Slti { dest, src, imm } => {
2613                imm.to_u32() | src.rs1() | 0b010 << 12 | dest.rd() | 0b0010011
2614            }
2615            Instruction::Sltiu { dest, src, imm } => {
2616                imm.to_u32() | src.rs1() | 0b011 << 12 | dest.rd() | 0b0010011
2617            }
2618            Instruction::Xori { dest, src, imm } => {
2619                imm.to_u32() | src.rs1() | 0b100 << 12 | dest.rd() | 0b0010011
2620            }
2621            Instruction::Ori { dest, src, imm } => {
2622                imm.to_u32() | src.rs1() | 0b110 << 12 | dest.rd() | 0b0010011
2623            }
2624            Instruction::Andi { dest, src, imm } => {
2625                imm.to_u32() | src.rs1() | 0b111 << 12 | dest.rd() | 0b0010011
2626            }
2627            Instruction::Slli { dest, src, shamt } => {
2628                shamt.to_u32() | src.rs1() | 0b001 << 12 | dest.rd() | 0b0010011
2629            }
2630            Instruction::Srli { dest, src, shamt } => {
2631                shamt.to_u32() | src.rs1() | 0b101 << 12 | dest.rd() | 0b0010011
2632            }
2633            Instruction::Srai { dest, src, shamt } => {
2634                0b0100000 << 25 | shamt.to_u32() | src.rs1() | 0b101 << 12 | dest.rd() | 0b0010011
2635            }
2636            Instruction::Add { dest, src1, src2 } => {
2637                src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b0110011
2638            }
2639            Instruction::Sub { dest, src1, src2 } => {
2640                0b0100000 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b0110011
2641            }
2642            Instruction::Sll { dest, src1, src2 } => {
2643                src2.rs2() | src1.rs1() | 0b001 << 12 | dest.rd() | 0b0110011
2644            }
2645            Instruction::Slt { dest, src1, src2 } => {
2646                src2.rs2() | src1.rs1() | 0b010 << 12 | dest.rd() | 0b0110011
2647            }
2648            Instruction::Sltu { dest, src1, src2 } => {
2649                src2.rs2() | src1.rs1() | 0b011 << 12 | dest.rd() | 0b0110011
2650            }
2651            Instruction::Xor { dest, src1, src2 } => {
2652                src2.rs2() | src1.rs1() | 0b100 << 12 | dest.rd() | 0b0110011
2653            }
2654            Instruction::Srl { dest, src1, src2 } => {
2655                src2.rs2() | src1.rs1() | 0b101 << 12 | dest.rd() | 0b0110011
2656            }
2657            Instruction::Sra { dest, src1, src2 } => {
2658                0b0100000 << 25 | src2.rs2() | src1.rs1() | 0b0101 << 12 | dest.rd() | 0b0110011
2659            }
2660            Instruction::Or { dest, src1, src2 } => {
2661                src2.rs2() | src1.rs1() | 0b110 << 12 | dest.rd() | 0b0110011
2662            }
2663            Instruction::And { dest, src1, src2 } => {
2664                src2.rs2() | src1.rs1() | 0b111 << 12 | dest.rd() | 0b0110011
2665            }
2666            Instruction::Fence { rd, rs1, ops, fm } => {
2667                (*fm as u32) << 28 | (*ops as u32) << 20 | rs1.rs1() | rd.rd() | 0b0001111
2668            }
2669            Instruction::Ecall => 0b1110011,
2670            Instruction::Ebreak => 0b1 << 20 | 0b1110011,
2671            Instruction::Lwu { dest, base, offset } => {
2672                offset.to_u32() | base.rs1() | 0b110 << 12 | dest.rd() | 0b0000011
2673            }
2674            Instruction::Ld { dest, base, offset } => {
2675                offset.to_u32() | base.rs1() | 0b011 << 12 | dest.rd() | 0b0000011
2676            }
2677            Instruction::Sd { src, base, offset } => {
2678                offset.to_u32() | src.rs2() | base.rs1() | 0b011 << 12 | 0b0100011
2679            }
2680            Instruction::Addiw { dest, src, imm } => {
2681                imm.to_u32() | src.rs1() | 0b000 << 12 | dest.rd() | 0b0011011
2682            }
2683            Instruction::Slliw { dest, src, shamt } => {
2684                shamt.to_u32() | src.rs1() | 0b001 << 12 | dest.rd() | 0b0011011
2685            }
2686            Instruction::Srliw { dest, src, shamt } => {
2687                shamt.to_u32() | src.rs1() | 0b101 << 12 | dest.rd() | 0b0011011
2688            }
2689            Instruction::Sraiw { dest, src, shamt } => {
2690                0b0100000 << 25 | shamt.to_u32() | src.rs1() | 0b101 << 12 | dest.rd() | 0b0011011
2691            }
2692            Instruction::Addw { dest, src1, src2 } => {
2693                src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b0111011
2694            }
2695            Instruction::Subw { dest, src1, src2 } => {
2696                0b0100000 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b0111011
2697            }
2698            Instruction::Sllw { dest, src1, src2 } => {
2699                src2.rs2() | src1.rs1() | 0b001 << 12 | dest.rd() | 0b0111011
2700            }
2701            Instruction::Srlw { dest, src1, src2 } => {
2702                src2.rs2() | src1.rs1() | 0b101 << 12 | dest.rd() | 0b0111011
2703            }
2704            Instruction::Sraw { dest, src1, src2 } => {
2705                0b0100000 << 25 | src2.rs2() | src1.rs1() | 0b101 << 12 | dest.rd() | 0b0111011
2706            }
2707            Instruction::Mul { dest, src1, src2 } => {
2708                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b0110011
2709            }
2710            Instruction::Mulh { dest, src1, src2 } => {
2711                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b001 << 12 | dest.rd() | 0b0110011
2712            }
2713            Instruction::Mulhsu { dest, src1, src2 } => {
2714                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b010 << 12 | dest.rd() | 0b0110011
2715            }
2716            Instruction::Mulhu { dest, src1, src2 } => {
2717                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b011 << 12 | dest.rd() | 0b0110011
2718            }
2719            Instruction::Div { dest, src1, src2 } => {
2720                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b100 << 12 | dest.rd() | 0b0110011
2721            }
2722            Instruction::Divu { dest, src1, src2 } => {
2723                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b101 << 12 | dest.rd() | 0b0110011
2724            }
2725            Instruction::Rem { dest, src1, src2 } => {
2726                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b110 << 12 | dest.rd() | 0b0110011
2727            }
2728            Instruction::Remu { dest, src1, src2 } => {
2729                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b111 << 12 | dest.rd() | 0b0110011
2730            }
2731            Instruction::Mulw { dest, src1, src2 } => {
2732                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b0111011
2733            }
2734            Instruction::Divw { dest, src1, src2 } => {
2735                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b100 << 12 | dest.rd() | 0b0111011
2736            }
2737            Instruction::Divuw { dest, src1, src2 } => {
2738                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b101 << 12 | dest.rd() | 0b0111011
2739            }
2740            Instruction::Remw { dest, src1, src2 } => {
2741                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b110 << 12 | dest.rd() | 0b0111011
2742            }
2743            Instruction::Remuw { dest, src1, src2 } => {
2744                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b111 << 12 | dest.rd() | 0b0111011
2745            }
2746            Instruction::LrW { dest, addr, aq, rl } => {
2747                0b00010 << 27
2748                    | aqb(*aq)
2749                    | rlb(*rl)
2750                    | addr.rs1()
2751                    | 0b010 << 12
2752                    | dest.rd()
2753                    | 0b0101111
2754            }
2755            Instruction::ScW {
2756                dest,
2757                addr,
2758                src,
2759                aq,
2760                rl,
2761            } => {
2762                0b00011 << 27
2763                    | aqb(*aq)
2764                    | rlb(*rl)
2765                    | src.rs2()
2766                    | addr.rs1()
2767                    | 0b010 << 12
2768                    | dest.rd()
2769                    | 0b0101111
2770            }
2771            Instruction::AmoswapW {
2772                dest,
2773                addr,
2774                src,
2775                aq,
2776                rl,
2777            } => {
2778                0b00001 << 27
2779                    | aqb(*aq)
2780                    | rlb(*rl)
2781                    | src.rs2()
2782                    | addr.rs1()
2783                    | 0b010 << 12
2784                    | dest.rd()
2785                    | 0b0101111
2786            }
2787            Instruction::AmoaddW {
2788                dest,
2789                addr,
2790                src,
2791                aq,
2792                rl,
2793            } => {
2794                0b00000 << 27
2795                    | aqb(*aq)
2796                    | rlb(*rl)
2797                    | src.rs2()
2798                    | addr.rs1()
2799                    | 0b010 << 12
2800                    | dest.rd()
2801                    | 0b0101111
2802            }
2803            Instruction::AmoxorW {
2804                dest,
2805                addr,
2806                src,
2807                aq,
2808                rl,
2809            } => {
2810                0b00100 << 27
2811                    | aqb(*aq)
2812                    | rlb(*rl)
2813                    | src.rs2()
2814                    | addr.rs1()
2815                    | 0b010 << 12
2816                    | dest.rd()
2817                    | 0b0101111
2818            }
2819            Instruction::AmoandW {
2820                dest,
2821                addr,
2822                src,
2823                aq,
2824                rl,
2825            } => {
2826                0b01100 << 27
2827                    | aqb(*aq)
2828                    | rlb(*rl)
2829                    | src.rs2()
2830                    | addr.rs1()
2831                    | 0b010 << 12
2832                    | dest.rd()
2833                    | 0b0101111
2834            }
2835            Instruction::AmoorW {
2836                dest,
2837                addr,
2838                src,
2839                aq,
2840                rl,
2841            } => {
2842                0b01000 << 27
2843                    | aqb(*aq)
2844                    | rlb(*rl)
2845                    | src.rs2()
2846                    | addr.rs1()
2847                    | 0b010 << 12
2848                    | dest.rd()
2849                    | 0b0101111
2850            }
2851            Instruction::AmominW {
2852                dest,
2853                addr,
2854                src,
2855                aq,
2856                rl,
2857            } => {
2858                0b10000 << 27
2859                    | aqb(*aq)
2860                    | rlb(*rl)
2861                    | src.rs2()
2862                    | addr.rs1()
2863                    | 0b010 << 12
2864                    | dest.rd()
2865                    | 0b0101111
2866            }
2867            Instruction::AmomaxW {
2868                dest,
2869                addr,
2870                src,
2871                aq,
2872                rl,
2873            } => {
2874                0b10100 << 27
2875                    | aqb(*aq)
2876                    | rlb(*rl)
2877                    | src.rs2()
2878                    | addr.rs1()
2879                    | 0b010 << 12
2880                    | dest.rd()
2881                    | 0b0101111
2882            }
2883            Instruction::AmominuW {
2884                dest,
2885                addr,
2886                src,
2887                aq,
2888                rl,
2889            } => {
2890                0b11000 << 27
2891                    | aqb(*aq)
2892                    | rlb(*rl)
2893                    | src.rs2()
2894                    | addr.rs1()
2895                    | 0b010 << 12
2896                    | dest.rd()
2897                    | 0b0101111
2898            }
2899            Instruction::AmomaxuW {
2900                dest,
2901                addr,
2902                src,
2903                aq,
2904                rl,
2905            } => {
2906                0b11100 << 27
2907                    | aqb(*aq)
2908                    | rlb(*rl)
2909                    | src.rs2()
2910                    | addr.rs1()
2911                    | 0b010 << 12
2912                    | dest.rd()
2913                    | 0b0101111
2914            }
2915            Instruction::LrD { dest, addr, aq, rl } => {
2916                0b00010 << 27
2917                    | aqb(*aq)
2918                    | rlb(*rl)
2919                    | addr.rs1()
2920                    | 0b011 << 12
2921                    | dest.rd()
2922                    | 0b0101111
2923            }
2924            Instruction::ScD {
2925                dest,
2926                addr,
2927                src,
2928                aq,
2929                rl,
2930            } => {
2931                0b00011 << 27
2932                    | aqb(*aq)
2933                    | rlb(*rl)
2934                    | src.rs2()
2935                    | addr.rs1()
2936                    | 0b011 << 12
2937                    | dest.rd()
2938                    | 0b0101111
2939            }
2940            Instruction::AmoswapD {
2941                dest,
2942                addr,
2943                src,
2944                aq,
2945                rl,
2946            } => {
2947                0b00001 << 27
2948                    | aqb(*aq)
2949                    | rlb(*rl)
2950                    | src.rs2()
2951                    | addr.rs1()
2952                    | 0b011 << 12
2953                    | dest.rd()
2954                    | 0b0101111
2955            }
2956            Instruction::AmoaddD {
2957                dest,
2958                addr,
2959                src,
2960                aq,
2961                rl,
2962            } => {
2963                0b00000 << 27
2964                    | aqb(*aq)
2965                    | rlb(*rl)
2966                    | src.rs2()
2967                    | addr.rs1()
2968                    | 0b011 << 12
2969                    | dest.rd()
2970                    | 0b0101111
2971            }
2972            Instruction::AmoxorD {
2973                dest,
2974                addr,
2975                src,
2976                aq,
2977                rl,
2978            } => {
2979                0b00100 << 27
2980                    | aqb(*aq)
2981                    | rlb(*rl)
2982                    | src.rs2()
2983                    | addr.rs1()
2984                    | 0b011 << 12
2985                    | dest.rd()
2986                    | 0b0101111
2987            }
2988            Instruction::AmoandD {
2989                dest,
2990                addr,
2991                src,
2992                aq,
2993                rl,
2994            } => {
2995                0b01100 << 27
2996                    | aqb(*aq)
2997                    | rlb(*rl)
2998                    | src.rs2()
2999                    | addr.rs1()
3000                    | 0b011 << 12
3001                    | dest.rd()
3002                    | 0b0101111
3003            }
3004            Instruction::AmoorD {
3005                dest,
3006                addr,
3007                src,
3008                aq,
3009                rl,
3010            } => {
3011                0b01000 << 27
3012                    | aqb(*aq)
3013                    | rlb(*rl)
3014                    | src.rs2()
3015                    | addr.rs1()
3016                    | 0b011 << 12
3017                    | dest.rd()
3018                    | 0b0101111
3019            }
3020            Instruction::AmominD {
3021                dest,
3022                addr,
3023                src,
3024                aq,
3025                rl,
3026            } => {
3027                0b10000 << 27
3028                    | aqb(*aq)
3029                    | rlb(*rl)
3030                    | src.rs2()
3031                    | addr.rs1()
3032                    | 0b011 << 12
3033                    | dest.rd()
3034                    | 0b0101111
3035            }
3036            Instruction::AmomaxD {
3037                dest,
3038                addr,
3039                src,
3040                aq,
3041                rl,
3042            } => {
3043                0b10100 << 27
3044                    | aqb(*aq)
3045                    | rlb(*rl)
3046                    | src.rs2()
3047                    | addr.rs1()
3048                    | 0b011 << 12
3049                    | dest.rd()
3050                    | 0b0101111
3051            }
3052            Instruction::AmominuD {
3053                dest,
3054                addr,
3055                src,
3056                aq,
3057                rl,
3058            } => {
3059                0b11000 << 27
3060                    | aqb(*aq)
3061                    | rlb(*rl)
3062                    | src.rs2()
3063                    | addr.rs1()
3064                    | 0b011 << 12
3065                    | dest.rd()
3066                    | 0b0101111
3067            }
3068            Instruction::AmomaxuD {
3069                dest,
3070                addr,
3071                src,
3072                aq,
3073                rl,
3074            } => {
3075                0b11100 << 27
3076                    | aqb(*aq)
3077                    | rlb(*rl)
3078                    | src.rs2()
3079                    | addr.rs1()
3080                    | 0b011 << 12
3081                    | dest.rd()
3082                    | 0b0101111
3083            }
3084            Instruction::Flw { dest, base, offset } => {
3085                offset.to_u32() | base.rs1() | 0b010 << 12 | dest.rd() | 0b0000111
3086            }
3087            Instruction::Fsw { base, src, offset } => {
3088                offset.to_u32() | src.rs2() | base.rs1() | 0b010 << 12 | 0b0100111
3089            }
3090            Instruction::FmaddS {
3091                dest,
3092                src1,
3093                src2,
3094                src3,
3095                rm,
3096            } => src3.rs3() | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1000011,
3097            Instruction::FmsubS {
3098                dest,
3099                src1,
3100                src2,
3101                src3,
3102                rm,
3103            } => src3.rs3() | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1000111,
3104            Instruction::FnmsubS {
3105                dest,
3106                src1,
3107                src2,
3108                src3,
3109                rm,
3110            } => src3.rs3() | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1001011,
3111            Instruction::FnmaddS {
3112                dest,
3113                src1,
3114                src2,
3115                src3,
3116                rm,
3117            } => src3.rs3() | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1001111,
3118            Instruction::FaddS {
3119                dest,
3120                src1,
3121                src2,
3122                rm,
3123            } => 0b0000000 << 25 | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011,
3124            Instruction::FsubS {
3125                dest,
3126                src1,
3127                src2,
3128                rm,
3129            } => 0b0000100 << 25 | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011,
3130            Instruction::FmulS {
3131                dest,
3132                src1,
3133                src2,
3134                rm,
3135            } => 0b0001000 << 25 | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011,
3136            Instruction::FdivS {
3137                dest,
3138                src1,
3139                src2,
3140                rm,
3141            } => 0b0001100 << 25 | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011,
3142            Instruction::FsqrtS { dest, src, rm } => {
3143                0b0101100 << 25 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3144            }
3145            Instruction::FsgnjS { dest, src1, src2 } => {
3146                0b0010000 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b1010011
3147            }
3148            Instruction::FsgnjnS { dest, src1, src2 } => {
3149                0b0010000 << 25 | src2.rs2() | src1.rs1() | 0b001 << 12 | dest.rd() | 0b1010011
3150            }
3151            Instruction::FsgnjxS { dest, src1, src2 } => {
3152                0b0010000 << 25 | src2.rs2() | src1.rs1() | 0b010 << 12 | dest.rd() | 0b1010011
3153            }
3154            Instruction::FminS { dest, src1, src2 } => {
3155                0b0010100 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b1010011
3156            }
3157            Instruction::FmaxS { dest, src1, src2 } => {
3158                0b0010100 << 25 | src2.rs2() | src1.rs1() | 0b001 << 12 | dest.rd() | 0b1010011
3159            }
3160            Instruction::FcvtWS { dest, src, rm } => {
3161                0b1100000 << 25 | 0b00000 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3162            }
3163            Instruction::FcvtWuS { dest, src, rm } => {
3164                0b1100000 << 25 | 0b00001 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3165            }
3166            Instruction::FmvXW { dest, src } => 0b1110000 << 25 | src.rs1() | dest.rd() | 0b1010011,
3167            Instruction::FeqS { dest, src1, src2 } => {
3168                0b1010000 << 25 | src2.rs2() | src1.rs1() | 0b010 << 12 | dest.rd() | 0b1010011
3169            }
3170            Instruction::FltS { dest, src1, src2 } => {
3171                0b1010000 << 25 | src2.rs2() | src1.rs1() | 0b001 << 12 | dest.rd() | 0b1010011
3172            }
3173            Instruction::FleS { dest, src1, src2 } => {
3174                0b1010000 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b1010011
3175            }
3176            Instruction::FclassS { dest, src } => {
3177                0b1110000 << 25 | src.rs1() | 0b001 << 12 | dest.rd() | 0b1010011
3178            }
3179            Instruction::FcvtSW { dest, src, rm } => {
3180                0b1101000 << 25 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3181            }
3182            Instruction::FcvtSWu { dest, src, rm } => {
3183                0b1101000 << 25 | 0b00001 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3184            }
3185            Instruction::FmvWX { dest, src } => 0b1111000 << 25 | src.rs1() | dest.rd() | 0b1010011,
3186            Instruction::FcvtLS { dest, src, rm } => {
3187                0b1100000 << 25 | 0b00010 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3188            }
3189            Instruction::FcvtLuS { dest, src, rm } => {
3190                0b1100000 << 25 | 0b00011 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3191            }
3192            Instruction::FcvtSL { dest, src, rm } => {
3193                0b1101000 << 25 | 0b00010 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3194            }
3195            Instruction::FcvtSLu { dest, src, rm } => {
3196                0b1101000 << 25 | 0b00011 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3197            }
3198            Instruction::Csrrw { dest, src, csr } => {
3199                csr.to_u32() | src.rs1() | 0b001 << 12 | dest.rd() | 0b1110011
3200            }
3201            Instruction::Csrrs { dest, src, csr } => {
3202                csr.to_u32() | src.rs1() | 0b010 << 12 | dest.rd() | 0b1110011
3203            }
3204            Instruction::Csrrc { dest, src, csr } => {
3205                csr.to_u32() | src.rs1() | 0b011 << 12 | dest.rd() | 0b1110011
3206            }
3207            Instruction::Csrrwi { dest, imm, csr } => {
3208                csr.to_u32() | imm.to_u32() | 0b101 << 12 | dest.rd() | 0b1110011
3209            }
3210            Instruction::Csrrsi { dest, imm, csr } => {
3211                csr.to_u32() | imm.to_u32() | 0b110 << 12 | dest.rd() | 0b1110011
3212            }
3213            Instruction::Csrrci { dest, imm, csr } => {
3214                csr.to_u32() | imm.to_u32() | 0b111 << 12 | dest.rd() | 0b1110011
3215            }
3216            Instruction::FenceI => 0b001 << 12 | 0b0001111,
3217            Instruction::Fld { dest, base, offset } => {
3218                offset.to_u32() | base.rs1() | 0b011 << 12 | dest.rd() | 0b0000111
3219            }
3220            Instruction::Fsd { src, base, offset } => {
3221                offset.to_u32() | base.rs1() | 0b011 << 12 | src.rs2() | 0b0100111
3222            }
3223            Instruction::FmaddD {
3224                dest,
3225                src1,
3226                src2,
3227                src3,
3228                rm,
3229            } => {
3230                src3.rs3()
3231                    | 0b01 << 25
3232                    | src2.rs2()
3233                    | src1.rs1()
3234                    | rm.to_u32()
3235                    | dest.rd()
3236                    | 0b1000011
3237            }
3238            Instruction::FmsubD {
3239                dest,
3240                src1,
3241                src2,
3242                src3,
3243                rm,
3244            } => {
3245                src3.rs3()
3246                    | 0b01 << 25
3247                    | src2.rs2()
3248                    | src1.rs1()
3249                    | rm.to_u32()
3250                    | dest.rd()
3251                    | 0b1000111
3252            }
3253            Instruction::FnmaddD {
3254                dest,
3255                src1,
3256                src2,
3257                src3,
3258                rm,
3259            } => {
3260                src3.rs3()
3261                    | 0b01 << 25
3262                    | src2.rs2()
3263                    | src1.rs1()
3264                    | rm.to_u32()
3265                    | dest.rd()
3266                    | 0b1001111
3267            }
3268            Instruction::FnmsubD {
3269                dest,
3270                src1,
3271                src2,
3272                src3,
3273                rm,
3274            } => {
3275                src3.rs3()
3276                    | 0b01 << 25
3277                    | src2.rs2()
3278                    | src1.rs1()
3279                    | rm.to_u32()
3280                    | dest.rd()
3281                    | 0b1001011
3282            }
3283            Instruction::FaddD {
3284                dest,
3285                src1,
3286                src2,
3287                rm,
3288            } => 0b0000001 << 25 | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011,
3289            Instruction::FsubD {
3290                dest,
3291                src1,
3292                src2,
3293                rm,
3294            } => 0b0000101 << 25 | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011,
3295            Instruction::FmulD {
3296                dest,
3297                src1,
3298                src2,
3299                rm,
3300            } => 0b0001001 << 25 | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011,
3301            Instruction::FdivD {
3302                dest,
3303                src1,
3304                src2,
3305                rm,
3306            } => 0b0001101 << 25 | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011,
3307            Instruction::FsqrtD {
3308                dest,
3309                src: src1,
3310                rm,
3311            } => 0b0101101 << 25 | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011,
3312            Instruction::FsgnjD { dest, src1, src2 } => {
3313                0b0010001 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b1010011
3314            }
3315            Instruction::FsgnjnD { dest, src1, src2 } => {
3316                0b0010001 << 25 | src2.rs2() | src1.rs1() | 0b001 << 12 | dest.rd() | 0b1010011
3317            }
3318            Instruction::FsgnjxD { dest, src1, src2 } => {
3319                0b0010001 << 25 | src2.rs2() | src1.rs1() | 0b010 << 12 | dest.rd() | 0b1010011
3320            }
3321            Instruction::FminD { dest, src1, src2 } => {
3322                0b0010101 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b1010011
3323            }
3324            Instruction::FmaxD { dest, src1, src2 } => {
3325                0b0010101 << 25 | src2.rs2() | src1.rs1() | 0b001 << 12 | dest.rd() | 0b1010011
3326            }
3327            Instruction::FcvtSD { dest, src, rm } => {
3328                0b0100000 << 25 | 0b00001 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3329            }
3330            Instruction::FcvtDS { dest, src, rm } => {
3331                0b0100001 << 25 | 0b00000 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3332            }
3333            Instruction::FeqD { dest, src1, src2 } => {
3334                0b1010001 << 25 | src2.rs2() | src1.rs1() | 0b010 << 12 | dest.rd() | 0b1010011
3335            }
3336            Instruction::FltD { dest, src1, src2 } => {
3337                0b1010001 << 25 | src2.rs2() | src1.rs1() | 0b001 << 12 | dest.rd() | 0b1010011
3338            }
3339            Instruction::FleD { dest, src1, src2 } => {
3340                0b1010001 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b1010011
3341            }
3342            Instruction::FclassD { dest, src1 } => {
3343                0b1110001 << 25 | 0b00000 << 20 | src1.rs1() | 0b001 << 12 | dest.rd() | 0b1010011
3344            }
3345            Instruction::FcvtWD { dest, src1, rm } => {
3346                0b1100001 << 25 | 0b00000 << 20 | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3347            }
3348            Instruction::FcvtWuD { dest, src1, rm } => {
3349                0b1100001 << 25 | 0b00001 << 20 | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3350            }
3351            Instruction::FcvtDW { dest, src1, rm } => {
3352                0b1101001 << 25 | 0b00000 << 20 | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3353            }
3354            Instruction::FcvtDWu { dest, src1, rm } => {
3355                0b1101001 << 25 | 0b00001 << 20 | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3356            }
3357            Instruction::FcvtLD { dest, src1, rm } => {
3358                0b1100001 << 25 | 0b00010 << 20 | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3359            }
3360            Instruction::FcvtLuD { dest, src1, rm } => {
3361                0b1100001 << 25 | 0b00011 << 20 | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011
3362            }
3363            Instruction::FmvXD { dest, src } => {
3364                0b1110001 << 25 | 0b00000 << 20 | src.rs1() | 0b000 << 12 | dest.rd() | 0b1010011
3365            }
3366            Instruction::FcvtDL {
3367                dest,
3368                src: src1,
3369                rm,
3370            } => 0b1101001 << 25 | 0b00010 << 20 | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011,
3371            Instruction::FcvtDLu {
3372                dest,
3373                src: src1,
3374                rm,
3375            } => 0b1101001 << 25 | 0b00011 << 20 | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011,
3376            Instruction::FmvDX { dest, src } => {
3377                0b1111001 << 25 | 0b00000 << 20 | src.rs1() | 0b000 << 12 | dest.rd() | 0b1010011
3378            }
3379        }
3380    }
3381}
3382
3383/// Disassembles an instruction.
3384pub fn disassemble_instruction(instruction: &Instruction) -> String {
3385    format!("{}", instruction)
3386}