gcrecomp_core/recompiler/decoder.rs
1//! PowerPC Instruction Decoder
2//!
3//! This module provides comprehensive decoding of PowerPC instructions from 32-bit words.
4//! It extracts opcodes, instruction types, and operands, with aggressive memory optimization
5//! to minimize memory footprint (saving even single bits where possible).
6//!
7//! # Memory Optimizations
8//! - `InstructionType` uses `#[repr(u8)]` to save 3 bytes per enum (4 bytes -> 1 byte)
9//! - `Operand` uses `SmallVec` for most instructions (≤4 operands) to avoid heap allocation
10//! - Structs are packed to minimize padding
11//! - Register indices use `u8` (PowerPC has 32 GPRs, fits in 5 bits)
12//!
13//! # Decoding Algorithm
14//! The decoder uses a two-stage approach:
15//! 1. Extract primary opcode (bits 26-31)
16//! 2. For opcode 31 (extended), decode secondary opcode (bits 1-10)
17//!
18//! Most PowerPC instructions have 3-4 operands, making `SmallVec<[Operand; 4]>` optimal.
19
20use anyhow::{Context, Result};
21use smallvec::SmallVec;
22
23/// PowerPC instruction representation with optimized memory layout.
24///
25/// # Memory Layout
26/// - `opcode`: 6 bits (bits 26-31 of instruction word)
27/// - `instruction_type`: 1 byte (enum with `#[repr(u8)]`)
28/// - `operands`: SmallVec with inline capacity for 4 operands (most instructions have ≤4)
29#[derive(Debug, Clone)]
30#[repr(C)] // Ensure C-compatible layout for potential FFI
31pub struct Instruction {
32 /// Primary opcode (6 bits, stored as u32 for alignment but only uses 6 bits)
33 pub opcode: u32,
34 /// Instruction type category (1 byte enum)
35 pub instruction_type: InstructionType,
36 /// Instruction operands (register, immediate, address, etc.)
37 /// Uses SmallVec to avoid heap allocation for common case (≤4 operands)
38 pub operands: SmallVec<[Operand; 4]>,
39}
40
41/// PowerPC instruction type categories.
42///
43/// # Memory Optimization
44/// Uses `#[repr(u8)]` to reduce size from 4 bytes (default enum size) to 1 byte,
45/// saving 3 bytes per instruction. This is safe because we have <256 variants.
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
47#[repr(u8)] // Save 3 bytes per enum (4 bytes -> 1 byte)
48pub enum InstructionType {
49 /// Arithmetic operations (add, sub, mul, div, and, or, xor, etc.)
50 Arithmetic = 0,
51 /// Branch instructions (b, bl, bc, bclr, etc.)
52 Branch = 1,
53 /// Load instructions (lwz, lbz, lhz, etc.)
54 Load = 2,
55 /// Store instructions (stw, stb, sth, etc.)
56 Store = 3,
57 /// Compare instructions (cmpw, cmplw, cmpwi, etc.)
58 Compare = 4,
59 /// Move instructions (mr, mflr, mtlr, etc.)
60 Move = 5,
61 /// System instructions (sync, isync, cache control, etc.)
62 System = 6,
63 /// Floating-point operations (fadd, fsub, fmul, fdiv, etc.)
64 FloatingPoint = 7,
65 /// Condition register operations (mfcr, mtcr, crand, cror, etc.)
66 ConditionRegister = 8,
67 /// Shift operations (slw, srw, sraw, etc.)
68 Shift = 9,
69 /// Rotate operations (rlwinm, rlwnm, etc.)
70 Rotate = 10,
71 /// Unknown or unimplemented instruction
72 Unknown = 11,
73}
74
75/// PowerPC instruction operand representation.
76///
77/// # Memory Optimization
78/// Uses appropriate integer sizes:
79/// - Register indices: `u8` (PowerPC has 32 GPRs, fits in 5 bits)
80/// - Immediate values: `i16` for 16-bit immediates, `i32` for 32-bit
81/// - Addresses: `u32` (full 32-bit address space)
82/// - Special registers: `u16` (SPR encoding uses 10 bits)
83#[derive(Debug, Clone, Copy, PartialEq, Eq)]
84pub enum Operand {
85 /// General-purpose register (GPR) - 32 registers (r0-r31), stored as u8
86 Register(u8),
87 /// Floating-point register (FPR) - 32 registers (f0-f31), stored as u8
88 FpRegister(u8),
89 /// 16-bit signed immediate value (SI field in instruction)
90 Immediate(i16),
91 /// 32-bit signed immediate value (used for branch targets, etc.)
92 Immediate32(i32),
93 /// 32-bit address (absolute or relative)
94 Address(u32),
95 /// Condition register field (4 bits, stored as u8)
96 Condition(u8),
97 /// Special-purpose register (SPR) - 10-bit encoding, stored as u16
98 SpecialRegister(u16),
99 /// Shift amount (5 bits, stored as u8)
100 ShiftAmount(u8),
101 /// Rotate mask (32 bits, stored as u32)
102 Mask(u32),
103}
104
105/// Decoded PowerPC instruction with raw word and address for reference.
106///
107/// # Memory Layout
108/// Packed to minimize padding:
109/// - `instruction`: Contains opcode, type, and operands
110/// - `raw`: Original 32-bit instruction word
111/// - `address`: Memory address where this instruction is located (for function mapping)
112#[derive(Debug, Clone)]
113pub struct DecodedInstruction {
114 /// Decoded instruction structure
115 pub instruction: Instruction,
116 /// Raw 32-bit instruction word (for debugging and re-encoding)
117 pub raw: u32,
118 /// Memory address where this instruction is located in the original binary
119 /// Used for mapping instructions to functions and control flow analysis
120 pub address: u32,
121}
122
123impl Instruction {
124 /// Decode a 32-bit PowerPC instruction word into a structured representation.
125 ///
126 /// # Algorithm
127 /// 1. Extract primary opcode (bits 26-31)
128 /// 2. For opcode 31 (extended), extract secondary opcode (bits 1-10)
129 /// 3. Extract operands based on instruction format
130 /// 4. Return decoded instruction with type and operands
131 ///
132 /// # Arguments
133 /// * `word` - 32-bit instruction word in big-endian format
134 /// * `address` - Memory address where this instruction is located (for function mapping)
135 ///
136 /// # Returns
137 /// `Result<DecodedInstruction>` - Decoded instruction or error if invalid
138 ///
139 /// # Errors
140 /// Returns error if instruction cannot be decoded (invalid opcode, malformed format)
141 ///
142 /// # Examples
143 /// ```rust
144 /// // Decode an addi instruction: addi r3, r4, 42
145 /// let word: u32 = 0x3864002A; // addi r3, r4, 42
146 /// let address: u32 = 0x80000000;
147 /// let decoded = Instruction::decode(word, address)?;
148 /// assert_eq!(decoded.instruction.instruction_type, InstructionType::Arithmetic);
149 /// assert_eq!(decoded.address, address);
150 /// ```
151 #[inline] // Hot path - called for every instruction
152 pub fn decode(word: u32, address: u32) -> Result<DecodedInstruction> {
153 // Extract primary opcode (bits 26-31)
154 let opcode: u32 = (word >> 26) & 0x3F;
155
156 // Decode instruction type and operands based on opcode
157 let (instruction_type, operands): (InstructionType, SmallVec<[Operand; 4]>) = match opcode {
158 // Opcode 31: Extended opcodes (arithmetic, logical, shifts, etc.)
159 // Secondary opcode is in bits 1-10
160 31 => Self::decode_extended(word)?,
161
162 // Opcode 14: Add immediate (addi)
163 // Format: addi RT, RA, SI
164 // RT = bits 21-25, RA = bits 16-20, SI = bits 0-15 (sign-extended)
165 14 => {
166 let rt: u8 = ((word >> 21) & 0x1F) as u8;
167 let ra: u8 = ((word >> 16) & 0x1F) as u8;
168 let si: i16 = (word & 0xFFFF) as i16; // Sign-extend handled by cast
169 (
170 InstructionType::Arithmetic,
171 SmallVec::from_slice(&[
172 Operand::Register(rt),
173 Operand::Register(ra),
174 Operand::Immediate(si),
175 ]),
176 )
177 }
178
179 // Opcode 15: Subtract from immediate (subfic)
180 // Format: subfic RT, RA, SI
181 15 => {
182 let rt: u8 = ((word >> 21) & 0x1F) as u8;
183 let ra: u8 = ((word >> 16) & 0x1F) as u8;
184 let si: i16 = (word & 0xFFFF) as i16;
185 (
186 InstructionType::Arithmetic,
187 SmallVec::from_slice(&[
188 Operand::Register(rt),
189 Operand::Register(ra),
190 Operand::Immediate(si),
191 ]),
192 )
193 }
194
195 // Opcode 32: Load word and zero (lwz)
196 // Format: lwz RT, D(RA)
197 // RT = bits 21-25, RA = bits 16-20, D = bits 0-15 (sign-extended offset)
198 32 => {
199 let rt: u8 = ((word >> 21) & 0x1F) as u8;
200 let ra: u8 = ((word >> 16) & 0x1F) as u8;
201 let d: i16 = (word & 0xFFFF) as i16;
202 (
203 InstructionType::Load,
204 SmallVec::from_slice(&[
205 Operand::Register(rt),
206 Operand::Register(ra),
207 Operand::Immediate(d),
208 ]),
209 )
210 }
211
212 // Opcode 36: Store word (stw)
213 // Format: stw RS, D(RA)
214 36 => {
215 let rs: u8 = ((word >> 21) & 0x1F) as u8;
216 let ra: u8 = ((word >> 16) & 0x1F) as u8;
217 let d: i16 = (word & 0xFFFF) as i16;
218 (
219 InstructionType::Store,
220 SmallVec::from_slice(&[
221 Operand::Register(rs),
222 Operand::Register(ra),
223 Operand::Immediate(d),
224 ]),
225 )
226 }
227
228 // Opcode 18: Branch (b, ba, bl, bla)
229 // Format: b LI, AA, LK
230 // LI = bits 0-23 (24-bit signed offset, aligned to 4 bytes)
231 // AA = bit 1 (absolute address flag)
232 // LK = bit 0 (link flag - save return address)
233 18 => {
234 let li: i32 = ((word & 0x3FFFFFC) as i32) >> 2; // Sign-extend and align
235 let aa: u8 = ((word >> 1) & 1) as u8;
236 let lk: u8 = (word & 1) as u8;
237 (
238 InstructionType::Branch,
239 SmallVec::from_slice(&[
240 Operand::Immediate32(li),
241 Operand::Immediate(aa as i16),
242 Operand::Immediate(lk as i16),
243 ]),
244 )
245 }
246
247 // Opcode 16: Branch conditional (bc, bca, bcl, bcla)
248 // Format: bc BO, BI, BD, AA, LK
249 // BO = bits 21-25 (branch options)
250 // BI = bits 16-20 (condition register bit)
251 // BD = bits 2-15 (14-bit signed branch displacement)
252 // AA = bit 1 (absolute address flag)
253 // LK = bit 0 (link flag)
254 16 => {
255 let bo: u8 = ((word >> 21) & 0x1F) as u8;
256 let bi: u8 = ((word >> 16) & 0x1F) as u8;
257 let bd: i16 = ((word & 0xFFFC) as i16) >> 2; // Sign-extend and align
258 let aa: u8 = ((word >> 1) & 1) as u8;
259 let lk: u8 = (word & 1) as u8;
260 (
261 InstructionType::Branch,
262 SmallVec::from_slice(&[
263 Operand::Condition(bo),
264 Operand::Condition(bi),
265 Operand::Immediate32(bd as i32),
266 Operand::Immediate(aa as i16),
267 Operand::Immediate(lk as i16),
268 ]),
269 )
270 }
271
272 // Opcode 11: Compare word immediate (cmpwi)
273 // Format: cmpwi BF, RA, SI
274 // BF = bits 23-25 (condition register field)
275 // RA = bits 16-20
276 // SI = bits 0-15 (sign-extended)
277 11 => {
278 let bf: u8 = ((word >> 23) & 0x7) as u8;
279 let ra: u8 = ((word >> 16) & 0x1F) as u8;
280 let si: i16 = (word & 0xFFFF) as i16;
281 (
282 InstructionType::Compare,
283 SmallVec::from_slice(&[
284 Operand::Condition(bf),
285 Operand::Register(ra),
286 Operand::Immediate(si),
287 ]),
288 )
289 }
290
291 // Opcode 10: Compare logical word immediate (cmplwi)
292 // Format: cmplwi BF, RA, UI
293 // UI = bits 0-15 (unsigned immediate)
294 10 => {
295 let bf: u8 = ((word >> 23) & 0x7) as u8;
296 let ra: u8 = ((word >> 16) & 0x1F) as u8;
297 let ui: u16 = (word & 0xFFFF) as u16;
298 (
299 InstructionType::Compare,
300 SmallVec::from_slice(&[
301 Operand::Condition(bf),
302 Operand::Register(ra),
303 Operand::Immediate(ui as i16), // Store as i16 for consistency
304 ]),
305 )
306 }
307
308 // Opcode 28: AND immediate (andi.)
309 // Format: andi. RT, RA, UI
310 28 => {
311 let rs: u8 = ((word >> 21) & 0x1F) as u8;
312 let ra: u8 = ((word >> 16) & 0x1F) as u8;
313 let ui: u16 = (word & 0xFFFF) as u16;
314 (
315 InstructionType::Arithmetic,
316 SmallVec::from_slice(&[
317 Operand::Register(rs),
318 Operand::Register(ra),
319 Operand::Immediate(ui as i16),
320 ]),
321 )
322 }
323
324 // Opcode 24: OR immediate (ori)
325 // Format: ori RT, RA, UI
326 24 => {
327 let rs: u8 = ((word >> 21) & 0x1F) as u8;
328 let ra: u8 = ((word >> 16) & 0x1F) as u8;
329 let ui: u16 = (word & 0xFFFF) as u16;
330 (
331 InstructionType::Arithmetic,
332 SmallVec::from_slice(&[
333 Operand::Register(rs),
334 Operand::Register(ra),
335 Operand::Immediate(ui as i16),
336 ]),
337 )
338 }
339
340 // Opcode 26: XOR immediate (xori)
341 // Format: xori RT, RA, UI
342 26 => {
343 let rs: u8 = ((word >> 21) & 0x1F) as u8;
344 let ra: u8 = ((word >> 16) & 0x1F) as u8;
345 let ui: u16 = (word & 0xFFFF) as u16;
346 (
347 InstructionType::Arithmetic,
348 SmallVec::from_slice(&[
349 Operand::Register(rs),
350 Operand::Register(ra),
351 Operand::Immediate(ui as i16),
352 ]),
353 )
354 }
355
356 // Opcode 34: Load byte and zero (lbz)
357 // Format: lbz RT, D(RA)
358 34 => {
359 let rt: u8 = ((word >> 21) & 0x1F) as u8;
360 let ra: u8 = ((word >> 16) & 0x1F) as u8;
361 let d: i16 = (word & 0xFFFF) as i16;
362 (
363 InstructionType::Load,
364 SmallVec::from_slice(&[
365 Operand::Register(rt),
366 Operand::Register(ra),
367 Operand::Immediate(d),
368 ]),
369 )
370 }
371
372 // Opcode 40: Load halfword and zero (lhz)
373 // Format: lhz RT, D(RA)
374 40 => {
375 let rt: u8 = ((word >> 21) & 0x1F) as u8;
376 let ra: u8 = ((word >> 16) & 0x1F) as u8;
377 let d: i16 = (word & 0xFFFF) as i16;
378 (
379 InstructionType::Load,
380 SmallVec::from_slice(&[
381 Operand::Register(rt),
382 Operand::Register(ra),
383 Operand::Immediate(d),
384 ]),
385 )
386 }
387
388 // Opcode 42: Load halfword algebraic (lha)
389 // Format: lha RT, D(RA)
390 42 => {
391 let rt: u8 = ((word >> 21) & 0x1F) as u8;
392 let ra: u8 = ((word >> 16) & 0x1F) as u8;
393 let d: i16 = (word & 0xFFFF) as i16;
394 (
395 InstructionType::Load,
396 SmallVec::from_slice(&[
397 Operand::Register(rt),
398 Operand::Register(ra),
399 Operand::Immediate(d),
400 ]),
401 )
402 }
403
404 // Opcode 38: Store byte (stb)
405 // Format: stb RS, D(RA)
406 38 => {
407 let rs: u8 = ((word >> 21) & 0x1F) as u8;
408 let ra: u8 = ((word >> 16) & 0x1F) as u8;
409 let d: i16 = (word & 0xFFFF) as i16;
410 (
411 InstructionType::Store,
412 SmallVec::from_slice(&[
413 Operand::Register(rs),
414 Operand::Register(ra),
415 Operand::Immediate(d),
416 ]),
417 )
418 }
419
420 // Opcode 44: Store halfword (sth)
421 // Format: sth RS, D(RA)
422 44 => {
423 let rs: u8 = ((word >> 21) & 0x1F) as u8;
424 let ra: u8 = ((word >> 16) & 0x1F) as u8;
425 let d: i16 = (word & 0xFFFF) as i16;
426 (
427 InstructionType::Store,
428 SmallVec::from_slice(&[
429 Operand::Register(rs),
430 Operand::Register(ra),
431 Operand::Immediate(d),
432 ]),
433 )
434 }
435
436 // Opcode 33: Load word with update (lwzu)
437 // Format: lwzu RT, D(RA) - updates RA with effective address
438 33 => {
439 let rt: u8 = ((word >> 21) & 0x1F) as u8;
440 let ra: u8 = ((word >> 16) & 0x1F) as u8;
441 let d: i16 = (word & 0xFFFF) as i16;
442 (
443 InstructionType::Load,
444 SmallVec::from_slice(&[
445 Operand::Register(rt),
446 Operand::Register(ra),
447 Operand::Immediate(d),
448 ]),
449 )
450 }
451
452 // Opcode 37: Store word with update (stwu)
453 // Format: stwu RS, D(RA) - updates RA with effective address
454 37 => {
455 let rs: u8 = ((word >> 21) & 0x1F) as u8;
456 let ra: u8 = ((word >> 16) & 0x1F) as u8;
457 let d: i16 = (word & 0xFFFF) as i16;
458 (
459 InstructionType::Store,
460 SmallVec::from_slice(&[
461 Operand::Register(rs),
462 Operand::Register(ra),
463 Operand::Immediate(d),
464 ]),
465 )
466 }
467
468 // Opcode 48: Floating-point load single (lfs)
469 // Format: lfs FRT, D(RA)
470 48 => {
471 let frt: u8 = ((word >> 21) & 0x1F) as u8;
472 let ra: u8 = ((word >> 16) & 0x1F) as u8;
473 let d: i16 = (word & 0xFFFF) as i16;
474 (
475 InstructionType::FloatingPoint,
476 SmallVec::from_slice(&[
477 Operand::FpRegister(frt),
478 Operand::Register(ra),
479 Operand::Immediate(d),
480 ]),
481 )
482 }
483
484 // Opcode 50: Floating-point load double (lfd)
485 // Format: lfd FRT, D(RA)
486 50 => {
487 let frt: u8 = ((word >> 21) & 0x1F) as u8;
488 let ra: u8 = ((word >> 16) & 0x1F) as u8;
489 let d: i16 = (word & 0xFFFF) as i16;
490 (
491 InstructionType::FloatingPoint,
492 SmallVec::from_slice(&[
493 Operand::FpRegister(frt),
494 Operand::Register(ra),
495 Operand::Immediate(d),
496 ]),
497 )
498 }
499
500 // Opcode 52: Floating-point store single (stfs)
501 // Format: stfs FRS, D(RA)
502 52 => {
503 let frs: u8 = ((word >> 21) & 0x1F) as u8;
504 let ra: u8 = ((word >> 16) & 0x1F) as u8;
505 let d: i16 = (word & 0xFFFF) as i16;
506 (
507 InstructionType::FloatingPoint,
508 SmallVec::from_slice(&[
509 Operand::FpRegister(frs),
510 Operand::Register(ra),
511 Operand::Immediate(d),
512 ]),
513 )
514 }
515
516 // Opcode 54: Floating-point store double (stfd)
517 // Format: stfd FRS, D(RA)
518 54 => {
519 let frs: u8 = ((word >> 21) & 0x1F) as u8;
520 let ra: u8 = ((word >> 16) & 0x1F) as u8;
521 let d: i16 = (word & 0xFFFF) as i16;
522 (
523 InstructionType::FloatingPoint,
524 SmallVec::from_slice(&[
525 Operand::FpRegister(frs),
526 Operand::Register(ra),
527 Operand::Immediate(d),
528 ]),
529 )
530 }
531
532 // Opcode 35: Load byte with update (lbzu)
533 // Format: lbzu RT, D(RA) - updates RA with effective address
534 35 => {
535 let rt: u8 = ((word >> 21) & 0x1F) as u8;
536 let ra: u8 = ((word >> 16) & 0x1F) as u8;
537 let d: i16 = (word & 0xFFFF) as i16;
538 (
539 InstructionType::Load,
540 SmallVec::from_slice(&[
541 Operand::Register(rt),
542 Operand::Register(ra),
543 Operand::Immediate(d),
544 ]),
545 )
546 }
547
548 // Opcode 41: Load halfword with update (lhzu)
549 // Format: lhzu RT, D(RA) - updates RA with effective address
550 41 => {
551 let rt: u8 = ((word >> 21) & 0x1F) as u8;
552 let ra: u8 = ((word >> 16) & 0x1F) as u8;
553 let d: i16 = (word & 0xFFFF) as i16;
554 (
555 InstructionType::Load,
556 SmallVec::from_slice(&[
557 Operand::Register(rt),
558 Operand::Register(ra),
559 Operand::Immediate(d),
560 ]),
561 )
562 }
563
564 // Opcode 43: Load halfword algebraic with update (lhau)
565 // Format: lhau RT, D(RA) - updates RA with effective address
566 43 => {
567 let rt: u8 = ((word >> 21) & 0x1F) as u8;
568 let ra: u8 = ((word >> 16) & 0x1F) as u8;
569 let d: i16 = (word & 0xFFFF) as i16;
570 (
571 InstructionType::Load,
572 SmallVec::from_slice(&[
573 Operand::Register(rt),
574 Operand::Register(ra),
575 Operand::Immediate(d),
576 ]),
577 )
578 }
579
580 // Opcode 39: Store byte with update (stbu)
581 // Format: stbu RS, D(RA) - updates RA with effective address
582 39 => {
583 let rs: u8 = ((word >> 21) & 0x1F) as u8;
584 let ra: u8 = ((word >> 16) & 0x1F) as u8;
585 let d: i16 = (word & 0xFFFF) as i16;
586 (
587 InstructionType::Store,
588 SmallVec::from_slice(&[
589 Operand::Register(rs),
590 Operand::Register(ra),
591 Operand::Immediate(d),
592 ]),
593 )
594 }
595
596 // Opcode 45: Store halfword with update (sthu)
597 // Format: sthu RS, D(RA) - updates RA with effective address
598 45 => {
599 let rs: u8 = ((word >> 21) & 0x1F) as u8;
600 let ra: u8 = ((word >> 16) & 0x1F) as u8;
601 let d: i16 = (word & 0xFFFF) as i16;
602 (
603 InstructionType::Store,
604 SmallVec::from_slice(&[
605 Operand::Register(rs),
606 Operand::Register(ra),
607 Operand::Immediate(d),
608 ]),
609 )
610 }
611
612 // Opcode 49: Floating-point load single with update (lfsu)
613 // Format: lfsu FRT, D(RA) - updates RA with effective address
614 49 => {
615 let frt: u8 = ((word >> 21) & 0x1F) as u8;
616 let ra: u8 = ((word >> 16) & 0x1F) as u8;
617 let d: i16 = (word & 0xFFFF) as i16;
618 (
619 InstructionType::FloatingPoint,
620 SmallVec::from_slice(&[
621 Operand::FpRegister(frt),
622 Operand::Register(ra),
623 Operand::Immediate(d),
624 ]),
625 )
626 }
627
628 // Opcode 51: Floating-point load double with update (lfdu)
629 // Format: lfdu FRT, D(RA) - updates RA with effective address
630 51 => {
631 let frt: u8 = ((word >> 21) & 0x1F) as u8;
632 let ra: u8 = ((word >> 16) & 0x1F) as u8;
633 let d: i16 = (word & 0xFFFF) as i16;
634 (
635 InstructionType::FloatingPoint,
636 SmallVec::from_slice(&[
637 Operand::FpRegister(frt),
638 Operand::Register(ra),
639 Operand::Immediate(d),
640 ]),
641 )
642 }
643
644 // Opcode 53: Floating-point store single with update (stfsu)
645 // Format: stfsu FRS, D(RA) - updates RA with effective address
646 53 => {
647 let frs: u8 = ((word >> 21) & 0x1F) as u8;
648 let ra: u8 = ((word >> 16) & 0x1F) as u8;
649 let d: i16 = (word & 0xFFFF) as i16;
650 (
651 InstructionType::FloatingPoint,
652 SmallVec::from_slice(&[
653 Operand::FpRegister(frs),
654 Operand::Register(ra),
655 Operand::Immediate(d),
656 ]),
657 )
658 }
659
660 // Opcode 55: Floating-point store double with update (stfdu)
661 // Format: stfdu FRS, D(RA) - updates RA with effective address
662 55 => {
663 let frs: u8 = ((word >> 21) & 0x1F) as u8;
664 let ra: u8 = ((word >> 16) & 0x1F) as u8;
665 let d: i16 = (word & 0xFFFF) as i16;
666 (
667 InstructionType::FloatingPoint,
668 SmallVec::from_slice(&[
669 Operand::FpRegister(frs),
670 Operand::Register(ra),
671 Operand::Immediate(d),
672 ]),
673 )
674 }
675
676 // Opcode 0: Illegal instruction (trap)
677 // Format: trap - causes system trap
678 0 => (InstructionType::System, SmallVec::new()),
679
680 // Opcode 1: Trap word immediate (twi)
681 // Format: twi TO, RA, SI
682 // TO = bits 6-10 (trap conditions), RA = bits 16-20, SI = bits 0-15
683 1 => {
684 let to: u8 = ((word >> 6) & 0x1F) as u8;
685 let ra: u8 = ((word >> 16) & 0x1F) as u8;
686 let si: i16 = (word & 0xFFFF) as i16;
687 (
688 InstructionType::System,
689 SmallVec::from_slice(&[
690 Operand::Condition(to),
691 Operand::Register(ra),
692 Operand::Immediate(si),
693 ]),
694 )
695 }
696
697 // Opcode 2: Multiply low immediate (mulli)
698 // Format: mulli RT, RA, SI
699 2 => {
700 let rt: u8 = ((word >> 21) & 0x1F) as u8;
701 let ra: u8 = ((word >> 16) & 0x1F) as u8;
702 let si: i16 = (word & 0xFFFF) as i16;
703 (
704 InstructionType::Arithmetic,
705 SmallVec::from_slice(&[
706 Operand::Register(rt),
707 Operand::Register(ra),
708 Operand::Immediate(si),
709 ]),
710 )
711 }
712
713 // Opcode 3: Subtract from immediate carrying (subfic)
714 // Already implemented as opcode 15, but opcode 3 is also used for some variants
715 // Opcode 3: Load word algebraic (lwa) - 64-bit only, not on GameCube
716 // For GameCube compatibility, treat as unknown or similar to lwz
717 3 => {
718 // On GameCube, this might be used differently, but we'll decode it as load
719 let rt: u8 = ((word >> 21) & 0x1F) as u8;
720 let ra: u8 = ((word >> 16) & 0x1F) as u8;
721 let d: i16 = (word & 0xFFFF) as i16;
722 (
723 InstructionType::Load,
724 SmallVec::from_slice(&[
725 Operand::Register(rt),
726 Operand::Register(ra),
727 Operand::Immediate(d),
728 ]),
729 )
730 }
731
732 // Opcode 4: Add carrying (addc)
733 // Format: addc RT, RA, RB - handled in extended opcodes
734 // Opcode 4: Load word and reserve indexed (lwarx) - extended opcode
735 // For primary opcode 4, treat as reserved/unknown on 32-bit
736 4 => (InstructionType::Unknown, SmallVec::new()),
737
738 // Opcode 5: Subtract from carrying (subfc)
739 // Format: subfc RT, RA, RB - handled in extended opcodes
740 // Opcode 5: Store word conditional indexed (stwcx.) - extended opcode
741 // For primary opcode 5, treat as reserved/unknown on 32-bit
742 5 => (InstructionType::Unknown, SmallVec::new()),
743
744 // Opcode 6: Add extended (adde)
745 // Format: adde RT, RA, RB - handled in extended opcodes
746 // Opcode 6: Load double word (ld) - 64-bit only, not on GameCube
747 6 => (InstructionType::Unknown, SmallVec::new()),
748
749 // Opcode 7: Subtract from extended (subfe)
750 // Format: subfe RT, RA, RB - handled in extended opcodes
751 // Opcode 7: Store double word (std) - 64-bit only, not on GameCube
752 7 => (InstructionType::Unknown, SmallVec::new()),
753
754 // Opcode 8: Add extended carrying (addze)
755 // Format: addze RT, RA - handled in extended opcodes
756 // Opcode 8: Load floating-point as integer word (lfq) - not on GameCube
757 8 => (InstructionType::Unknown, SmallVec::new()),
758
759 // Opcode 9: Subtract from extended zero (subfze)
760 // Format: subfze RT, RA - handled in extended opcodes
761 // Opcode 9: Store floating-point as integer word (stfq) - not on GameCube
762 9 => (InstructionType::Unknown, SmallVec::new()),
763
764 // Opcode 10: Compare logical word immediate (cmplwi) - already implemented above
765
766 // Opcode 11: Compare word immediate (cmpwi) - already implemented above
767
768 // Opcode 12: Add immediate shifted (addis)
769 // Format: addis RT, RA, SI
770 12 => {
771 let rt: u8 = ((word >> 21) & 0x1F) as u8;
772 let ra: u8 = ((word >> 16) & 0x1F) as u8;
773 let si: i16 = (word & 0xFFFF) as i16;
774 (
775 InstructionType::Arithmetic,
776 SmallVec::from_slice(&[
777 Operand::Register(rt),
778 Operand::Register(ra),
779 Operand::Immediate(si),
780 ]),
781 )
782 }
783
784 // Opcode 13: Compare immediate (cmpi)
785 // Format: cmpi BF, L, RA, SI
786 // BF = bits 23-25, L = bit 21, RA = bits 16-20, SI = bits 0-15
787 13 => {
788 let bf: u8 = ((word >> 23) & 0x7) as u8;
789 let l: u8 = ((word >> 21) & 1) as u8;
790 let ra: u8 = ((word >> 16) & 0x1F) as u8;
791 let si: i16 = (word & 0xFFFF) as i16;
792 (
793 InstructionType::Compare,
794 SmallVec::from_slice(&[
795 Operand::Condition(bf),
796 Operand::Immediate(l as i16),
797 Operand::Register(ra),
798 Operand::Immediate(si),
799 ]),
800 )
801 }
802
803 // Opcode 14: Add immediate (addi) - already implemented above
804
805 // Opcode 15: Subtract from immediate (subfic) - already implemented above
806
807 // Opcode 16: Branch conditional (bc) - already implemented above
808
809 // Opcode 17: Sc (system call) - not typically used on GameCube
810 17 => (InstructionType::System, SmallVec::new()),
811
812 // Opcode 18: Branch (b) - already implemented above
813
814 // Opcode 19: Branch conditional to count register (bcctr)
815 // Format: bcctr BO, BI, LK
816 // BO = bits 21-25, BI = bits 16-20, LK = bit 0
817 19 => {
818 let bo: u8 = ((word >> 21) & 0x1F) as u8;
819 let bi: u8 = ((word >> 16) & 0x1F) as u8;
820 let lk: u8 = (word & 1) as u8;
821 (
822 InstructionType::Branch,
823 SmallVec::from_slice(&[
824 Operand::Condition(bo),
825 Operand::Condition(bi),
826 Operand::Immediate(lk as i16),
827 ]),
828 )
829 }
830
831 // Opcode 20: Rotate left word immediate then AND with mask (rlwimi)
832 // Format: rlwimi RA, RS, SH, MB, ME
833 // Handled in extended opcodes, but primary opcode 20 is also used
834 20 => {
835 let rs: u8 = ((word >> 21) & 0x1F) as u8;
836 let ra: u8 = ((word >> 16) & 0x1F) as u8;
837 let sh: u8 = ((word >> 11) & 0x1F) as u8;
838 let mb: u8 = ((word >> 6) & 0x1F) as u8;
839 let me: u8 = (word & 0x1F) as u8;
840 let mask: u32 = compute_mask(mb, me);
841 (
842 InstructionType::Rotate,
843 SmallVec::from_slice(&[
844 Operand::Register(rs),
845 Operand::Register(ra),
846 Operand::ShiftAmount(sh),
847 Operand::Mask(mask),
848 ]),
849 )
850 }
851
852 // Opcode 21: Rotate left word immediate then AND with mask (rlwinm)
853 // Format: rlwinm RA, RS, SH, MB, ME
854 21 => {
855 let rs: u8 = ((word >> 21) & 0x1F) as u8;
856 let ra: u8 = ((word >> 16) & 0x1F) as u8;
857 let sh: u8 = ((word >> 11) & 0x1F) as u8;
858 let mb: u8 = ((word >> 6) & 0x1F) as u8;
859 let me: u8 = (word & 0x1F) as u8;
860 let mask: u32 = compute_mask(mb, me);
861 (
862 InstructionType::Rotate,
863 SmallVec::from_slice(&[
864 Operand::Register(rs),
865 Operand::Register(ra),
866 Operand::ShiftAmount(sh),
867 Operand::Mask(mask),
868 ]),
869 )
870 }
871
872 // Opcode 22: Rotate left word then AND with mask (rlwnm)
873 // Format: rlwnm RA, RS, RB, MB, ME
874 // Handled in extended opcodes
875 22 => {
876 let rs: u8 = ((word >> 21) & 0x1F) as u8;
877 let ra: u8 = ((word >> 16) & 0x1F) as u8;
878 let rb: u8 = ((word >> 11) & 0x1F) as u8;
879 let mb: u8 = ((word >> 6) & 0x1F) as u8;
880 let me: u8 = (word & 0x1F) as u8;
881 let mask: u32 = compute_mask(mb, me);
882 (
883 InstructionType::Rotate,
884 SmallVec::from_slice(&[
885 Operand::Register(rs),
886 Operand::Register(ra),
887 Operand::Register(rb),
888 Operand::Mask(mask),
889 ]),
890 )
891 }
892
893 // Opcode 23: Rotate left word immediate then OR immediate (rlwimi)
894 // Format: rlwimi RA, RS, SH, MB, ME
895 // Similar to opcode 20, but with OR semantics
896 23 => {
897 let rs: u8 = ((word >> 21) & 0x1F) as u8;
898 let ra: u8 = ((word >> 16) & 0x1F) as u8;
899 let sh: u8 = ((word >> 11) & 0x1F) as u8;
900 let mb: u8 = ((word >> 6) & 0x1F) as u8;
901 let me: u8 = (word & 0x1F) as u8;
902 let mask: u32 = compute_mask(mb, me);
903 (
904 InstructionType::Rotate,
905 SmallVec::from_slice(&[
906 Operand::Register(rs),
907 Operand::Register(ra),
908 Operand::ShiftAmount(sh),
909 Operand::Mask(mask),
910 ]),
911 )
912 }
913
914 // Opcode 24: OR immediate (ori) - already implemented above
915
916 // Opcode 25: OR immediate shifted (oris)
917 // Format: oris RT, RA, UI
918 25 => {
919 let rt: u8 = ((word >> 21) & 0x1F) as u8;
920 let ra: u8 = ((word >> 16) & 0x1F) as u8;
921 let ui: u16 = (word & 0xFFFF) as u16;
922 (
923 InstructionType::Arithmetic,
924 SmallVec::from_slice(&[
925 Operand::Register(rt),
926 Operand::Register(ra),
927 Operand::Immediate(ui as i16),
928 ]),
929 )
930 }
931
932 // Opcode 26: XOR immediate (xori) - already implemented above
933
934 // Opcode 27: XOR immediate shifted (xoris)
935 // Format: xoris RT, RA, UI
936 27 => {
937 let rt: u8 = ((word >> 21) & 0x1F) as u8;
938 let ra: u8 = ((word >> 16) & 0x1F) as u8;
939 let ui: u16 = (word & 0xFFFF) as u16;
940 (
941 InstructionType::Arithmetic,
942 SmallVec::from_slice(&[
943 Operand::Register(rt),
944 Operand::Register(ra),
945 Operand::Immediate(ui as i16),
946 ]),
947 )
948 }
949
950 // Opcode 28: AND immediate (andi.) - already implemented above
951
952 // Opcode 29: AND immediate shifted (andis.)
953 // Format: andis. RT, RA, UI
954 29 => {
955 let rt: u8 = ((word >> 21) & 0x1F) as u8;
956 let ra: u8 = ((word >> 16) & 0x1F) as u8;
957 let ui: u16 = (word & 0xFFFF) as u16;
958 (
959 InstructionType::Arithmetic,
960 SmallVec::from_slice(&[
961 Operand::Register(rt),
962 Operand::Register(ra),
963 Operand::Immediate(ui as i16),
964 ]),
965 )
966 }
967
968 // Opcode 30: Load word and reserve (lwarx)
969 // Format: lwarx RT, RA, RB
970 // Handled in extended opcodes, but primary opcode 30 is reserved
971 30 => (InstructionType::Unknown, SmallVec::new()),
972
973 // Opcode 31: Extended opcodes - already handled above
974
975 // Opcode 32: Load word and zero (lwz) - already implemented above
976
977 // Opcode 33: Load word with update (lwzu) - already implemented above
978
979 // Opcode 34: Load byte and zero (lbz) - already implemented above
980
981 // Opcode 35: Load byte with update (lbzu) - already implemented above
982
983 // Opcode 36: Store word (stw) - already implemented above
984
985 // Opcode 37: Store word with update (stwu) - already implemented above
986
987 // Opcode 38: Store byte (stb) - already implemented above
988
989 // Opcode 39: Store byte with update (stbu) - already implemented above
990
991 // Opcode 40: Load halfword and zero (lhz) - already implemented above
992
993 // Opcode 41: Load halfword with update (lhzu) - already implemented above
994
995 // Opcode 42: Load halfword algebraic (lha) - already implemented above
996
997 // Opcode 43: Load halfword algebraic with update (lhau) - already implemented above
998
999 // Opcode 44: Store halfword (sth) - already implemented above
1000
1001 // Opcode 45: Store halfword with update (sthu) - already implemented above
1002
1003 // Opcode 46: Load multiple word (lmw)
1004 // Format: lmw RT, D(RA)
1005 46 => {
1006 let rt: u8 = ((word >> 21) & 0x1F) as u8;
1007 let ra: u8 = ((word >> 16) & 0x1F) as u8;
1008 let d: i16 = (word & 0xFFFF) as i16;
1009 (
1010 InstructionType::Load,
1011 SmallVec::from_slice(&[
1012 Operand::Register(rt),
1013 Operand::Register(ra),
1014 Operand::Immediate(d),
1015 ]),
1016 )
1017 }
1018
1019 // Opcode 47: Store multiple word (stmw)
1020 // Format: stmw RS, D(RA)
1021 47 => {
1022 let rs: u8 = ((word >> 21) & 0x1F) as u8;
1023 let ra: u8 = ((word >> 16) & 0x1F) as u8;
1024 let d: i16 = (word & 0xFFFF) as i16;
1025 (
1026 InstructionType::Store,
1027 SmallVec::from_slice(&[
1028 Operand::Register(rs),
1029 Operand::Register(ra),
1030 Operand::Immediate(d),
1031 ]),
1032 )
1033 }
1034
1035 // Opcode 48: Floating-point load single (lfs) - already implemented above
1036
1037 // Opcode 49: Floating-point load single with update (lfsu) - already implemented above
1038
1039 // Opcode 50: Floating-point load double (lfd) - already implemented above
1040
1041 // Opcode 51: Floating-point load double with update (lfdu) - already implemented above
1042
1043 // Opcode 52: Floating-point store single (stfs) - already implemented above
1044
1045 // Opcode 53: Floating-point store single with update (stfsu) - already implemented above
1046
1047 // Opcode 54: Floating-point store double (stfd) - already implemented above
1048
1049 // Opcode 55: Floating-point store double with update (stfdu) - already implemented above
1050
1051 // Opcode 56: Load floating-point as integer word (lfiwax)
1052 // Format: lfiwax FRT, RA, RB
1053 // Handled in extended opcodes
1054 56 => (InstructionType::Unknown, SmallVec::new()),
1055
1056 // Opcode 57: Load floating-point as integer word zero (lfiwzx)
1057 // Format: lfiwzx FRT, RA, RB
1058 // Handled in extended opcodes
1059 57 => (InstructionType::Unknown, SmallVec::new()),
1060
1061 // Opcode 58: Store floating-point as integer word (stfiwx)
1062 // Format: stfiwx FRS, RA, RB
1063 // Handled in extended opcodes
1064 58 => (InstructionType::Unknown, SmallVec::new()),
1065
1066 // Opcode 59: Floating-point operations (primary opcode 59)
1067 // Format: Various floating-point instructions
1068 // Handled in extended opcodes (opcode 63)
1069 59 => (InstructionType::Unknown, SmallVec::new()),
1070
1071 // Opcode 60: Floating-point operations (primary opcode 60)
1072 // Format: Various floating-point instructions
1073 // Handled in extended opcodes (opcode 63)
1074 60 => (InstructionType::Unknown, SmallVec::new()),
1075
1076 // Opcode 61: Floating-point operations (primary opcode 61)
1077 // Format: Various floating-point instructions
1078 // Handled in extended opcodes (opcode 63)
1079 61 => (InstructionType::Unknown, SmallVec::new()),
1080
1081 // Opcode 62: Floating-point operations (primary opcode 62)
1082 // Format: Various floating-point instructions
1083 // Handled in extended opcodes (opcode 63)
1084 62 => (InstructionType::Unknown, SmallVec::new()),
1085
1086 // Opcode 63: Floating-point operations
1087 // Format: Various floating-point instructions (fadd, fsub, fmul, fdiv, etc.)
1088 // Handled in extended opcodes
1089 63 => Self::decode_extended(word)?,
1090
1091 // Opcode 31 with specific patterns for move instructions
1092 // Move from link register (mflr) - extended opcode 8
1093 31 if ((word >> 21) & 0x1F) == 8 && (word & 0x7FF) == 0 => {
1094 let rt: u8 = ((word >> 21) & 0x1F) as u8;
1095 (
1096 InstructionType::Move,
1097 SmallVec::from_slice(&[Operand::Register(rt)]),
1098 )
1099 }
1100 // Move to link register (mtlr) - extended opcode 9
1101 31 if ((word >> 21) & 0x1F) == 9 && (word & 0x7FF) == 0 => {
1102 let rs: u8 = ((word >> 21) & 0x1F) as u8;
1103 (
1104 InstructionType::Move,
1105 SmallVec::from_slice(&[Operand::Register(rs)]),
1106 )
1107 }
1108 // Move from count register (mfctr) - extended opcode 9, sub-opcode 9
1109 31 if ((word >> 21) & 0x1F) == 9 && ((word >> 11) & 0x1F) == 9 && (word & 0x7FF) == 0 => {
1110 let rt: u8 = ((word >> 21) & 0x1F) as u8;
1111 (
1112 InstructionType::Move,
1113 SmallVec::from_slice(&[Operand::Register(rt)]),
1114 )
1115 }
1116 // Move to count register (mtctr) - extended opcode 9, sub-opcode 9
1117 31 if ((word >> 21) & 0x1F) == 9 && ((word >> 11) & 0x1F) == 9 && (word & 0x7FF) == 0 => {
1118 let rs: u8 = ((word >> 21) & 0x1F) as u8;
1119 (
1120 InstructionType::Move,
1121 SmallVec::from_slice(&[Operand::Register(rs)]),
1122 )
1123 }
1124
1125 // Unknown opcode - return unknown instruction type
1126 _ => (InstructionType::Unknown, SmallVec::new()),
1127 };
1128
1129 Ok(DecodedInstruction {
1130 instruction: Instruction {
1131 opcode,
1132 instruction_type,
1133 operands,
1134 },
1135 raw: word,
1136 address,
1137 })
1138 }
1139
1140 /// Decode extended opcodes (opcode 31 instructions).
1141 ///
1142 /// Extended opcodes use a secondary opcode field in bits 1-10 of the instruction word.
1143 /// This function handles arithmetic, logical, shift, rotate, floating-point, and system instructions.
1144 ///
1145 /// # Arguments
1146 /// * `word` - 32-bit instruction word with opcode 31
1147 ///
1148 /// # Returns
1149 /// `Result<(InstructionType, SmallVec<[Operand; 4]>)>` - Instruction type and operands
1150 #[inline] // Hot path for extended opcodes
1151 fn decode_extended(word: u32) -> Result<(InstructionType, SmallVec<[Operand; 4]>)> {
1152 // Extract secondary opcode (bits 1-10)
1153 let extended_opcode: u32 = (word >> 1) & 0x3FF;
1154
1155 // Extract common register fields
1156 let ra: u8 = ((word >> 16) & 0x1F) as u8;
1157 let rb: u8 = ((word >> 11) & 0x1F) as u8;
1158 let rs: u8 = ((word >> 21) & 0x1F) as u8;
1159 let rt: u8 = ((word >> 21) & 0x1F) as u8;
1160 let rc: bool = (word & 1) != 0; // Record bit (update condition register)
1161
1162 // Check for specific instruction patterns first (move instructions)
1163 // Move from link register (mflr) - RT field = 8, all other fields = 0
1164 if ((word >> 21) & 0x1F) == 8 && (word & 0x7FF) == 0 {
1165 return Ok((
1166 InstructionType::Move,
1167 SmallVec::from_slice(&[Operand::Register(rt)]),
1168 ));
1169 }
1170 // Move to link register (mtlr) - RS field = 9, all other fields = 0
1171 if ((word >> 21) & 0x1F) == 9 && (word & 0x7FF) == 0 {
1172 return Ok((
1173 InstructionType::Move,
1174 SmallVec::from_slice(&[Operand::Register(rs)]),
1175 ));
1176 }
1177
1178 // Decode based on extended opcode
1179 match extended_opcode {
1180 // Extended opcode 266: Add (add)
1181 // Format: add RT, RA, RB
1182 // Only if primary opcode is 31 (not 63)
1183 266 if (word >> 26) == 31 => Ok((
1184 InstructionType::Arithmetic,
1185 SmallVec::from_slice(&[
1186 Operand::Register(rt),
1187 Operand::Register(ra),
1188 Operand::Register(rb),
1189 ]),
1190 )),
1191
1192 // Extended opcode 40: Subtract from (subf)
1193 // Format: subf RT, RA, RB (RT = RB - RA)
1194 // Only if primary opcode is 31 (not 63, which is fneg)
1195 40 if (word >> 26) == 31 => Ok((
1196 InstructionType::Arithmetic,
1197 SmallVec::from_slice(&[
1198 Operand::Register(rt),
1199 Operand::Register(ra),
1200 Operand::Register(rb),
1201 ]),
1202 )),
1203
1204 // Extended opcode 138: Add carrying (addc)
1205 // Format: addc RT, RA, RB (RT = RA + RB, with carry)
1206 138 => Ok((
1207 InstructionType::Arithmetic,
1208 SmallVec::from_slice(&[
1209 Operand::Register(rt),
1210 Operand::Register(ra),
1211 Operand::Register(rb),
1212 ]),
1213 )),
1214
1215 // Extended opcode 10: Add extended (adde)
1216 // Format: adde RT, RA, RB (RT = RA + RB + CA, with carry)
1217 10 => Ok((
1218 InstructionType::Arithmetic,
1219 SmallVec::from_slice(&[
1220 Operand::Register(rt),
1221 Operand::Register(ra),
1222 Operand::Register(rb),
1223 ]),
1224 )),
1225
1226 // Extended opcode 202: Add extended carrying (addze)
1227 // Format: addze RT, RA (RT = RA + CA, with carry)
1228 202 => Ok((
1229 InstructionType::Arithmetic,
1230 SmallVec::from_slice(&[
1231 Operand::Register(rt),
1232 Operand::Register(ra),
1233 ]),
1234 )),
1235
1236 // Extended opcode 234: Add to minus one extended (addme)
1237 // Format: addme RT, RA (RT = RA + CA - 1, with carry)
1238 234 => Ok((
1239 InstructionType::Arithmetic,
1240 SmallVec::from_slice(&[
1241 Operand::Register(rt),
1242 Operand::Register(ra),
1243 ]),
1244 )),
1245
1246 // Extended opcode 74: Subtract from extended zero (subfze)
1247 // Format: subfze RT, RA (RT = CA - RA - 1, with carry)
1248 74 => Ok((
1249 InstructionType::Arithmetic,
1250 SmallVec::from_slice(&[
1251 Operand::Register(rt),
1252 Operand::Register(ra),
1253 ]),
1254 )),
1255
1256 // Extended opcode 106: Subtract from minus one extended (subfme)
1257 // Format: subfme RT, RA (RT = CA - RA - 2, with carry)
1258 106 => Ok((
1259 InstructionType::Arithmetic,
1260 SmallVec::from_slice(&[
1261 Operand::Register(rt),
1262 Operand::Register(ra),
1263 ]),
1264 )),
1265
1266 // Extended opcode 75: Negate (neg)
1267 // Format: neg RT, RA (RT = -RA)
1268 75 => Ok((
1269 InstructionType::Arithmetic,
1270 SmallVec::from_slice(&[
1271 Operand::Register(rt),
1272 Operand::Register(ra),
1273 ]),
1274 )),
1275
1276 // Extended opcode 104: Negate with overflow (nego)
1277 // Format: nego RT, RA (RT = -RA, sets overflow)
1278 104 if (word >> 26) == 31 && ra != 0 => Ok((
1279 InstructionType::Arithmetic,
1280 SmallVec::from_slice(&[
1281 Operand::Register(rt),
1282 Operand::Register(ra),
1283 ]),
1284 )),
1285
1286 // Extended opcode 232: Add carrying with overflow (addco)
1287 // Format: addco RT, RA, RB (RT = RA + RB, with carry and overflow)
1288 232 => Ok((
1289 InstructionType::Arithmetic,
1290 SmallVec::from_slice(&[
1291 Operand::Register(rt),
1292 Operand::Register(ra),
1293 Operand::Register(rb),
1294 ]),
1295 )),
1296
1297 // Extended opcode 233: Add extended with overflow (addeo)
1298 // Format: addeo RT, RA, RB (RT = RA + RB + CA, with carry and overflow)
1299 233 if (word >> 26) == 31 => Ok((
1300 InstructionType::Arithmetic,
1301 SmallVec::from_slice(&[
1302 Operand::Register(rt),
1303 Operand::Register(ra),
1304 Operand::Register(rb),
1305 ]),
1306 )),
1307
1308 // Extended opcode 234: Add to minus one extended with overflow (addmeo)
1309 // Format: addmeo RT, RA (RT = RA + CA - 1, with carry and overflow)
1310 234 if (word >> 26) == 31 => Ok((
1311 InstructionType::Arithmetic,
1312 SmallVec::from_slice(&[
1313 Operand::Register(rt),
1314 Operand::Register(ra),
1315 ]),
1316 )),
1317
1318 // Extended opcode 202: Add extended carrying with overflow (addzeo)
1319 // Format: addzeo RT, RA (RT = RA + CA, with carry and overflow)
1320 202 if (word >> 26) == 31 => Ok((
1321 InstructionType::Arithmetic,
1322 SmallVec::from_slice(&[
1323 Operand::Register(rt),
1324 Operand::Register(ra),
1325 ]),
1326 )),
1327
1328 // Extended opcode 8: Subtract from carrying with overflow (subfco)
1329 // Format: subfco RT, RA, RB (RT = RB - RA, with carry and overflow)
1330 8 if (word >> 26) == 31 => Ok((
1331 InstructionType::Arithmetic,
1332 SmallVec::from_slice(&[
1333 Operand::Register(rt),
1334 Operand::Register(ra),
1335 Operand::Register(rb),
1336 ]),
1337 )),
1338
1339 // Extended opcode 136: Subtract from extended with overflow (subfeo)
1340 // Format: subfeo RT, RA, RB (RT = RB - RA - (1 - CA), with carry and overflow)
1341 136 if (word >> 26) == 31 && ra != 0 => Ok((
1342 InstructionType::Arithmetic,
1343 SmallVec::from_slice(&[
1344 Operand::Register(rt),
1345 Operand::Register(ra),
1346 Operand::Register(rb),
1347 ]),
1348 )),
1349
1350 // Extended opcode 74: Subtract from extended zero with overflow (subfzeo)
1351 // Format: subfzeo RT, RA (RT = CA - RA - 1, with carry and overflow)
1352 74 if (word >> 26) == 31 => Ok((
1353 InstructionType::Arithmetic,
1354 SmallVec::from_slice(&[
1355 Operand::Register(rt),
1356 Operand::Register(ra),
1357 ]),
1358 )),
1359
1360 // Extended opcode 106: Subtract from minus one extended with overflow (subfmeo)
1361 // Format: subfmeo RT, RA (RT = CA - RA - 2, with carry and overflow)
1362 106 if (word >> 26) == 31 => Ok((
1363 InstructionType::Arithmetic,
1364 SmallVec::from_slice(&[
1365 Operand::Register(rt),
1366 Operand::Register(ra),
1367 ]),
1368 )),
1369
1370 // Extended opcode 107: Multiply low word with overflow (mullwo)
1371 // Format: mullwo RT, RA, RB (RT = RA * RB, sets overflow)
1372 107 => Ok((
1373 InstructionType::Arithmetic,
1374 SmallVec::from_slice(&[
1375 Operand::Register(rt),
1376 Operand::Register(ra),
1377 Operand::Register(rb),
1378 ]),
1379 )),
1380
1381 // Extended opcode 200: Divide word with overflow (divwo)
1382 // Format: divwo RT, RA, RB (RT = RA / RB, sets overflow)
1383 200 if (word >> 26) == 31 => Ok((
1384 InstructionType::Arithmetic,
1385 SmallVec::from_slice(&[
1386 Operand::Register(rt),
1387 Operand::Register(ra),
1388 Operand::Register(rb),
1389 ]),
1390 )),
1391
1392 // Extended opcode 201: Divide word unsigned with overflow (divwuo)
1393 // Format: divwuo RT, RA, RB (RT = RA / RB unsigned, sets overflow)
1394 201 => Ok((
1395 InstructionType::Arithmetic,
1396 SmallVec::from_slice(&[
1397 Operand::Register(rt),
1398 Operand::Register(ra),
1399 Operand::Register(rb),
1400 ]),
1401 )),
1402
1403 // Extended opcode 235: Multiply low word (mullw)
1404 // Format: mullw RT, RA, RB
1405 235 => Ok((
1406 InstructionType::Arithmetic,
1407 SmallVec::from_slice(&[
1408 Operand::Register(rt),
1409 Operand::Register(ra),
1410 Operand::Register(rb),
1411 ]),
1412 )),
1413
1414 // Extended opcode 233: Multiply high word (mulhw)
1415 // Format: mulhw RT, RA, RB
1416 233 => Ok((
1417 InstructionType::Arithmetic,
1418 SmallVec::from_slice(&[
1419 Operand::Register(rt),
1420 Operand::Register(ra),
1421 Operand::Register(rb),
1422 ]),
1423 )),
1424
1425 // Extended opcode 11: Multiply high word unsigned (mulhwu)
1426 // Format: mulhwu RT, RA, RB
1427 11 => Ok((
1428 InstructionType::Arithmetic,
1429 SmallVec::from_slice(&[
1430 Operand::Register(rt),
1431 Operand::Register(ra),
1432 Operand::Register(rb),
1433 ]),
1434 )),
1435
1436 // Extended opcode 200: Divide word unsigned (divwu)
1437 // Format: divwu RT, RA, RB (RT = RA / RB, unsigned)
1438 200 => Ok((
1439 InstructionType::Arithmetic,
1440 SmallVec::from_slice(&[
1441 Operand::Register(rt),
1442 Operand::Register(ra),
1443 Operand::Register(rb),
1444 ]),
1445 )),
1446
1447 // Extended opcode 104: Divide word (divw) - already implemented above
1448 // Extended opcode 40: Subtract from (subf) - already implemented above
1449
1450 // Extended opcode 8: Subtract from carrying (subfc)
1451 // Format: subfc RT, RA, RB (RT = RB - RA, with carry)
1452 8 => Ok((
1453 InstructionType::Arithmetic,
1454 SmallVec::from_slice(&[
1455 Operand::Register(rt),
1456 Operand::Register(ra),
1457 Operand::Register(rb),
1458 ]),
1459 )),
1460
1461 // Extended opcode 136: Subtract from extended (subfe)
1462 // Format: subfe RT, RA, RB (RT = RB - RA - (1 - CA), with carry)
1463 // Only if primary opcode is 31 (not 63, which is fnabs)
1464 136 if (word >> 26) == 31 => Ok((
1465 InstructionType::Arithmetic,
1466 SmallVec::from_slice(&[
1467 Operand::Register(rt),
1468 Operand::Register(ra),
1469 Operand::Register(rb),
1470 ]),
1471 )),
1472
1473 // Extended opcode 104: Divide word (divw)
1474 // Format: divw RT, RA, RB (RT = RA / RB)
1475 // Only if primary opcode is 31 (not 63)
1476 104 if (word >> 26) == 31 => Ok((
1477 InstructionType::Arithmetic,
1478 SmallVec::from_slice(&[
1479 Operand::Register(rt),
1480 Operand::Register(ra),
1481 Operand::Register(rb),
1482 ]),
1483 )),
1484
1485 // Extended opcode 28: AND (and)
1486 // Format: and RS, RA, RB
1487 // Only if primary opcode is 31 (not 63)
1488 28 if (word >> 26) == 31 => Ok((
1489 InstructionType::Arithmetic,
1490 SmallVec::from_slice(&[
1491 Operand::Register(rs),
1492 Operand::Register(ra),
1493 Operand::Register(rb),
1494 ]),
1495 )),
1496
1497 // Extended opcode 60: AND with complement (andc)
1498 // Format: andc RS, RA, RB (RS = RA & ~RB)
1499 60 => Ok((
1500 InstructionType::Arithmetic,
1501 SmallVec::from_slice(&[
1502 Operand::Register(rs),
1503 Operand::Register(ra),
1504 Operand::Register(rb),
1505 ]),
1506 )),
1507
1508 // Extended opcode 444: OR (or)
1509 // Format: or RS, RA, RB
1510 // Only if primary opcode is 31 (not 63)
1511 444 if (word >> 26) == 31 => Ok((
1512 InstructionType::Arithmetic,
1513 SmallVec::from_slice(&[
1514 Operand::Register(rs),
1515 Operand::Register(ra),
1516 Operand::Register(rb),
1517 ]),
1518 )),
1519
1520 // Extended opcode 412: OR with complement (orc)
1521 // Format: orc RS, RA, RB (RS = RA | ~RB)
1522 412 => Ok((
1523 InstructionType::Arithmetic,
1524 SmallVec::from_slice(&[
1525 Operand::Register(rs),
1526 Operand::Register(ra),
1527 Operand::Register(rb),
1528 ]),
1529 )),
1530
1531 // Extended opcode 316: XOR (xor)
1532 // Format: xor RS, RA, RB
1533 // Only if primary opcode is 31 (not 63)
1534 316 if (word >> 26) == 31 => Ok((
1535 InstructionType::Arithmetic,
1536 SmallVec::from_slice(&[
1537 Operand::Register(rs),
1538 Operand::Register(ra),
1539 Operand::Register(rb),
1540 ]),
1541 )),
1542
1543 // Extended opcode 476: NAND (nand)
1544 // Format: nand RS, RA, RB
1545 // Only if primary opcode is 31 (not 63)
1546 476 if (word >> 26) == 31 => Ok((
1547 InstructionType::Arithmetic,
1548 SmallVec::from_slice(&[
1549 Operand::Register(rs),
1550 Operand::Register(ra),
1551 Operand::Register(rb),
1552 ]),
1553 )),
1554
1555 // Extended opcode 124: NOR (nor)
1556 // Format: nor RS, RA, RB
1557 // Only if primary opcode is 31 (not 63)
1558 124 if (word >> 26) == 31 => Ok((
1559 InstructionType::Arithmetic,
1560 SmallVec::from_slice(&[
1561 Operand::Register(rs),
1562 Operand::Register(ra),
1563 Operand::Register(rb),
1564 ]),
1565 )),
1566
1567 // Extended opcode 284: Equivalent (eqv)
1568 // Format: eqv RS, RA, RB (RS = ~(RA ^ RB))
1569 284 => Ok((
1570 InstructionType::Arithmetic,
1571 SmallVec::from_slice(&[
1572 Operand::Register(rs),
1573 Operand::Register(ra),
1574 Operand::Register(rb),
1575 ]),
1576 )),
1577
1578 // Extended opcode 24: Shift left word (slw)
1579 // Format: slw RA, RS, RB (RA = RS << (RB & 0x1F))
1580 // Only if primary opcode is 31 (not 63)
1581 24 if (word >> 26) == 31 => {
1582 let sh: u8 = ((word >> 11) & 0x1F) as u8;
1583 Ok((
1584 InstructionType::Shift,
1585 SmallVec::from_slice(&[
1586 Operand::Register(rs),
1587 Operand::Register(ra),
1588 Operand::ShiftAmount(sh),
1589 ]),
1590 ))
1591 }
1592
1593 // Extended opcode 536: Shift right word (srw)
1594 // Format: srw RA, RS, RB (RA = RS >> (RB & 0x1F))
1595 // Only if primary opcode is 31 (not 63)
1596 536 if (word >> 26) == 31 => {
1597 let sh: u8 = ((word >> 11) & 0x1F) as u8;
1598 Ok((
1599 InstructionType::Shift,
1600 SmallVec::from_slice(&[
1601 Operand::Register(rs),
1602 Operand::Register(ra),
1603 Operand::ShiftAmount(sh),
1604 ]),
1605 ))
1606 }
1607
1608 // Extended opcode 824: Shift left word immediate (slwi)
1609 // Format: slwi RA, RS, SH (RA = RS << SH)
1610 // This is actually rlwinm with MB=0, ME=31-SH
1611 824 => {
1612 let sh: u8 = ((word >> 11) & 0x1F) as u8;
1613 Ok((
1614 InstructionType::Shift,
1615 SmallVec::from_slice(&[
1616 Operand::Register(rs),
1617 Operand::Register(ra),
1618 Operand::ShiftAmount(sh),
1619 ]),
1620 ))
1621 }
1622
1623 // Extended opcode 792: Shift right word immediate (srwi)
1624 // Format: srwi RA, RS, SH (RA = RS >> SH)
1625 // This is actually rlwinm with SH=32-SH, MB=SH, ME=31
1626 792 if (word >> 26) == 31 => {
1627 let sh: u8 = ((word >> 11) & 0x1F) as u8;
1628 Ok((
1629 InstructionType::Shift,
1630 SmallVec::from_slice(&[
1631 Operand::Register(rs),
1632 Operand::Register(ra),
1633 Operand::ShiftAmount(sh),
1634 ]),
1635 ))
1636 }
1637
1638 // Extended opcode 794: Shift right algebraic word (sraw)
1639 // Format: sraw RA, RS, RB (arithmetic right shift)
1640 794 => {
1641 let sh: u8 = ((word >> 11) & 0x1F) as u8;
1642 Ok((
1643 InstructionType::Shift,
1644 SmallVec::from_slice(&[
1645 Operand::Register(rs),
1646 Operand::Register(ra),
1647 Operand::ShiftAmount(sh),
1648 ]),
1649 ))
1650 }
1651
1652 // Extended opcode 826: Shift right algebraic word immediate (srawi)
1653 // Format: srawi RA, RS, SH (arithmetic right shift by immediate)
1654 826 => {
1655 let sh: u8 = ((word >> 11) & 0x1F) as u8;
1656 Ok((
1657 InstructionType::Shift,
1658 SmallVec::from_slice(&[
1659 Operand::Register(rs),
1660 Operand::Register(ra),
1661 Operand::ShiftAmount(sh),
1662 ]),
1663 ))
1664 }
1665
1666 // Extended opcode 26: Count leading zeros word (cntlzw)
1667 // Format: cntlzw RA, RS
1668 26 => Ok((
1669 InstructionType::Arithmetic,
1670 SmallVec::from_slice(&[
1671 Operand::Register(rs),
1672 Operand::Register(ra),
1673 ]),
1674 )),
1675
1676 // Extended opcode 0: Compare word (cmpw)
1677 // Format: cmpw BF, RA, RB
1678 // Only if primary opcode is 31 and extended opcode is 0
1679 0 if (word >> 26) == 31 && ((word >> 1) & 0x3FF) == 0 => {
1680 let bf: u8 = ((word >> 23) & 0x7) as u8;
1681 Ok((
1682 InstructionType::Compare,
1683 SmallVec::from_slice(&[
1684 Operand::Condition(bf),
1685 Operand::Register(ra),
1686 Operand::Register(rb),
1687 ]),
1688 ))
1689 }
1690
1691 // Extended opcode 32: Compare logical word (cmplw)
1692 // Format: cmplw BF, RA, RB
1693 32 => {
1694 let bf: u8 = ((word >> 23) & 0x7) as u8;
1695 Ok((
1696 InstructionType::Compare,
1697 SmallVec::from_slice(&[
1698 Operand::Condition(bf),
1699 Operand::Register(ra),
1700 Operand::Register(rb),
1701 ]),
1702 ))
1703 }
1704
1705 // Extended opcode 20: Load word and reserve indexed (lwarx)
1706 // Format: lwarx RT, RA, RB (load word and set reservation)
1707 20 if (word >> 26) == 31 => Ok((
1708 InstructionType::Load,
1709 SmallVec::from_slice(&[
1710 Operand::Register(rt),
1711 Operand::Register(ra),
1712 Operand::Register(rb),
1713 ]),
1714 )),
1715
1716 // Extended opcode 23: Load word indexed (lwzx)
1717 // Format: lwzx RT, RA, RB
1718 23 => Ok((
1719 InstructionType::Load,
1720 SmallVec::from_slice(&[
1721 Operand::Register(rt),
1722 Operand::Register(ra),
1723 Operand::Register(rb),
1724 ]),
1725 )),
1726
1727 // Extended opcode 150: Store word conditional indexed (stwcx.)
1728 // Format: stwcx. RS, RA, RB (store word conditional, sets CR0)
1729 150 if (word >> 26) == 31 => Ok((
1730 InstructionType::Store,
1731 SmallVec::from_slice(&[
1732 Operand::Register(rs),
1733 Operand::Register(ra),
1734 Operand::Register(rb),
1735 ]),
1736 )),
1737
1738 // Extended opcode 87: Load byte indexed (lbzx)
1739 // Format: lbzx RT, RA, RB
1740 87 => Ok((
1741 InstructionType::Load,
1742 SmallVec::from_slice(&[
1743 Operand::Register(rt),
1744 Operand::Register(ra),
1745 Operand::Register(rb),
1746 ]),
1747 )),
1748
1749 // Extended opcode 279: Load halfword indexed (lhzx)
1750 // Format: lhzx RT, RA, RB
1751 279 => Ok((
1752 InstructionType::Load,
1753 SmallVec::from_slice(&[
1754 Operand::Register(rt),
1755 Operand::Register(ra),
1756 Operand::Register(rb),
1757 ]),
1758 )),
1759
1760 // Extended opcode 343: Load halfword algebraic indexed (lhax)
1761 // Format: lhax RT, RA, RB
1762 343 => Ok((
1763 InstructionType::Load,
1764 SmallVec::from_slice(&[
1765 Operand::Register(rt),
1766 Operand::Register(ra),
1767 Operand::Register(rb),
1768 ]),
1769 )),
1770
1771 // Extended opcode 151: Store word indexed (stwx)
1772 // Format: stwx RS, RA, RB
1773 151 => Ok((
1774 InstructionType::Store,
1775 SmallVec::from_slice(&[
1776 Operand::Register(rs),
1777 Operand::Register(ra),
1778 Operand::Register(rb),
1779 ]),
1780 )),
1781
1782 // Extended opcode 215: Store byte indexed (stbx)
1783 // Format: stbx RS, RA, RB
1784 215 => Ok((
1785 InstructionType::Store,
1786 SmallVec::from_slice(&[
1787 Operand::Register(rs),
1788 Operand::Register(ra),
1789 Operand::Register(rb),
1790 ]),
1791 )),
1792
1793 // Extended opcode 407: Store halfword indexed (sthx)
1794 // Format: sthx RS, RA, RB
1795 407 => Ok((
1796 InstructionType::Store,
1797 SmallVec::from_slice(&[
1798 Operand::Register(rs),
1799 Operand::Register(ra),
1800 Operand::Register(rb),
1801 ]),
1802 )),
1803
1804 // Extended opcode 55: Load word with update indexed (lwzux)
1805 // Format: lwzux RT, RA, RB - updates RA with effective address
1806 55 => Ok((
1807 InstructionType::Load,
1808 SmallVec::from_slice(&[
1809 Operand::Register(rt),
1810 Operand::Register(ra),
1811 Operand::Register(rb),
1812 ]),
1813 )),
1814
1815 // Extended opcode 119: Load byte with update indexed (lbzux)
1816 // Format: lbzux RT, RA, RB - updates RA with effective address
1817 119 => Ok((
1818 InstructionType::Load,
1819 SmallVec::from_slice(&[
1820 Operand::Register(rt),
1821 Operand::Register(ra),
1822 Operand::Register(rb),
1823 ]),
1824 )),
1825
1826 // Extended opcode 311: Load halfword with update indexed (lhzux)
1827 // Format: lhzux RT, RA, RB - updates RA with effective address
1828 311 => Ok((
1829 InstructionType::Load,
1830 SmallVec::from_slice(&[
1831 Operand::Register(rt),
1832 Operand::Register(ra),
1833 Operand::Register(rb),
1834 ]),
1835 )),
1836
1837 // Extended opcode 375: Store word with update indexed (stwux)
1838 // Format: stwux RS, RA, RB - updates RA with effective address
1839 375 => Ok((
1840 InstructionType::Store,
1841 SmallVec::from_slice(&[
1842 Operand::Register(rs),
1843 Operand::Register(ra),
1844 Operand::Register(rb),
1845 ]),
1846 )),
1847
1848 // Extended opcode 439: Store byte with update indexed (stbux)
1849 // Format: stbux RS, RA, RB - updates RA with effective address
1850 439 => Ok((
1851 InstructionType::Store,
1852 SmallVec::from_slice(&[
1853 Operand::Register(rs),
1854 Operand::Register(ra),
1855 Operand::Register(rb),
1856 ]),
1857 )),
1858
1859 // Extended opcode 695: Store halfword with update indexed (sthux)
1860 // Format: sthux RS, RA, RB - updates RA with effective address
1861 695 => Ok((
1862 InstructionType::Store,
1863 SmallVec::from_slice(&[
1864 Operand::Register(rs),
1865 Operand::Register(ra),
1866 Operand::Register(rb),
1867 ]),
1868 )),
1869
1870 // Extended opcode 567: Floating-point load single indexed (lfsx)
1871 // Format: lfsx FRT, RA, RB
1872 567 => {
1873 let frt: u8 = ((word >> 21) & 0x1F) as u8;
1874 Ok((
1875 InstructionType::FloatingPoint,
1876 SmallVec::from_slice(&[
1877 Operand::FpRegister(frt),
1878 Operand::Register(ra),
1879 Operand::Register(rb),
1880 ]),
1881 ))
1882 }
1883
1884 // Extended opcode 599: Floating-point load double indexed (lfdx)
1885 // Format: lfdx FRT, RA, RB
1886 599 => {
1887 let frt: u8 = ((word >> 21) & 0x1F) as u8;
1888 Ok((
1889 InstructionType::FloatingPoint,
1890 SmallVec::from_slice(&[
1891 Operand::FpRegister(frt),
1892 Operand::Register(ra),
1893 Operand::Register(rb),
1894 ]),
1895 ))
1896 }
1897
1898 // Extended opcode 663: Floating-point store single indexed (stfsx)
1899 // Format: stfsx FRS, RA, RB
1900 663 => {
1901 let frs: u8 = ((word >> 21) & 0x1F) as u8;
1902 Ok((
1903 InstructionType::FloatingPoint,
1904 SmallVec::from_slice(&[
1905 Operand::FpRegister(frs),
1906 Operand::Register(ra),
1907 Operand::Register(rb),
1908 ]),
1909 ))
1910 }
1911
1912 // Extended opcode 727: Floating-point store double indexed (stfdx)
1913 // Format: stfdx FRS, RA, RB
1914 727 => {
1915 let frs: u8 = ((word >> 21) & 0x1F) as u8;
1916 Ok((
1917 InstructionType::FloatingPoint,
1918 SmallVec::from_slice(&[
1919 Operand::FpRegister(frs),
1920 Operand::Register(ra),
1921 Operand::Register(rb),
1922 ]),
1923 ))
1924 }
1925
1926 // Extended opcode 597: Load multiple word (lmw)
1927 // Format: lmw RT, D(RA) - loads words from RA+D to RT, RT+1, ..., RT+31
1928 // Note: Conflicts with lswi, but lmw uses primary opcode 46, lswi uses extended opcode
1929 // This is handled in primary opcode 46
1930
1931 // Extended opcode 533: Store multiple word (stmw)
1932 // Format: stmw RS, D(RA) - stores words from RS, RS+1, ..., RS+31 to RA+D
1933 // Note: Conflicts with stswi, but stmw uses primary opcode 47, stswi uses extended opcode
1934 // This is handled in primary opcode 47
1935
1936 // Extended opcode 16: Branch to link register (blr)
1937 // Format: blr - branch to address in link register
1938 16 if (word & 0x03E00001) == 0x00000001 => Ok((
1939 InstructionType::Branch,
1940 SmallVec::from_slice(&[Operand::Register(0)]), // Placeholder for LR
1941 )),
1942
1943 // Extended opcode 528: Branch to count register (bctr)
1944 // Format: bctr - branch to address in count register
1945 // Only if primary opcode is 31 (not 63)
1946 528 if (word >> 26) == 31 && (word & 0x03E00001) == 0x00000001 => Ok((
1947 InstructionType::Branch,
1948 SmallVec::from_slice(&[Operand::Register(9)]), // Placeholder for CTR
1949 )),
1950
1951 // Extended opcode 528: Branch conditional to count register (bcctr)
1952 // Format: bcctr BO, BI - conditional branch to CTR
1953 // Only if primary opcode is 31 (not 63)
1954 528 if (word >> 26) == 31 => {
1955 let bo: u8 = ((word >> 21) & 0x1F) as u8;
1956 let bi: u8 = ((word >> 16) & 0x1F) as u8;
1957 Ok((
1958 InstructionType::Branch,
1959 SmallVec::from_slice(&[
1960 Operand::Condition(bo),
1961 Operand::Condition(bi),
1962 ]),
1963 ))
1964 }
1965
1966 // Extended opcode 16: Branch conditional to link register (bclr)
1967 // Format: bclr BO, BI - conditional branch to LR
1968 // Only if primary opcode is 31 (not 63)
1969 16 if (word >> 26) == 31 => {
1970 let bo: u8 = ((word >> 21) & 0x1F) as u8;
1971 let bi: u8 = ((word >> 16) & 0x1F) as u8;
1972 Ok((
1973 InstructionType::Branch,
1974 SmallVec::from_slice(&[
1975 Operand::Condition(bo),
1976 Operand::Condition(bi),
1977 ]),
1978 ))
1979 }
1980
1981 // Extended opcode 21: Rotate left word immediate then mask insert (rlwinm)
1982 // Format: rlwinm RA, RS, SH, MB, ME
1983 // Only if primary opcode is 31 (to distinguish from floating-point add)
1984 21 if (word >> 26) == 31 => {
1985 let sh: u8 = ((word >> 11) & 0x1F) as u8;
1986 let mb: u8 = ((word >> 6) & 0x1F) as u8;
1987 let me: u8 = (word & 0x1F) as u8;
1988 let mask: u32 = compute_mask(mb, me);
1989 Ok((
1990 InstructionType::Rotate,
1991 SmallVec::from_slice(&[
1992 Operand::Register(rs),
1993 Operand::Register(ra),
1994 Operand::ShiftAmount(sh),
1995 Operand::Mask(mask),
1996 ]),
1997 ))
1998 }
1999
2000 // Extended opcode 20: Rotate left word then AND with mask (rlwnm)
2001 // Format: rlwnm RA, RS, RB, MB, ME
2002 // Only if primary opcode is 31
2003 20 if (word >> 26) == 31 => {
2004 let mb: u8 = ((word >> 6) & 0x1F) as u8;
2005 let me: u8 = (word & 0x1F) as u8;
2006 let mask: u32 = compute_mask(mb, me);
2007 Ok((
2008 InstructionType::Rotate,
2009 SmallVec::from_slice(&[
2010 Operand::Register(rs),
2011 Operand::Register(ra),
2012 Operand::Register(rb),
2013 Operand::Mask(mask),
2014 ]),
2015 ))
2016 }
2017
2018 // Extended opcode 19: Rotate left word immediate then mask insert (rlwimi)
2019 // Format: rlwimi RA, RS, SH, MB, ME
2020 // Only if primary opcode is 31
2021 19 if (word >> 26) == 31 => {
2022 let sh: u8 = ((word >> 11) & 0x1F) as u8;
2023 let mb: u8 = ((word >> 6) & 0x1F) as u8;
2024 let me: u8 = (word & 0x1F) as u8;
2025 let mask: u32 = compute_mask(mb, me);
2026 Ok((
2027 InstructionType::Rotate,
2028 SmallVec::from_slice(&[
2029 Operand::Register(rs),
2030 Operand::Register(ra),
2031 Operand::ShiftAmount(sh),
2032 Operand::Mask(mask),
2033 ]),
2034 ))
2035 }
2036
2037 // Extended opcode 21: Floating-point add (fadd)
2038 // Format: fadd FRT, FRA, FRB
2039 // Only if primary opcode is 63 (floating-point instruction)
2040 21 => {
2041 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2042 let fra: u8 = ((word >> 16) & 0x1F) as u8;
2043 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2044 Ok((
2045 InstructionType::FloatingPoint,
2046 SmallVec::from_slice(&[
2047 Operand::FpRegister(frt),
2048 Operand::FpRegister(fra),
2049 Operand::FpRegister(frb),
2050 ]),
2051 ))
2052 }
2053
2054 // Extended opcode 20: Floating-point subtract (fsub)
2055 // Format: fsub FRT, FRA, FRB
2056 20 => {
2057 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2058 let fra: u8 = ((word >> 16) & 0x1F) as u8;
2059 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2060 Ok((
2061 InstructionType::FloatingPoint,
2062 SmallVec::from_slice(&[
2063 Operand::FpRegister(frt),
2064 Operand::FpRegister(fra),
2065 Operand::FpRegister(frb),
2066 ]),
2067 ))
2068 }
2069
2070 // Extended opcode 25: Floating-point multiply (fmul)
2071 // Format: fmul FRT, FRA, FRC, FRB (FRA * FRC for some variants)
2072 // Only if primary opcode is 63
2073 25 if (word >> 26) == 63 => {
2074 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2075 let fra: u8 = ((word >> 16) & 0x1F) as u8;
2076 let frc: u8 = ((word >> 6) & 0x1F) as u8;
2077 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2078 Ok((
2079 InstructionType::FloatingPoint,
2080 SmallVec::from_slice(&[
2081 Operand::FpRegister(frt),
2082 Operand::FpRegister(fra),
2083 Operand::FpRegister(frc),
2084 Operand::FpRegister(frb),
2085 ]),
2086 ))
2087 }
2088
2089 // Extended opcode 14: Floating-point multiply-add (fmadd)
2090 // Format: fmadd FRT, FRA, FRC, FRB (FRT = FRA * FRC + FRB)
2091 // Only if primary opcode is 63
2092 14 if (word >> 26) == 63 => {
2093 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2094 let fra: u8 = ((word >> 16) & 0x1F) as u8;
2095 let frc: u8 = ((word >> 6) & 0x1F) as u8;
2096 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2097 Ok((
2098 InstructionType::FloatingPoint,
2099 SmallVec::from_slice(&[
2100 Operand::FpRegister(frt),
2101 Operand::FpRegister(fra),
2102 Operand::FpRegister(frc),
2103 Operand::FpRegister(frb),
2104 ]),
2105 ))
2106 }
2107
2108 // Extended opcode 15: Floating-point multiply-subtract (fmsub)
2109 // Format: fmsub FRT, FRA, FRC, FRB (FRT = FRA * FRC - FRB)
2110 // Only if primary opcode is 63
2111 15 if (word >> 26) == 63 => {
2112 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2113 let fra: u8 = ((word >> 16) & 0x1F) as u8;
2114 let frc: u8 = ((word >> 6) & 0x1F) as u8;
2115 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2116 Ok((
2117 InstructionType::FloatingPoint,
2118 SmallVec::from_slice(&[
2119 Operand::FpRegister(frt),
2120 Operand::FpRegister(fra),
2121 Operand::FpRegister(frc),
2122 Operand::FpRegister(frb),
2123 ]),
2124 ))
2125 }
2126
2127 // Extended opcode 28: Floating-point negative multiply-add (fnmadd)
2128 // Format: fnmadd FRT, FRA, FRC, FRB (FRT = -(FRA * FRC + FRB))
2129 // Only if primary opcode is 63
2130 28 if (word >> 26) == 63 => {
2131 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2132 let fra: u8 = ((word >> 16) & 0x1F) as u8;
2133 let frc: u8 = ((word >> 6) & 0x1F) as u8;
2134 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2135 Ok((
2136 InstructionType::FloatingPoint,
2137 SmallVec::from_slice(&[
2138 Operand::FpRegister(frt),
2139 Operand::FpRegister(fra),
2140 Operand::FpRegister(frc),
2141 Operand::FpRegister(frb),
2142 ]),
2143 ))
2144 }
2145
2146 // Extended opcode 29: Floating-point negative multiply-subtract (fnmsub)
2147 // Format: fnmsub FRT, FRA, FRC, FRB (FRT = -(FRA * FRC - FRB))
2148 // Only if primary opcode is 63
2149 29 if (word >> 26) == 63 => {
2150 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2151 let fra: u8 = ((word >> 16) & 0x1F) as u8;
2152 let frc: u8 = ((word >> 6) & 0x1F) as u8;
2153 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2154 Ok((
2155 InstructionType::FloatingPoint,
2156 SmallVec::from_slice(&[
2157 Operand::FpRegister(frt),
2158 Operand::FpRegister(fra),
2159 Operand::FpRegister(frc),
2160 Operand::FpRegister(frb),
2161 ]),
2162 ))
2163 }
2164
2165 // Extended opcode 32: Floating-point square root (fsqrt)
2166 // Format: fsqrt FRT, FRB
2167 // Only if primary opcode is 63
2168 32 if (word >> 26) == 63 => {
2169 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2170 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2171 Ok((
2172 InstructionType::FloatingPoint,
2173 SmallVec::from_slice(&[
2174 Operand::FpRegister(frt),
2175 Operand::FpRegister(frb),
2176 ]),
2177 ))
2178 }
2179
2180 // Extended opcode 33: Floating-point square root single (fsqrts)
2181 // Format: fsqrts FRT, FRB
2182 // Only if primary opcode is 63
2183 33 if (word >> 26) == 63 => {
2184 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2185 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2186 Ok((
2187 InstructionType::FloatingPoint,
2188 SmallVec::from_slice(&[
2189 Operand::FpRegister(frt),
2190 Operand::FpRegister(frb),
2191 ]),
2192 ))
2193 }
2194
2195 // Extended opcode 38: Floating-point select (fsel)
2196 // Format: fsel FRT, FRA, FRC, FRB (FRT = FRA >= 0 ? FRC : FRB)
2197 // Only if primary opcode is 63
2198 38 if (word >> 26) == 63 => {
2199 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2200 let fra: u8 = ((word >> 16) & 0x1F) as u8;
2201 let frc: u8 = ((word >> 6) & 0x1F) as u8;
2202 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2203 Ok((
2204 InstructionType::FloatingPoint,
2205 SmallVec::from_slice(&[
2206 Operand::FpRegister(frt),
2207 Operand::FpRegister(fra),
2208 Operand::FpRegister(frc),
2209 Operand::FpRegister(frb),
2210 ]),
2211 ))
2212 }
2213
2214 // Extended opcode 72: Floating-point move register (fmr)
2215 // Format: fmr FRT, FRB
2216 // Only if primary opcode is 63
2217 72 if (word >> 26) == 63 => {
2218 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2219 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2220 Ok((
2221 InstructionType::FloatingPoint,
2222 SmallVec::from_slice(&[
2223 Operand::FpRegister(frt),
2224 Operand::FpRegister(frb),
2225 ]),
2226 ))
2227 }
2228
2229 // Extended opcode 583: Floating-point move from integer word (fctiw)
2230 // Format: fctiw FRT, FRB (convert integer word to FP)
2231 // Only if primary opcode is 63
2232 583 if (word >> 26) == 63 => {
2233 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2234 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2235 Ok((
2236 InstructionType::FloatingPoint,
2237 SmallVec::from_slice(&[
2238 Operand::FpRegister(frt),
2239 Operand::FpRegister(frb),
2240 ]),
2241 ))
2242 }
2243
2244 // Extended opcode 711: Floating-point move from integer word zero (fctiwz)
2245 // Format: fctiwz FRT, FRB (convert integer word to FP, zero upper)
2246 // Only if primary opcode is 63
2247 711 if (word >> 26) == 63 => {
2248 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2249 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2250 Ok((
2251 InstructionType::FloatingPoint,
2252 SmallVec::from_slice(&[
2253 Operand::FpRegister(frt),
2254 Operand::FpRegister(frb),
2255 ]),
2256 ))
2257 }
2258
2259 // Extended opcode 815: Floating-point move to integer word zero (fctiwz)
2260 // Format: fctiwz FRT, FRB (convert FP to integer word, round toward zero)
2261 // Only if primary opcode is 63
2262 815 if (word >> 26) == 63 => {
2263 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2264 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2265 Ok((
2266 InstructionType::FloatingPoint,
2267 SmallVec::from_slice(&[
2268 Operand::FpRegister(frt),
2269 Operand::FpRegister(frb),
2270 ]),
2271 ))
2272 }
2273
2274 // Extended opcode 70: Floating-point move to condition register (mffs)
2275 // Format: mffs FRT (move FPSCR to FRT)
2276 // Only if primary opcode is 63
2277 70 if (word >> 26) == 63 => {
2278 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2279 Ok((
2280 InstructionType::FloatingPoint,
2281 SmallVec::from_slice(&[Operand::FpRegister(frt)]),
2282 ))
2283 }
2284
2285 // Extended opcode 134: Floating-point move from condition register (mtfsf)
2286 // Format: mtfsf BF, FRB (move FRB to FPSCR field BF)
2287 // Only if primary opcode is 63
2288 134 if (word >> 26) == 63 => {
2289 let bf: u8 = ((word >> 23) & 0x7) as u8;
2290 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2291 Ok((
2292 InstructionType::FloatingPoint,
2293 SmallVec::from_slice(&[
2294 Operand::Condition(bf),
2295 Operand::FpRegister(frb),
2296 ]),
2297 ))
2298 }
2299
2300 // Extended opcode 711: Floating-point move from condition register field (mtfsfi)
2301 // Format: mtfsfi BF, IMM (move immediate to FPSCR field BF)
2302 // Only if primary opcode is 63
2303 711 if (word >> 26) == 63 && ((word >> 12) & 0x7) != 0 => {
2304 let bf: u8 = ((word >> 23) & 0x7) as u8;
2305 let imm: u8 = ((word >> 12) & 0xF) as u8;
2306 Ok((
2307 InstructionType::FloatingPoint,
2308 SmallVec::from_slice(&[
2309 Operand::Condition(bf),
2310 Operand::Immediate(imm as i16),
2311 ]),
2312 ))
2313 }
2314
2315 // Extended opcode 18: Floating-point divide (fdiv)
2316 // Format: fdiv FRT, FRA, FRB
2317 // Only if primary opcode is 63
2318 18 if (word >> 26) == 63 => {
2319 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2320 let fra: u8 = ((word >> 16) & 0x1F) as u8;
2321 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2322 Ok((
2323 InstructionType::FloatingPoint,
2324 SmallVec::from_slice(&[
2325 Operand::FpRegister(frt),
2326 Operand::FpRegister(fra),
2327 Operand::FpRegister(frb),
2328 ]),
2329 ))
2330 }
2331
2332 // Extended opcode 0: Floating-point compare (fcmpu/fcmpo)
2333 // Format: fcmpu BF, FRA, FRB
2334 // Only if primary opcode is 63
2335 0 if (word >> 26) == 63 => {
2336 let bf: u8 = ((word >> 23) & 0x7) as u8;
2337 let fra: u8 = ((word >> 16) & 0x1F) as u8;
2338 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2339 Ok((
2340 InstructionType::FloatingPoint,
2341 SmallVec::from_slice(&[
2342 Operand::Condition(bf),
2343 Operand::FpRegister(fra),
2344 Operand::FpRegister(frb),
2345 ]),
2346 ))
2347 }
2348
2349 // Extended opcode 15: Floating-point convert to integer word (fctiw)
2350 // Format: fctiw FRT, FRB
2351 // Only if primary opcode is 63
2352 15 if (word >> 26) == 63 => {
2353 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2354 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2355 Ok((
2356 InstructionType::FloatingPoint,
2357 SmallVec::from_slice(&[
2358 Operand::FpRegister(frt),
2359 Operand::FpRegister(frb),
2360 ]),
2361 ))
2362 }
2363
2364 // Extended opcode 31: Floating-point convert to integer word with round toward zero (fctiwz)
2365 // Format: fctiwz FRT, FRB
2366 // Only if primary opcode is 63
2367 31 if (word >> 26) == 63 => {
2368 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2369 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2370 Ok((
2371 InstructionType::FloatingPoint,
2372 SmallVec::from_slice(&[
2373 Operand::FpRegister(frt),
2374 Operand::FpRegister(frb),
2375 ]),
2376 ))
2377 }
2378
2379 // Extended opcode 12: Floating-point round to single precision (frsp)
2380 // Format: frsp FRT, FRB
2381 // Only if primary opcode is 63
2382 12 if (word >> 26) == 63 => {
2383 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2384 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2385 Ok((
2386 InstructionType::FloatingPoint,
2387 SmallVec::from_slice(&[
2388 Operand::FpRegister(frt),
2389 Operand::FpRegister(frb),
2390 ]),
2391 ))
2392 }
2393
2394 // Extended opcode 264: Floating-point absolute value (fabs)
2395 // Format: fabs FRT, FRB
2396 // Only if primary opcode is 63
2397 264 if (word >> 26) == 63 => {
2398 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2399 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2400 Ok((
2401 InstructionType::FloatingPoint,
2402 SmallVec::from_slice(&[
2403 Operand::FpRegister(frt),
2404 Operand::FpRegister(frb),
2405 ]),
2406 ))
2407 }
2408
2409 // Extended opcode 136: Floating-point negative absolute value (fnabs)
2410 // Format: fnabs FRT, FRB
2411 // Only if primary opcode is 63
2412 136 if (word >> 26) == 63 => {
2413 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2414 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2415 Ok((
2416 InstructionType::FloatingPoint,
2417 SmallVec::from_slice(&[
2418 Operand::FpRegister(frt),
2419 Operand::FpRegister(frb),
2420 ]),
2421 ))
2422 }
2423
2424 // Extended opcode 40: Floating-point negate (fneg)
2425 // Format: fneg FRT, FRB
2426 // Only if primary opcode is 63
2427 40 if (word >> 26) == 63 => {
2428 let frt: u8 = ((word >> 21) & 0x1F) as u8;
2429 let frb: u8 = ((word >> 11) & 0x1F) as u8;
2430 Ok((
2431 InstructionType::FloatingPoint,
2432 SmallVec::from_slice(&[
2433 Operand::FpRegister(frt),
2434 Operand::FpRegister(frb),
2435 ]),
2436 ))
2437 }
2438
2439 // Extended opcode 339: Move from special-purpose register (mfspr)
2440 // Format: mfspr RT, SPR
2441 // SPR encoding: ((SPR[0:4] << 5) | SPR[5:9])
2442 339 => {
2443 let rt: u8 = ((word >> 21) & 0x1F) as u8;
2444 let spr: u16 = ((((word >> 16) & 0x1F) << 5) | ((word >> 11) & 0x1F)) as u16;
2445 Ok((
2446 InstructionType::System,
2447 SmallVec::from_slice(&[
2448 Operand::Register(rt),
2449 Operand::SpecialRegister(spr),
2450 ]),
2451 ))
2452 }
2453
2454 // Extended opcode 467: Move to special-purpose register (mtspr)
2455 // Format: mtspr SPR, RS
2456 467 => {
2457 let rs: u8 = ((word >> 21) & 0x1F) as u8;
2458 let spr: u16 = ((((word >> 16) & 0x1F) << 5) | ((word >> 11) & 0x1F)) as u16;
2459 Ok((
2460 InstructionType::System,
2461 SmallVec::from_slice(&[
2462 Operand::Register(rs),
2463 Operand::SpecialRegister(spr),
2464 ]),
2465 ))
2466 }
2467
2468 // Extended opcode 19: Move from condition register (mfcr)
2469 // Format: mfcr RT
2470 // Only if primary opcode is 31 (not 63)
2471 19 if (word >> 26) == 31 => {
2472 let rt: u8 = ((word >> 21) & 0x1F) as u8;
2473 Ok((
2474 InstructionType::ConditionRegister,
2475 SmallVec::from_slice(&[Operand::Register(rt)]),
2476 ))
2477 }
2478
2479 // Extended opcode 83: Move from condition register field (mfcrf)
2480 // Format: mfcrf RT, CRM (move specific CR field)
2481 83 => {
2482 let rt: u8 = ((word >> 21) & 0x1F) as u8;
2483 let crm: u8 = ((word >> 12) & 0xFF) as u8;
2484 Ok((
2485 InstructionType::ConditionRegister,
2486 SmallVec::from_slice(&[
2487 Operand::Register(rt),
2488 Operand::Condition(crm),
2489 ]),
2490 ))
2491 }
2492
2493 // Extended opcode 144: Move to condition register (mtcr)
2494 // Format: mtcr RS
2495 // Only if primary opcode is 31 (not 63)
2496 144 if (word >> 26) == 31 => {
2497 let rs: u8 = ((word >> 21) & 0x1F) as u8;
2498 Ok((
2499 InstructionType::ConditionRegister,
2500 SmallVec::from_slice(&[Operand::Register(rs)]),
2501 ))
2502 }
2503
2504 // Extended opcode 146: Move to condition register field (mtcrf)
2505 // Format: mtcrf CRM, RS (move to specific CR field)
2506 146 => {
2507 let rs: u8 = ((word >> 21) & 0x1F) as u8;
2508 let crm: u8 = ((word >> 12) & 0xFF) as u8;
2509 Ok((
2510 InstructionType::ConditionRegister,
2511 SmallVec::from_slice(&[
2512 Operand::Register(rs),
2513 Operand::Condition(crm),
2514 ]),
2515 ))
2516 }
2517
2518 // Extended opcode 210: Move from XER (mfxer)
2519 // Format: mfxer RT
2520 210 => {
2521 let rt: u8 = ((word >> 21) & 0x1F) as u8;
2522 Ok((
2523 InstructionType::System,
2524 SmallVec::from_slice(&[Operand::Register(rt)]),
2525 ))
2526 }
2527
2528 // Extended opcode 242: Move to XER (mtxer)
2529 // Format: mtxer RS
2530 242 => {
2531 let rs: u8 = ((word >> 21) & 0x1F) as u8;
2532 Ok((
2533 InstructionType::System,
2534 SmallVec::from_slice(&[Operand::Register(rs)]),
2535 ))
2536 }
2537
2538 // Extended opcode 512: Move from link register (mflr)
2539 // Format: mflr RT
2540 512 => {
2541 let rt: u8 = ((word >> 21) & 0x1F) as u8;
2542 Ok((
2543 InstructionType::Move,
2544 SmallVec::from_slice(&[Operand::Register(rt)]),
2545 ))
2546 }
2547
2548 // Extended opcode 576: Move to link register (mtlr)
2549 // Format: mtlr RS
2550 576 => {
2551 let rs: u8 = ((word >> 21) & 0x1F) as u8;
2552 Ok((
2553 InstructionType::Move,
2554 SmallVec::from_slice(&[Operand::Register(rs)]),
2555 ))
2556 }
2557
2558 // Extended opcode 528: Move from count register (mfctr)
2559 // Format: mfctr RT
2560 528 if (word >> 26) == 31 => {
2561 let rt: u8 = ((word >> 21) & 0x1F) as u8;
2562 Ok((
2563 InstructionType::Move,
2564 SmallVec::from_slice(&[Operand::Register(rt)]),
2565 ))
2566 }
2567
2568 // Extended opcode 592: Move to count register (mtctr)
2569 // Format: mtctr RS
2570 592 => {
2571 let rs: u8 = ((word >> 21) & 0x1F) as u8;
2572 Ok((
2573 InstructionType::Move,
2574 SmallVec::from_slice(&[Operand::Register(rs)]),
2575 ))
2576 }
2577
2578 // Extended opcode 257: Condition register AND (crand)
2579 // Format: crand BT, BA, BB
2580 257 => {
2581 let bt: u8 = ((word >> 21) & 0x1F) as u8;
2582 let ba: u8 = ((word >> 16) & 0x1F) as u8;
2583 let bb: u8 = ((word >> 11) & 0x1F) as u8;
2584 Ok((
2585 InstructionType::ConditionRegister,
2586 SmallVec::from_slice(&[
2587 Operand::Condition(bt),
2588 Operand::Condition(ba),
2589 Operand::Condition(bb),
2590 ]),
2591 ))
2592 }
2593
2594 // Extended opcode 449: Condition register OR (cror)
2595 // Format: cror BT, BA, BB
2596 449 => {
2597 let bt: u8 = ((word >> 21) & 0x1F) as u8;
2598 let ba: u8 = ((word >> 16) & 0x1F) as u8;
2599 let bb: u8 = ((word >> 11) & 0x1F) as u8;
2600 Ok((
2601 InstructionType::ConditionRegister,
2602 SmallVec::from_slice(&[
2603 Operand::Condition(bt),
2604 Operand::Condition(ba),
2605 Operand::Condition(bb),
2606 ]),
2607 ))
2608 }
2609
2610 // Extended opcode 193: Condition register XOR (crxor)
2611 // Format: crxor BT, BA, BB
2612 193 => {
2613 let bt: u8 = ((word >> 21) & 0x1F) as u8;
2614 let ba: u8 = ((word >> 16) & 0x1F) as u8;
2615 let bb: u8 = ((word >> 11) & 0x1F) as u8;
2616 Ok((
2617 InstructionType::ConditionRegister,
2618 SmallVec::from_slice(&[
2619 Operand::Condition(bt),
2620 Operand::Condition(ba),
2621 Operand::Condition(bb),
2622 ]),
2623 ))
2624 }
2625
2626 // Extended opcode 225: Condition register NAND (crnand)
2627 // Format: crnand BT, BA, BB
2628 225 => {
2629 let bt: u8 = ((word >> 21) & 0x1F) as u8;
2630 let ba: u8 = ((word >> 16) & 0x1F) as u8;
2631 let bb: u8 = ((word >> 11) & 0x1F) as u8;
2632 Ok((
2633 InstructionType::ConditionRegister,
2634 SmallVec::from_slice(&[
2635 Operand::Condition(bt),
2636 Operand::Condition(ba),
2637 Operand::Condition(bb),
2638 ]),
2639 ))
2640 }
2641
2642 // Extended opcode 33: Condition register NOR (crnor)
2643 // Format: crnor BT, BA, BB
2644 33 => {
2645 let bt: u8 = ((word >> 21) & 0x1F) as u8;
2646 let ba: u8 = ((word >> 16) & 0x1F) as u8;
2647 let bb: u8 = ((word >> 11) & 0x1F) as u8;
2648 Ok((
2649 InstructionType::ConditionRegister,
2650 SmallVec::from_slice(&[
2651 Operand::Condition(bt),
2652 Operand::Condition(ba),
2653 Operand::Condition(bb),
2654 ]),
2655 ))
2656 }
2657
2658 // Extended opcode 289: Condition register equivalent (creqv)
2659 // Format: creqv BT, BA, BB
2660 289 => {
2661 let bt: u8 = ((word >> 21) & 0x1F) as u8;
2662 let ba: u8 = ((word >> 16) & 0x1F) as u8;
2663 let bb: u8 = ((word >> 11) & 0x1F) as u8;
2664 Ok((
2665 InstructionType::ConditionRegister,
2666 SmallVec::from_slice(&[
2667 Operand::Condition(bt),
2668 Operand::Condition(ba),
2669 Operand::Condition(bb),
2670 ]),
2671 ))
2672 }
2673
2674 // Extended opcode 129: Condition register AND with complement (crandc)
2675 // Format: crandc BT, BA, BB
2676 129 => {
2677 let bt: u8 = ((word >> 21) & 0x1F) as u8;
2678 let ba: u8 = ((word >> 16) & 0x1F) as u8;
2679 let bb: u8 = ((word >> 11) & 0x1F) as u8;
2680 Ok((
2681 InstructionType::ConditionRegister,
2682 SmallVec::from_slice(&[
2683 Operand::Condition(bt),
2684 Operand::Condition(ba),
2685 Operand::Condition(bb),
2686 ]),
2687 ))
2688 }
2689
2690 // Extended opcode 417: Condition register OR with complement (crorc)
2691 // Format: crorc BT, BA, BB
2692 417 => {
2693 let bt: u8 = ((word >> 21) & 0x1F) as u8;
2694 let ba: u8 = ((word >> 16) & 0x1F) as u8;
2695 let bb: u8 = ((word >> 11) & 0x1F) as u8;
2696 Ok((
2697 InstructionType::ConditionRegister,
2698 SmallVec::from_slice(&[
2699 Operand::Condition(bt),
2700 Operand::Condition(ba),
2701 Operand::Condition(bb),
2702 ]),
2703 ))
2704 }
2705
2706 // Cache control instructions (system instructions)
2707 // Extended opcode 86: Data cache block flush (dcbf)
2708 // Format: dcbf RA, RB
2709 86 => Ok((
2710 InstructionType::System,
2711 SmallVec::from_slice(&[
2712 Operand::Register(ra),
2713 Operand::Register(rb),
2714 ]),
2715 )),
2716 // Extended opcode 54: Data cache block store (dcbst)
2717 // Format: dcbst RA, RB
2718 54 => Ok((
2719 InstructionType::System,
2720 SmallVec::from_slice(&[
2721 Operand::Register(ra),
2722 Operand::Register(rb),
2723 ]),
2724 )),
2725 // Extended opcode 278: Data cache block touch (dcbt)
2726 // Format: dcbt RA, RB
2727 278 => Ok((
2728 InstructionType::System,
2729 SmallVec::from_slice(&[
2730 Operand::Register(ra),
2731 Operand::Register(rb),
2732 ]),
2733 )),
2734 // Extended opcode 246: Data cache block touch for store (dcbtst)
2735 // Format: dcbtst RA, RB
2736 246 => Ok((
2737 InstructionType::System,
2738 SmallVec::from_slice(&[
2739 Operand::Register(ra),
2740 Operand::Register(rb),
2741 ]),
2742 )),
2743 // Extended opcode 1014: Data cache block set to zero (dcbz)
2744 // Format: dcbz RA, RB
2745 1014 => Ok((
2746 InstructionType::System,
2747 SmallVec::from_slice(&[
2748 Operand::Register(ra),
2749 Operand::Register(rb),
2750 ]),
2751 )),
2752 // Extended opcode 470: Instruction cache block invalidate (icbi)
2753 // Format: icbi RA, RB
2754 470 => Ok((
2755 InstructionType::System,
2756 SmallVec::from_slice(&[
2757 Operand::Register(ra),
2758 Operand::Register(rb),
2759 ]),
2760 )),
2761
2762 // Memory synchronization instructions
2763 // Extended opcode 598: Synchronize (sync)
2764 598 => Ok((InstructionType::System, SmallVec::new())),
2765 // Extended opcode 150: Instruction synchronize (isync)
2766 150 => Ok((InstructionType::System, SmallVec::new())),
2767 // Extended opcode 854: Enforce in-order execution of I/O (eieio)
2768 854 => Ok((InstructionType::System, SmallVec::new())),
2769
2770 // String operations (rare on GameCube, but included for completeness)
2771 // Extended opcode 597: Load string word immediate (lswi)
2772 // Format: lswi RT, RA, NB - loads NB bytes starting at RA into RT, RT+1, ...
2773 // Note: This conflicts with lmw, but lswi uses different encoding
2774 // Extended opcode 533: Store string word immediate (stswi)
2775 // Format: stswi RS, RA, NB - stores NB bytes from RS, RS+1, ... starting at RA
2776 // Note: This conflicts with stmw, but stswi uses different encoding
2777 // Extended opcode 534: Load string word indexed (lswx)
2778 // Format: lswx RT, RA, RB - loads bytes starting at RA+RB into RT, RT+1, ...
2779 // Only if primary opcode is 31 (not 63)
2780 534 if (word >> 26) == 31 => Ok((
2781 InstructionType::Load,
2782 SmallVec::from_slice(&[
2783 Operand::Register(rt),
2784 Operand::Register(ra),
2785 Operand::Register(rb),
2786 ]),
2787 )),
2788 // Extended opcode 662: Store string word indexed (stswx)
2789 // Format: stswx RS, RA, RB - stores bytes from RS, RS+1, ... starting at RA+RB
2790 // Only if primary opcode is 31 (not 63)
2791 662 if (word >> 26) == 31 => Ok((
2792 InstructionType::Store,
2793 SmallVec::from_slice(&[
2794 Operand::Register(rs),
2795 Operand::Register(ra),
2796 Operand::Register(rb),
2797 ]),
2798 )),
2799
2800 // Extended opcode 597: Load string word immediate (lswi)
2801 // Format: lswi RT, RA, NB - loads NB bytes starting at RA into RT, RT+1, ...
2802 // Only if primary opcode is 31 (not 63)
2803 597 if (word >> 26) == 31 => {
2804 let rt: u8 = ((word >> 21) & 0x1F) as u8;
2805 let ra: u8 = ((word >> 16) & 0x1F) as u8;
2806 let nb: u8 = ((word >> 11) & 0x1F) as u8;
2807 Ok((
2808 InstructionType::Load,
2809 SmallVec::from_slice(&[
2810 Operand::Register(rt),
2811 Operand::Register(ra),
2812 Operand::Immediate(nb as i16),
2813 ]),
2814 ))
2815 }
2816
2817 // Extended opcode 533: Store string word immediate (stswi)
2818 // Format: stswi RS, RA, NB - stores NB bytes from RS, RS+1, ... starting at RA
2819 // Only if primary opcode is 31 (not 63)
2820 533 if (word >> 26) == 31 => {
2821 let rs: u8 = ((word >> 21) & 0x1F) as u8;
2822 let ra: u8 = ((word >> 16) & 0x1F) as u8;
2823 let nb: u8 = ((word >> 11) & 0x1F) as u8;
2824 Ok((
2825 InstructionType::Store,
2826 SmallVec::from_slice(&[
2827 Operand::Register(rs),
2828 Operand::Register(ra),
2829 Operand::Immediate(nb as i16),
2830 ]),
2831 ))
2832 }
2833
2834 // TLB management instructions (system-level, rare)
2835 // Extended opcode 306: TLB invalidate entry (tlbie)
2836 // Format: tlbie RA, RB
2837 306 => Ok((
2838 InstructionType::System,
2839 SmallVec::from_slice(&[
2840 Operand::Register(ra),
2841 Operand::Register(rb),
2842 ]),
2843 )),
2844 // Extended opcode 566: TLB synchronize (tlbsync)
2845 // Format: tlbsync
2846 566 => Ok((InstructionType::System, SmallVec::new())),
2847
2848 // Unknown extended opcode
2849 _ => Ok((InstructionType::Unknown, SmallVec::new())),
2850 }
2851 }
2852}
2853
2854/// Compute rotate mask from MB (mask begin) and ME (mask end) fields.
2855///
2856/// The mask is used in rotate-and-mask instructions (rlwinm, rlwnm, etc.).
2857/// MB and ME are 5-bit fields specifying which bits to preserve.
2858///
2859/// # Arguments
2860/// * `mb` - Mask begin (5 bits, 0-31)
2861/// * `me` - Mask end (5 bits, 0-31)
2862///
2863/// # Returns
2864/// `u32` - 32-bit mask with bits MB through ME set
2865///
2866/// # Algorithm
2867/// If MB <= ME: set bits MB through ME (inclusive)
2868/// If MB > ME: wraparound case - set bits 0 through ME and MB through 31
2869#[inline] // Called frequently for rotate instructions
2870fn compute_mask(mb: u8, me: u8) -> u32 {
2871 let mut mask: u32 = 0u32;
2872
2873 if mb <= me {
2874 // Normal case: set bits MB through ME (inclusive)
2875 for i in mb..=me {
2876 mask |= 1u32 << (31u32 - i as u32);
2877 }
2878 } else {
2879 // Wraparound case: set bits 0 through ME and MB through 31
2880 for i in 0u8..=me {
2881 mask |= 1u32 << (31u32 - i as u32);
2882 }
2883 for i in mb..32u8 {
2884 mask |= 1u32 << (31u32 - i as u32);
2885 }
2886 }
2887
2888 mask
2889}