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 std::fmt::{Display, Formatter};
7
8#[derive(Debug, PartialEq, Clone, Copy)]
9pub enum RoundingMode {
10    /// round to nearest, ties to even
11    RNE = 0b000,
12    /// round towards zero
13    RTZ = 0b001,
14    /// round down
15    RDN = 0b010,
16    /// round up
17    RUP = 0b011,
18    /// round to nearest, ties to max magnitude
19    RMM = 0b100,
20    /// use rounding mode in fcsr
21    DYN = 0b111,
22}
23
24impl Display for RoundingMode {
25    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
26        match self {
27            RoundingMode::RNE => write!(f, "rne"),
28            RoundingMode::RTZ => write!(f, "rtz"),
29            RoundingMode::RDN => write!(f, "rdn"),
30            RoundingMode::RUP => write!(f, "rup"),
31            RoundingMode::RMM => write!(f, "rmm"),
32            RoundingMode::DYN => write!(f, "dyn"),
33        }
34    }
35}
36
37impl RoundingMode {
38    pub fn from_int(x: u32) -> Result<RoundingMode, String> {
39        match x {
40            0b000 => Ok(RoundingMode::RNE),
41            0b001 => Ok(RoundingMode::RTZ),
42            0b010 => Ok(RoundingMode::RDN),
43            0b011 => Ok(RoundingMode::RUP),
44            0b100 => Ok(RoundingMode::RMM),
45            0b111 => Ok(RoundingMode::DYN),
46            _ => Err("attempted to create invalid rounding mode".to_owned()),
47        }
48    }
49    pub fn from_str(x: &str) -> Result<RoundingMode, String> {
50        match x {
51            "rne" => Ok(RoundingMode::RNE),
52            "rtz" => Ok(RoundingMode::RTZ),
53            "rdn" => Ok(RoundingMode::RDN),
54            "rup" => Ok(RoundingMode::RUP),
55            "rmm" => Ok(RoundingMode::RMM),
56            "dyn" => Ok(RoundingMode::DYN),
57            _ => Err("attempted to create invalid rounding mode".to_owned()),
58        }
59    }
60
61    pub fn to_u32(self) -> u32 {
62        return (self as u32) << 12;
63    }
64}
65
66#[derive(Debug, PartialEq)]
67pub enum Instruction {
68    //
69    // Instructions from RV32I
70    //
71    /// Load upper immediate
72    LUI {
73        dest: IRegister,
74        imm: UImmediate,
75    },
76    /// Add upper immediate to PC
77    AUIPC {
78        dest: IRegister,
79        imm: UImmediate,
80    },
81    /// Jump and Link
82    JAL {
83        dest: IRegister,
84        offset: JImmediate,
85    },
86    /// Jump and Link Register
87    JALR {
88        dest: IRegister,
89        base: IRegister,
90        offset: IImmediate,
91    },
92    BEQ {
93        src1: IRegister,
94        src2: IRegister,
95        offset: BImmediate,
96    },
97    BNE {
98        src1: IRegister,
99        src2: IRegister,
100        offset: BImmediate,
101    },
102    BLT {
103        src1: IRegister,
104        src2: IRegister,
105        offset: BImmediate,
106    },
107    BGE {
108        src1: IRegister,
109        src2: IRegister,
110        offset: BImmediate,
111    },
112    BLTU {
113        src1: IRegister,
114        src2: IRegister,
115        offset: BImmediate,
116    },
117    BGEU {
118        src1: IRegister,
119        src2: IRegister,
120        offset: BImmediate,
121    },
122    /// Load Byte
123    LB {
124        dest: IRegister,
125        base: IRegister,
126        offset: IImmediate,
127    },
128    /// Load Halfword
129    LH {
130        dest: IRegister,
131        base: IRegister,
132        offset: IImmediate,
133    },
134    /// Load Word
135    LW {
136        dest: IRegister,
137        base: IRegister,
138        offset: IImmediate,
139    },
140    /// Load Byte Unsigned
141    LBU {
142        dest: IRegister,
143        base: IRegister,
144        offset: IImmediate,
145    },
146    /// Load Halfword Unsigned
147    LHU {
148        dest: IRegister,
149        base: IRegister,
150        offset: IImmediate,
151    },
152    /// Store Byte
153    SB {
154        src: IRegister,
155        base: IRegister,
156        offset: SImmediate,
157    },
158    /// Store Halfword
159    SH {
160        src: IRegister,
161        base: IRegister,
162        offset: SImmediate,
163    },
164    /// Store Word
165    SW {
166        src: IRegister,
167        base: IRegister,
168        offset: SImmediate,
169    },
170    ADDI {
171        dest: IRegister,
172        src: IRegister,
173        imm: IImmediate,
174    },
175    SLTI {
176        dest: IRegister,
177        src: IRegister,
178        imm: IImmediate,
179    },
180    SLTIU {
181        dest: IRegister,
182        src: IRegister,
183        imm: IImmediate,
184    },
185    XORI {
186        dest: IRegister,
187        src: IRegister,
188        imm: IImmediate,
189    },
190    ORI {
191        dest: IRegister,
192        src: IRegister,
193        imm: IImmediate,
194    },
195    ANDI {
196        dest: IRegister,
197        src: IRegister,
198        imm: IImmediate,
199    },
200    /// Left Shift Immediate
201    SLLI {
202        dest: IRegister,
203        src: IRegister,
204        shamt: Shamt,
205    },
206    /// Logical Right Shift Immediate
207    SRLI {
208        dest: IRegister,
209        src: IRegister,
210        shamt: Shamt,
211    },
212    /// Arithmetic Right Shift Immediate
213    SRAI {
214        dest: IRegister,
215        src: IRegister,
216        shamt: Shamt,
217    },
218    ADD {
219        dest: IRegister,
220        src1: IRegister,
221        src2: IRegister,
222    },
223    SUB {
224        dest: IRegister,
225        src1: IRegister,
226        src2: IRegister,
227    },
228    /// Left Shift
229    SLL {
230        dest: IRegister,
231        src1: IRegister,
232        src2: IRegister,
233    },
234    /// Branch if Equal
235    SLT {
236        dest: IRegister,
237        src1: IRegister,
238        src2: IRegister,
239    },
240    SLTU {
241        dest: IRegister,
242        src1: IRegister,
243        src2: IRegister,
244    },
245    XOR {
246        dest: IRegister,
247        src1: IRegister,
248        src2: IRegister,
249    },
250    /// Logical Right Shift Immediate
251    SRL {
252        dest: IRegister,
253        src1: IRegister,
254        src2: IRegister,
255    },
256    /// Arithmetic Right Shift Immediate
257    SRA {
258        dest: IRegister,
259        src1: IRegister,
260        src2: IRegister,
261    },
262    OR {
263        dest: IRegister,
264        src1: IRegister,
265        src2: IRegister,
266    },
267    AND {
268        dest: IRegister,
269        src1: IRegister,
270        src2: IRegister,
271    },
272    FENCE {
273        rd: IRegister,
274        rs1: IRegister,
275        ops: u8,
276        fm: u8,
277    },
278    ECALL,
279    EBREAK,
280    //
281    // Instructions Added In RV64I
282    //
283    /// Load Word Unsigned
284    LWU {
285        dest: IRegister,
286        base: IRegister,
287        offset: IImmediate,
288    },
289    /// Load Doubleword
290    LD {
291        dest: IRegister,
292        base: IRegister,
293        offset: IImmediate,
294    },
295    /// Store Doubleword
296    SD {
297        src: IRegister,
298        base: IRegister,
299        offset: SImmediate,
300    },
301    /// Add Immediate (word)
302    ADDIW {
303        dest: IRegister,
304        src: IRegister,
305        imm: IImmediate,
306    },
307    /// Left Shift Immediate (word)
308    SLLIW {
309        dest: IRegister,
310        src: IRegister,
311        shamt: ShamtW,
312    },
313    /// Logical Right Shift Immediate (word)
314    SRLIW {
315        dest: IRegister,
316        src: IRegister,
317        shamt: ShamtW,
318    },
319    /// Arithmetic Right Shift Immediate (word)
320    SRAIW {
321        dest: IRegister,
322        src: IRegister,
323        shamt: ShamtW,
324    },
325    /// Add (word)
326    ADDW {
327        dest: IRegister,
328        src1: IRegister,
329        src2: IRegister,
330    },
331    /// Subtract (word)
332    SUBW {
333        dest: IRegister,
334        src1: IRegister,
335        src2: IRegister,
336    },
337    /// Left Shift (word)
338    SLLW {
339        dest: IRegister,
340        src1: IRegister,
341        src2: IRegister,
342    },
343    /// Logical Right Shift (word)
344    SRLW {
345        dest: IRegister,
346        src1: IRegister,
347        src2: IRegister,
348    },
349    /// Arithmetic Right Shift (word)
350    SRAW {
351        dest: IRegister,
352        src1: IRegister,
353        src2: IRegister,
354    },
355    //
356    // Instructions In M Extension
357    //
358    /// Multiply
359    MUL {
360        dest: IRegister,
361        src1: IRegister,
362        src2: IRegister,
363    },
364    /// Multiply (High bits)
365    MULH {
366        dest: IRegister,
367        src1: IRegister,
368        src2: IRegister,
369    },
370    /// Multiply Signed-Unsigned (High bits)
371    MULHSU {
372        dest: IRegister,
373        src1: IRegister,
374        src2: IRegister,
375    },
376    /// Multiply Unsigned (High)
377    MULHU {
378        dest: IRegister,
379        src1: IRegister,
380        src2: IRegister,
381    },
382    /// Divide
383    DIV {
384        dest: IRegister,
385        src1: IRegister,
386        src2: IRegister,
387    },
388    /// Divide (Unsigned)
389    DIVU {
390        dest: IRegister,
391        src1: IRegister,
392        src2: IRegister,
393    },
394    /// Remainder
395    REM {
396        dest: IRegister,
397        src1: IRegister,
398        src2: IRegister,
399    },
400    /// Remainder (Unsigned)
401    REMU {
402        dest: IRegister,
403        src1: IRegister,
404        src2: IRegister,
405    },
406    /// Multiply Word
407    MULW {
408        dest: IRegister,
409        src1: IRegister,
410        src2: IRegister,
411    },
412    /// Divide Word
413    DIVW {
414        dest: IRegister,
415        src1: IRegister,
416        src2: IRegister,
417    },
418    /// Divide Unsigned Word
419    DIVUW {
420        dest: IRegister,
421        src1: IRegister,
422        src2: IRegister,
423    },
424    /// Remainder Word
425    REMW {
426        dest: IRegister,
427        src1: IRegister,
428        src2: IRegister,
429    },
430    /// Remainder Unsigned Word
431    REMUW {
432        dest: IRegister,
433        src1: IRegister,
434        src2: IRegister,
435    },
436    //
437    // Instructions In A Extension
438    //
439    /// Load Reserved Word
440    // rd, rs1, ac, rl
441    LRW {
442        dest: IRegister,
443        addr: IRegister,
444        aq: bool,
445        rl: bool,
446    },
447    SCW {
448        dest: IRegister,
449        addr: IRegister,
450        src: IRegister,
451        aq: bool,
452        rl: bool,
453    },
454    AMOSWAPW {
455        dest: IRegister,
456        addr: IRegister,
457        src: IRegister,
458        aq: bool,
459        rl: bool,
460    },
461    AMOADDW {
462        dest: IRegister,
463        addr: IRegister,
464        src: IRegister,
465        aq: bool,
466        rl: bool,
467    },
468    AMOXORW {
469        dest: IRegister,
470        addr: IRegister,
471        src: IRegister,
472        aq: bool,
473        rl: bool,
474    },
475    AMOANDW {
476        dest: IRegister,
477        addr: IRegister,
478        src: IRegister,
479        aq: bool,
480        rl: bool,
481    },
482    AMOORW {
483        dest: IRegister,
484        addr: IRegister,
485        src: IRegister,
486        aq: bool,
487        rl: bool,
488    },
489    AMOMINW {
490        dest: IRegister,
491        addr: IRegister,
492        src: IRegister,
493        aq: bool,
494        rl: bool,
495    },
496    AMOMAXW {
497        dest: IRegister,
498        addr: IRegister,
499        src: IRegister,
500        aq: bool,
501        rl: bool,
502    },
503    AMOMINUW {
504        dest: IRegister,
505        addr: IRegister,
506        src: IRegister,
507        aq: bool,
508        rl: bool,
509    },
510    AMOMAXUW {
511        dest: IRegister,
512        addr: IRegister,
513        src: IRegister,
514        aq: bool,
515        rl: bool,
516    },
517    //
518    LRD {
519        dest: IRegister,
520        addr: IRegister,
521        aq: bool,
522        rl: bool,
523    },
524    SCD {
525        dest: IRegister,
526        addr: IRegister,
527        src: IRegister,
528        aq: bool,
529        rl: bool,
530    },
531    AMOSWAPD {
532        dest: IRegister,
533        addr: IRegister,
534        src: IRegister,
535        aq: bool,
536        rl: bool,
537    },
538    AMOADDD {
539        dest: IRegister,
540        addr: IRegister,
541        src: IRegister,
542        aq: bool,
543        rl: bool,
544    },
545    AMOXORD {
546        dest: IRegister,
547        addr: IRegister,
548        src: IRegister,
549        aq: bool,
550        rl: bool,
551    },
552    AMOANDD {
553        dest: IRegister,
554        addr: IRegister,
555        src: IRegister,
556        aq: bool,
557        rl: bool,
558    },
559    AMOORD {
560        dest: IRegister,
561        addr: IRegister,
562        src: IRegister,
563        aq: bool,
564        rl: bool,
565    },
566    AMOMIND {
567        dest: IRegister,
568        addr: IRegister,
569        src: IRegister,
570        aq: bool,
571        rl: bool,
572    },
573    AMOMAXD {
574        dest: IRegister,
575        addr: IRegister,
576        src: IRegister,
577        aq: bool,
578        rl: bool,
579    },
580    AMOMINUD {
581        dest: IRegister,
582        addr: IRegister,
583        src: IRegister,
584        aq: bool,
585        rl: bool,
586    },
587    AMOMAXUD {
588        dest: IRegister,
589        addr: IRegister,
590        src: IRegister,
591        aq: bool,
592        rl: bool,
593    },
594    //
595    // Instructions in F Extension
596    //
597    FLW {
598        dest: FRegister,
599        base: IRegister,
600        offset: IImmediate,
601    },
602    FSW {
603        base: IRegister,
604        src: FRegister,
605        offset: SImmediate,
606    },
607    FMADDS {
608        dest: FRegister,
609        src1: FRegister,
610        src2: FRegister,
611        src3: FRegister,
612        rm: RoundingMode,
613    },
614    FMSUBS {
615        dest: FRegister,
616        src1: FRegister,
617        src2: FRegister,
618        src3: FRegister,
619        rm: RoundingMode,
620    },
621    FNMSUBS {
622        dest: FRegister,
623        src1: FRegister,
624        src2: FRegister,
625        src3: FRegister,
626        rm: RoundingMode,
627    },
628    FNMADDS {
629        dest: FRegister,
630        src1: FRegister,
631        src2: FRegister,
632        src3: FRegister,
633        rm: RoundingMode,
634    },
635    FADDS {
636        dest: FRegister,
637        src1: FRegister,
638        src2: FRegister,
639        rm: RoundingMode,
640    },
641    FSUBS {
642        dest: FRegister,
643        src1: FRegister,
644        src2: FRegister,
645        rm: RoundingMode,
646    },
647    FMULS {
648        dest: FRegister,
649        src1: FRegister,
650        src2: FRegister,
651        rm: RoundingMode,
652    },
653    FDIVS {
654        dest: FRegister,
655        src1: FRegister,
656        src2: FRegister,
657        rm: RoundingMode,
658    },
659    FSQRTS {
660        dest: FRegister,
661        src: FRegister,
662        rm: RoundingMode,
663    },
664    FSGNJS {
665        dest: FRegister,
666        src1: FRegister,
667        src2: FRegister,
668    },
669    FSGNJNS {
670        dest: FRegister,
671        src1: FRegister,
672        src2: FRegister,
673    },
674    FSGNJXS {
675        dest: FRegister,
676        src1: FRegister,
677        src2: FRegister,
678    },
679    FMINS {
680        dest: FRegister,
681        src1: FRegister,
682        src2: FRegister,
683    },
684    FMAXS {
685        dest: FRegister,
686        src1: FRegister,
687        src2: FRegister,
688    },
689    FCVTWS {
690        dest: IRegister,
691        src: FRegister,
692        rm: RoundingMode,
693    },
694    FCVTWUS {
695        dest: IRegister,
696        src: FRegister,
697        rm: RoundingMode,
698    },
699    FMVXW {
700        dest: IRegister,
701        src: FRegister,
702    },
703    FEQS {
704        dest: IRegister,
705        src1: FRegister,
706        src2: FRegister,
707    },
708    FLTS {
709        dest: IRegister,
710        src1: FRegister,
711        src2: FRegister,
712    },
713    FLES {
714        dest: IRegister,
715        src1: FRegister,
716        src2: FRegister,
717    },
718    FCLASSS {
719        dest: IRegister,
720        src: FRegister,
721    },
722    FCVTSW {
723        dest: FRegister,
724        src: IRegister,
725        rm: RoundingMode,
726    },
727    FCVTSWU {
728        dest: FRegister,
729        src: IRegister,
730        rm: RoundingMode,
731    },
732    FMVWX {
733        dest: FRegister,
734        src: IRegister,
735    },
736    //
737    // Instructions in F Extension (RV64)
738    //
739    FCVTLS {
740        dest: IRegister,
741        src: FRegister,
742        rm: RoundingMode,
743    },
744    FCVTLUS {
745        dest: IRegister,
746        src: FRegister,
747        rm: RoundingMode,
748    },
749    FCVTSL {
750        dest: FRegister,
751        src: IRegister,
752        rm: RoundingMode,
753    },
754    FCVTSLU {
755        dest: FRegister,
756        src: IRegister,
757        rm: RoundingMode,
758    },
759    //
760    // Instructions in Zicsr Extension
761    //
762    CSRRW {
763        dest: IRegister,
764        src: IRegister,
765        csr: CSR,
766    },
767    CSRRS {
768        dest: IRegister,
769        src: IRegister,
770        csr: CSR,
771    },
772    CSRRC {
773        dest: IRegister,
774        src: IRegister,
775        csr: CSR,
776    },
777    CSRRWI {
778        dest: IRegister,
779        imm: CSRImmediate,
780        csr: CSR,
781    },
782    CSRRSI {
783        dest: IRegister,
784        imm: CSRImmediate,
785        csr: CSR,
786    },
787    CSRRCI {
788        dest: IRegister,
789        imm: CSRImmediate,
790        csr: CSR,
791    },
792    //
793    // Instructions in Zifencei Extension
794    //
795    FENCEI,
796}
797
798fn aq_rl_suffix(aq: &bool, rl: &bool) -> &'static str {
799    match (aq, rl) {
800        (true, true) => ".aqrl",
801        (true, false) => ".aq",
802        (false, true) => ".rl",
803        (false, false) => "",
804    }
805}
806
807/// puts the aquire bit in the correct location
808fn aqb(aq: bool) -> u32 {
809    if aq { 1 << 26 } else { 0 }
810}
811
812/// puts the release bit in the correct location
813fn rlb(rl: bool) -> u32 {
814    if rl { 1 << 25 } else { 0 }
815}
816
817impl Display for Instruction {
818    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
819        match self {
820            Instruction::LUI { dest, imm } => write!(f, "lui {dest},{imm}"),
821            Instruction::AUIPC { dest, imm } => write!(f, "auipc {dest},{imm}"),
822            Instruction::JAL { dest, offset } => write!(f, "jal {dest},{offset}"),
823            Instruction::JALR { dest, base, offset } => write!(f, "jalr {dest},{offset}({base})"),
824            Instruction::BEQ { src1, src2, offset } => write!(f, "beq {src1},{src2},{offset}"),
825            Instruction::BNE { src1, src2, offset } => write!(f, "bne {src1},{src2},{offset}"),
826            Instruction::BLT { src1, src2, offset } => write!(f, "blt {src1},{src2},{offset}"),
827            Instruction::BGE { src1, src2, offset } => write!(f, "bge {src1},{src2},{offset}"),
828            Instruction::BLTU { src1, src2, offset } => write!(f, "bltu {src1},{src2},{offset}"),
829            Instruction::BGEU { src1, src2, offset } => write!(f, "bgeu {src1},{src2},{offset}"),
830            Instruction::LB { dest, base, offset } => write!(f, "lb {dest},{offset}({base})"),
831            Instruction::LH { dest, base, offset } => write!(f, "lh {dest},{offset}({base})"),
832            Instruction::LW { dest, base, offset } => write!(f, "lw {dest},{offset}({base})"),
833            Instruction::LBU { dest, base, offset } => write!(f, "lbu {dest},{offset}({base})"),
834            Instruction::LHU { dest, base, offset } => write!(f, "lhu {dest},{offset}({base})"),
835            Instruction::SB { src, base, offset } => write!(f, "sb {src},{offset}({base})"),
836            Instruction::SH { src, base, offset } => write!(f, "sh {src},{offset}({base})"),
837            Instruction::SW { src, base, offset } => write!(f, "sw {src},{offset}({base})"),
838            Instruction::ADDI { dest, src, imm } => write!(f, "addi {dest},{src},{imm}"),
839            Instruction::SLTI { dest, src, imm } => write!(f, "slti {dest},{src},{imm}"),
840            Instruction::SLTIU { dest, src, imm } => write!(f, "sltiu {dest},{src},{imm}"),
841            Instruction::XORI { dest, src, imm } => write!(f, "xori {dest},{src},{imm}"),
842            Instruction::ORI { dest, src, imm } => write!(f, "ori {dest},{src},{imm}"),
843            Instruction::ANDI { dest, src, imm } => write!(f, "andi {dest},{src},{imm}"),
844            Instruction::SLLI { dest, src, shamt } => write!(f, "slli {dest},{src},{shamt}"),
845            Instruction::SRLI { dest, src, shamt } => write!(f, "srli {dest},{src},{shamt}"),
846            Instruction::SRAI { dest, src, shamt } => write!(f, "srai {dest},{src},{shamt}"),
847            Instruction::ADD { dest, src1, src2 } => write!(f, "add {dest},{src1},{src2}"),
848            Instruction::SUB { dest, src1, src2 } => write!(f, "sub {dest},{src1},{src2}"),
849            Instruction::SLL { dest, src1, src2 } => write!(f, "sll {dest},{src1},{src2}"),
850            Instruction::SLT { dest, src1, src2 } => write!(f, "slt {dest},{src1},{src2}"),
851            Instruction::SLTU { dest, src1, src2 } => write!(f, "sltu {dest},{src1},{src2}"),
852            Instruction::XOR { dest, src1, src2 } => write!(f, "xor {dest},{src1},{src2}"),
853            Instruction::SRL { dest, src1, src2 } => write!(f, "srl {dest},{src1},{src2}"),
854            Instruction::SRA { dest, src1, src2 } => write!(f, "sra {dest},{src1},{src2}"),
855            Instruction::OR { dest, src1, src2 } => write!(f, "or {dest},{src1},{src2}"),
856            Instruction::AND { dest, src1, src2 } => write!(f, "and {dest},{src1},{src2}"),
857            Instruction::FENCE { .. } => write!(f, "{}", self.fmt_fence()),
858            Instruction::ECALL => write!(f, "ecall"),
859            Instruction::EBREAK => write!(f, "ebreak"),
860            Instruction::LWU { dest, base, offset } => write!(f, "lwu {dest},{offset}({base})"),
861            Instruction::LD { dest, base, offset } => write!(f, "ld {dest},{offset}({base})"),
862            Instruction::SD { src, base, offset } => write!(f, "sd {src},{offset}({base})"),
863            Instruction::ADDIW { dest, src, imm } => write!(f, "addiw {dest},{src},{imm}"),
864            Instruction::SLLIW { dest, src, shamt } => write!(f, "slliw {dest},{src},{shamt}"),
865            Instruction::SRLIW { dest, src, shamt } => write!(f, "srliw {dest},{src},{shamt}"),
866            Instruction::SRAIW { dest, src, shamt } => write!(f, "sraiw {dest},{src},{shamt}"),
867            Instruction::ADDW { dest, src1, src2 } => write!(f, "addw {dest},{src1},{src2}"),
868            Instruction::SUBW { dest, src1, src2 } => write!(f, "subw {dest},{src1},{src2}"),
869            Instruction::SLLW { dest, src1, src2 } => write!(f, "sllw {dest},{src1},{src2}"),
870            Instruction::SRLW { dest, src1, src2 } => write!(f, "srlw {dest},{src1},{src2}"),
871            Instruction::SRAW { dest, src1, src2 } => write!(f, "sraw {dest},{src1},{src2}"),
872            Instruction::MUL { dest, src1, src2 } => write!(f, "mul {dest},{src1},{src2}"),
873            Instruction::MULH { dest, src1, src2 } => write!(f, "mulh {dest},{src1},{src2}"),
874            Instruction::MULHSU { dest, src1, src2 } => write!(f, "mulhsu {dest},{src1},{src2}"),
875            Instruction::MULHU { dest, src1, src2 } => write!(f, "mulhu {dest},{src1},{src2}"),
876            Instruction::DIV { dest, src1, src2 } => write!(f, "div {dest},{src1},{src2}"),
877            Instruction::DIVU { dest, src1, src2 } => write!(f, "divu {dest},{src1},{src2}"),
878            Instruction::REM { dest, src1, src2 } => write!(f, "rem {dest},{src1},{src2}"),
879            Instruction::REMU { dest, src1, src2 } => write!(f, "remu {dest},{src1},{src2}"),
880            Instruction::MULW { dest, src1, src2 } => write!(f, "mulw {dest},{src1},{src2}"),
881            Instruction::DIVW { dest, src1, src2 } => write!(f, "divw {dest},{src1},{src2}"),
882            Instruction::DIVUW { dest, src1, src2 } => write!(f, "divuw {dest},{src1},{src2}"),
883            Instruction::REMW { dest, src1, src2 } => write!(f, "remw {dest},{src1},{src2}"),
884            Instruction::REMUW { dest, src1, src2 } => write!(f, "remuw {dest},{src1},{src2}"),
885            Instruction::LRW { dest, addr, aq, rl } => {
886                write!(f, "lr.w{} {dest},{addr}", aq_rl_suffix(aq, rl))
887            }
888            Instruction::SCW {
889                dest,
890                addr,
891                src,
892                aq,
893                rl,
894            } => {
895                write!(f, "sc.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
896            }
897            Instruction::AMOSWAPW {
898                dest,
899                addr,
900                src,
901                aq,
902                rl,
903            } => {
904                write!(f, "amoswap.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
905            }
906            Instruction::AMOADDW {
907                dest,
908                addr,
909                src,
910                aq,
911                rl,
912            } => {
913                write!(f, "amoadd.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
914            }
915            Instruction::AMOXORW {
916                dest,
917                addr,
918                src,
919                aq,
920                rl,
921            } => {
922                write!(f, "amoxor.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
923            }
924            Instruction::AMOANDW {
925                dest,
926                addr,
927                src,
928                aq,
929                rl,
930            } => {
931                write!(f, "amoand.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
932            }
933            Instruction::AMOORW {
934                dest,
935                addr,
936                src,
937                aq,
938                rl,
939            } => {
940                write!(f, "amoor.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
941            }
942
943            Instruction::AMOMINW {
944                dest,
945                addr,
946                src,
947                aq,
948                rl,
949            } => {
950                write!(f, "amomin.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
951            }
952            Instruction::AMOMAXW {
953                dest,
954                addr,
955                src,
956                aq,
957                rl,
958            } => {
959                write!(f, "amomax.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
960            }
961            Instruction::AMOMINUW {
962                dest,
963                addr,
964                src,
965                aq,
966                rl,
967            } => {
968                write!(f, "amominu.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
969            }
970            Instruction::AMOMAXUW {
971                dest,
972                addr,
973                src,
974                aq,
975                rl,
976            } => {
977                write!(f, "amomaxu.w{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
978            }
979            Instruction::LRD { dest, addr, aq, rl } => {
980                write!(f, "lr.d{} {dest},{addr}", aq_rl_suffix(aq, rl))
981            }
982            Instruction::SCD {
983                dest,
984                addr,
985                src,
986                aq,
987                rl,
988            } => {
989                write!(f, "sc.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
990            }
991            Instruction::AMOSWAPD {
992                dest,
993                addr,
994                src,
995                aq,
996                rl,
997            } => {
998                write!(f, "amoswap.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
999            }
1000            Instruction::AMOADDD {
1001                dest,
1002                addr,
1003                src,
1004                aq,
1005                rl,
1006            } => {
1007                write!(f, "amoadd.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1008            }
1009            Instruction::AMOXORD {
1010                dest,
1011                addr,
1012                src,
1013                aq,
1014                rl,
1015            } => {
1016                write!(f, "amoxor.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1017            }
1018            Instruction::AMOANDD {
1019                dest,
1020                addr,
1021                src,
1022                aq,
1023                rl,
1024            } => {
1025                write!(f, "amoand.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1026            }
1027            Instruction::AMOORD {
1028                dest,
1029                addr,
1030                src,
1031                aq,
1032                rl,
1033            } => {
1034                write!(f, "amoor.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1035            }
1036            Instruction::AMOMIND {
1037                dest,
1038                addr,
1039                src,
1040                aq,
1041                rl,
1042            } => {
1043                write!(f, "amomin.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1044            }
1045            Instruction::AMOMAXD {
1046                dest,
1047                addr,
1048                src,
1049                aq,
1050                rl,
1051            } => {
1052                write!(f, "amomax.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1053            }
1054            Instruction::AMOMINUD {
1055                dest,
1056                addr,
1057                src,
1058                aq,
1059                rl,
1060            } => {
1061                write!(f, "amominu.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1062            }
1063            Instruction::AMOMAXUD {
1064                dest,
1065                addr,
1066                src,
1067                aq,
1068                rl,
1069            } => {
1070                write!(f, "amomaxu.d{} {dest},{addr},{src}", aq_rl_suffix(aq, rl))
1071            }
1072            Instruction::FLW { dest, base, offset } => write!(f, "flw {dest},{offset}({base})"),
1073            Instruction::FSW { base, src, offset } => write!(f, "fsw {src},{offset}({base})"),
1074            Instruction::FMADDS {
1075                dest,
1076                src1,
1077                src2,
1078                src3,
1079                rm,
1080            } => {
1081                write!(f, "fmadd.s.{rm} {dest},{src1},{src2},{src3}")
1082            }
1083            Instruction::FMSUBS {
1084                dest,
1085                src1,
1086                src2,
1087                src3,
1088                rm,
1089            } => {
1090                write!(f, "fmsub.s.{rm} {dest},{src1},{src2},{src3}")
1091            }
1092            Instruction::FNMSUBS {
1093                dest,
1094                src1,
1095                src2,
1096                src3,
1097                rm,
1098            } => {
1099                write!(f, "fnmsub.s.{rm} {dest},{src1},{src2},{src3}")
1100            }
1101            Instruction::FNMADDS {
1102                dest,
1103                src1,
1104                src2,
1105                src3,
1106                rm,
1107            } => {
1108                write!(f, "fnmadd.s.{rm} {dest},{src1},{src2},{src3}")
1109            }
1110            Instruction::FADDS {
1111                dest,
1112                src1,
1113                src2,
1114                rm,
1115            } => write!(f, "fadd.s.{rm} {dest},{src1},{src2}"),
1116            Instruction::FSUBS {
1117                dest,
1118                src1,
1119                src2,
1120                rm,
1121            } => write!(f, "fsub.s.{rm} {dest},{src1},{src2}"),
1122            Instruction::FMULS {
1123                dest,
1124                src1,
1125                src2,
1126                rm,
1127            } => write!(f, "fmul.s.{rm} {dest},{src1},{src2}"),
1128            Instruction::FDIVS {
1129                dest,
1130                src1,
1131                src2,
1132                rm,
1133            } => write!(f, "fdiv.s.{rm} {dest},{src1},{src2}"),
1134            Instruction::FSQRTS { dest, src, rm } => write!(f, "fsqrt.s.{rm} {dest},{src}"),
1135            Instruction::FSGNJS { dest, src1, src2 } => write!(f, "fsgnj.s {dest},{src1},{src2}"),
1136            Instruction::FSGNJNS { dest, src1, src2 } => write!(f, "fsgnjn.s {dest},{src1},{src2}"),
1137            Instruction::FSGNJXS { dest, src1, src2 } => write!(f, "fsgnjx.s {dest},{src1},{src2}"),
1138            Instruction::FMINS { dest, src1, src2 } => write!(f, "fmin.s {dest},{src1},{src2}"),
1139            Instruction::FMAXS { dest, src1, src2 } => write!(f, "fmax.s {dest},{src1},{src2}"),
1140            Instruction::FCVTWS { dest, src, rm } => write!(f, "fcvt.w.s.{rm} {dest},{src}"),
1141            Instruction::FCVTWUS { dest, src, rm } => write!(f, "fcvt.wu.s.{rm} {dest},{src}"),
1142            Instruction::FMVXW { dest, src } => write!(f, "fmv.x.w {dest},{src}"),
1143            Instruction::FEQS { dest, src1, src2 } => write!(f, "feq.s {dest},{src1},{src2}"),
1144            Instruction::FLTS { dest, src1, src2 } => write!(f, "flt.s {dest},{src1},{src2}"),
1145            Instruction::FLES { dest, src1, src2 } => write!(f, "fle.s {dest},{src1},{src2}"),
1146            Instruction::FCLASSS { dest, src } => write!(f, "fclass.s {dest},{src}"),
1147            Instruction::FCVTSW { dest, src, rm } => write!(f, "fcvt.s.w.{rm} {dest},{src}"),
1148            Instruction::FCVTSWU { dest, src, rm } => write!(f, "fcvt.s.wu.{rm} {dest},{src}"),
1149            Instruction::FMVWX { dest, src } => write!(f, "fmv.w.x {dest},{src}"),
1150            Instruction::FCVTLS { dest, src, rm } => write!(f, "fcvt.l.s.{rm} {dest},{src}"),
1151            Instruction::FCVTLUS { dest, src, rm } => write!(f, "fcvt.lu.s.{rm} {dest},{src}"),
1152            Instruction::FCVTSL { dest, src, rm } => write!(f, "fcvt.s.l.{rm} {dest},{src}"),
1153            Instruction::FCVTSLU { dest, src, rm } => write!(f, "fcvt.s.lu.{rm} {dest},{src}"),
1154            Instruction::CSRRW { dest, src, csr } => write!(f, "csrrw {dest},{csr},{src}"),
1155            Instruction::CSRRS { dest, src, csr } => write!(f, "csrrs {dest},{csr},{src}"),
1156            Instruction::CSRRC { dest, src, csr } => write!(f, "csrrc {dest},{csr},{src}"),
1157            Instruction::CSRRWI { dest, imm, csr } => write!(f, "csrrwi {dest},{csr},{imm}"),
1158            Instruction::CSRRSI { dest, imm, csr } => write!(f, "csrrsi {dest},{csr},{imm}"),
1159            Instruction::CSRRCI { dest, imm, csr } => write!(f, "csrrci {dest},{csr},{imm}"),
1160            Instruction::FENCEI => write!(f, "fence.i"),
1161        }
1162    }
1163}
1164
1165impl Instruction {
1166    fn fmt_fence(&self) -> String {
1167        if let Instruction::FENCE {
1168            rd: _,
1169            rs1: _,
1170            ops,
1171            fm,
1172        } = *self
1173        {
1174            let sw = if ops & 0b0000_0001 != 0 { "w" } else { "" };
1175            let sr = if ops & 0b0000_0010 != 0 { "r" } else { "" };
1176            let so = if ops & 0b0000_0100 != 0 { "o" } else { "" };
1177            let si = if ops & 0b0000_1000 != 0 { "i" } else { "" };
1178            let pw = if ops & 0b0001_0000 != 0 { "w" } else { "" };
1179            let pr = if ops & 0b0010_0000 != 0 { "r" } else { "" };
1180            let po = if ops & 0b0100_0000 != 0 { "o" } else { "" };
1181            let pi = if ops & 0b1000_0000 != 0 { "i" } else { "" };
1182            if fm == 0b1000 {
1183                format!("fence.tso {pi}{po}{pr}{pw},{si}{so}{sr}{sw}")
1184            } else {
1185                format!("fence {pi}{po}{pr}{pw},{si}{so}{sr}{sw}")
1186            }
1187        } else {
1188            unreachable!();
1189        }
1190    }
1191
1192    /// Constructs an `Instruction` from it's machine code representation.
1193    pub fn decode(instruction: u32) -> Result<Instruction, String> {
1194        let opcode = Opcode::from_int(instruction & 0b111_1111);
1195
1196        let func3 = (instruction >> 12) & 0b111;
1197        let func7 = (instruction >> 25) & 0b111_1111;
1198
1199        let rd = IRegister::from_int((instruction >> 7) & 0b1_1111);
1200        let rs1 = IRegister::from_int((instruction >> 15) & 0b1_1111);
1201        let rs2 = IRegister::from_int((instruction >> 20) & 0b1_1111);
1202
1203        let frd = FRegister::try_from((instruction >> 7) & 0b1_1111).unwrap();
1204        let frs1 = FRegister::try_from((instruction >> 15) & 0b1_1111).unwrap();
1205        let frs2 = FRegister::try_from((instruction >> 20) & 0b1_1111).unwrap();
1206        let frs3 = FRegister::try_from((instruction >> 27) & 0b1_1111).unwrap();
1207
1208        let i_immediate: IImmediate = IImmediate::from_u32(instruction);
1209
1210        let s_immediate: SImmediate = SImmediate::from_u32(instruction);
1211
1212        let u_immediate = UImmediate::from_u32(instruction);
1213
1214        let b_immediate = BImmediate::from_u32(instruction);
1215
1216        let shamt: Shamt = Shamt::from_u32(instruction);
1217
1218        let shamtw: ShamtW = ShamtW::from_u32(instruction);
1219
1220        // aq is bit 26, rl is bit 25
1221        let aq: bool = ((instruction >> 26) & 0b1) == 0b1;
1222        let rl: bool = ((instruction >> 25) & 0b1) == 0b1;
1223
1224        match opcode {
1225            Opcode::Load => match func3 {
1226                0b000 => Ok(Instruction::LB {
1227                    dest: rd,
1228                    base: rs1,
1229                    offset: i_immediate,
1230                }),
1231                0b001 => Ok(Instruction::LH {
1232                    dest: rd,
1233                    base: rs1,
1234                    offset: i_immediate,
1235                }),
1236                0b010 => Ok(Instruction::LW {
1237                    dest: rd,
1238                    base: rs1,
1239                    offset: i_immediate,
1240                }),
1241                0b011 => Ok(Instruction::LD {
1242                    dest: rd,
1243                    base: rs1,
1244                    offset: i_immediate,
1245                }),
1246                0b100 => Ok(Instruction::LBU {
1247                    dest: rd,
1248                    base: rs1,
1249                    offset: i_immediate,
1250                }),
1251                0b101 => Ok(Instruction::LHU {
1252                    dest: rd,
1253                    base: rs1,
1254                    offset: i_immediate,
1255                }),
1256                0b110 => Ok(Instruction::LWU {
1257                    dest: rd,
1258                    base: rs1,
1259                    offset: i_immediate,
1260                }),
1261                0b111 => Err("Invalid load func3".to_owned()),
1262                _ => unreachable!(),
1263            },
1264            Opcode::Auipc => Ok(Instruction::AUIPC {
1265                dest: rd,
1266                imm: u_immediate,
1267            }),
1268            Opcode::Store => match func3 {
1269                0b000 => Ok(Instruction::SB {
1270                    src: rs2,
1271                    base: rs1,
1272                    offset: s_immediate,
1273                }),
1274                0b001 => Ok(Instruction::SH {
1275                    src: rs2,
1276                    base: rs1,
1277                    offset: s_immediate,
1278                }),
1279                0b010 => Ok(Instruction::SW {
1280                    src: rs2,
1281                    base: rs1,
1282                    offset: s_immediate,
1283                }),
1284                0b011 => Ok(Instruction::SD {
1285                    src: rs2,
1286                    base: rs1,
1287                    offset: s_immediate,
1288                }),
1289                x => Err(format!("invalid store func3: {}", x)),
1290            },
1291            Opcode::Lui => Ok(Instruction::LUI {
1292                dest: rd,
1293                imm: u_immediate,
1294            }),
1295            Opcode::Op => match (func7, func3) {
1296                (0b000_0000, 0b000) => Ok(Instruction::ADD {
1297                    dest: rd,
1298                    src1: rs1,
1299                    src2: rs2,
1300                }),
1301                (0b000_0000, 0b001) => Ok(Instruction::SLL {
1302                    dest: rd,
1303                    src1: rs1,
1304                    src2: rs2,
1305                }),
1306                (0b000_0000, 0b010) => Ok(Instruction::SLT {
1307                    dest: rd,
1308                    src1: rs1,
1309                    src2: rs2,
1310                }),
1311                (0b000_0000, 0b011) => Ok(Instruction::SLTU {
1312                    dest: rd,
1313                    src1: rs1,
1314                    src2: rs2,
1315                }),
1316                (0b000_0000, 0b100) => Ok(Instruction::XOR {
1317                    dest: rd,
1318                    src1: rs1,
1319                    src2: rs2,
1320                }),
1321                (0b000_0000, 0b101) => Ok(Instruction::SRL {
1322                    dest: rd,
1323                    src1: rs1,
1324                    src2: rs2,
1325                }),
1326                (0b000_0000, 0b110) => Ok(Instruction::OR {
1327                    dest: rd,
1328                    src1: rs1,
1329                    src2: rs2,
1330                }),
1331                (0b000_0000, 0b111) => Ok(Instruction::AND {
1332                    dest: rd,
1333                    src1: rs1,
1334                    src2: rs2,
1335                }),
1336                (0b010_0000, 0b000) => Ok(Instruction::SUB {
1337                    dest: rd,
1338                    src1: rs1,
1339                    src2: rs2,
1340                }),
1341                (0b010_0000, 0b101) => Ok(Instruction::SRA {
1342                    dest: rd,
1343                    src1: rs1,
1344                    src2: rs2,
1345                }),
1346                (0b000_0001, 0b000) => Ok(Instruction::MUL {
1347                    dest: rd,
1348                    src1: rs1,
1349                    src2: rs2,
1350                }),
1351                (0b000_0001, 0b001) => Ok(Instruction::MULH {
1352                    dest: rd,
1353                    src1: rs1,
1354                    src2: rs2,
1355                }),
1356                (0b000_0001, 0b010) => Ok(Instruction::MULHSU {
1357                    dest: rd,
1358                    src1: rs1,
1359                    src2: rs2,
1360                }),
1361                (0b000_0001, 0b011) => Ok(Instruction::MULHU {
1362                    dest: rd,
1363                    src1: rs1,
1364                    src2: rs2,
1365                }),
1366                (0b000_0001, 0b100) => Ok(Instruction::DIV {
1367                    dest: rd,
1368                    src1: rs1,
1369                    src2: rs2,
1370                }),
1371                (0b000_0001, 0b101) => Ok(Instruction::DIVU {
1372                    dest: rd,
1373                    src1: rs1,
1374                    src2: rs2,
1375                }),
1376                (0b000_0001, 0b110) => Ok(Instruction::REM {
1377                    dest: rd,
1378                    src1: rs1,
1379                    src2: rs2,
1380                }),
1381                (0b000_0001, 0b111) => Ok(Instruction::REMU {
1382                    dest: rd,
1383                    src1: rs1,
1384                    src2: rs2,
1385                }),
1386                _ => Err(format!("unknown Op. func3: {}, func7: {}", func3, func7)),
1387            },
1388            Opcode::Op32 => match (func3, func7) {
1389                (0b000, 0b000_0000) => Ok(Instruction::ADDW {
1390                    dest: rd,
1391                    src1: rs1,
1392                    src2: rs2,
1393                }),
1394                (0b000, 0b000_0001) => Ok(Instruction::MULW {
1395                    dest: rd,
1396                    src1: rs1,
1397                    src2: rs2,
1398                }),
1399                (0b000, 0b010_0000) => Ok(Instruction::SUBW {
1400                    dest: rd,
1401                    src1: rs1,
1402                    src2: rs2,
1403                }),
1404                (0b001, 0b000_0000) => Ok(Instruction::SLLW {
1405                    dest: rd,
1406                    src1: rs1,
1407                    src2: rs2,
1408                }),
1409                (0b100, 0b0000_001) => Ok(Instruction::DIVW {
1410                    dest: rd,
1411                    src1: rs1,
1412                    src2: rs2,
1413                }),
1414                (0b101, 0b000_0000) => Ok(Instruction::SRLW {
1415                    dest: rd,
1416                    src1: rs1,
1417                    src2: rs2,
1418                }),
1419                (0b101, 0b000_0001) => Ok(Instruction::DIVUW {
1420                    dest: rd,
1421                    src1: rs1,
1422                    src2: rs2,
1423                }),
1424                (0b101, 0b010_0000) => Ok(Instruction::SRAW {
1425                    dest: rd,
1426                    src1: rs1,
1427                    src2: rs2,
1428                }),
1429                (0b110, 0b000_0001) => Ok(Instruction::REMW {
1430                    dest: rd,
1431                    src1: rs1,
1432                    src2: rs2,
1433                }),
1434                (0b111, 0b000_0001) => Ok(Instruction::REMUW {
1435                    dest: rd,
1436                    src1: rs1,
1437                    src2: rs2,
1438                }),
1439                _ => Err(format!("unknown Op32. func3: {}, func7: {}", func3, func7)),
1440            },
1441            Opcode::OpImm => match func3 {
1442                0b000 => Ok(Instruction::ADDI {
1443                    dest: rd,
1444                    src: rs1,
1445                    imm: i_immediate,
1446                }),
1447                // SLLi requires special handling because shamt uses the bottom bit of func7
1448                0b001 => match func7 | 0b1 {
1449                    0b000000_1 => Ok(Instruction::SLLI {
1450                        dest: rd,
1451                        src: rs1,
1452                        shamt,
1453                    }),
1454                    _ => Err(format!("unknown OpImm. func3: {}, func7: {}", func3, func7)),
1455                },
1456                0b010 => Ok(Instruction::SLTI {
1457                    dest: rd,
1458                    src: rs1,
1459                    imm: i_immediate,
1460                }),
1461                0b011 => Ok(Instruction::SLTIU {
1462                    dest: rd,
1463                    src: rs1,
1464                    imm: i_immediate,
1465                }),
1466                0b100 => Ok(Instruction::XORI {
1467                    dest: rd,
1468                    src: rs1,
1469                    imm: i_immediate,
1470                }),
1471                // SRLI SRAI require special handling because shamt uses the bottom bit of func7
1472                0b101 => match func7 | 0b1 {
1473                    0b000000_1 => Ok(Instruction::SRLI {
1474                        dest: rd,
1475                        src: rs1,
1476                        shamt,
1477                    }),
1478                    0b010000_1 => Ok(Instruction::SRAI {
1479                        dest: rd,
1480                        src: rs1,
1481                        shamt,
1482                    }),
1483                    _ => Err(format!("unknown OpImm. func3: {}, func7: {}", func3, func7)),
1484                },
1485                0b110 => Ok(Instruction::ORI {
1486                    dest: rd,
1487                    src: rs1,
1488                    imm: i_immediate,
1489                }),
1490                0b111 => Ok(Instruction::ANDI {
1491                    dest: rd,
1492                    src: rs1,
1493                    imm: i_immediate,
1494                }),
1495                _ => Err(format!("unknown OpImm. func3: {}, func7: {}", func3, func7)),
1496            },
1497            Opcode::OpImm32 => match func3 {
1498                0b000 => Ok(Instruction::ADDIW {
1499                    dest: rd,
1500                    src: rs1,
1501                    imm: i_immediate,
1502                }),
1503                0b001 => Ok(Instruction::SLLIW {
1504                    dest: rd,
1505                    src: rs1,
1506                    shamt: shamtw,
1507                }),
1508                0b101 => match func7 {
1509                    0b000_0000 => Ok(Instruction::SRLIW {
1510                        dest: rd,
1511                        src: rs1,
1512                        shamt: shamtw,
1513                    }),
1514                    0b010_0000 => Ok(Instruction::SRAIW {
1515                        dest: rd,
1516                        src: rs1,
1517                        shamt: shamtw,
1518                    }),
1519                    x => Err(format!("unknown OpImm32(101) func7: {}", x).to_owned()),
1520                },
1521                x => Err(format!("unkown OpImm32 func3: {}", x).to_owned()),
1522            },
1523            Opcode::Jalr => Ok(Instruction::JALR {
1524                dest: rd,
1525                base: rs1,
1526                offset: i_immediate,
1527            }),
1528            Opcode::Jal => Ok(Instruction::JAL {
1529                dest: rd,
1530                offset: JImmediate::from_u32(instruction),
1531            }),
1532            Opcode::Branch => match func3 {
1533                0b000 => Ok(Instruction::BEQ {
1534                    src1: rs1,
1535                    src2: rs2,
1536                    offset: b_immediate,
1537                }),
1538                0b001 => Ok(Instruction::BNE {
1539                    src1: rs1,
1540                    src2: rs2,
1541                    offset: b_immediate,
1542                }),
1543                0b100 => Ok(Instruction::BLT {
1544                    src1: rs1,
1545                    src2: rs2,
1546                    offset: b_immediate,
1547                }),
1548                0b101 => Ok(Instruction::BGE {
1549                    src1: rs1,
1550                    src2: rs2,
1551                    offset: b_immediate,
1552                }),
1553                0b110 => Ok(Instruction::BLTU {
1554                    src1: rs1,
1555                    src2: rs2,
1556                    offset: b_immediate,
1557                }),
1558                0b111 => Ok(Instruction::BGEU {
1559                    src1: rs1,
1560                    src2: rs2,
1561                    offset: b_immediate,
1562                }),
1563                x => Err(format!("invalid branch func3: {x}").to_owned()),
1564            },
1565            Opcode::MiscMem => match func3 {
1566                0b000 => {
1567                    if rd != IRegister::Zero || rs1 != IRegister::Zero {
1568                        // technicially, we are supposed to ignore these fields
1569                        Err("reserved register fields not set to zero".to_owned())
1570                    } else {
1571                        let fm = ((instruction >> 28) & 0b1111) as u8;
1572                        if fm != 0 && fm != 0b1000 {
1573                            Err(format!("reserved fence FM: {fm}").to_owned())
1574                        } else if fm == 0b1000 && ((instruction >> 20) & 0xFF) != 0b0011_0011 {
1575                            Err("fence.tso must be rw,rw".to_owned())
1576                        } else {
1577                            Ok(Instruction::FENCE {
1578                                rd,
1579                                rs1,
1580                                ops: ((instruction >> 20) & 0xFF) as u8,
1581                                fm: ((instruction >> 28) & 0b1111) as u8,
1582                            })
1583                        }
1584                    }
1585                }
1586                0b001 => {
1587                    if rd != IRegister::Zero || rs1 != IRegister::Zero {
1588                        // technicially, we are supposed to ignore these fields
1589                        Err("reserved register fields not set to zero".to_owned())
1590                    } else {
1591                        let func12 = instruction >> 20;
1592                        if func12 != 0 {
1593                            Err("reserved register fields not set to zero".to_owned())
1594                        } else {
1595                            Ok(Instruction::FENCEI)
1596                        }
1597                    }
1598                }
1599                x => Err(format!("unknown fence func3: {x}")),
1600            },
1601            Opcode::AMO => match (func3, func7 >> 2) {
1602                (0b010, 0b00010) => {
1603                    if rs2 != IRegister::Zero {
1604                        Err("LR.W expects rs2 to be 0".to_owned())
1605                    } else {
1606                        Ok(Instruction::LRW {
1607                            dest: rd,
1608                            addr: rs1,
1609                            aq,
1610                            rl,
1611                        })
1612                    }
1613                }
1614                (0b011, 0b00010) => {
1615                    if rs2 != IRegister::Zero {
1616                        Err("LR.D expects rs2 to be 0".to_owned())
1617                    } else {
1618                        Ok(Instruction::LRD {
1619                            dest: rd,
1620                            addr: rs1,
1621                            aq,
1622                            rl,
1623                        })
1624                    }
1625                }
1626                (0b010, 0b00011) => Ok(Instruction::SCW {
1627                    dest: rd,
1628                    addr: rs1,
1629                    src: rs2,
1630                    aq,
1631                    rl,
1632                }),
1633                (0b011, 0b00011) => Ok(Instruction::SCD {
1634                    dest: rd,
1635                    addr: rs1,
1636                    src: rs2,
1637                    aq,
1638                    rl,
1639                }),
1640                (0b010, 0b00001) => Ok(Instruction::AMOSWAPW {
1641                    dest: rd,
1642                    addr: rs1,
1643                    src: rs2,
1644                    aq,
1645                    rl,
1646                }),
1647                (0b011, 0b00001) => Ok(Instruction::AMOSWAPD {
1648                    dest: rd,
1649                    addr: rs1,
1650                    src: rs2,
1651                    aq,
1652                    rl,
1653                }),
1654                (0b010, 0b00000) => Ok(Instruction::AMOADDW {
1655                    dest: rd,
1656                    addr: rs1,
1657                    src: rs2,
1658                    aq,
1659                    rl,
1660                }),
1661                (0b011, 0b00000) => Ok(Instruction::AMOADDD {
1662                    dest: rd,
1663                    addr: rs1,
1664                    src: rs2,
1665                    aq,
1666                    rl,
1667                }),
1668                (0b010, 0b00100) => Ok(Instruction::AMOXORW {
1669                    dest: rd,
1670                    addr: rs1,
1671                    src: rs2,
1672                    aq,
1673                    rl,
1674                }),
1675                (0b011, 0b00100) => Ok(Instruction::AMOXORD {
1676                    dest: rd,
1677                    addr: rs1,
1678                    src: rs2,
1679                    aq,
1680                    rl,
1681                }),
1682                (0b010, 0b01100) => Ok(Instruction::AMOANDW {
1683                    dest: rd,
1684                    addr: rs1,
1685                    src: rs2,
1686                    aq,
1687                    rl,
1688                }),
1689                (0b011, 0b01100) => Ok(Instruction::AMOANDD {
1690                    dest: rd,
1691                    addr: rs1,
1692                    src: rs2,
1693                    aq,
1694                    rl,
1695                }),
1696                (0b010, 0b01000) => Ok(Instruction::AMOORW {
1697                    dest: rd,
1698                    addr: rs1,
1699                    src: rs2,
1700                    aq,
1701                    rl,
1702                }),
1703                (0b011, 0b01000) => Ok(Instruction::AMOORD {
1704                    dest: rd,
1705                    addr: rs1,
1706                    src: rs2,
1707                    aq,
1708                    rl,
1709                }),
1710                (0b010, 0b10000) => Ok(Instruction::AMOMINW {
1711                    dest: rd,
1712                    addr: rs1,
1713                    src: rs2,
1714                    aq,
1715                    rl,
1716                }),
1717                (0b011, 0b10000) => Ok(Instruction::AMOMIND {
1718                    dest: rd,
1719                    addr: rs1,
1720                    src: rs2,
1721                    aq,
1722                    rl,
1723                }),
1724                (0b010, 0b10100) => Ok(Instruction::AMOMAXW {
1725                    dest: rd,
1726                    addr: rs1,
1727                    src: rs2,
1728                    aq,
1729                    rl,
1730                }),
1731                (0b011, 0b10100) => Ok(Instruction::AMOMAXD {
1732                    dest: rd,
1733                    addr: rs1,
1734                    src: rs2,
1735                    aq,
1736                    rl,
1737                }),
1738                (0b010, 0b11000) => Ok(Instruction::AMOMINUW {
1739                    dest: rd,
1740                    addr: rs1,
1741                    src: rs2,
1742                    aq,
1743                    rl,
1744                }),
1745                (0b011, 0b11000) => Ok(Instruction::AMOMINUD {
1746                    dest: rd,
1747                    addr: rs1,
1748                    src: rs2,
1749                    aq,
1750                    rl,
1751                }),
1752                (0b010, 0b11100) => Ok(Instruction::AMOMAXUW {
1753                    dest: rd,
1754                    addr: rs1,
1755                    src: rs2,
1756                    aq,
1757                    rl,
1758                }),
1759                (0b011, 0b11100) => Ok(Instruction::AMOMAXUD {
1760                    dest: rd,
1761                    addr: rs1,
1762                    src: rs2,
1763                    aq,
1764                    rl,
1765                }),
1766                _ => Err(format!("unknown AMO. func3: {func3}, func7: {func7}")),
1767            },
1768            Opcode::LoadFp => {
1769                println!("{i_immediate}, {:b}", instruction);
1770                if func3 == 0b010 {
1771                    Ok(Instruction::FLW {
1772                        dest: frd,
1773                        base: rs1,
1774                        offset: i_immediate,
1775                    })
1776                } else {
1777                    Err(format!("unknown func3: {func3} in opcode LoadFp"))
1778                }
1779            }
1780            Opcode::StoreFp => {
1781                if func3 == 0b010 {
1782                    Ok(Instruction::FSW {
1783                        base: rs1,
1784                        src: frs2,
1785                        offset: s_immediate,
1786                    })
1787                } else {
1788                    Err(format!("unknown func3: {func3} in opcode LoadFp"))
1789                }
1790            }
1791            Opcode::OpFp => match func7 {
1792                0b000_0000 => Ok(Instruction::FADDS {
1793                    dest: frd,
1794                    src1: frs1,
1795                    src2: frs2,
1796                    rm: RoundingMode::from_int(func3)?,
1797                }),
1798                0b000_0100 => Ok(Instruction::FSUBS {
1799                    dest: frd,
1800                    src1: frs1,
1801                    src2: frs2,
1802                    rm: RoundingMode::from_int(func3)?,
1803                }),
1804                0b000_1000 => Ok(Instruction::FMULS {
1805                    dest: frd,
1806                    src1: frs1,
1807                    src2: frs2,
1808                    rm: RoundingMode::from_int(func3)?,
1809                }),
1810                0b000_1100 => Ok(Instruction::FDIVS {
1811                    dest: frd,
1812                    src1: frs1,
1813                    src2: frs2,
1814                    rm: RoundingMode::from_int(func3)?,
1815                }),
1816                0b010_1100 => Ok(Instruction::FSQRTS {
1817                    dest: frd,
1818                    src: frs1,
1819                    rm: RoundingMode::from_int(func3)?,
1820                }),
1821                0b001_0000 => match func3 {
1822                    0b000 => Ok(Instruction::FSGNJS {
1823                        dest: frd,
1824                        src1: frs1,
1825                        src2: frs2,
1826                    }),
1827                    0b001 => Ok(Instruction::FSGNJNS {
1828                        dest: frd,
1829                        src1: frs1,
1830                        src2: frs2,
1831                    }),
1832                    0b010 => Ok(Instruction::FSGNJXS {
1833                        dest: frd,
1834                        src1: frs1,
1835                        src2: frs2,
1836                    }),
1837                    x => Err(format!("unknown OpFp func7=0b001_0000 func3: {}", x)),
1838                },
1839                0b001_0100 => match func3 {
1840                    0b000 => Ok(Instruction::FMINS {
1841                        dest: frd,
1842                        src1: frs1,
1843                        src2: frs2,
1844                    }),
1845                    0b001 => Ok(Instruction::FMAXS {
1846                        dest: frd,
1847                        src1: frs1,
1848                        src2: frs2,
1849                    }),
1850                    x => Err(format!("unknown OpFp func7=0b001_0100 func3: {}", x)),
1851                },
1852                0b101_0000 => match func3 {
1853                    0b000 => Ok(Instruction::FLES {
1854                        dest: rd,
1855                        src1: frs1,
1856                        src2: frs2,
1857                    }),
1858                    0b001 => Ok(Instruction::FLTS {
1859                        dest: rd,
1860                        src1: frs1,
1861                        src2: frs2,
1862                    }),
1863                    0b010 => Ok(Instruction::FEQS {
1864                        dest: rd,
1865                        src1: frs1,
1866                        src2: frs2,
1867                    }),
1868                    x => Err(format!("unknown OpFp func7=0b101_0000 func3: {}", x)),
1869                },
1870                0b110_0000 => match (instruction >> 20) & 0b1_1111 {
1871                    0b0_0000 => Ok(Instruction::FCVTWS {
1872                        dest: rd,
1873                        src: frs1,
1874                        rm: RoundingMode::from_int(func3)?,
1875                    }),
1876                    0b0_0001 => Ok(Instruction::FCVTWUS {
1877                        dest: rd,
1878                        src: frs1,
1879                        rm: RoundingMode::from_int(func3)?,
1880                    }),
1881                    0b0_0010 => Ok(Instruction::FCVTLS {
1882                        dest: rd,
1883                        src: frs1,
1884                        rm: RoundingMode::from_int(func3)?,
1885                    }),
1886                    0b0_0011 => Ok(Instruction::FCVTLUS {
1887                        dest: rd,
1888                        src: frs1,
1889                        rm: RoundingMode::from_int(func3)?,
1890                    }),
1891                    x => Err(format!("unknown OpFp func7=0b001_0100 rs2: {}", x)),
1892                },
1893                0b110_1000 => match (instruction >> 20) & 0b1_1111 {
1894                    0b0_0000 => Ok(Instruction::FCVTSW {
1895                        dest: frd,
1896                        src: rs1,
1897                        rm: RoundingMode::from_int(func3)?,
1898                    }),
1899                    0b0_0001 => Ok(Instruction::FCVTSWU {
1900                        dest: frd,
1901                        src: rs1,
1902                        rm: RoundingMode::from_int(func3)?,
1903                    }),
1904                    0b0_0010 => Ok(Instruction::FCVTSL {
1905                        dest: frd,
1906                        src: rs1,
1907                        rm: RoundingMode::from_int(func3)?,
1908                    }),
1909                    0b0_0011 => Ok(Instruction::FCVTSLU {
1910                        dest: frd,
1911                        src: rs1,
1912                        rm: RoundingMode::from_int(func3)?,
1913                    }),
1914                    x => Err(format!("unknown OpFp func7=0b001_0100 rs2: {}", x)),
1915                },
1916                0b111_0000 => {
1917                    if (instruction >> 20) & 0b1_1111 == 0 {
1918                        if func3 == 0 {
1919                            Ok(Instruction::FMVXW {
1920                                dest: rd,
1921                                src: frs1,
1922                            })
1923                        } else if func3 == 1 {
1924                            Ok(Instruction::FCLASSS {
1925                                dest: rd,
1926                                src: frs1,
1927                            })
1928                        } else {
1929                            Err(format!(
1930                                "unknown OpFp func7=0b111_0000 rs2=0 func3: {}",
1931                                func3
1932                            ))
1933                        }
1934                    } else {
1935                        Err(format!(
1936                            "unknown OpFp func7=0b111_0000 unknown rs2: {} and func3: {}",
1937                            (instruction >> 20) & 0b1_1111,
1938                            func3
1939                        ))
1940                    }
1941                }
1942                0b111_1000 => {
1943                    if (instruction >> 20) & 0b1_1111 == 0 {
1944                        if func3 == 0 {
1945                            Ok(Instruction::FMVWX {
1946                                dest: frd,
1947                                src: rs1,
1948                            })
1949                        } else {
1950                            Err(format!(
1951                                "unknown OpFp func7=0b111_1000 rs2=0 func3: {}",
1952                                func3
1953                            ))
1954                        }
1955                    } else {
1956                        Err(format!(
1957                            "unknown OpFp func7=0b111_0000 unknown rs2: {} and func3: {}",
1958                            (instruction >> 20) & 0b1_1111,
1959                            func3
1960                        ))
1961                    }
1962                }
1963                x => Err(format!("Unknown OpFp func7: {x}")),
1964            },
1965            Opcode::Reserved => Err("instruction uses reserved opcode".to_owned()),
1966            Opcode::Madd => {
1967                if func7 & 0b11 == 0 {
1968                    Ok(Instruction::FMADDS {
1969                        dest: frd,
1970                        src1: frs1,
1971                        src2: frs2,
1972                        src3: frs3,
1973                        rm: RoundingMode::from_int(func3)?,
1974                    })
1975                } else {
1976                    Err(format!(
1977                        "FMADD unknown lower 2 bits of func7: {}",
1978                        func7 & 0b11
1979                    ))
1980                }
1981            }
1982            Opcode::Msub => {
1983                if func7 & 0b11 == 0 {
1984                    Ok(Instruction::FMSUBS {
1985                        dest: frd,
1986                        src1: frs1,
1987                        src2: frs2,
1988                        src3: frs3,
1989                        rm: RoundingMode::from_int(func3)?,
1990                    })
1991                } else {
1992                    Err(format!(
1993                        "FMSUB unknown lower 2 bits of func7: {}",
1994                        func7 & 0b11
1995                    ))
1996                }
1997            }
1998            Opcode::Nmsub => {
1999                if func7 & 0b11 == 0 {
2000                    Ok(Instruction::FNMSUBS {
2001                        dest: frd,
2002                        src1: frs1,
2003                        src2: frs2,
2004                        src3: frs3,
2005                        rm: RoundingMode::from_int(func3)?,
2006                    })
2007                } else {
2008                    Err(format!(
2009                        "FMNSUB unknown lower 2 bits of func7: {}",
2010                        func7 & 0b11
2011                    ))
2012                }
2013            }
2014            Opcode::Nmadd => {
2015                if func7 & 0b11 == 0 {
2016                    Ok(Instruction::FNMADDS {
2017                        dest: frd,
2018                        src1: frs1,
2019                        src2: frs2,
2020                        src3: frs3,
2021                        rm: RoundingMode::from_int(func3)?,
2022                    })
2023                } else {
2024                    Err(format!(
2025                        "FNMADD unknown lower 2 bits of func7: {}",
2026                        func7 & 0b11
2027                    ))
2028                }
2029            }
2030            Opcode::System => match func3 {
2031                0b000 => Err("Reserved func3 in Opcode SYSTEM".to_owned()),
2032                0b001 => Ok(Instruction::CSRRW {
2033                    dest: rd,
2034                    src: rs1,
2035                    csr: CSR::from_u32(instruction),
2036                }),
2037                0b010 => Ok(Instruction::CSRRS {
2038                    dest: rd,
2039                    src: rs1,
2040                    csr: CSR::from_u32(instruction),
2041                }),
2042                0b011 => Ok(Instruction::CSRRC {
2043                    dest: rd,
2044                    src: rs1,
2045                    csr: CSR::from_u32(instruction),
2046                }),
2047                0b100 => Err("Reserved func3 in Opcode SYSTEM".to_owned()),
2048                0b101 => Ok(Instruction::CSRRWI {
2049                    dest: rd,
2050                    imm: CSRImmediate::from_u32(instruction),
2051                    csr: CSR::from_u32(instruction),
2052                }),
2053                0b110 => Ok(Instruction::CSRRSI {
2054                    dest: rd,
2055                    imm: CSRImmediate::from_u32(instruction),
2056                    csr: CSR::from_u32(instruction),
2057                }),
2058                0b111 => Ok(Instruction::CSRRCI {
2059                    dest: rd,
2060                    imm: CSRImmediate::from_u32(instruction),
2061                    csr: CSR::from_u32(instruction),
2062                }),
2063                _ => unreachable!(),
2064            },
2065        }
2066    }
2067
2068    pub fn encode(instruction: &Instruction) -> u32 {
2069        match instruction {
2070            Instruction::LUI { dest, imm } => imm.to_u32() | dest.rd() | 0b0110111,
2071            Instruction::AUIPC { dest, imm } => imm.to_u32() | dest.rd() | 0b0010111,
2072            Instruction::JAL { dest, offset } => offset.to_u32() | dest.rd() | 0b1101111,
2073            Instruction::JALR { dest, base, offset } => {
2074                offset.to_u32() | base.rs1() | dest.rd() | 0b1100111
2075            }
2076            Instruction::BEQ { src1, src2, offset } => {
2077                offset.to_u32() | src2.rs2() | src1.rs1() | 0b000 << 12 | 0b1100011
2078            }
2079            Instruction::BNE { src1, src2, offset } => {
2080                offset.to_u32() | src2.rs2() | src1.rs1() | 0b001 << 12 | 0b1100011
2081            }
2082            Instruction::BLT { src1, src2, offset } => {
2083                offset.to_u32() | src2.rs2() | src1.rs1() | 0b100 << 12 | 0b1100011
2084            }
2085            Instruction::BGE { src1, src2, offset } => {
2086                offset.to_u32() | src2.rs2() | src1.rs1() | 0b101 << 12 | 0b1100011
2087            }
2088            Instruction::BLTU { src1, src2, offset } => {
2089                offset.to_u32() | src2.rs2() | src1.rs1() | 0b110 << 12 | 0b1100011
2090            }
2091            Instruction::BGEU { src1, src2, offset } => {
2092                offset.to_u32() | src2.rs2() | src1.rs1() | 0b111 << 12 | 0b1100011
2093            }
2094            Instruction::LB { dest, base, offset } => {
2095                offset.to_u32() | base.rs1() | 0b000 << 12 | dest.rd() | 0b0000011
2096            }
2097            Instruction::LH { dest, base, offset } => {
2098                offset.to_u32() | base.rs1() | 0b001 << 12 | dest.rd() | 0b0000011
2099            }
2100            Instruction::LW { dest, base, offset } => {
2101                offset.to_u32() | base.rs1() | 0b010 << 12 | dest.rd() | 0b0000011
2102            }
2103            Instruction::LBU { dest, base, offset } => {
2104                offset.to_u32() | base.rs1() | 0b100 << 12 | dest.rd() | 0b0000011
2105            }
2106            Instruction::LHU { dest, base, offset } => {
2107                offset.to_u32() | base.rs1() | 0b101 << 12 | dest.rd() | 0b0000011
2108            }
2109            Instruction::SB { src, base, offset } => {
2110                offset.to_u32() | src.rs2() | base.rs1() | 0b000 << 12 | 0b0100011
2111            }
2112            Instruction::SH { src, base, offset } => {
2113                offset.to_u32() | src.rs2() | base.rs1() | 0b001 << 12 | 0b0100011
2114            }
2115            Instruction::SW { src, base, offset } => {
2116                offset.to_u32() | src.rs2() | base.rs1() | 0b010 << 12 | 0b0100011
2117            }
2118            Instruction::ADDI { dest, src, imm } => {
2119                imm.to_u32() | src.rs1() | 0b000 << 12 | dest.rd() | 0b0010011
2120            }
2121            Instruction::SLTI { dest, src, imm } => {
2122                imm.to_u32() | src.rs1() | 0b010 << 12 | dest.rd() | 0b0010011
2123            }
2124            Instruction::SLTIU { dest, src, imm } => {
2125                imm.to_u32() | src.rs1() | 0b011 << 12 | dest.rd() | 0b0010011
2126            }
2127            Instruction::XORI { dest, src, imm } => {
2128                imm.to_u32() | src.rs1() | 0b100 << 12 | dest.rd() | 0b0010011
2129            }
2130            Instruction::ORI { dest, src, imm } => {
2131                imm.to_u32() | src.rs1() | 0b110 << 12 | dest.rd() | 0b0010011
2132            }
2133            Instruction::ANDI { dest, src, imm } => {
2134                imm.to_u32() | src.rs1() | 0b111 << 12 | dest.rd() | 0b0010011
2135            }
2136            Instruction::SLLI { dest, src, shamt } => {
2137                shamt.to_u32() | src.rs1() | 0b001 << 12 | dest.rd() | 0b0010011
2138            }
2139            Instruction::SRLI { dest, src, shamt } => {
2140                shamt.to_u32() | src.rs1() | 0b101 << 12 | dest.rd() | 0b0010011
2141            }
2142            Instruction::SRAI { dest, src, shamt } => {
2143                0b0100000 << 25 | shamt.to_u32() | src.rs1() | 0b101 << 12 | dest.rd() | 0b0010011
2144            }
2145            Instruction::ADD { dest, src1, src2 } => {
2146                src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b0110011
2147            }
2148            Instruction::SUB { dest, src1, src2 } => {
2149                0b0100000 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b0110011
2150            }
2151            Instruction::SLL { dest, src1, src2 } => {
2152                src2.rs2() | src1.rs1() | 0b001 << 12 | dest.rd() | 0b0110011
2153            }
2154            Instruction::SLT { dest, src1, src2 } => {
2155                src2.rs2() | src1.rs1() | 0b010 << 12 | dest.rd() | 0b0110011
2156            }
2157            Instruction::SLTU { dest, src1, src2 } => {
2158                src2.rs2() | src1.rs1() | 0b011 << 12 | dest.rd() | 0b0110011
2159            }
2160            Instruction::XOR { dest, src1, src2 } => {
2161                src2.rs2() | src1.rs1() | 0b100 << 12 | dest.rd() | 0b0110011
2162            }
2163            Instruction::SRL { dest, src1, src2 } => {
2164                src2.rs2() | src1.rs1() | 0b101 << 12 | dest.rd() | 0b0110011
2165            }
2166            Instruction::SRA { dest, src1, src2 } => {
2167                0b0100000 << 25 | src2.rs2() | src1.rs1() | 0b0101 << 12 | dest.rd() | 0b0110011
2168            }
2169            Instruction::OR { dest, src1, src2 } => {
2170                src2.rs2() | src1.rs1() | 0b110 << 12 | dest.rd() | 0b0110011
2171            }
2172            Instruction::AND { dest, src1, src2 } => {
2173                src2.rs2() | src1.rs1() | 0b111 << 12 | dest.rd() | 0b0110011
2174            }
2175            Instruction::FENCE { rd, rs1, ops, fm } => {
2176                (*fm as u32) << 28 | (*ops as u32) << 20 | rs1.rs1() | rd.rd() | 0b0001111
2177            }
2178            Instruction::ECALL => 0b1110011,
2179            Instruction::EBREAK => 0b1 << 20 | 0b1110011,
2180            Instruction::LWU { dest, base, offset } => {
2181                offset.to_u32() | base.rs1() | 0b110 << 12 | dest.rd() | 0b0000011
2182            }
2183            Instruction::LD { dest, base, offset } => {
2184                offset.to_u32() | base.rs1() | 0b011 << 12 | dest.rd() | 0b0000011
2185            }
2186            Instruction::SD { src, base, offset } => {
2187                offset.to_u32() | src.rs2() | base.rs1() | 0b011 << 12 | 0b0100011
2188            }
2189            Instruction::ADDIW { dest, src, imm } => {
2190                imm.to_u32() | src.rs1() | 0b000 << 12 | dest.rd() | 0b0011011
2191            }
2192            Instruction::SLLIW { dest, src, shamt } => {
2193                shamt.to_u32() | src.rs1() | 0b001 << 12 | dest.rd() | 0b0011011
2194            }
2195            Instruction::SRLIW { dest, src, shamt } => {
2196                shamt.to_u32() | src.rs1() | 0b101 << 12 | dest.rd() | 0b0011011
2197            }
2198            Instruction::SRAIW { dest, src, shamt } => {
2199                0b0100000 << 25 | shamt.to_u32() | src.rs1() | 0b101 << 12 | dest.rd() | 0b0011011
2200            }
2201            Instruction::ADDW { dest, src1, src2 } => {
2202                src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b0111011
2203            }
2204            Instruction::SUBW { dest, src1, src2 } => {
2205                0b0100000 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b0111011
2206            }
2207            Instruction::SLLW { dest, src1, src2 } => {
2208                src2.rs2() | src1.rs1() | 0b001 << 12 | dest.rd() | 0b0111011
2209            }
2210            Instruction::SRLW { dest, src1, src2 } => {
2211                src2.rs2() | src1.rs1() | 0b101 << 12 | dest.rd() | 0b0111011
2212            }
2213            Instruction::SRAW { dest, src1, src2 } => {
2214                0b0100000 << 25 | src2.rs2() | src1.rs1() | 0b101 << 12 | dest.rd() | 0b0111011
2215            }
2216            Instruction::MUL { dest, src1, src2 } => {
2217                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b0110011
2218            }
2219            Instruction::MULH { dest, src1, src2 } => {
2220                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b001 << 12 | dest.rd() | 0b0110011
2221            }
2222            Instruction::MULHSU { dest, src1, src2 } => {
2223                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b010 << 12 | dest.rd() | 0b0110011
2224            }
2225            Instruction::MULHU { dest, src1, src2 } => {
2226                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b011 << 12 | dest.rd() | 0b0110011
2227            }
2228            Instruction::DIV { dest, src1, src2 } => {
2229                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b100 << 12 | dest.rd() | 0b0110011
2230            }
2231            Instruction::DIVU { dest, src1, src2 } => {
2232                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b101 << 12 | dest.rd() | 0b0110011
2233            }
2234            Instruction::REM { dest, src1, src2 } => {
2235                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b110 << 12 | dest.rd() | 0b0110011
2236            }
2237            Instruction::REMU { dest, src1, src2 } => {
2238                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b111 << 12 | dest.rd() | 0b0110011
2239            }
2240            Instruction::MULW { dest, src1, src2 } => {
2241                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b0111011
2242            }
2243            Instruction::DIVW { dest, src1, src2 } => {
2244                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b100 << 12 | dest.rd() | 0b0111011
2245            }
2246            Instruction::DIVUW { dest, src1, src2 } => {
2247                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b101 << 12 | dest.rd() | 0b0111011
2248            }
2249            Instruction::REMW { dest, src1, src2 } => {
2250                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b110 << 12 | dest.rd() | 0b0111011
2251            }
2252            Instruction::REMUW { dest, src1, src2 } => {
2253                0b0000001 << 25 | src2.rs2() | src1.rs1() | 0b111 << 12 | dest.rd() | 0b0111011
2254            }
2255            Instruction::LRW { dest, addr, aq, rl } => {
2256                0b00010 << 27
2257                    | aqb(*aq)
2258                    | rlb(*rl)
2259                    | addr.rs1()
2260                    | 0b010 << 12
2261                    | dest.rd()
2262                    | 0b0101111
2263            }
2264            Instruction::SCW {
2265                dest,
2266                addr,
2267                src,
2268                aq,
2269                rl,
2270            } => {
2271                0b00011 << 27
2272                    | aqb(*aq)
2273                    | rlb(*rl)
2274                    | src.rs2()
2275                    | addr.rs1()
2276                    | 0b010 << 12
2277                    | dest.rd()
2278                    | 0b0101111
2279            }
2280            Instruction::AMOSWAPW {
2281                dest,
2282                addr,
2283                src,
2284                aq,
2285                rl,
2286            } => {
2287                0b00001 << 27
2288                    | aqb(*aq)
2289                    | rlb(*rl)
2290                    | src.rs2()
2291                    | addr.rs1()
2292                    | 0b010 << 12
2293                    | dest.rd()
2294                    | 0b0101111
2295            }
2296            Instruction::AMOADDW {
2297                dest,
2298                addr,
2299                src,
2300                aq,
2301                rl,
2302            } => {
2303                0b00000 << 27
2304                    | aqb(*aq)
2305                    | rlb(*rl)
2306                    | src.rs2()
2307                    | addr.rs1()
2308                    | 0b010 << 12
2309                    | dest.rd()
2310                    | 0b0101111
2311            }
2312            Instruction::AMOXORW {
2313                dest,
2314                addr,
2315                src,
2316                aq,
2317                rl,
2318            } => {
2319                0b00100 << 27
2320                    | aqb(*aq)
2321                    | rlb(*rl)
2322                    | src.rs2()
2323                    | addr.rs1()
2324                    | 0b010 << 12
2325                    | dest.rd()
2326                    | 0b0101111
2327            }
2328            Instruction::AMOANDW {
2329                dest,
2330                addr,
2331                src,
2332                aq,
2333                rl,
2334            } => {
2335                0b01100 << 27
2336                    | aqb(*aq)
2337                    | rlb(*rl)
2338                    | src.rs2()
2339                    | addr.rs1()
2340                    | 0b010 << 12
2341                    | dest.rd()
2342                    | 0b0101111
2343            }
2344            Instruction::AMOORW {
2345                dest,
2346                addr,
2347                src,
2348                aq,
2349                rl,
2350            } => {
2351                0b01000 << 27
2352                    | aqb(*aq)
2353                    | rlb(*rl)
2354                    | src.rs2()
2355                    | addr.rs1()
2356                    | 0b010 << 12
2357                    | dest.rd()
2358                    | 0b0101111
2359            }
2360            Instruction::AMOMINW {
2361                dest,
2362                addr,
2363                src,
2364                aq,
2365                rl,
2366            } => {
2367                0b10000 << 27
2368                    | aqb(*aq)
2369                    | rlb(*rl)
2370                    | src.rs2()
2371                    | addr.rs1()
2372                    | 0b010 << 12
2373                    | dest.rd()
2374                    | 0b0101111
2375            }
2376            Instruction::AMOMAXW {
2377                dest,
2378                addr,
2379                src,
2380                aq,
2381                rl,
2382            } => {
2383                0b10100 << 27
2384                    | aqb(*aq)
2385                    | rlb(*rl)
2386                    | src.rs2()
2387                    | addr.rs1()
2388                    | 0b010 << 12
2389                    | dest.rd()
2390                    | 0b0101111
2391            }
2392            Instruction::AMOMINUW {
2393                dest,
2394                addr,
2395                src,
2396                aq,
2397                rl,
2398            } => {
2399                0b11000 << 27
2400                    | aqb(*aq)
2401                    | rlb(*rl)
2402                    | src.rs2()
2403                    | addr.rs1()
2404                    | 0b010 << 12
2405                    | dest.rd()
2406                    | 0b0101111
2407            }
2408            Instruction::AMOMAXUW {
2409                dest,
2410                addr,
2411                src,
2412                aq,
2413                rl,
2414            } => {
2415                0b11100 << 27
2416                    | aqb(*aq)
2417                    | rlb(*rl)
2418                    | src.rs2()
2419                    | addr.rs1()
2420                    | 0b010 << 12
2421                    | dest.rd()
2422                    | 0b0101111
2423            }
2424            Instruction::LRD { dest, addr, aq, rl } => {
2425                0b00010 << 27
2426                    | aqb(*aq)
2427                    | rlb(*rl)
2428                    | addr.rs1()
2429                    | 0b011 << 12
2430                    | dest.rd()
2431                    | 0b0101111
2432            }
2433            Instruction::SCD {
2434                dest,
2435                addr,
2436                src,
2437                aq,
2438                rl,
2439            } => {
2440                0b00011 << 27
2441                    | aqb(*aq)
2442                    | rlb(*rl)
2443                    | src.rs2()
2444                    | addr.rs1()
2445                    | 0b011 << 12
2446                    | dest.rd()
2447                    | 0b0101111
2448            }
2449            Instruction::AMOSWAPD {
2450                dest,
2451                addr,
2452                src,
2453                aq,
2454                rl,
2455            } => {
2456                0b00001 << 27
2457                    | aqb(*aq)
2458                    | rlb(*rl)
2459                    | src.rs2()
2460                    | addr.rs1()
2461                    | 0b011 << 12
2462                    | dest.rd()
2463                    | 0b0101111
2464            }
2465            Instruction::AMOADDD {
2466                dest,
2467                addr,
2468                src,
2469                aq,
2470                rl,
2471            } => {
2472                0b00000 << 27
2473                    | aqb(*aq)
2474                    | rlb(*rl)
2475                    | src.rs2()
2476                    | addr.rs1()
2477                    | 0b011 << 12
2478                    | dest.rd()
2479                    | 0b0101111
2480            }
2481            Instruction::AMOXORD {
2482                dest,
2483                addr,
2484                src,
2485                aq,
2486                rl,
2487            } => {
2488                0b00100 << 27
2489                    | aqb(*aq)
2490                    | rlb(*rl)
2491                    | src.rs2()
2492                    | addr.rs1()
2493                    | 0b011 << 12
2494                    | dest.rd()
2495                    | 0b0101111
2496            }
2497            Instruction::AMOANDD {
2498                dest,
2499                addr,
2500                src,
2501                aq,
2502                rl,
2503            } => {
2504                0b01100 << 27
2505                    | aqb(*aq)
2506                    | rlb(*rl)
2507                    | src.rs2()
2508                    | addr.rs1()
2509                    | 0b011 << 12
2510                    | dest.rd()
2511                    | 0b0101111
2512            }
2513            Instruction::AMOORD {
2514                dest,
2515                addr,
2516                src,
2517                aq,
2518                rl,
2519            } => {
2520                0b01000 << 27
2521                    | aqb(*aq)
2522                    | rlb(*rl)
2523                    | src.rs2()
2524                    | addr.rs1()
2525                    | 0b011 << 12
2526                    | dest.rd()
2527                    | 0b0101111
2528            }
2529            Instruction::AMOMIND {
2530                dest,
2531                addr,
2532                src,
2533                aq,
2534                rl,
2535            } => {
2536                0b10000 << 27
2537                    | aqb(*aq)
2538                    | rlb(*rl)
2539                    | src.rs2()
2540                    | addr.rs1()
2541                    | 0b011 << 12
2542                    | dest.rd()
2543                    | 0b0101111
2544            }
2545            Instruction::AMOMAXD {
2546                dest,
2547                addr,
2548                src,
2549                aq,
2550                rl,
2551            } => {
2552                0b10100 << 27
2553                    | aqb(*aq)
2554                    | rlb(*rl)
2555                    | src.rs2()
2556                    | addr.rs1()
2557                    | 0b011 << 12
2558                    | dest.rd()
2559                    | 0b0101111
2560            }
2561            Instruction::AMOMINUD {
2562                dest,
2563                addr,
2564                src,
2565                aq,
2566                rl,
2567            } => {
2568                0b11000 << 27
2569                    | aqb(*aq)
2570                    | rlb(*rl)
2571                    | src.rs2()
2572                    | addr.rs1()
2573                    | 0b011 << 12
2574                    | dest.rd()
2575                    | 0b0101111
2576            }
2577            Instruction::AMOMAXUD {
2578                dest,
2579                addr,
2580                src,
2581                aq,
2582                rl,
2583            } => {
2584                0b11100 << 27
2585                    | aqb(*aq)
2586                    | rlb(*rl)
2587                    | src.rs2()
2588                    | addr.rs1()
2589                    | 0b011 << 12
2590                    | dest.rd()
2591                    | 0b0101111
2592            }
2593            Instruction::FLW { dest, base, offset } => {
2594                offset.to_u32() | base.rs1() | 0b010 << 12 | dest.rd() | 0b0000111
2595            }
2596            Instruction::FSW { base, src, offset } => {
2597                offset.to_u32() | src.rs2() | base.rs1() | 0b010 << 12 | 0b0100111
2598            }
2599            Instruction::FMADDS {
2600                dest,
2601                src1,
2602                src2,
2603                src3,
2604                rm,
2605            } => src3.rs3() | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1000011,
2606            Instruction::FMSUBS {
2607                dest,
2608                src1,
2609                src2,
2610                src3,
2611                rm,
2612            } => src3.rs3() | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1000111,
2613            Instruction::FNMSUBS {
2614                dest,
2615                src1,
2616                src2,
2617                src3,
2618                rm,
2619            } => src3.rs3() | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1001011,
2620            Instruction::FNMADDS {
2621                dest,
2622                src1,
2623                src2,
2624                src3,
2625                rm,
2626            } => src3.rs3() | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1001111,
2627            Instruction::FADDS {
2628                dest,
2629                src1,
2630                src2,
2631                rm,
2632            } => 0b0000000 << 25 | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011,
2633            Instruction::FSUBS {
2634                dest,
2635                src1,
2636                src2,
2637                rm,
2638            } => 0b0000100 << 25 | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011,
2639            Instruction::FMULS {
2640                dest,
2641                src1,
2642                src2,
2643                rm,
2644            } => 0b0001000 << 25 | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011,
2645            Instruction::FDIVS {
2646                dest,
2647                src1,
2648                src2,
2649                rm,
2650            } => 0b0001100 << 25 | src2.rs2() | src1.rs1() | rm.to_u32() | dest.rd() | 0b1010011,
2651            Instruction::FSQRTS { dest, src, rm } => {
2652                0b0101100 << 25 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
2653            }
2654            Instruction::FSGNJS { dest, src1, src2 } => {
2655                0b0010000 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b1010011
2656            }
2657
2658            Instruction::FSGNJNS { dest, src1, src2 } => {
2659                0b0010000 << 25 | src2.rs2() | src1.rs1() | 0b001 << 12 | dest.rd() | 0b1010011
2660            }
2661            Instruction::FSGNJXS { dest, src1, src2 } => {
2662                0b0010000 << 25 | src2.rs2() | src1.rs1() | 0b010 << 12 | dest.rd() | 0b1010011
2663            }
2664            Instruction::FMINS { dest, src1, src2 } => {
2665                0b0010100 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b1010011
2666            }
2667            Instruction::FMAXS { dest, src1, src2 } => {
2668                0b0010100 << 25 | src2.rs2() | src1.rs1() | 0b001 << 12 | dest.rd() | 0b1010011
2669            }
2670            Instruction::FCVTWS { dest, src, rm } => {
2671                0b1100000 << 25 | 0b00000 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
2672            }
2673            Instruction::FCVTWUS { dest, src, rm } => {
2674                0b1100000 << 25 | 0b00001 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
2675            }
2676            Instruction::FMVXW { dest, src } => 0b1110000 << 25 | src.rs1() | dest.rd() | 0b1010011,
2677            Instruction::FEQS { dest, src1, src2 } => {
2678                0b1010000 << 25 | src2.rs2() | src1.rs1() | 0b010 << 12 | dest.rd() | 0b1010011
2679            }
2680            Instruction::FLTS { dest, src1, src2 } => {
2681                0b1010000 << 25 | src2.rs2() | src1.rs1() | 0b001 << 12 | dest.rd() | 0b1010011
2682            }
2683            Instruction::FLES { dest, src1, src2 } => {
2684                0b1010000 << 25 | src2.rs2() | src1.rs1() | 0b000 << 12 | dest.rd() | 0b1010011
2685            }
2686            Instruction::FCLASSS { dest, src } => {
2687                0b1110000 << 25 | src.rs1() | 0b001 << 12 | dest.rd() | 0b1010011
2688            }
2689            Instruction::FCVTSW { dest, src, rm } => {
2690                0b1101000 << 25 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
2691            }
2692            Instruction::FCVTSWU { dest, src, rm } => {
2693                0b1101000 << 25 | 0b00001 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
2694            }
2695            Instruction::FMVWX { dest, src } => 0b1111000 << 25 | src.rs1() | dest.rd() | 0b1010011,
2696            Instruction::FCVTLS { dest, src, rm } => {
2697                0b1100000 << 25 | 0b00010 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
2698            }
2699            Instruction::FCVTLUS { dest, src, rm } => {
2700                0b1100000 << 25 | 0b00011 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
2701            }
2702            Instruction::FCVTSL { dest, src, rm } => {
2703                0b1101000 << 25 | 0b00010 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
2704            }
2705            Instruction::FCVTSLU { dest, src, rm } => {
2706                0b1101000 << 25 | 0b00011 << 20 | src.rs1() | rm.to_u32() | dest.rd() | 0b1010011
2707            }
2708            Instruction::CSRRW { dest, src, csr } => {
2709                csr.to_u32() | src.rs1() | 0b001 << 12 | dest.rd() | 0b1110011
2710            }
2711            Instruction::CSRRS { dest, src, csr } => {
2712                csr.to_u32() | src.rs1() | 0b010 << 12 | dest.rd() | 0b1110011
2713            }
2714            Instruction::CSRRC { dest, src, csr } => {
2715                csr.to_u32() | src.rs1() | 0b011 << 12 | dest.rd() | 0b1110011
2716            }
2717            Instruction::CSRRWI { dest, imm, csr } => {
2718                csr.to_u32() | imm.to_u32() | 0b101 << 12 | dest.rd() | 0b1110011
2719            }
2720            Instruction::CSRRSI { dest, imm, csr } => {
2721                csr.to_u32() | imm.to_u32() | 0b110 << 12 | dest.rd() | 0b1110011
2722            }
2723            Instruction::CSRRCI { dest, imm, csr } => {
2724                csr.to_u32() | imm.to_u32() | 0b111 << 12 | dest.rd() | 0b1110011
2725            }
2726            Instruction::FENCEI => 0b001 << 12 | 0b0001111,
2727        }
2728    }
2729}
2730
2731/// Disassembles an instruction.
2732pub fn disassemble_instruction(instruction: &Instruction) -> String {
2733    format!("{}", instruction)
2734}