mipsasm_rsp/
ast.rs

1use alloc::{
2    format,
3    string::{String, ToString},
4};
5use core::convert::{From, TryFrom};
6use core::fmt;
7use core::str::FromStr;
8use strum_macros::{Display, EnumString};
9
10#[derive(Debug)]
11pub enum RegParseError {
12    RegParseError(String),
13}
14
15#[derive(Debug, PartialEq, Eq)]
16pub struct Target(pub u32);
17
18#[derive(Debug, PartialEq, Eq)]
19pub struct Immediate(pub u16);
20
21struct Signed(u16);
22// Format an i16 as a sign-aware hex string
23// https://stackoverflow.com/a/44712309
24impl fmt::LowerHex for Signed {
25    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
26        let val = self.0 as i16;
27        let p = if f.alternate() { "0x" } else { "" };
28        let x = format!("{:x}", val.abs());
29        f.pad_integral(val >= 0, p, &x)
30    }
31}
32
33#[derive(PartialEq, Eq)]
34pub enum Instruction {
35    Immediate {
36        op: ITypeOp,
37        rs: Register,
38        rt: Register,
39        imm: Immediate,
40    },
41    Jump {
42        op: JTypeOp,
43        target: Target,
44    },
45    Register {
46        op: RTypeOp,
47        rs: Register,
48        rt: Register,
49        rd: Register,
50        sa: u32,
51    },
52}
53
54type I = ITypeOp;
55type R = RTypeOp;
56
57impl fmt::Display for Instruction {
58    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
59        match &self {
60            Instruction::Immediate {
61                op,
62                rs,
63                rt,
64                imm: Immediate(imm),
65            } => match op {
66                I::Lb
67                | I::Lbu
68                | I::Ld
69                | I::Ldl
70                | I::Ldr
71                | I::Lh
72                | I::Lhu
73                | I::Ll
74                | I::Lld
75                | I::Lw
76                | I::Lwl
77                | I::Lwr
78                | I::Lwu
79                | I::Sb
80                | I::Sc
81                | I::Scd
82                | I::Sd
83                | I::Sdl
84                | I::Sdr
85                | I::Sh
86                | I::Sw
87                | I::Swl
88                | I::Swr => {
89                    write!(f, "{:7} {}, {:#x}({})", op, rt, Signed(*imm), rs)
90                }
91                I::Lbv => {
92                    write!(
93                        f,
94                        "{:7} {}[{}], {:#x}({})",
95                        op,
96                        rt,
97                        *imm >> 7,
98                        *imm & 0b1111111,
99                        rs
100                    )
101                }
102                I::Cache => {
103                    write!(
104                        f,
105                        "{:7} {:#x}, {:#x}({})",
106                        op,
107                        rt.as_num(),
108                        Signed(*imm),
109                        rs
110                    )
111                }
112                I::Addi | I::Addiu | I::Daddi | I::Daddiu | I::Slti | I::Sltiu => {
113                    write!(f, "{:7} {}, {}, {:#x}", op, rt, rs, Signed(*imm))
114                }
115                I::Andi | I::Ori | I::Xori => write!(f, "{:7} {}, {}, {:#x}", op, rt, rs, imm),
116                I::Lui => write!(f, "{:7} {}, {:#x}", op, rt, imm),
117                I::Beqz | I::Bgtz | I::Bgtzl | I::Blez | I::Blezl | I::Bnez => {
118                    write!(f, "{:7} {}, {:#x}", op, rs, Signed(*imm))
119                }
120                I::Beq | I::Beql | I::Bne | I::Bnel => {
121                    write!(f, "{:7} {}, {}, {:#x}", op, rs, rt, Signed(*imm))
122                }
123                I::Bgez
124                | I::Bgezal
125                | I::Bgezall
126                | I::Bgezl
127                | I::Bltz
128                | I::Bltzal
129                | I::Bltzall
130                | I::Bltzl
131                | I::Teqi
132                | I::Tgei
133                | I::Tgeiu
134                | I::Tlti
135                | I::Tltiu
136                | I::Tnei => {
137                    write!(f, "{:7} {}, {:#x}", op, rs, Signed(*imm))
138                }
139                I::Bc0f
140                | I::Bc1f
141                | I::Bc0fl
142                | I::Bc1fl
143                | I::Bc0t
144                | I::Bc1t
145                | I::Bc0tl
146                | I::Bc1tl => {
147                    write!(f, "{:7}{:#x}", op, Signed(*imm))
148                }
149                I::Ldc1 | I::Lwc1 | I::Sdc1 | I::Swc1 => {
150                    write!(
151                        f,
152                        "{:7} {}, {:#x}({})",
153                        op,
154                        FloatRegister::from(*rt),
155                        Signed(*imm),
156                        rs
157                    )
158                }
159                e => panic!("Unhandled immediate instruction: {:?}", e),
160            },
161            Instruction::Jump {
162                op,
163                target: Target(target),
164            } => {
165                write!(f, "{:7}{:#X?}", op, target)
166            }
167            Instruction::Register { op, rs, rt, rd, sa } => match op {
168                R::Sync => write!(f, "{}", op),
169                R::Add
170                | R::Addu
171                | R::And
172                | R::Dadd
173                | R::Daddu
174                | R::Dsub
175                | R::Dsubu
176                | R::Nor
177                | R::Or
178                | R::Slt
179                | R::Sltu
180                | R::Sub
181                | R::Subu
182                | R::Xor => {
183                    write!(f, "{:7} {}, {}, {}", op, rd, rs, rt)
184                }
185                R::Dsll
186                | R::Dsll32
187                | R::Dsra
188                | R::Dsra32
189                | R::Dsrl
190                | R::Dsrl32
191                | R::Sll
192                | R::Sra
193                | R::Srl => {
194                    write!(f, "{:7} {}, {}, {:#x?}", op, rd, rt, sa)
195                }
196                R::Dsllv | R::Dsrav | R::Dsrlv | R::Sllv | R::Srav | R::Srlv => {
197                    write!(f, "{:7} {}, {}, {}", op, rd, rt, rs)
198                }
199                R::Break | R::Syscall => {
200                    if *sa == 0 {
201                        write!(f, "{}", op)
202                    } else {
203                        write!(f, "{:7} {:#x?}", op, sa)
204                    }
205                }
206                R::Ddiv
207                | R::Ddivu
208                | R::Div
209                | R::Divu
210                | R::Dmult
211                | R::Dmultu
212                | R::Mult
213                | R::Multu
214                | R::Teq
215                | R::Tge
216                | R::Tgeu
217                | R::Tlt
218                | R::Tltu
219                | R::Tne => {
220                    write!(f, "{:7} {}, {}", op, rs, rt)
221                }
222                R::Jalr => {
223                    if let &Register::Ra = rd {
224                        write!(f, "{:7} {}", op, rs)
225                    } else {
226                        write!(f, "{:7} {},  {}", op, rd, rs)
227                    }
228                }
229                R::Jr | R::Mthi | R::Mtlo => {
230                    write!(f, "{:7} {}", op, rs)
231                }
232                R::Mfhi | R::Mflo => {
233                    write!(f, "{:7} {}", op, rd)
234                }
235                R::Cfc0 | R::Ctc0 | R::Dmfc0 | R::Dmtc0 | R::Mfc0 | R::Mtc0 => {
236                    write!(f, "{:7} {}, {}", op, rt, Cop0Register::from(*rd))
237                }
238                R::Cfc1 | R::Ctc1 | R::Dmfc1 | R::Dmtc1 | R::Mfc1 | R::Mtc1 => {
239                    write!(f, "{:7} {}, {}", op, rt, FloatRegister::from(*rd))
240                }
241                R::Eret | R::Tlbp | R::Tlbr | R::Tlbwi | R::Tlbwr => {
242                    write!(f, "{}", op)
243                }
244                R::AddS | R::AddD | R::SubS | R::SubD | R::MulS | R::MulD | R::DivS | R::DivD => {
245                    let x = op.to_string().replace('_', ".");
246                    write!(
247                        f,
248                        "{:7} {},  {},  {}",
249                        x,
250                        FloatRegister::from(*rd),
251                        FloatRegister::from(*rs),
252                        FloatRegister::from(*rt)
253                    )
254                }
255                R::AbsS
256                | R::AbsD
257                | R::CvtDS
258                | R::CvtDW
259                | R::CvtDL
260                | R::CvtLS
261                | R::CvtLD
262                | R::CvtSD
263                | R::CvtSW
264                | R::CvtSL
265                | R::CvtWD
266                | R::CvtWS
267                | R::MovS
268                | R::MovD
269                | R::NegS
270                | R::NegD
271                | R::SqrtS
272                | R::SqrtD => {
273                    let x = op.to_string().replace('_', ".");
274                    write!(
275                        f,
276                        "{:7} {},  {}",
277                        x,
278                        FloatRegister::from(*rd),
279                        FloatRegister::from(*rs)
280                    )
281                }
282                R::CeilLS | R::CeilLD | R::CeilWS | R::CeilWD => {
283                    let x = op.to_string().replace('_', ".");
284                    write!(
285                        f,
286                        "{} {}, {}",
287                        x,
288                        FloatRegister::from(*rd),
289                        FloatRegister::from(*rs)
290                    )
291                }
292                R::FloorLS
293                | R::FloorLD
294                | R::FloorWS
295                | R::FloorWD
296                | R::RoundLS
297                | R::RoundLD
298                | R::RoundWS
299                | R::RoundWD
300                | R::TruncLS
301                | R::TruncLD
302                | R::TruncWS
303                | R::TruncWD => {
304                    let x = op.to_string().replace('_', ".");
305                    write!(
306                        f,
307                        "{} {}, {}",
308                        x,
309                        FloatRegister::from(*rd),
310                        FloatRegister::from(*rs)
311                    )
312                }
313                R::Cs => {
314                    write!(
315                        f,
316                        "c.{}.s {}, {}",
317                        FloatCond::try_from(*sa).unwrap(),
318                        FloatRegister::from(*rs),
319                        FloatRegister::from(*rt)
320                    )
321                }
322                R::Cd => {
323                    write!(
324                        f,
325                        "c.{}.d {}, {}",
326                        FloatCond::try_from(*sa).unwrap(),
327                        FloatRegister::from(*rs),
328                        FloatRegister::from(*rt)
329                    )
330                }
331                e => panic!("{:?} not implemented", e),
332            },
333        }
334    }
335}
336
337#[derive(Clone, Copy, Debug, Display, PartialEq, Eq)]
338#[strum(serialize_all = "snake_case")]
339pub enum Register {
340    Zero,
341    At,
342    V0,
343    V1,
344    A0,
345    A1,
346    A2,
347    A3,
348    T0,
349    T1,
350    T2,
351    T3,
352    T4,
353    T5,
354    T6,
355    T7,
356    S0,
357    S1,
358    S2,
359    S3,
360    S4,
361    S5,
362    S6,
363    S7,
364    T8,
365    T9,
366    K0,
367    K1,
368    Gp,
369    Sp,
370    Fp,
371    Ra,
372}
373
374impl Register {
375    pub fn null() -> Self {
376        Register::Zero
377    }
378
379    pub fn as_num(&self) -> u32 {
380        *self as u32
381    }
382}
383
384impl TryFrom<u32> for Register {
385    type Error = RegParseError;
386
387    fn try_from(reg: u32) -> Result<Self, Self::Error> {
388        match reg {
389            0 => Ok(Register::Zero),
390            1 => Ok(Register::At),
391            2 => Ok(Register::V0),
392            3 => Ok(Register::V1),
393            4 => Ok(Register::A0),
394            5 => Ok(Register::A1),
395            6 => Ok(Register::A2),
396            7 => Ok(Register::A3),
397            8 => Ok(Register::T0),
398            9 => Ok(Register::T1),
399            10 => Ok(Register::T2),
400            11 => Ok(Register::T3),
401            12 => Ok(Register::T4),
402            13 => Ok(Register::T5),
403            14 => Ok(Register::T6),
404            15 => Ok(Register::T7),
405            16 => Ok(Register::S0),
406            17 => Ok(Register::S1),
407            18 => Ok(Register::S2),
408            19 => Ok(Register::S3),
409            20 => Ok(Register::S4),
410            21 => Ok(Register::S5),
411            22 => Ok(Register::S6),
412            23 => Ok(Register::S7),
413            24 => Ok(Register::T8),
414            25 => Ok(Register::T9),
415            26 => Ok(Register::K0),
416            27 => Ok(Register::K1),
417            28 => Ok(Register::Gp),
418            29 => Ok(Register::Sp),
419            30 => Ok(Register::Fp),
420            31 => Ok(Register::Ra),
421            e => Err(RegParseError::RegParseError(e.to_string())),
422        }
423    }
424}
425
426impl From<FloatRegister> for Register {
427    fn from(reg: FloatRegister) -> Self {
428        Register::try_from(reg as u32).unwrap()
429    }
430}
431
432impl From<Cop0Register> for Register {
433    fn from(reg: Cop0Register) -> Self {
434        Register::try_from(reg as u32).unwrap()
435    }
436}
437
438#[derive(Clone, Copy, Debug, Display)]
439#[strum(serialize_all = "snake_case")]
440pub enum FloatRegister {
441    Fv0,
442    Fv0f,
443    Fv1,
444    Fv1f,
445    Ft0,
446    Ft0f,
447    Ft1,
448    Ft1f,
449    Ft2,
450    Ft2f,
451    Ft3,
452    Ft3f,
453    Fa0,
454    Fa0f,
455    Fa1,
456    Fa1f,
457    Ft4,
458    Ft4f,
459    Ft5,
460    Ft5f,
461    Fs0,
462    Fs0f,
463    Fs1,
464    Fs1f,
465    Fs2,
466    Fs2f,
467    Fs3,
468    Fs3f,
469    Fs4,
470    Fs4f,
471    Fs5,
472    Fs5f,
473}
474
475impl TryFrom<u32> for FloatRegister {
476    type Error = RegParseError;
477
478    fn try_from(reg: u32) -> Result<Self, Self::Error> {
479        match reg {
480            0 => Ok(FloatRegister::Fv0),
481            1 => Ok(FloatRegister::Fv0f),
482            2 => Ok(FloatRegister::Fv1),
483            3 => Ok(FloatRegister::Fv1f),
484            4 => Ok(FloatRegister::Ft0),
485            5 => Ok(FloatRegister::Ft0f),
486            6 => Ok(FloatRegister::Ft1),
487            7 => Ok(FloatRegister::Ft1f),
488            8 => Ok(FloatRegister::Ft2),
489            9 => Ok(FloatRegister::Ft2f),
490            10 => Ok(FloatRegister::Ft3),
491            11 => Ok(FloatRegister::Ft3f),
492            12 => Ok(FloatRegister::Fa0),
493            13 => Ok(FloatRegister::Fa0f),
494            14 => Ok(FloatRegister::Fa1),
495            15 => Ok(FloatRegister::Fa1f),
496            16 => Ok(FloatRegister::Ft4),
497            17 => Ok(FloatRegister::Ft4f),
498            18 => Ok(FloatRegister::Ft5),
499            19 => Ok(FloatRegister::Ft5f),
500            20 => Ok(FloatRegister::Fs0),
501            21 => Ok(FloatRegister::Fs0f),
502            22 => Ok(FloatRegister::Fs1),
503            23 => Ok(FloatRegister::Fs1f),
504            24 => Ok(FloatRegister::Fs2),
505            25 => Ok(FloatRegister::Fs2f),
506            26 => Ok(FloatRegister::Fs3),
507            27 => Ok(FloatRegister::Fs3f),
508            28 => Ok(FloatRegister::Fs4),
509            29 => Ok(FloatRegister::Fs4f),
510            30 => Ok(FloatRegister::Fs5),
511            31 => Ok(FloatRegister::Fs5f),
512            e => Err(RegParseError::RegParseError(e.to_string())),
513        }
514    }
515}
516
517impl FromStr for FloatRegister {
518    type Err = RegParseError;
519
520    fn from_str(reg: &str) -> Result<Self, Self::Err> {
521        let reg = reg.trim().trim_start_matches('$');
522
523        if let Ok(x) = reg.parse::<u32>() {
524            return FloatRegister::try_from(x);
525        }
526
527        match reg.to_lowercase().as_str() {
528            "f0" | "fv0" => Ok(FloatRegister::Fv0),
529            "f1" | "fv0f" => Ok(FloatRegister::Fv0f),
530            "f2" | "fv1" => Ok(FloatRegister::Fv1),
531            "f3" | "fv1f" => Ok(FloatRegister::Fv1f),
532            "f4" | "ft0" => Ok(FloatRegister::Ft0),
533            "f5" | "ft0f" => Ok(FloatRegister::Ft0f),
534            "f6" | "ft1" => Ok(FloatRegister::Ft1),
535            "f7" | "ft1f" => Ok(FloatRegister::Ft1f),
536            "f8" | "ft2" => Ok(FloatRegister::Ft2),
537            "f9" | "ft2f" => Ok(FloatRegister::Ft2f),
538            "f10" | "ft3" => Ok(FloatRegister::Ft3),
539            "f11" | "ft3f" => Ok(FloatRegister::Ft3f),
540            "f12" | "fa0" => Ok(FloatRegister::Fa0),
541            "f13" | "fa0f" => Ok(FloatRegister::Fa0f),
542            "f14" | "fa1" => Ok(FloatRegister::Fa1),
543            "f15" | "fa1f" => Ok(FloatRegister::Fa1f),
544            "f16" | "ft4" => Ok(FloatRegister::Ft4),
545            "f17" | "ft4f" => Ok(FloatRegister::Ft4f),
546            "f18" | "ft5" => Ok(FloatRegister::Ft5),
547            "f19" | "ft5f" => Ok(FloatRegister::Ft5f),
548            "f20" | "fs0" => Ok(FloatRegister::Fs0),
549            "f21" | "fs0f" => Ok(FloatRegister::Fs0f),
550            "f22" | "fs1" => Ok(FloatRegister::Fs1),
551            "f23" | "fs1f" => Ok(FloatRegister::Fs1f),
552            "f24" | "fs2" => Ok(FloatRegister::Fs2),
553            "f25" | "fs2f" => Ok(FloatRegister::Fs2f),
554            "f26" | "fs3" => Ok(FloatRegister::Fs3),
555            "f27" | "fs3f" => Ok(FloatRegister::Fs3f),
556            "f28" | "fs4" => Ok(FloatRegister::Fs4),
557            "f29" | "fs4f" => Ok(FloatRegister::Fs4f),
558            "f30" | "fs5" => Ok(FloatRegister::Fs5),
559            "f31" | "fs5f" => Ok(FloatRegister::Fs5f),
560            e => {
561                if let Ok(x) = u32::from_str_radix(reg, 16) {
562                    return FloatRegister::try_from(x);
563                }
564                Err(RegParseError::RegParseError(e.to_string()))
565            }
566        }
567    }
568}
569
570impl From<Register> for FloatRegister {
571    fn from(reg: Register) -> Self {
572        FloatRegister::try_from(reg as u32).unwrap()
573    }
574}
575
576#[derive(Clone, Copy, Debug, Display)]
577#[strum(serialize_all = "PascalCase")]
578pub enum Cop0Register {
579    IDMemAddressForDMA,
580    DramAddressForDMA,
581    DmaReadLength,
582    DmaWriteLength,
583    RspStatus,
584    DmaFull,
585    DmaBusy,
586    CpuRspSemaphore,
587    RdpCommandBufferStart,
588    RdpCommandBufferEnd,
589    RdpCommandBufferCurrent,
590    RdpStatus,
591    RdpClockCounter,
592    RdpCommandBufferBusyCounter,
593    RdpPipeBusyCounter,
594    RdpTmemBusyCounter,
595}
596
597impl TryFrom<u32> for Cop0Register {
598    type Error = RegParseError;
599
600    fn try_from(reg: u32) -> Result<Self, Self::Error> {
601        match reg {
602            0 => Ok(Cop0Register::IDMemAddressForDMA),
603            1 => Ok(Cop0Register::DramAddressForDMA),
604            2 => Ok(Cop0Register::DmaReadLength),
605            3 => Ok(Cop0Register::DmaWriteLength),
606            4 => Ok(Cop0Register::RspStatus),
607            5 => Ok(Cop0Register::DmaFull),
608            6 => Ok(Cop0Register::DmaBusy),
609            7 => Ok(Cop0Register::CpuRspSemaphore),
610            8 => Ok(Cop0Register::RdpCommandBufferStart),
611            9 => Ok(Cop0Register::RdpCommandBufferEnd),
612            10 => Ok(Cop0Register::RdpCommandBufferCurrent),
613            11 => Ok(Cop0Register::RdpStatus),
614            12 => Ok(Cop0Register::RdpClockCounter),
615            13 => Ok(Cop0Register::RdpCommandBufferBusyCounter),
616            14 => Ok(Cop0Register::RdpPipeBusyCounter),
617            15 => Ok(Cop0Register::RdpTmemBusyCounter),
618            e => Err(RegParseError::RegParseError(e.to_string())),
619        }
620    }
621}
622
623impl From<Register> for Cop0Register {
624    fn from(reg: Register) -> Self {
625        Cop0Register::try_from(reg as u32).unwrap()
626    }
627}
628
629#[derive(Clone, Copy, Debug, Display, EnumString, PartialEq, Eq)]
630#[strum(ascii_case_insensitive)]
631#[strum(serialize_all = "snake_case")]
632pub enum ITypeOp {
633    Addi,
634    Addiu,
635    Andi,
636    Bc0f,
637    Bc0fl,
638    Bc0t,
639    Bc0tl,
640    Bc1f,
641    Bc1fl,
642    Bc1t,
643    Bc1tl,
644    Beq,
645    Beql,
646    Bgez,
647    Bgezal,
648    Bgezall,
649    Bgezl,
650    Bgtz,
651    Bgtzl,
652    Blez,
653    Blezl,
654    Bltz,
655    Bltzal,
656    Bltzall,
657    Bltzl,
658    Bne,
659    Bnel,
660    Cache,
661    Daddi,
662    Daddiu,
663    Lb,
664    Lbu,
665    Ld,
666    Ldc1,
667    Ldl,
668    Ldr,
669    Lh,
670    Lhu,
671    Ll,
672    Lld,
673    Lui,
674    Lw,
675    Lwc1,
676    Lbv,
677    Lwl,
678    Lwr,
679    Lwu,
680    Ori,
681    Sb,
682    Sc,
683    Scd,
684    Sd,
685    Sdc1,
686    Sdl,
687    Sdr,
688    Sh,
689    Slti,
690    Sltiu,
691    Sw,
692    Swc1,
693    Swl,
694    Swr,
695    Teqi,
696    Tgei,
697    Tgeiu,
698    Tlti,
699    Tltiu,
700    Tnei,
701    Xori,
702    // Pseudoinstructions
703    B,
704    Bal,
705    Beqz,
706    Bnez,
707    Beqzl,
708    Bnezl,
709    Bge,
710    Bgt,
711    Ble,
712    Blt,
713    Bgeu,
714    Bgtu,
715    Bleu,
716    Bltu,
717    Bgel,
718    Bgtl,
719    Blel,
720    Bltl,
721    Bgeul,
722    Bgtul,
723    Bleul,
724    Bltul,
725    Dli,
726    Dsubi,
727    Dsubiu,
728    Lli,
729    Li,
730    Subi,
731    Subiu,
732}
733
734#[derive(Clone, Copy, Debug, Display, EnumString, PartialEq, Eq)]
735#[strum(ascii_case_insensitive)]
736#[strum(serialize_all = "snake_case")]
737pub enum JTypeOp {
738    J,
739    Jal,
740}
741
742#[derive(Clone, Copy, Debug, Display, EnumString, PartialEq, Eq)]
743#[strum(ascii_case_insensitive)]
744#[strum(serialize_all = "snake_case")]
745pub enum RTypeOp {
746    #[strum(to_string = "abs.s")]
747    AbsS,
748    #[strum(to_string = "abs.d")]
749    AbsD,
750    Add,
751    Addu,
752    #[strum(to_string = "add.s")]
753    AddS,
754    #[strum(to_string = "add.d")]
755    AddD,
756    And,
757    Break,
758    #[strum(to_string = "c.s")]
759    Cs,
760    #[strum(to_string = "c.d")]
761    Cd,
762    #[strum(to_string = "ceil.l.s")]
763    CeilLS,
764    #[strum(to_string = "ceil.l.d")]
765    CeilLD,
766    #[strum(to_string = "ceil.w.s")]
767    CeilWS,
768    #[strum(to_string = "ceil.w.d")]
769    CeilWD,
770    Cfc0,
771    Cfc1,
772    Ctc0,
773    Ctc1,
774    #[strum(to_string = "cvt.d.s")]
775    CvtDS,
776    #[strum(to_string = "cvt.d.w")]
777    CvtDW,
778    #[strum(to_string = "cvt.d.l")]
779    CvtDL,
780    #[strum(to_string = "cvt.l.s")]
781    CvtLS,
782    #[strum(to_string = "cvt.l.d")]
783    CvtLD,
784    #[strum(to_string = "cvt.s.d")]
785    CvtSD,
786    #[strum(to_string = "cvt.s.w")]
787    CvtSW,
788    #[strum(to_string = "cvt.s.l")]
789    CvtSL,
790    #[strum(to_string = "cvt.w.s")]
791    CvtWS,
792    #[strum(to_string = "cvt.w.d")]
793    CvtWD,
794    Dadd,
795    Daddu,
796    Ddiv,
797    Ddivu,
798    Div,
799    Divu,
800    #[strum(to_string = "div.s")]
801    DivS,
802    #[strum(to_string = "div.d")]
803    DivD,
804    Dmfc0,
805    Dmfc1,
806    Dmtc0,
807    Dmtc1,
808    Dmult,
809    Dmultu,
810    Dsll,
811    Dsll32,
812    Dsllv,
813    Dsra,
814    Dsra32,
815    Dsrav,
816    Dsrl,
817    Dsrl32,
818    Dsrlv,
819    Dsub,
820    Dsubu,
821    Eret,
822    #[strum(to_string = "floor.l.s")]
823    FloorLS,
824    #[strum(to_string = "floor.l.d")]
825    FloorLD,
826    #[strum(to_string = "floor.w.s")]
827    FloorWS,
828    #[strum(to_string = "floor.w.d")]
829    FloorWD,
830    Jalr,
831    Jr,
832    Mfc0,
833    Mfc1,
834    Mfhi,
835    Mflo,
836    #[strum(to_string = "mov.s")]
837    MovS,
838    #[strum(to_string = "mov.d")]
839    MovD,
840    Mtc0,
841    Mtc1,
842    Mthi,
843    Mtlo,
844    #[strum(to_string = "mul.s")]
845    MulS,
846    #[strum(to_string = "mul.d")]
847    MulD,
848    Mult,
849    Multu,
850    #[strum(to_string = "neg.s")]
851    NegS,
852    #[strum(to_string = "neg.d")]
853    NegD,
854    Nor,
855    Or,
856    #[strum(to_string = "round.l.s")]
857    RoundLS,
858    #[strum(to_string = "round.l.d")]
859    RoundLD,
860    #[strum(to_string = "round.w.s")]
861    RoundWS,
862    #[strum(to_string = "round.w.d")]
863    RoundWD,
864    Sll,
865    Sllv,
866    Slt,
867    Sltu,
868    #[strum(to_string = "sqrt.s")]
869    SqrtS,
870    #[strum(to_string = "sqrt.d")]
871    SqrtD,
872    Sra,
873    Srav,
874    Srl,
875    Srlv,
876    Sub,
877    Subu,
878    #[strum(to_string = "sub.s")]
879    SubS,
880    #[strum(to_string = "sub.d")]
881    SubD,
882    Sync,
883    Syscall,
884    Teq,
885    Tge,
886    Tgeu,
887    Tlbp,
888    Tlbr,
889    Tlbwi,
890    Tlbwr,
891    Tlt,
892    Tltu,
893    Tne,
894    #[strum(to_string = "trunc.l.s")]
895    TruncLS,
896    #[strum(to_string = "trunc.l.d")]
897    TruncLD,
898    #[strum(to_string = "trunc.w.s")]
899    TruncWS,
900    #[strum(to_string = "trunc.w.d")]
901    TruncWD,
902    Xor,
903    // pseudoinstructions
904    Abs,
905    Clear,
906    Dabs,
907    Dmove,
908    Dmul,
909    Dmulu,
910    Dmulo,
911    Dmulou,
912    Dneg,
913    Dnegu,
914    Drem,
915    Dremu,
916    Drol,
917    Dror,
918    Move,
919    Mul,
920    Mulu,
921    Mulo,
922    Mulou,
923    Neg,
924    Negu,
925    Nop,
926    Not,
927    Rem,
928    Remu,
929    Seq,
930    Sge,
931    Sgeu,
932    Sgt,
933    Sgtu,
934    Sle,
935    Sleu,
936    Sne,
937}
938
939#[derive(Clone, Copy, Debug, Display, EnumString)]
940#[strum(ascii_case_insensitive)]
941#[strum(serialize_all = "snake_case")]
942pub enum FloatCond {
943    F,
944    Un,
945    Eq,
946    Ueq,
947    Olt,
948    Ult,
949    Ole,
950    Ule,
951    Sf,
952    Ngle,
953    Seq,
954    Ngl,
955    Lt,
956    Nge,
957    Le,
958    Ngt,
959}
960
961impl TryFrom<u32> for FloatCond {
962    type Error = RegParseError;
963
964    fn try_from(cond: u32) -> Result<Self, Self::Error> {
965        match cond {
966            0 => Ok(FloatCond::F),
967            1 => Ok(FloatCond::Un),
968            2 => Ok(FloatCond::Eq),
969            3 => Ok(FloatCond::Ueq),
970            4 => Ok(FloatCond::Olt),
971            5 => Ok(FloatCond::Ult),
972            6 => Ok(FloatCond::Ole),
973            7 => Ok(FloatCond::Ule),
974            8 => Ok(FloatCond::Sf),
975            9 => Ok(FloatCond::Ngle),
976            10 => Ok(FloatCond::Seq),
977            11 => Ok(FloatCond::Ngl),
978            12 => Ok(FloatCond::Lt),
979            13 => Ok(FloatCond::Nge),
980            14 => Ok(FloatCond::Le),
981            15 => Ok(FloatCond::Ngt),
982            e => Err(RegParseError::RegParseError(e.to_string())),
983        }
984    }
985}