1use std::fmt;
2
3use super::instructions_table::{PRIMARY_OPCODES, SECONDARY_OPCODES};
4use super::RegisterType;
5
6#[derive(Copy, Clone, Debug, PartialEq, Eq)]
7pub enum Opcode {
8 #[doc(hidden)]
9 SecondaryOpcode,
14 Invalid,
15
16 Nop,
17
18 Lb,
20 Lbu,
21 Lh,
22 Lhu,
23 Lw,
24
25 Lwl,
26 Lwr,
27
28 Sb,
29 Sh,
30 Sw,
31
32 Swl,
33 Swr,
34
35 Slt,
36 Sltu,
37 Slti,
38 Sltiu,
39
40 Addu,
41 Add,
42 Subu,
43 Sub,
44 Addiu,
45 Addi,
46
47 And,
48 Or,
49 Xor,
50 Nor,
51 Andi,
52 Ori,
53 Xori,
54
55 Sllv,
56 Srlv,
57 Srav,
58 Sll,
59 Srl,
60 Sra,
61 Lui,
62
63 Mult,
64 Multu,
65 Div,
66 Divu,
67
68 Mfhi,
69 Mthi,
70 Mflo,
71 Mtlo,
72
73 J,
74 Jal,
75
76 Jr,
77 Jalr,
78
79 Beq,
80 Bne,
81 Bgtz,
82 Blez,
83 Bcondz,
91 Bltz,
92 Bgez,
93 Bltzal,
94 Bgezal,
95
96 Syscall,
97 Break,
98
99 Cop(u8),
100 Mfc(u8),
101 Cfc(u8),
102 Mtc(u8),
103 Ctc(u8),
104
105 Bcf(u8),
106 Bct(u8),
107
108 Rfe,
110
111 Lwc(u8),
112 Swc(u8),
113}
114
115#[derive(Debug, Clone)]
125pub struct Instruction {
126 pub pc: u32,
127
128 pub opcode: Opcode,
129
130 pub instruction: u32,
131 pub(crate) rd_raw: u8,
132 pub(crate) rt_raw: u8,
133 pub(crate) rs_raw: u8,
134}
135
136impl Instruction {
137 pub fn from_u32(instruction: u32, pc: u32) -> Self {
138 if instruction == 0 {
139 return Self {
140 pc,
141
142 opcode: Opcode::Nop,
143 instruction,
144 rd_raw: 0,
145 rt_raw: 0,
146 rs_raw: 0,
147 };
148 }
149
150 let primary_identifier = (instruction >> 26) as u8;
151 let rd_raw = (instruction >> 11) as u8 & 0x1F;
152 let rt_raw = (instruction >> 16) as u8 & 0x1F;
153 let rs_raw = (instruction >> 21) as u8 & 0x1F;
154
155 let opcode = Self::get_opcode_from_primary(primary_identifier);
156
157 let opcode = match opcode {
158 Opcode::SecondaryOpcode => {
159 let secondary_identifier = instruction as u8 & 0x3F;
160 Self::get_opcode_from_secondary(secondary_identifier)
161 }
162 Opcode::Cop(n) => {
163 let secondary_identifier = instruction as u8 & 0x3F;
164 Self::get_cop_opcode(n, secondary_identifier, rt_raw, rs_raw)
165 }
166 Opcode::Bcondz => Self::get_bcondz_opcode(rt_raw),
167 _ => opcode,
168 };
169
170 Self {
171 pc,
172
173 opcode,
174 instruction,
175 rd_raw,
176 rt_raw,
177 rs_raw,
178 }
179 }
180
181 pub fn is_branch(&self) -> bool {
182 matches!(
183 self.opcode,
184 Opcode::J
185 | Opcode::Jal
186 | Opcode::Jalr
187 | Opcode::Jr
188 | Opcode::Beq
189 | Opcode::Bne
190 | Opcode::Bgtz
191 | Opcode::Blez
192 | Opcode::Bltz
193 | Opcode::Bgez
194 | Opcode::Bltzal
195 | Opcode::Bgezal
196 )
197 }
198
199 #[inline]
200 pub fn rd(&self) -> RegisterType {
201 RegisterType::from(self.rd_raw)
202 }
203
204 #[inline]
205 pub fn rt(&self) -> RegisterType {
206 RegisterType::from(self.rt_raw)
207 }
208
209 #[inline]
210 pub fn rs(&self) -> RegisterType {
211 RegisterType::from(self.rs_raw)
212 }
213
214 #[inline]
215 pub const fn imm5(&self) -> u8 {
216 (self.instruction >> 6) as u8 & 0x1F
217 }
218
219 #[inline]
220 pub const fn imm16(&self) -> u16 {
221 self.instruction as u16
222 }
223
224 #[inline]
225 pub const fn imm25(&self) -> u32 {
226 self.instruction & 0x1FFFFFF
227 }
228
229 #[inline]
230 pub const fn imm26(&self) -> u32 {
231 self.instruction & 0x3FFFFFF
232 }
233}
234
235impl Instruction {
236 fn get_opcode_from_primary(primary: u8) -> Opcode {
237 PRIMARY_OPCODES[primary as usize & 0x3F]
238 }
239
240 fn get_opcode_from_secondary(secondary: u8) -> Opcode {
241 SECONDARY_OPCODES[secondary as usize & 0x3F]
242 }
243
244 fn get_bcondz_opcode(rt_raw: u8) -> Opcode {
245 match rt_raw {
246 0x10 => Opcode::Bltzal,
247 0x11 => Opcode::Bgezal,
248 x if x & 1 == 0 => Opcode::Bltz,
249 _ => Opcode::Bgez,
251 }
252 }
253
254 fn get_cop_opcode(cop_n: u8, secondary: u8, part_20_16: u8, part_25_21: u8) -> Opcode {
255 match part_25_21 {
256 0 if secondary == 0 => Opcode::Mfc(cop_n),
257 2 if secondary == 0 => Opcode::Cfc(cop_n),
258 4 if secondary == 0 => Opcode::Mtc(cop_n),
259 6 if secondary == 0 => Opcode::Ctc(cop_n),
260 8 => match part_20_16 {
261 0 => Opcode::Bcf(cop_n),
262 1 => Opcode::Bct(cop_n),
263 _ => Opcode::Invalid,
264 },
265 _ if part_25_21 & 0x10 != 0 => {
266 if cop_n == 0 {
267 if secondary == 0x10 && part_25_21 == 0x10 {
268 Opcode::Rfe
271 } else {
272 Opcode::Invalid
273 }
274 } else {
275 Opcode::Cop(cop_n)
276 }
277 }
278 _ => Opcode::Invalid,
279 }
280 }
281}
282
283const fn opcode_str(opcode: Opcode) -> &'static str {
284 match opcode {
285 Opcode::Nop => "nop",
286 Opcode::Lb => "lb",
287 Opcode::Lh => "lh",
288 Opcode::Lw => "lw",
289 Opcode::Lbu => "lbu",
290 Opcode::Lhu => "lhu",
291 Opcode::Sb => "sb",
292 Opcode::Lwl => "lwl",
293 Opcode::Lwr => "lwr",
294 Opcode::Sh => "sh",
295 Opcode::Sw => "sw",
296 Opcode::Swl => "swl",
297 Opcode::Swr => "swr",
298 Opcode::Slt => "slt",
299 Opcode::Sltu => "sltu",
300 Opcode::Slti => "slti",
301 Opcode::Sltiu => "sltiu",
302 Opcode::Addu => "addu",
303 Opcode::Add => "add",
304 Opcode::Subu => "subu",
305 Opcode::Sub => "sub",
306 Opcode::Addiu => "addiu",
307 Opcode::Addi => "addi",
308 Opcode::And => "and",
309 Opcode::Or => "or",
310 Opcode::Xor => "xor",
311 Opcode::Nor => "nor",
312 Opcode::Andi => "andi",
313 Opcode::Ori => "ori",
314 Opcode::Xori => "xori",
315 Opcode::Sllv => "sllv",
316 Opcode::Srlv => "srlv",
317 Opcode::Srav => "srav",
318 Opcode::Sll => "sll",
319 Opcode::Srl => "srl",
320 Opcode::Sra => "sra",
321 Opcode::Lui => "lui",
322 Opcode::Mult => "mult",
323 Opcode::Multu => "multu",
324 Opcode::Div => "div",
325 Opcode::Divu => "divu",
326 Opcode::Mfhi => "mfhi",
327 Opcode::Mthi => "mthi",
328 Opcode::Mflo => "mflo",
329 Opcode::Mtlo => "mtlo",
330 Opcode::J => "j",
331 Opcode::Jal => "jal",
332 Opcode::Jr => "jr",
333 Opcode::Jalr => "jalr",
334 Opcode::Beq => "beq",
335 Opcode::Bne => "bne",
336 Opcode::Bgtz => "bgtz",
337 Opcode::Blez => "blez",
338 Opcode::Bcondz => "bcondz",
339 Opcode::Bltz => "bltz",
340 Opcode::Bgez => "bgez",
341 Opcode::Bltzal => "bltzal",
342 Opcode::Bgezal => "bgezal",
343 Opcode::Syscall => "syscall",
344 Opcode::Break => "break",
345 Opcode::Cop(0) => "cop0",
346 Opcode::Cop(1) => "cop1",
347 Opcode::Cop(2) => "cop2",
348 Opcode::Cop(3) => "cop3",
349 Opcode::Mfc(0) => "mfc0",
350 Opcode::Mfc(1) => "mfc1",
351 Opcode::Mfc(2) => "mfc2",
352 Opcode::Mfc(3) => "mfc3",
353 Opcode::Cfc(0) => "cfc0",
354 Opcode::Cfc(1) => "cfc1",
355 Opcode::Cfc(2) => "cfc2",
356 Opcode::Cfc(3) => "cfc3",
357 Opcode::Mtc(0) => "mtc0",
358 Opcode::Mtc(1) => "mtc1",
359 Opcode::Mtc(2) => "mtc2",
360 Opcode::Mtc(3) => "mtc3",
361 Opcode::Ctc(0) => "ctc0",
362 Opcode::Ctc(1) => "ctc1",
363 Opcode::Ctc(2) => "ctc2",
364 Opcode::Ctc(3) => "ctc3",
365 Opcode::Bcf(0) => "bcf0",
366 Opcode::Bcf(1) => "bcf1",
367 Opcode::Bcf(2) => "bcf2",
368 Opcode::Bcf(3) => "bcf3",
369 Opcode::Bct(0) => "bct0",
370 Opcode::Bct(1) => "bct1",
371 Opcode::Bct(2) => "bct2",
372 Opcode::Bct(3) => "bct3",
373 Opcode::Rfe => "rfe",
374 Opcode::Lwc(0) => "lwc0",
375 Opcode::Lwc(1) => "lwc1",
376 Opcode::Lwc(2) => "lwc2",
377 Opcode::Lwc(3) => "lwc3",
378 Opcode::Swc(0) => "swc0",
379 Opcode::Swc(1) => "swc1",
380 Opcode::Swc(2) => "swc2",
381 Opcode::Swc(3) => "swc3",
382 _ => unreachable!(),
383 }
384}
385
386fn format_load_store(f: &mut fmt::Formatter, instr: &Instruction) -> fmt::Result {
387 let opcode = instr.opcode;
388
389 let src = instr.rs();
390 let off = instr.imm16();
391 let dst = instr.rt();
392
393 write!(f, "{} {}, 0x{:04X}({})", opcode_str(opcode), dst, off, src)
394}
395
396fn format_alu(f: &mut fmt::Formatter, instr: &Instruction, imm: bool) -> fmt::Result {
397 let opcode = instr.opcode;
398
399 let (first, third) = if imm {
400 (instr.rt(), format!("0x{:04X}", instr.imm16()))
401 } else {
402 (instr.rd(), format!("{}", instr.rt()))
403 };
404
405 write!(
406 f,
407 "{} {}, {}, {}",
408 opcode_str(opcode),
409 first,
410 instr.rs(),
411 third
412 )
413}
414
415fn format_shift(f: &mut fmt::Formatter, instr: &Instruction, imm: bool) -> fmt::Result {
416 let opcode = instr.opcode;
417
418 let third = if imm {
419 format!("0x{:02X}", instr.imm5())
420 } else {
421 format!("{}", instr.rs())
422 };
423
424 write!(
425 f,
426 "{} {}, {}, {}",
427 opcode_str(opcode),
428 instr.rd(),
429 instr.rt(),
430 third
431 )
432}
433
434fn format_mult_div(f: &mut fmt::Formatter, instr: &Instruction) -> fmt::Result {
435 let opcode = instr.opcode;
436
437 write!(f, "{} {}, {}", opcode_str(opcode), instr.rs(), instr.rt())
438}
439
440fn format_branch(f: &mut fmt::Formatter, instr: &Instruction, rt: bool) -> fmt::Result {
441 let opcode = instr.opcode;
442
443 let dest = instr.imm16();
444
445 if rt {
446 write!(
447 f,
448 "{} {}, {}, 0x{:04X} => 0x{:08X}",
449 opcode_str(opcode),
450 instr.rs(),
451 instr.rt(),
452 dest,
453 instr
454 .pc
455 .wrapping_add((dest as i16 as i32 as u32).wrapping_mul(4))
456 .wrapping_add(4)
457 )
458 } else {
459 write!(
460 f,
461 "{} {}, 0x{:04X} => 0x{:08X}",
462 opcode_str(opcode),
463 instr.rs(),
464 dest,
465 instr
466 .pc
467 .wrapping_add((dest as i16 as i32 as u32).wrapping_mul(4))
468 .wrapping_add(4)
469 )
470 }
471}
472
473fn format_cop_ops(f: &mut fmt::Formatter, instr: &Instruction) -> fmt::Result {
474 let opcode = instr.opcode;
475
476 write!(f, "{} {}, {}", opcode_str(opcode), instr.rt(), instr.rd())
477}
478
479impl fmt::Display for Instruction {
480 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
481 match self.opcode {
482 Opcode::Lb
483 | Opcode::Lbu
484 | Opcode::Lh
485 | Opcode::Lhu
486 | Opcode::Lw
487 | Opcode::Lwl
488 | Opcode::Lwr
489 | Opcode::Sb
490 | Opcode::Sh
491 | Opcode::Sw
492 | Opcode::Swl
493 | Opcode::Swr => format_load_store(f, self),
494 Opcode::Slt | Opcode::Sltu => format_alu(f, self, false),
495 Opcode::Slti | Opcode::Sltiu => format_alu(f, self, true),
496 Opcode::Addu | Opcode::Add | Opcode::Subu | Opcode::Sub => format_alu(f, self, false),
497 Opcode::Addiu | Opcode::Addi => format_alu(f, self, true),
498 Opcode::And | Opcode::Or | Opcode::Xor | Opcode::Nor => format_alu(f, self, false),
499 Opcode::Andi | Opcode::Ori | Opcode::Xori => format_alu(f, self, true),
500 Opcode::Sllv | Opcode::Srlv | Opcode::Srav => format_shift(f, self, false),
501 Opcode::Sll | Opcode::Srl | Opcode::Sra => format_shift(f, self, true),
502 Opcode::Lui => write!(
503 f,
504 "{} {}, 0x{:04X}",
505 opcode_str(self.opcode),
506 self.rt(),
507 self.imm16()
508 ),
509 Opcode::Mult | Opcode::Multu | Opcode::Div | Opcode::Divu => format_mult_div(f, self),
510 Opcode::Mfhi => write!(f, "{} {}", opcode_str(self.opcode), self.rd()),
511 Opcode::Mthi => write!(f, "{} {}", opcode_str(self.opcode), self.rs()),
512 Opcode::Mflo => write!(f, "{} {}", opcode_str(self.opcode), self.rd()),
513 Opcode::Mtlo => write!(f, "{} {}", opcode_str(self.opcode), self.rs()),
514 Opcode::J => write!(
515 f,
516 "{} 0x{:07X} => 0x{:08X}",
517 opcode_str(self.opcode),
518 self.imm26(),
519 (self.pc & 0xF0000000) | (self.imm26() * 4)
520 ),
521 Opcode::Jal => write!(
522 f,
523 "{} 0x{:07X} => 0x{:08X}",
524 opcode_str(self.opcode),
525 self.imm26(),
526 (self.pc & 0xF0000000) | (self.imm26() * 4)
527 ),
528 Opcode::Jr => write!(f, "{} {}", opcode_str(self.opcode), self.rs()),
529 Opcode::Jalr => write!(
531 f,
532 "{} {}, {}",
533 opcode_str(self.opcode),
534 self.rs(),
535 self.rd()
536 ),
537 Opcode::Beq | Opcode::Bne => format_branch(f, self, true),
538 Opcode::Bgtz
539 | Opcode::Blez
540 | Opcode::Bltz
541 | Opcode::Bgez
542 | Opcode::Bltzal
543 | Opcode::Bgezal => format_branch(f, self, false),
544 Opcode::Nop | Opcode::Syscall | Opcode::Break | Opcode::Rfe => {
545 f.write_str(opcode_str(self.opcode))
546 }
547 Opcode::Cop(_) => write!(f, "{} 0x{:07X}", opcode_str(self.opcode), self.imm25()),
548 Opcode::Mfc(_) | Opcode::Cfc(_) | Opcode::Mtc(_) | Opcode::Ctc(_) => {
549 format_cop_ops(f, self)
550 }
551 Opcode::Bcf(_) => todo!(),
552 Opcode::Bct(_) => todo!(),
553 Opcode::Lwc(_) | Opcode::Swc(_) => format_load_store(f, self),
554 Opcode::Invalid => write!(f, "Invalid instruction"),
555 _ => unreachable!(),
556 }
557 }
558}