yaxpeax_mips/
display.rs

1use std::fmt;
2
3use crate::{Instruction, Opcode, Operand};
4
5impl fmt::Display for Instruction {
6    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7        if self.opcode == Opcode::OR {
8            match (self.operand(&self.operands[0]), self.operand(&self.operands[1]), self.operand(&self.operands[2])) {
9                (Some(a), Some(b), Some(Operand::Reg(0))) => {
10                    return write!(f, "move {}, {}", a, b);
11                }
12                _ => {}
13            }
14        } else if self.opcode == Opcode::BEQ {
15            match (self.operand(&self.operands[0]), self.operand(&self.operands[1]), self.operand(&self.operands[2])) {
16                (Some(Operand::Reg(a)), Some(Operand::Reg(b)), Some(Operand::Imm(offs))) => {
17                    if a == b {
18                        if offs < 0 {
19                            return write!(f, "b $-{:#x}", offs.wrapping_neg());
20                        } else {
21                            return write!(f, "b $+{:#x}", offs);
22                        }
23                    }
24                }
25                _ => {}
26            }
27        } else if self.opcode == Opcode::SLL {
28            match (self.operand(&self.operands[0]), self.operand(&self.operands[1]), self.operand(&self.operands[2])) {
29                (Some(Operand::Reg(dest)), Some(Operand::Reg(src)), Some(Operand::Shift(0))) => {
30                    // TODO: should this also test for dest == `zero`?
31                    if dest == src {
32                        return write!(f, "nop");
33                    }
34                }
35                _ => { }
36            }
37        }
38
39        fn display_operand(f: &mut fmt::Formatter, opcode: &Opcode, op: &Operand) -> fmt::Result {
40            if *opcode == Opcode::LUI {
41                // we show the immediate of LUI as an unsigned integer, becaue the docs say so.
42                if let Operand::Imm(imm) = op {
43                    return write!(f, "{:#x}", *imm as u16);
44                }
45            } else if let Operand::Imm(imm) = op {
46                if *imm < 0 {
47                    return write!(f, "-{:#x}", imm.wrapping_neg());
48                } else {
49                    return write!(f, "{:#x}", imm);
50                }
51            }
52
53            write!(f, "{}", op)
54        }
55        write!(f, "{}", self.opcode)?;
56
57        let mut wrote_operand = false;
58        for op in self.operands.iter() {
59            match self.operand(op) {
60                Some(op) => {
61                    if wrote_operand {
62                        write!(f, ", ")?;
63                    } else {
64                        write!(f, " ")?;
65                        wrote_operand = true;
66                    }
67                    display_operand(f, &self.opcode, &op)?;
68                }
69                _ => {
70                    return Ok(());
71                }
72            }
73        }
74
75        Ok(())
76    }
77}
78
79impl fmt::Display for Operand {
80    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81        match self {
82            Operand::Reg(reg) => {
83                let name = [
84                    "zero", "at",
85                    "v0", "v1",
86                    "a0", "a1", "a2", "a3",
87                    "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
88                    "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
89                    "t8", "t9",
90                    "k0", "k1",
91                    "gp", "sp", "fp", "ra"
92                ][*reg as usize];
93                write!(f, "{}", name)
94            }
95            Operand::Imm(imm) => {
96                write!(f, "{:#x}", imm)
97            }
98            Operand::BaseOffset(reg, offs) => {
99                let name = [
100                    "zero", "at",
101                    "v0", "v1",
102                    "a0", "a1", "a2", "a3",
103                    "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
104                    "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
105                    "t8", "t9",
106                    "k0", "k1",
107                    "gp", "sp", "fp", "ra"
108                ][*reg as usize];
109                if *offs == 0 {
110                    write!(f, "({})", name)
111                } else {
112                    if *offs < 0 {
113                        write!(f, "-{:#x}({})", offs.wrapping_neg(), name)
114                    } else {
115                        write!(f, "{:#x}({})", offs, name)
116                    }
117                }
118            }
119            Operand::Shift(sa) => {
120                write!(f, "{:#x}", sa)
121            }
122            Operand::LongImm(imm) => {
123                write!(f, "{:#x}", imm)
124            }
125            Operand::JOffset(offs) => {
126                write!(f, "$+{:#x}", offs)
127            }
128        }
129    }
130}
131
132impl fmt::Display for Opcode {
133    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134        match self {
135            Opcode::J => write!(f, "j"),
136            Opcode::JAL => write!(f, "jal"),
137            Opcode::BEQ => write!(f, "beq"),
138            Opcode::BNE => write!(f, "bne"),
139            Opcode::BLEZ => write!(f, "blez"),
140            Opcode::BGTZ => write!(f, "bgtz"),
141            Opcode::ADDI => write!(f, "addi"),
142            Opcode::ADDIU => write!(f, "addiu"),
143            Opcode::SLTI => write!(f, "slti"),
144            Opcode::SLTIU => write!(f, "sltiu"),
145            Opcode::ANDI => write!(f, "andi"),
146            Opcode::ORI => write!(f, "ori"),
147            Opcode::XORI => write!(f, "xori"),
148            Opcode::LUI => write!(f, "lui"),
149            Opcode::COP1 => write!(f, "cop1"),
150            Opcode::COP2 => write!(f, "cop2"),
151            Opcode::COP3 => write!(f, "cop3"),
152            Opcode::COP4 => write!(f, "cop4"),
153            Opcode::BEQL => write!(f, "beql"),
154            Opcode::BNEL => write!(f, "bnel"),
155            Opcode::BLEZL => write!(f, "blezl"),
156            Opcode::BGTZL => write!(f, "bgtzl"),
157            Opcode::DADDI => write!(f, "daddi"),
158            Opcode::DADDIU => write!(f, "daddiu"),
159            Opcode::LDL => write!(f, "ldl"),
160            Opcode::LDR => write!(f, "ldr"),
161            Opcode::LB => write!(f, "lb"),
162            Opcode::LH => write!(f, "lh"),
163            Opcode::LWL => write!(f, "lwl"),
164            Opcode::LW => write!(f, "lw"),
165            Opcode::LBU => write!(f, "lbu"),
166            Opcode::LHU => write!(f, "lhu"),
167            Opcode::LWR => write!(f, "lwr"),
168            Opcode::LWU => write!(f, "lwu"),
169            Opcode::SB => write!(f, "sb"),
170            Opcode::SH => write!(f, "sh"),
171            Opcode::SWL => write!(f, "swl"),
172            Opcode::SW => write!(f, "sw"),
173            Opcode::SDL => write!(f, "sdl"),
174            Opcode::SDR => write!(f, "sdr"),
175            Opcode::SWR => write!(f, "swr"),
176            Opcode::LL => write!(f, "ll"),
177            Opcode::LWC1 => write!(f, "lwc1"),
178            Opcode::LWC2 => write!(f, "lwc2"),
179            Opcode::PREF => write!(f, "pref"),
180            Opcode::LLD => write!(f, "lld"),
181            Opcode::LDC1 => write!(f, "ldc1"),
182            Opcode::LDC2 => write!(f, "ldc2"),
183            Opcode::LD => write!(f, "ld"),
184            Opcode::SC => write!(f, "sc"),
185            Opcode::SWC1 => write!(f, "swc1"),
186            Opcode::SWC2 => write!(f, "swc2"),
187            Opcode::SCD => write!(f, "scd"),
188            Opcode::SDC1 => write!(f, "sdc1"),
189            Opcode::SDC2 => write!(f, "sdc2"),
190            Opcode::SD => write!(f, "sd"),
191            Opcode::SLL => write!(f, "sll"),
192            Opcode::SRL => write!(f, "srl"),
193            Opcode::SRA => write!(f, "sra"),
194            Opcode::SLLV => write!(f, "sllv"),
195            Opcode::SRLV => write!(f, "srlv"),
196            Opcode::SRAV => write!(f, "srav"),
197            Opcode::JR => write!(f, "jr"),
198            Opcode::JALR => write!(f, "jalr"),
199            Opcode::MOVZ => write!(f, "movz"),
200            Opcode::MOVN => write!(f, "movn"),
201            Opcode::SYSCALL => write!(f, "syscall"),
202            Opcode::BREAK => write!(f, "break"),
203            Opcode::SYNC => write!(f, "sync"),
204            Opcode::MFHI => write!(f, "mfhi"),
205            Opcode::MTHI => write!(f, "mthi"),
206            Opcode::MFLO => write!(f, "mflo"),
207            Opcode::MTLO => write!(f, "mtlo"),
208            Opcode::DSLLV => write!(f, "dsllv"),
209            Opcode::DSRLV => write!(f, "dsrlv"),
210            Opcode::DSRAV => write!(f, "dsrav"),
211            Opcode::MULT => write!(f, "mult"),
212            Opcode::MULTU => write!(f, "multu"),
213            Opcode::DIV => write!(f, "div"),
214            Opcode::DIVU => write!(f, "divu"),
215            Opcode::DMULT => write!(f, "dmult"),
216            Opcode::DMULTU => write!(f, "dmultu"),
217            Opcode::DDIV => write!(f, "ddiv"),
218            Opcode::DDIVU => write!(f, "ddivu"),
219            Opcode::ADD => write!(f, "add"),
220            Opcode::ADDU => write!(f, "addu"),
221            Opcode::SUB => write!(f, "sub"),
222            Opcode::SUBU => write!(f, "subu"),
223            Opcode::AND => write!(f, "and"),
224            Opcode::OR => write!(f, "or"),
225            Opcode::XOR => write!(f, "xor"),
226            Opcode::NOR => write!(f, "nor"),
227            Opcode::SLT => write!(f, "slt"),
228            Opcode::DADD => write!(f, "dadd"),
229            Opcode::DADDU => write!(f, "daddu"),
230            Opcode::DSUB => write!(f, "dsub"),
231            Opcode::DSUBU => write!(f, "dsubu"),
232            Opcode::TGE => write!(f, "tge"),
233            Opcode::TGEU => write!(f, "tgeu"),
234            Opcode::TLT => write!(f, "tlt"),
235            Opcode::TLTU => write!(f, "tltu"),
236            Opcode::TEQ => write!(f, "teq"),
237            Opcode::TNE => write!(f, "tne"),
238            Opcode::DSLL => write!(f, "dsll"),
239            Opcode::DSRL => write!(f, "dsrl"),
240            Opcode::DSRA => write!(f, "dsra"),
241            Opcode::DSLL32 => write!(f, "dsll32"),
242            Opcode::DSRL32 => write!(f, "dsrl32"),
243            Opcode::DSRA32 => write!(f, "dsra32"),
244            Opcode::BLTZ => write!(f, "bltz"),
245            Opcode::BGEZ => write!(f, "bgez"),
246            Opcode::BLTZL => write!(f, "bltzl"),
247            Opcode::BGEZL => write!(f, "bgezl"),
248            Opcode::TGEI => write!(f, "tgei"),
249            Opcode::TGEIU => write!(f, "tgeiu"),
250            Opcode::TLTI => write!(f, "tlti"),
251            Opcode::TLTIU => write!(f, "tltiu"),
252            Opcode::TEQI => write!(f, "teqi"),
253            Opcode::TNEI => write!(f, "tnei"),
254            Opcode::BLTZAL => write!(f, "bltzal"),
255            Opcode::BGEZAL => write!(f, "bgezal"),
256            Opcode::BLTZALL => write!(f, "bltzall"),
257            Opcode::BGEZALL => write!(f, "bgezall"),
258        }
259    }
260}