use yaxpeax_arch::Decoder; use yaxpeax_power::{InstDecoder, IsaVersion, Opcode, display::DefaultRules}; use yaxpeax_power::HintStyle; use std::fmt; mod compare_objdump; mod compare_gekko; mod compare_xenia; mod compare_rpcs3; mod display; mod exhaustive; mod tools; #[derive(Debug, Eq)] struct ParsedInstr { mnemonic: String, operands: Vec, } impl PartialEq for ParsedInstr { fn eq(&self, other: &Self) -> bool { if self.mnemonic == other.mnemonic && self.operands == other.operands { return true; } if self.mnemonic == "twi" && self.mnemonic == other.mnemonic { // HELP: it sure seems like there are two twi condition bits that are processed // like `twnei`. either 3, or 24. but the default alias handling converts twi 3, .. // to twnei, so twi 24, .. needs more .. manual comparison. if self.operands[1..] == other.operands[1..] && self.operands[0] == ParsedOperand::Immediate(24) && other.operands[0] == ParsedOperand::Immediate(3) { return true; } } if self.mnemonic == "twi" && self.mnemonic == other.mnemonic { // HELP: it sure seems like there are two twi condition bits that are processed // like `twnei`. either 3, or 24. but the default alias handling converts twi 3, .. // to twnei, so twi 24, .. needs more .. manual comparison. if self.operands[1..] == other.operands[1..] && other.operands[0] == ParsedOperand::Immediate(24) && self.operands[0] == ParsedOperand::Immediate(3) { return true; } } false } } #[derive(Debug, Eq, Clone)] enum ParsedOperand { Other(String), // a GPR in 0..31 Reg(u8), // an FPR in 0..31 Fpr(u8), // a graphics quantization register (should be 0..7) Gqr(u8), // an SPR Spr(u16), // a vector register in 0..31 or 0..127 if VMX128 is implemented Vr(u16), // a VSE register in 0..63 Vsr(u16), CrField(u8), FpscrField(u8), CrBit(u8), Memory { offset: i64, base: String }, Immediate(i64), RelBranch(i64), XeniaUnhandledShb, XeniaUnhandledCrm, XeniaUnhandledFpscrd, } impl PartialEq for ParsedOperand { fn eq(&self, other: &Self) -> bool { match (self, other) { (ParsedOperand::Other(left), ParsedOperand::Other(right)) => { left == right } (ParsedOperand::Reg(left), ParsedOperand::Reg(right)) => { left == right } (ParsedOperand::Fpr(left), ParsedOperand::Fpr(right)) => { left == right } (ParsedOperand::Spr(left), ParsedOperand::Spr(right)) => { left == right } (ParsedOperand::Vr(left), ParsedOperand::Vr(right)) => { left == right } (ParsedOperand::Vsr(left), ParsedOperand::Vsr(right)) => { left == right } (ParsedOperand::Gqr(left), ParsedOperand::Gqr(right)) => { left == right } // xenia prints unknown SPRs as plain immediates, so match that up here.. (ParsedOperand::Immediate(left), ParsedOperand::Spr(right)) => { *left == *right as i64 } (ParsedOperand::Spr(left), ParsedOperand::Immediate(right)) => { *left as i64 == *right } (ParsedOperand::CrField(nr_l), ParsedOperand::CrField(nr_r)) => { nr_l == nr_r } (ParsedOperand::FpscrField(nr_l), ParsedOperand::FpscrField(nr_r)) => { nr_l == nr_r } // xenia prints FPSCR fields as normal "crf*", we're pickier, so paper over that.. (ParsedOperand::FpscrField(nr_l), ParsedOperand::CrField(nr_r)) => { nr_l == nr_r } (ParsedOperand::CrField(nr_l), ParsedOperand::FpscrField(nr_r)) => { nr_l == nr_r } (ParsedOperand::CrBit(nr_l), ParsedOperand::CrBit(nr_r)) => { nr_l == nr_r } ( ParsedOperand::Memory { offset: offset_l, base: base_l }, ParsedOperand::Memory { offset: offset_r, base: base_r } ) => { (offset_l == offset_r) && ( base_l == base_r || (base_l == "0" && base_r == "r0") ) } (ParsedOperand::CrBit(nr_l), ParsedOperand::Other(nr_r)) | (ParsedOperand::Other(nr_r), ParsedOperand::CrBit(nr_l)) => { match (nr_l, nr_r.as_str()) { (0, "lt") => true, (1, "gt") => true, (2, "eq") => true, (3, "so") => true, (4, "ge") => true, (5, "le") => true, (6, "ne") => true, (7, "ns") => true, _ => false, } } (ParsedOperand::RelBranch(left), ParsedOperand::RelBranch(right)) => { left == right } (ParsedOperand::Immediate(left), ParsedOperand::Immediate(right)) => { if left == right { return true; } if *left < 0 { if (65536 + *left) == *right { return true; } } else if *right < 0 { if *left == (65536 + *right) { return true; } } false } (ParsedOperand::RelBranch(left), ParsedOperand::Immediate(right)) => { left.wrapping_add(4) as u32 == *right as u32 } (ParsedOperand::Immediate(left), ParsedOperand::RelBranch(right)) => { *left as u32 == right.wrapping_add(4) as u32 } (ParsedOperand::XeniaUnhandledFpscrd, ParsedOperand::Immediate(_)) | (ParsedOperand::Immediate(_), ParsedOperand::XeniaUnhandledFpscrd) | (ParsedOperand::XeniaUnhandledShb, ParsedOperand::Immediate(_)) | (ParsedOperand::Immediate(_), ParsedOperand::XeniaUnhandledShb) | (ParsedOperand::XeniaUnhandledCrm, ParsedOperand::Immediate(_)) | (ParsedOperand::Immediate(_), ParsedOperand::XeniaUnhandledCrm) => { // Xenia says "UNHANDLED ..." here, but we .. handle it :3 true } _ => { false } } } } impl ParsedOperand { fn rel_branch(i: i64) -> Self { ParsedOperand::RelBranch(i) } fn try_parse_hex_or_dec(s: &str) -> Option { let mut s = s.trim(); let mut negate = false; if s.as_bytes()[0] == b'-' { negate = true; s = &s[1..]; } else if s.as_bytes()[0] == b'+' { s = &s[1..]; } let v = if s.starts_with("0x") { u64::from_str_radix(&s[2..], 16).ok()? as i64 } else if s.ends_with("h") { u64::from_str_radix(&s[..s.len() - 1], 16).ok()? as i64 } else { i64::from_str_radix(s, 10).ok()? }; if negate { Some(-v) } else { Some(v) } } fn from_str(s: &str) -> Result { let s = s.trim(); let first = s.as_bytes()[0]; if s == "(UNHANDLED SHB)" { Ok(ParsedOperand::XeniaUnhandledShb) } else if s == "(UNHANDLED CRM)" { Ok(ParsedOperand::XeniaUnhandledCrm) } else if s == "(UNHANDLED FPSCRD)" { Ok(ParsedOperand::XeniaUnhandledFpscrd) } else if let Some(imm) = Self::try_parse_hex_or_dec(s) { Ok(ParsedOperand::Immediate(imm)) } else if first == b'$' { let rest = &s[1..]; let offset = Self::try_parse_hex_or_dec(rest).ok_or(ParseError::Offset)?; Ok(ParsedOperand::rel_branch(offset)) } else if s.as_bytes()[s.as_bytes().len() - 1] == b')' { let paren_start = s.find('(').ok_or(ParseError::WrongParens)?; let offset = &s[..paren_start]; let base = &s[paren_start + 1..s.as_bytes().len() - 1]; let offset = Self::try_parse_hex_or_dec(offset).ok_or(ParseError::Offset)?; Ok(ParsedOperand::Memory { offset, base: base.to_string(), }) } else if s.starts_with("gqr") { let rest = &s[3..]; let num: u8 = rest.parse().map_err(|_| ParseError::RegNum)?; Ok(ParsedOperand::Gqr(num)) } else if s.starts_with("r") { let rest = &s[1..]; let num: u8 = rest.parse().map_err(|_| ParseError::RegNum)?; Ok(ParsedOperand::Reg(num)) } else if s.starts_with("spr") { let rest = &s[3..]; let num: u16 = rest.parse().map_err(|_| ParseError::RegNum)?; Ok(ParsedOperand::Spr(num)) } else if s.starts_with("fpscrf") { let rest = &s[6..]; let num: u8 = rest.parse().map_err(|_| ParseError::RegNum)?; Ok(ParsedOperand::FpscrField(num)) } else if s.starts_with("vs") { let rest = &s[2..]; let num: u16 = rest.parse().map_err(|_| ParseError::RegNum)?; Ok(ParsedOperand::Vsr(num)) } else if s.starts_with("vr") { let rest = &s[2..]; let num: u16 = rest.parse().map_err(|_| ParseError::RegNum)?; Ok(ParsedOperand::Vr(num)) } else if s.starts_with("v") { let rest = &s[1..]; let num: u16 = rest.parse().map_err(|_| ParseError::RegNum)?; Ok(ParsedOperand::Vr(num)) } else if s.starts_with("fcr") { let rest = &s[3..]; Ok(ParsedOperand::Other(rest.to_string())) } else if s.starts_with("fr") { let rest = &s[2..]; let num: u8 = rest.parse().map_err(|_| ParseError::RegNum)?; Ok(ParsedOperand::Fpr(num)) } else if s.starts_with("f") { let rest = &s[1..]; let num: u8 = rest.parse().map_err(|_| ParseError::RegNum)?; Ok(ParsedOperand::Fpr(num)) } else if s.starts_with("crf") { // the Power ISA books call these operands "cr", see `cmpi` and related. start with // "crf" though because it is more specific than "cr" and is the form that xenia // calls this.. consider: // xenia calls these "crf", such as: // edbce82a: cmpli crf5, 1, r8, 0xBCED let rest = &s[3..]; let num: u8 = rest.parse().map_err(|_| ParseError::RegNum)?; Ok(ParsedOperand::CrField(num)) } else if s.starts_with("cr") && s.contains("[") && s.ends_with("]") { // an rpcs3-style `cr0[lt]`-like operand, maybe.. let (crf, field) = s[..s.len() - 1].split_once("[").ok_or(ParseError::Crb)?; static FIELDS: &'static [&'static str] = &[ "lt", "gt", "eq", "so" ]; let bit_idx = FIELDS.iter().position(|f| f == &field).ok_or(ParseError::Crb)?; let cr_field = crf.strip_prefix("cr").ok_or(ParseError::Crb)?; let cr_field: u8 = cr_field.parse().map_err(|_| ParseError::RegNum)?; Ok(ParsedOperand::CrBit(cr_field * 4 + bit_idx as u8)) } else if s.contains("*") && s.contains("+") { let crf_plus = s.strip_prefix("4*").ok_or(ParseError::Crb)?; let (crf, field) = crf_plus.split_once("+").ok_or(ParseError::Crb)?; static FIELDS: &'static [&'static str] = &[ "lt", "gt", "eq", "so" ]; let bit_idx = FIELDS.iter().position(|f| f == &field).ok_or(ParseError::Crb)?; let cr_field = crf.strip_prefix("cr").ok_or(ParseError::Crb)?; let cr_field: u8 = cr_field.parse().map_err(|_| ParseError::RegNum)?; Ok(ParsedOperand::CrBit(cr_field * 4 + bit_idx as u8)) } else if s.starts_with("crb") { let rest = &s[3..]; let num: u8 = rest.parse().map_err(|_| ParseError::RegNum)?; Ok(ParsedOperand::CrBit(num)) } else if s.starts_with("cr") { let rest = &s[2..]; let num: u8 = rest.parse().map_err(|_| ParseError::RegNum)?; Ok(ParsedOperand::CrField(num)) } else { static FIELDS: &'static [&'static str] = &[ "lt", "gt", "eq", "so" ]; if let Some(bit_idx) = FIELDS.iter().position(|f| f == &s) { Ok(ParsedOperand::CrBit(bit_idx as u8)) } else { Ok(ParsedOperand::Other(s.to_string())) } } } } #[derive(Debug)] enum ParseError { InstructionAddress, Offset, RegNum, Crb, WrongDelimiters, WrongParens, NoBase, BranchDest, } impl fmt::Display for ParseError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { ParseError::InstructionAddress => { f.write_str("bad instruction address") } ParseError::Offset => { f.write_str("failed to parse memory offset") } ParseError::RegNum => { f.write_str("failed to register number") } ParseError::Crb => { f.write_str("failed to parse CR bit") } ParseError::WrongDelimiters => { f.write_str("instruction looked like objdump but wrong number of columns?") } ParseError::WrongParens => { f.write_str("instruction has a mem operand but wrong parens?") } ParseError::NoBase => { f.write_str("objdump-like instruction did not have a base address") } ParseError::BranchDest => { f.write_str("couldn't parse branch destination") } } } } impl ParsedInstr { // accepts either objdump format (`addr:\tb y t e s \tinstr`) or plain instructions. sorry. fn from_str(mut s: &str) -> Result { s = s.trim(); let mut instr = ParsedInstr { mnemonic: String::new(), operands: Vec::new(), }; let mut base: Option = None; if let Some((addr, rest)) = s.split_once(":\t") { let Some((_bytes, rest)) = rest.split_once("\t") else { return Err(ParseError::WrongDelimiters); }; s = rest.trim(); base = Some(u64::from_str_radix(addr.trim(), 16).map_err(|_e| { ParseError::InstructionAddress })?); } let Some((mnemonic, rest)) = s.split_once(' ') else { instr.mnemonic = s.to_owned(); ParsedInstr::canonicalize(&mut instr)?; return Ok(instr); }; instr.mnemonic = mnemonic.to_owned(); let rest = rest.trim(); if rest.len() == 0 { // such as "sync " return Ok(instr); } for op in rest.split(',') { if let Some((lhs, _rhs)) = op.split_once("<") { // MASM-style Xenon output shows d3d instructions' type as imm, like // 0. so if lhs is an integer in the range 0..7, with no space between it // and , assume this is that. if !lhs.ends_with(" ") { let ty = u64::from_str_radix(lhs.trim(), 10).map_err(|_e| { ParseError::BranchDest })?; if ty > 7 { return Err(ParseError::BranchDest); } if op.ends_with(">") { instr.operands.push(ParsedOperand::Other(op.to_string())); continue; } } let base = base.ok_or(ParseError::NoBase)?; let dest = u64::from_str_radix(lhs.trim(), 16).map_err(|_e| { ParseError::BranchDest })?; let offset = dest.wrapping_sub(base) as i64; let relativized = if offset < 0 { format!("$-0x{:x}", -offset) } else if offset > 10 { format!("$+0x{:x}", offset) } else { format!("$+{}", offset) }; instr.operands.push(ParsedOperand::from_str(relativized.as_str()).expect("can parse op")); } else { // rpcs3 is willing to say some really strange operands, like `lfsx f0, r0(r0)`. // this isn't strictly allowed by the manual, but it's a fair interpretation of the // RA+RB indexing, i suppose. let res = ParsedOperand::from_str(op); match res { Ok(parsed) => { instr.operands.push(parsed); } Err(err) => { if let Some((left, right)) = op[..op.len() - 1].split_once("(") { instr.operands.push(ParsedOperand::from_str(left).expect("left op")); instr.operands.push(ParsedOperand::from_str(right).expect("left op")); } else { panic!("parsing {}, got {}", op, err); } } } } } ParsedInstr::canonicalize(&mut instr)?; Ok(instr) } fn canonicalize(inst: &mut Self) -> Result<(), ParseError> { let mut dot_suffix = false; let mut to_normalize = inst.mnemonic.clone(); if let Some(rest) = to_normalize.strip_suffix(".") { dot_suffix = true; to_normalize = rest.to_string(); } match to_normalize.as_str() { "mftb" => { if inst.operands.len() == 1 { // this is "mftb rN", which implies TBR=268 inst.operands.push(ParsedOperand::Immediate(268)); } Ok(()) } "mftbu" => { if inst.operands.len() == 1 { // this is "mftbu rN", which implies mftb with TBR=269 inst.mnemonic = "mftb".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(ParsedOperand::Immediate(269)); } Ok(()) } "hwsync" => { inst.mnemonic = "sync".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(ParsedOperand::Immediate(0)); return Ok(()); } "lwsync" => { inst.mnemonic = "sync".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(ParsedOperand::Immediate(1)); return Ok(()); } "ptesync" => { inst.mnemonic = "sync".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(ParsedOperand::Immediate(2)); return Ok(()); } "crclr" => { inst.mnemonic = "crxor".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(inst.operands[0].clone()); inst.operands.push(inst.operands[0].clone()); return Ok(()); } "crnot" => { inst.mnemonic = "crnor".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(inst.operands[1].clone()); return Ok(()); } // the splat instructions (that take an immediate) are defined in the Power manuals as // having their upper bits ignored when they're out of range. some disassemblers don't // care about this and report the hardware-ignored upper bits, so fix that up here. "vspltw" => { match inst.operands[2].clone() { ParsedOperand::Immediate(lane) => { inst.operands.remove(2); inst.operands.push(ParsedOperand::Immediate(lane & 0b11)); return Ok(()); } other => { panic!("impossible lane operand: {:?}", other); } } } "vsplth" => { match inst.operands[2].clone() { ParsedOperand::Immediate(lane) => { inst.operands.remove(2); inst.operands.push(ParsedOperand::Immediate(lane & 0b111)); return Ok(()); } other => { panic!("impossible lane operand: {:?}", other); } } } "vspltb" => { match inst.operands[2].clone() { ParsedOperand::Immediate(lane) => { inst.operands.remove(2); inst.operands.push(ParsedOperand::Immediate(lane & 0b1111)); return Ok(()); } other => { panic!("impossible lane operand: {:?}", other); } } } "or" => { // `or ra, rb, rb` has an alias to `mr ra, rb` as in "move register" if inst.operands.len() == 3 && inst.operands[1] == inst.operands[2] { inst.operands.remove(2); inst.mnemonic = "mr".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } } Ok(()) } "nor" => { // `or ra, rb, rb` has an alias to `mr ra, rb` as in "move register" if inst.operands.len() == 3 && inst.operands[1] == inst.operands[2] { inst.operands.remove(2); inst.mnemonic = "not".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } } Ok(()) } "ori" => { // `or r0, r0, 0` alias `nop` if inst.operands.len() == 3 && inst.operands[0] == inst.operands[1] && inst.operands[2] == ParsedOperand::Immediate(0) && inst.operands[0] == ParsedOperand::Reg(0) { inst.operands = Vec::new(); inst.mnemonic = "nop".to_string(); } // this is an alias rpcs3 produces.. if inst.operands.len() == 3 && inst.operands[2] == ParsedOperand::Immediate(0) { inst.operands.remove(2); inst.mnemonic = "mr".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } } Ok(()) } "addi" => { if inst.operands.len() == 2 { let ParsedOperand::Memory { offset, base } = inst.operands[1].clone() else { panic!("two-operand addi and it's not cell?"); }; inst.operands.remove(1); inst.operands.push(ParsedOperand::from_str(&base).expect("can parse")); inst.operands.push(ParsedOperand::Immediate(offset)); } if inst.operands[1] == ParsedOperand::Reg(0) { inst.mnemonic = "li".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.remove(1); } else if let ParsedOperand::Immediate(i) = inst.operands[2] { if i < 0 { inst.mnemonic = "subi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands[2] = ParsedOperand::Immediate(-i); } } Ok(()) } "addic" => { if inst.operands.len() == 2 { let ParsedOperand::Memory { offset, base } = inst.operands[1].clone() else { panic!("two-operand addic and it's not cell?"); }; inst.operands.remove(1); inst.operands.push(ParsedOperand::from_str(&base).expect("can parse")); inst.operands.push(ParsedOperand::Immediate(offset)); } if let ParsedOperand::Immediate(i) = inst.operands[2] { if i < 0 { inst.mnemonic = "subic".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands[2] = ParsedOperand::Immediate(-i); } } Ok(()) } "addis" => { if inst.operands.len() == 2 { let ParsedOperand::Memory { offset, base } = inst.operands[1].clone() else { panic!("two-operand addis and it's not cell?"); }; inst.operands.remove(1); inst.operands.push(ParsedOperand::from_str(&base).expect("can parse")); inst.operands.push(ParsedOperand::Immediate(offset)); } if inst.operands[1] == ParsedOperand::Reg(0) { inst.mnemonic = "lis".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.remove(1); } else if let ParsedOperand::Immediate(i) = inst.operands[2] { if i < 0 { inst.mnemonic = "subis".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands[2] = ParsedOperand::Immediate(-i); } } Ok(()) } "cmp" => { let width = inst.operands[1].clone(); match width { ParsedOperand::Immediate(0) => { inst.mnemonic = "cmpw".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.remove(1); } ParsedOperand::Immediate(1) => { inst.mnemonic = "cmpd".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.remove(1); } _ => { /* other widths are totally bogus, nothing to say here */ } } // the named condition register field is optional iff it's 0 if inst.operands[0] == ParsedOperand::CrField(0) { inst.operands.remove(0); } Ok(()) } "cmpi" => { let width = inst.operands[1].clone(); match width { ParsedOperand::Immediate(0) => { inst.mnemonic = "cmpwi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.remove(1); } ParsedOperand::Immediate(1) => { inst.mnemonic = "cmpdi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.remove(1); } _ => { /* other widths are totally bogus, nothing to say here */ } } // the named condition register field is optional iff it's 0 if inst.operands[0] == ParsedOperand::CrField(0) { inst.operands.remove(0); } Ok(()) } "cmpl" => { let width = inst.operands[1].clone(); match width { ParsedOperand::Immediate(0) => { inst.mnemonic = "cmplw".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.remove(1); } ParsedOperand::Immediate(1) => { inst.mnemonic = "cmpld".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.remove(1); } _ => { /* other widths are totally bogus, nothing to say here */ } } // the named condition register field is optional iff it's 0 if inst.operands[0] == ParsedOperand::CrField(0) { inst.operands.remove(0); } Ok(()) } "cmpli" => { let width = inst.operands[1].clone(); match width { ParsedOperand::Immediate(0) => { inst.mnemonic = "cmplwi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.remove(1); } ParsedOperand::Immediate(1) => { inst.mnemonic = "cmpldi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.remove(1); } _ => { /* other widths are totally bogus, nothing to say here */ } } // the named condition register field is optional iff it's 0 if inst.operands[0] == ParsedOperand::CrField(0) { inst.operands.remove(0); } Ok(()) } "rlwnm" => { if let (ParsedOperand::Immediate(0), ParsedOperand::Immediate(31)) = (inst.operands[3].clone(), inst.operands[4].clone()) { inst.mnemonic = "rotlw".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.remove(4); inst.operands.remove(3); } Ok(()) } "rlwimi" => { if let ParsedOperand::Immediate(mb) = inst.operands[3].clone() { let me = if let ParsedOperand::Immediate(me) = inst.operands[4].clone() { me } else { panic!("impossible operand"); }; if me != 31 { inst.mnemonic = "inslwi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.remove(4); inst.operands.remove(3); inst.operands.remove(2); inst.operands.push(ParsedOperand::Immediate(mb)); inst.operands.push(ParsedOperand::Immediate((me + 1).wrapping_sub(mb))); } } Ok(()) } "rlwinm" => { if let ( ParsedOperand::Immediate(sh), ParsedOperand::Immediate(mb), ParsedOperand::Immediate(me), ) = ( inst.operands[2].clone(), inst.operands[3].clone(), inst.operands[4].clone(), ) { inst.operands.remove(4); inst.operands.remove(3); inst.operands.remove(2); if sh == 0 && mb == 0 && me != 31 { inst.mnemonic = "clrrwi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(ParsedOperand::Immediate(31 - me)); } else if sh == 0 && me == 31 && mb != 0 { inst.mnemonic = "clrlwi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(ParsedOperand::Immediate(mb)); } else if mb == 0 && me == 31 && sh != 0 { inst.mnemonic = "rotlwi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(ParsedOperand::Immediate(sh)); } else if sh + me == 31 && mb == 0 { inst.mnemonic = "slwi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(ParsedOperand::Immediate(sh)); } else if sh + mb == 32 && me == 31 { inst.mnemonic = "srwi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(ParsedOperand::Immediate(mb)); } else if mb == 0 && me != 31 { inst.mnemonic = "extlwi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(ParsedOperand::Immediate(me + 1)); inst.operands.push(ParsedOperand::Immediate(sh)); } else { inst.operands.push(ParsedOperand::Immediate(sh)); inst.operands.push(ParsedOperand::Immediate(mb)); inst.operands.push(ParsedOperand::Immediate(me)); } } Ok(()) } "rldicl" => { if let ( ParsedOperand::Immediate(sh), ParsedOperand::Immediate(mb), ) = ( inst.operands[2].clone(), inst.operands[3].clone(), ) { inst.operands.remove(3); inst.operands.remove(2); if sh + mb == 64 { inst.mnemonic = "srdi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(ParsedOperand::Immediate(64 - sh)); } else if sh == 0 { inst.mnemonic = "clrldi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(ParsedOperand::Immediate(mb)); } else { inst.operands.push(ParsedOperand::Immediate(sh)); inst.operands.push(ParsedOperand::Immediate(mb)); } } Ok(()) } "rldicr" => { if let ( ParsedOperand::Immediate(sh), ParsedOperand::Immediate(mb), ) = ( inst.operands[2].clone(), inst.operands[3].clone(), ) { inst.operands.remove(3); inst.operands.remove(2); if sh + mb == 63 { inst.mnemonic = "sldi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(ParsedOperand::Immediate(sh)); } else if sh == 0 { inst.mnemonic = "clrrdi".to_string(); if dot_suffix { inst.mnemonic.push_str("."); } inst.operands.push(ParsedOperand::Immediate(63 - mb)); } else { inst.operands.push(ParsedOperand::Immediate(sh)); inst.operands.push(ParsedOperand::Immediate(mb)); } } Ok(()) } "tdlt" => { inst.mnemonic = "td".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(1)); Ok(()) } "tdgt" => { inst.mnemonic = "td".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(2)); Ok(()) } "tdne" => { inst.mnemonic = "td".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(24)); Ok(()) } "tdeq" => { inst.mnemonic = "td".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(4)); Ok(()) } "tdlge" => { inst.mnemonic = "td".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(5)); Ok(()) } "tdlle" => { inst.mnemonic = "td".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(6)); Ok(()) } "tdlgti" => { inst.mnemonic = "tdi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(1)); Ok(()) } "tdllti" => { inst.mnemonic = "tdi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(2)); Ok(()) } "tdeqi" => { inst.mnemonic = "tdi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(4)); Ok(()) } "tdlgei" => { inst.mnemonic = "tdi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(5)); Ok(()) } "tdllei" => { inst.mnemonic = "tdi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(6)); Ok(()) } "twlt" => { inst.mnemonic = "tw".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(1)); Ok(()) } "twgt" => { inst.mnemonic = "tw".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(2)); Ok(()) } "twne" => { inst.mnemonic = "tw".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(3)); Ok(()) } "tweq" => { inst.mnemonic = "tw".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(4)); Ok(()) } "twlge" => { inst.mnemonic = "tw".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(5)); Ok(()) } "twlle" => { inst.mnemonic = "tw".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(6)); Ok(()) } "tdgti" => { inst.mnemonic = "tdi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(8)); Ok(()) } "tdgei" => { inst.mnemonic = "tdi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(12)); Ok(()) } "tdlti" => { inst.mnemonic = "tdi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(16)); Ok(()) } "tdlei" => { inst.mnemonic = "tdi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(20)); Ok(()) } "tdnei" => { inst.mnemonic = "tdi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(24)); Ok(()) } "twlgti" => { inst.mnemonic = "twi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(1)); Ok(()) } "twllti" => { inst.mnemonic = "twi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(2)); Ok(()) } "tweqi" => { inst.mnemonic = "twi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(4)); Ok(()) } "twlgei" => { inst.mnemonic = "twi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(5)); Ok(()) } "twllei" => { inst.mnemonic = "twi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(6)); Ok(()) } "twgti" => { inst.mnemonic = "twi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(8)); Ok(()) } "twgei" => { inst.mnemonic = "twi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(12)); Ok(()) } "twlti" => { inst.mnemonic = "twi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(16)); Ok(()) } "twlei" => { inst.mnemonic = "twi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(20)); Ok(()) } "twnei" => { inst.mnemonic = "twi".to_string(); inst.operands.insert(0, ParsedOperand::Immediate(24)); Ok(()) } "tw" => { if inst.operands[0] == ParsedOperand::Immediate(31) { inst.mnemonic = "trap".to_string(); inst.operands = Vec::new(); } Ok(()) } _ => { ParsedInstr::canonicalize_branch(inst) } } } fn canonicalize_branch(inst: &mut Self) -> Result<(), ParseError> { let mut a_suffix = false; let mut l_suffix = false; let mut has_lr = false; let mut has_ctr = false; let mut canonicalize = false; if inst.mnemonic == "bc" { canonicalize = true; } else if inst.mnemonic == "bca" { a_suffix = true; canonicalize = true; } else if inst.mnemonic == "bcl" { l_suffix = true; canonicalize = true; } else if inst.mnemonic == "bcla" { l_suffix = true; a_suffix = true; canonicalize = true; } let mut computed_bo = 0; let mut computed_bi = 0; if let Some(rest) = inst.mnemonic.strip_prefix("b") { // the suffix bits are.. // * `+/-` for prediction hints, optionally // * `a` for absolute addressing, optionally // * `lr` for "branch to LR", optionally // * `l` for "write to LR", optionally // // the tricky bit is that writing to LR in an absolute branch versus branch to LR swap // the order of the l/a and lr/l bits. let mut prediction = ""; let rest = rest.strip_suffix("-") .map(|r| { prediction = "-"; r }) .unwrap_or(rest); let rest = rest.strip_suffix("+") .map(|r| { prediction = "+"; r }) .unwrap_or(rest); // a trailing `t` is not interesting; it's the default. /* let rest = if !rest.ends_with("lt") && !rest.ends_with("gt") { rest.strip_suffix("t") .unwrap_or(rest) } else { rest }; */ let rest = rest.strip_suffix("a") .map(|r| { a_suffix = true; r }) .unwrap_or(rest); let rest = rest.strip_suffix("l") .map(|r| { l_suffix = true; r }) .unwrap_or(rest); let rest = rest.strip_suffix("lr") .map(|r| { has_lr = true; r }) .unwrap_or(rest); let rest = rest.strip_suffix("ctr") .map(|r| { has_ctr = true; r }) .unwrap_or(rest); // now we're down to the stem of the branch alias, which is one of: // * empty string ("b", "bl") // * "c", "cl" ("bc", "bcl") with a condition detached as the first "operand" // * "dnz", "dz" with a condition either detached or with bare BO/BI operands // * "dnzt", "dnzf" like above // * "dzt", "dzf" like above if ["", "c"].contains(&rest) { if prediction != "" { computed_bo |= 0b10; if prediction == "+" { computed_bo |= 1; } } canonicalize = true; } else if ["lt", "gt", "eq", "so", "ge", "le", "ne", "ns"].contains(&rest) { canonicalize = true; } else { match rest { "dnzt" | "dnz" => { computed_bo |= 0; canonicalize = true; } "dzt" | "dz" => { computed_bo |= 2; canonicalize = true; } "dnzf" => { computed_bo |= 0b1000; canonicalize = true; } "dzf" => { computed_bo |= 0b1010; canonicalize = true; } /* these three come from rpcs3/cell */ "dnzff" => { computed_bo |= 0b1000; canonicalize = true; } "dzff" => { computed_bo |= 0b1010; canonicalize = true; } "dnzflf" => { computed_bo |= 0b1000; l_suffix = true; canonicalize = true; } "dzflf" => { computed_bo |= 0b1010; l_suffix = true; canonicalize = true; } "dnzfaf" => { computed_bo |= 0b1000; a_suffix = true; canonicalize = true; } "dzfaf" => { computed_bo |= 0b1010; a_suffix = true; canonicalize = true; } "dnzflaf" => { computed_bo |= 0b1000; a_suffix = true; l_suffix = true; canonicalize = true; } "dzflaf" => { computed_bo |= 0b1010; a_suffix = true; l_suffix = true; canonicalize = true; } "dnzflrf" => { computed_bo |= 0b1000; has_lr = true; canonicalize = true; } _ => { /* nothing */ //eprintln!("rest is {}", rest); //eprintln!("inst is {:?}", inst); if rest == "rw" || rest == "rd" || rest == "rh" { // brw return Ok(()); } if rest == "permd" { // bpermd return Ok(()); } if inst.mnemonic == "bblels" || inst.mnemonic == "bbelr" { // e500 BTB locking instructions return Ok(()); } return Err(ParseError::BranchDest); } } } } if !canonicalize { return Ok(()); } // either there are two operands or three. with two, branching on crf0. if three, it's // BO and BI. // if inst.operands.len() == 3 { match inst.operands.get(0).as_ref().unwrap() { ParsedOperand::Immediate(bo) => { computed_bo = *bo; }, ParsedOperand::CrBit(bit) => { assert!(*bit < 4); computed_bo |= 0b01000; computed_bi = *bit as i64; } ParsedOperand::Other(cond) => { // if there's an explicit condition, we have to unwind that back into bits // of BO and BI.. in either case, there will be a crf operand to follow // which adjusts BI we compute here. let (bi_lo, inverted) = match cond.as_str() { "lt" => (0, true), "gt" => (1, true), "eq" => (2, true), "so" => (3, true), "ge" => (0, false), "le" => (1, false), "ne" => (2, false), "ns" => (3, false), other => panic!("unknown predicate {other}"), }; if inverted { computed_bo |= 0b01000; } computed_bi = bi_lo; } other => panic!("unexpected operand type {other:?}"), }; match inst.operands.get(1).as_ref().unwrap() { ParsedOperand::Immediate(bi) => { computed_bi = *bi; }, ParsedOperand::CrField(crf) => { computed_bi += *crf as i64 * 4; } other => panic!("unexpected operand type {other:?}"), }; // at this point we've hopefully inferred the original BO and BI fields for the // instruction, as well as absolute. run that back through canonicalization and see // where that gets it let mut new_mnemonic = String::new(); let suffix = yaxpeax_power::compute_branch_mnemonic( &mut new_mnemonic, &DefaultRules::new(), // TODO: probably should plumb a notion of version-appropriate hint style but... Some(HintStyle::PowerIsa), computed_bo as u8, computed_bi as u8, // PowerIsa hinting does not need an offset. 0, a_suffix, l_suffix, has_lr, has_ctr, ).expect("can normalize branch instr"); inst.mnemonic = new_mnemonic; let mut new_ops = Vec::new(); if let Some(suffix) = suffix.cond { new_ops.push(ParsedOperand::Other(suffix.to_string())); } if suffix.crf > 0 { new_ops.push(ParsedOperand::CrField(suffix.crf)); } new_ops.push(inst.operands[2].clone()); inst.operands = new_ops; return Ok(()); } else if inst.operands.len() == 2 { match inst.operands.get(0).as_ref().unwrap() { ParsedOperand::CrField(field) => { // if there's a conditional branch, crf0 can be mentioned or omitted. in a // two-operand form, the branch instruction if *field == 0 { inst.operands.remove(0); } } ParsedOperand::Other(cond) => { // THE instruction may have omitted crf0 and instead we just have a condition // code to work with. let (bi_lo, inverted) = match cond.as_str() { "lt" => (0, true), "gt" => (1, true), "eq" => (2, true), "so" => (3, true), "ge" => (0, false), "le" => (1, false), "ne" => (2, false), "ns" => (3, false), other => panic!("unknown predicate {other}"), }; if inverted { computed_bo |= 0b01000; } computed_bi = bi_lo; // at this point we've hopefully inferred the original BO and BI fields for the // instruction, as well as absolute. run that back through canonicalization and // see where that gets it let mut new_mnemonic = String::new(); let mut new_mnemonic = String::new(); let suffix = yaxpeax_power::compute_branch_mnemonic( &mut new_mnemonic, &DefaultRules::new(), // TODO: probably should plumb a notion of version-appropriate hint style but... Some(HintStyle::PowerIsa), computed_bo as u8, computed_bi as u8, // PowerIsa hinting does not need an offset. 0, a_suffix, l_suffix, has_lr, has_ctr, ).expect("can normalize branch instr"); inst.mnemonic = new_mnemonic; let mut new_ops = Vec::new(); if let Some(suffix) = suffix.cond { new_ops.push(ParsedOperand::Other(suffix.to_string())); } assert_eq!(suffix.crf, 0); new_ops.push(inst.operands[1].clone()); inst.operands = new_ops; } ParsedOperand::Immediate(i) => { if let Some(ParsedOperand::Immediate(bi)) = inst.operands.get(1) { let bo = i; let mut new_mnemonic = String::new(); let suffix = yaxpeax_power::compute_branch_mnemonic( &mut new_mnemonic, &DefaultRules::new(), // TODO: probably should plumb a notion of version-appropriate hint style but... Some(HintStyle::PowerIsa), *bo as u8, *bi as u8, // PowerIsa hinting does not need an offset. 0, a_suffix, l_suffix, has_lr, has_ctr, ).expect("can normalize branch instr"); inst.mnemonic = new_mnemonic; let mut new_ops = Vec::new(); if let Some(suffix) = suffix.cond { new_ops.push(ParsedOperand::Other(suffix.to_string())); } if suffix.crf > 0 { new_ops.push(ParsedOperand::CrField(suffix.crf)); } inst.operands = new_ops; } return Ok(()); } ParsedOperand::CrBit(_bit) => { // TODO: normalize instructions like bdnzl lt, $+0x1234 return Ok(()); } other => panic!("unexpected operand type {other:?}"), }; return Ok(()); } else { return Ok(()); } } } #[test] fn parse_instructions() { let parsed_objdump = ParsedInstr::from_str("c000000000025008:\t54 ff ff 4b \tb c000000000024f5c ") .expect("can parse"); let offset = (0xc000000000024f5cu64.wrapping_sub(0xc000000000025008u64)) as i64; let expected = ParsedInstr { mnemonic: "b".to_owned(), operands: vec![ParsedOperand::rel_branch(offset)] }; assert_eq!(parsed_objdump, expected); // well, this one doesn't quite work because it's ambiguous in general if the number is an // immediate or a branch destination. need to know the mnemonic at that point and that's more // than ParsedInstr cares to do right now. /* let parsed_objdump_2 = ParsedInstr::from_str(" 0:\t54 ff ff 4b \tb 0xffffffffffffff54") .expect("can parse"); assert_eq!(parsed_objdump_2, expected); */ let parsed = ParsedInstr::from_str("b $-0xac") .expect("can parse"); assert_eq!(parsed, expected); let parsed_objdump = ParsedInstr::from_str("lhzu r16, 27005(r3)").expect("can parse"); let parsed_yax = ParsedInstr::from_str("lhzu r16, 0x697d(r3)").expect("can parse"); assert_eq!(parsed_objdump, parsed_yax); let parsed_xenia = ParsedInstr::from_str("bc 8, 23, 0x194C").expect("can parse"); let parsed_yax = ParsedInstr::from_str("bdnz so, crf5, $+0x1948").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("bcl 0, 0, 0xFFFFBDD4").expect("can parse"); let parsed_yax = ParsedInstr::from_str("bdnzl ge, $-0x4230").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("bc 2, 20, 0x174C").expect("can parse"); let parsed_yax = ParsedInstr::from_str("bdz ge, crf5, $+0x1748").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("bcla 9, 20, 0xFFFFD548").expect("can parse"); let parsed_yax = ParsedInstr::from_str("bdnzla lt, crf5, 0xffffd548").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("bca 5, 3, 0x5480").expect("can parse"); let parsed_yax = ParsedInstr::from_str("bnsa 0x5480").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("vsldoi128 vr102, vr42, vr52, (UNHANDLED SHB)").expect("can parse"); let parsed_yax = ParsedInstr::from_str("vsldoi128 vr102, vr42, vr52, 3").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("rlwnm. r19, r2, r24, 0, 31").expect("can parse"); let parsed_yax = ParsedInstr::from_str("rotlw. r19, r2, r24").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("cmpl crf0, 0, r4, r19").expect("can parse"); let parsed_yax = ParsedInstr::from_str("cmplw r4, r19").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("rlwinm r0, r0, 12, 0, 28").expect("can parse"); let parsed_yax = ParsedInstr::from_str("extlwi r0, r0, 29, 12").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("beq- crf0, 0x44C").expect("can parse"); let parsed_yax = ParsedInstr::from_str("beq- $+0x448").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("rldicr r28, r22, 47, 16").expect("can parse"); let parsed_yax = ParsedInstr::from_str("sldi r28, r22, 47").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("rldicr. r29, r7, 0, 28").expect("can parse"); let parsed_yax = ParsedInstr::from_str("clrrdi. r29, r7, 35").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("rlwinm r21, r1, 28, 4, 31").expect("can parse"); let parsed_yax = ParsedInstr::from_str("srwi r21, r1, 4").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("rlwinm r21, r1, 28, 4, 31").expect("can parse"); let parsed_yax = ParsedInstr::from_str("srwi r21, r1, 4").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("or. r8, r1, r1").expect("can parse"); let parsed_yax = ParsedInstr::from_str("mr. r8, r1").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("cror 4*cr1+eq,4*cr1+eq,eq").expect("can parse"); let parsed_yax = ParsedInstr::from_str("cror crb6, crb6, crb2").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("bcctrl 31, 30").expect("can parse"); let parsed_yax = ParsedInstr::from_str("bctrl crf7").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("twi 24,r31,-7").expect("can parse"); let parsed_yax = ParsedInstr::from_str("twnei r31, -0x7").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); let parsed_xenia = ParsedInstr::from_str("crnor crb0, crb0, crb0").expect("can parse"); let parsed_yax = ParsedInstr::from_str("crnot crb0, crb0").expect("can parse"); assert_eq!(parsed_xenia, parsed_yax); } fn test_invalid_under(decoder: &InstDecoder, data: &[u8]) { let mut reader = yaxpeax_arch::U8Reader::new(&data[..]); match decoder.decode(&mut reader) { Err(_) => { }, Ok(inst) => { panic!( "unexpected successful decode for {:02x}{:02x}{:02x}{:02x}\ngot: {}", data[0], data[1], data[2], data[3], inst ); } } } fn test_display_under(decoder: &InstDecoder, data: &[u8], expected: &'static str) { let mut reader = yaxpeax_arch::U8Reader::new(data); let instr = match decoder.decode(&mut reader) { Err(e) => { panic!("failed to decode {:02x}{:02x}{:02x}{:02x}: {}", data[0], data[1], data[2], data[3], e) }, Ok(instr) => instr, }; let displayed = format!("{}", instr); let parsed_displayed = ParsedInstr::from_str(&displayed).expect("can parse"); let parsed_expected = ParsedInstr::from_str(expected).expect("can parse"); /* if parsed_displayed != parsed_expected { panic!("decoded: {:?}\nexpected: {:?}", parsed_displayed, parsed_expected); } */ assert!( parsed_displayed == parsed_expected, "decode error for {:02x}{:02x}{:02x}{:02x}:\n displayed: {}\n expected: {}\n", data[0], data[1], data[2], data[3], displayed, expected ); } fn test_display_under_literal(decoder: &InstDecoder, data: &[u8], expected: &'static str) { let mut reader = yaxpeax_arch::U8Reader::new(data); let instr = match decoder.decode(&mut reader) { Err(e) => { panic!("failed to decode {:02x}{:02x}{:02x}{:02x}: {}", data[0], data[1], data[2], data[3], e) }, Ok(instr) => instr, }; let displayed = format!("{}", instr); /* if parsed_displayed != parsed_expected { panic!("decoded: {:?}\nexpected: {:?}", parsed_displayed, parsed_expected); } */ assert!( displayed == expected, "decode error for {:02x}{:02x}{:02x}{:02x}:\n displayed: {}\n expected: {}\n", data[0], data[1], data[2], data[3], displayed, expected ); } fn test_invalid(data: &[u8]) { test_invalid_under(&InstDecoder::default(), data); } fn test_display(data: &[u8], expected: &'static str) { eprintln!("testing decode into {}", expected); test_display_under(&InstDecoder::default(), data, expected); } fn test_display_vmx128(data: &[u8], expected: &'static str) { eprintln!("testing decode (vmx128) into {}", expected); test_display_under(&InstDecoder::for_cpu(IsaVersion::Xenon), data, expected); } fn test_display_le(data: &[u8], expected: &'static str) { test_display_under(&InstDecoder::default().with_be(false), data, expected); } fn test_display_le_literal(data: &[u8], expected: &'static str) { test_display_under_literal(&InstDecoder::default().with_be(false), data, expected); } /* fn test_gekko_le(data: &[u8], expected: &'static str) { test_display_le(data, expected); test_display_under(&InstDecoder::for_cpu(IsaVersion::Gekko).with_be(false), data, expected); } */ fn test_cell_le(data: &[u8], expected: &'static str) { test_display_le(data, expected); test_display_under(&InstDecoder::for_cpu(IsaVersion::Cell).with_be(false), data, expected); } fn test_xenon_le(data: &[u8], expected: &'static str) { test_display_le(data, expected); test_display_under(&InstDecoder::for_cpu(IsaVersion::Xenon).with_be(false), data, expected); } fn test_not_gekko_le(data: &[u8], expected: &'static str) { test_invalid_under(&InstDecoder::for_cpu(IsaVersion::Gekko).with_be(false), data); test_display_le(data, expected); } fn test_not_xenon_le(data: &[u8], expected: &'static str) { test_invalid_under(&InstDecoder::for_cpu(IsaVersion::Xenon).with_be(false), data); test_display_le(data, expected); } #[test] fn test_floats() { let power1 = InstDecoder::for_cpu(IsaVersion::RIOS).with_be(false); let power2 = InstDecoder::for_cpu(IsaVersion::RIOS2).with_be(false); let e500 = InstDecoder::for_cpu(IsaVersion::e500).with_be(false); let p200 = InstDecoder::for_cpu(IsaVersion::V2_0).with_be(false); let p300 = InstDecoder::for_cpu(IsaVersion::V3_0).with_be(false); test_display_le(&[0x04, 0x00, 0x00, 0xfc], "daddq f0, f0, f0"); test_display_le(&[0x05, 0x00, 0x00, 0xfc], "daddq. f0, f0, f0"); test_display_le(&[0x44, 0x00, 0x00, 0xfc], "dmulq f0, f0, f0"); test_display_le(&[0x45, 0x00, 0x00, 0xfc], "dmulq. f0, f0, f0"); test_display_le(&[0x04, 0x04, 0x00, 0xfc], "dsubq f0, f0, f0"); test_display_le(&[0x05, 0x04, 0x00, 0xfc], "dsubq. f0, f0, f0"); test_display_le(&[0x04, 0x00, 0x00, 0xec], "dadd f0, f0, f0"); test_display_le(&[0x05, 0x00, 0x00, 0xec], "dadd. f0, f0, f0"); test_display_le(&[0x44, 0x00, 0x00, 0xec], "dmul f0, f0, f0"); test_display_le(&[0x45, 0x00, 0x00, 0xec], "dmul. f0, f0, f0"); test_display_le(&[0x04, 0x04, 0x00, 0xec], "dsub f0, f0, f0"); test_display_le(&[0x05, 0x04, 0x00, 0xec], "dsub. f0, f0, f0"); test_display_le(&[0x10, 0x20, 0x00, 0xfc], "fcpsgn f0, f0, f4"); test_display_le(&[0x11, 0x20, 0x00, 0xfc], "fcpsgn. f0, f0, f4"); test_display_under(&p300, &[0x10, 0x0b, 0x00, 0xfc], "frin fr0, fr1"); test_invalid_under(&e500, &[0x10, 0x0b, 0x00, 0xfc]); test_display_under(&p300, &[0x11, 0x0b, 0x00, 0xfc], "frin. fr0, fr1"); test_display_under(&p300, &[0x50, 0x0b, 0x00, 0xfc], "friz fr0, fr1"); test_display_under(&p300, &[0x51, 0x0b, 0x00, 0xfc], "friz. fr0, fr1"); test_display_under(&p300, &[0x90, 0x0b, 0x00, 0xfc], "frip fr0, fr1"); test_display_under(&p300, &[0x91, 0x0b, 0x00, 0xfc], "frip. fr0, fr1"); test_invalid_under(&e500, &[0x91, 0x0b, 0x00, 0xfc]); test_display_under(&p300, &[0xd0, 0x0b, 0x00, 0xfc], "frim fr0, fr1"); test_display_under(&p300, &[0xd1, 0x0b, 0x00, 0xfc], "frim. fr0, fr1"); test_display_under(&p300, &[0x06, 0x04, 0x00, 0xfc], "dquaq fr0, fr0, fr0, 2"); test_display_under(&p300, &[0x07, 0x04, 0x00, 0xfc], "dquaq. fr0, fr0, fr0, 2"); test_display_under(&p300, &[0x06, 0x20, 0x00, 0xfc], "dquaq fr0, fr0, fr4, 0"); test_display_under(&p300, &[0x07, 0x20, 0x00, 0xfc], "dquaq. fr0, fr0, fr4, 0"); test_display_under(&p300, &[0x46, 0x20, 0x00, 0xec], "drrnd fr0, fr0, fr4, 0"); test_display_under(&p300, &[0x47, 0x20, 0x00, 0xec], "drrnd. fr0, fr0, fr4, 0"); test_display_under(&p300, &[0x46, 0x20, 0x00, 0xfc], "drrndq fr0, fr0, fr4, 0"); test_display_under(&p300, &[0x47, 0x20, 0x00, 0xfc], "drrndq. fr0, fr0, fr4, 0"); test_display_under(&p300, &[0xc6, 0x03, 0x00, 0xfc], "drintnq 0, fr0, fr0, 1"); test_display_under(&p300, &[0xc7, 0x03, 0x00, 0xfc], "drintnq. 0, fr0, fr0, 1"); test_display_under(&p300, &[0xc6, 0x02, 0x00, 0xfc], "drintxq 0, fr0, fr0, 1"); test_display_under(&p300, &[0xc7, 0x02, 0x00, 0xfc], "drintxq. 0, fr0, fr0, 1"); test_display_under(&p300, &[0xc4, 0x00, 0x0a, 0xec], "dscri fr0, fr10, 0"); test_display_under(&p300, &[0xc5, 0x00, 0x0a, 0xec], "dscri. fr0, fr10, 0"); test_display_under(&p300, &[0xc4, 0x0c, 0x00, 0xfc], "dscriq fr0, fr0, 3"); test_display_under(&p300, &[0xc5, 0x0c, 0x00, 0xfc], "dscriq. fr0, fr0, 3"); test_display_under(&p300, &[0x84, 0x0c, 0x44, 0xec], "dscli fr2, fr4, 3"); test_display_under(&p300, &[0x85, 0x0c, 0x44, 0xec], "dscli. fr2, fr4, 3"); test_display_under(&p300, &[0x84, 0x08, 0x44, 0xec], "dscli fr2, fr4, 2"); test_display_under(&p300, &[0x85, 0x08, 0x44, 0xec], "dscli. fr2, fr4, 2"); test_display_under(&p300, &[0x84, 0x00, 0x00, 0xfc], "dscliq fr0, fr0, 0"); test_display_under(&p300, &[0x85, 0x00, 0x00, 0xfc], "dscliq. fr0, fr0, 0"); test_display_under(&p300, &[0x86, 0x00, 0x00, 0xfc], "dquaiq 0, fr0, fr0, 0"); test_display_under(&p300, &[0x87, 0x00, 0x00, 0xfc], "dquaiq. 0, fr0, fr0, 0"); test_display_under(&p300, &[0xc4, 0x14, 0x01, 0xfc], "dscriq fr0, fr0, 5"); test_display_under(&p300, &[0xc5, 0x14, 0x01, 0xfc], "dscriq. fr0, fr0, 5"); test_display_under(&p300, &[0x84, 0x09, 0x84, 0xec], "dtstdc cr1, fr4, 2"); test_display_under(&p300, &[0xc4, 0x09, 0x84, 0xec], "dtstdg cr1, fr4, 2"); test_display_under(&p300, &[0x84, 0x05, 0x00, 0xfc], "dtstdcq cr0, fr0, 1"); test_display_under(&p300, &[0xc4, 0x05, 0x00, 0xfc], "dtstdgq cr0, fr0, 1"); test_display_under(&p300, &[0x84, 0x79, 0x01, 0xfc], "dtstdcq cr0, fr0, 0x1e"); test_display_under(&p300, &[0xc4, 0x79, 0x01, 0xfc], "dtstdgq cr0, fr0, 0x1e"); test_display_under(&p300, &[0x9c, 0x2f, 0x84, 0xec], "fcfidus fr4, fr5"); test_display_under(&p300, &[0x9d, 0x2f, 0x84, 0xec], "fcfidus. fr4, fr5"); test_display_under(&p300, &[0x86, 0x0e, 0x00, 0xfc], "dquaiq 0, f0, f0, 3"); test_display_under(&p300, &[0x87, 0x0e, 0x00, 0xfc], "dquaiq. 0, f0, f0, 3"); test_display_under(&p300, &[0x84, 0x12, 0x00, 0xfc], "ddedpdq 0, fr0, fr2"); test_display_under(&p300, &[0x85, 0x12, 0x00, 0xfc], "ddedpdq. 0, fr0, fr2"); test_display_under(&p300, &[0xc4, 0x12, 0x00, 0xfc], "dxexq f0, f2"); test_display_under(&p300, &[0xc5, 0x12, 0x00, 0xfc], "dxexq. f0, f2"); test_display_under(&p300, &[0xc4, 0x1a, 0x00, 0xfc], "dxexq f0, f2"); test_display_under(&p300, &[0xc5, 0x1a, 0x00, 0xfc], "dxexq. f0, f2"); test_display_under(&p300, &[0x04, 0x06, 0x00, 0xfc], "drdpq fr0, fr0"); test_display_under(&p300, &[0x05, 0x06, 0x00, 0xfc], "drdpq. fr0, fr0"); test_display_under(&p300, &[0x04, 0x12, 0x00, 0xfc], "dctqpq fr0, fr2"); test_display_under(&p300, &[0x05, 0x12, 0x00, 0xfc], "dctqpq. fr0, fr2"); test_display_under(&p300, &[0x9c, 0x0f, 0x00, 0xfc], "fcfidu fr0, fr1"); test_display_under(&p300, &[0x9d, 0x0f, 0x00, 0xfc], "fcfidu. fr0, fr1"); test_display_under(&p300, &[0x44, 0x11, 0x00, 0xec], "dtstex cr0, fr0, fr2"); test_display_under(&p300, &[0x45, 0x11, 0x00, 0xec], "dtstex cr0, fr0, fr2"); test_display_under(&p300, &[0x44, 0x11, 0x00, 0xfc], "dtstexq cr0, fr0, fr2"); test_display_under(&p300, &[0x45, 0x11, 0x00, 0xfc], "dtstexq cr0, fr0, fr2"); test_display_under(&p300, &[0x45, 0x06, 0x00, 0xfc], "dcffixq. fr0, fr0"); test_display_under(&p300, &[0x40, 0x11, 0x00, 0xfc], "ftsqrt cr0, fr2"); test_display_under(&p300, &[0x44, 0x14, 0x00, 0xfc], "ddivq fr0, fr0, fr2"); test_display_under(&p300, &[0x45, 0x14, 0x00, 0xfc], "ddivq. fr0, fr0, fr2"); test_display_under(&p300, &[0x04, 0x39, 0x00, 0xfc], "dcmpoq cr0, fr0, fr6"); test_display_under(&p300, &[0x04, 0x3d, 0x00, 0xfc], "dcmpuq cr0, fr0, fr6"); test_display_under(&p300, &[0x00, 0x59, 0x00, 0xfc], "ftdiv cr0, fr0, fr11"); test_display_under(&p300, &[0x46, 0x0e, 0x01, 0xfc], "drrndq fr0, fr1, fr0, 3"); test_display_under(&p300, &[0x47, 0x0e, 0x01, 0xfc], "drrndq. fr0, fr1, fr0, 3"); // these come from comparing with Xenia test_xenon_le(&[0x2f, 0x05, 0x7f, 0xff], "fsel. fr27, fr31, fr20, fr0"); test_xenon_le(&[0x39, 0x6b, 0x47, 0xec], "fmsubs. fr2, fr7, fr12, fr13"); test_xenon_le(&[0x3a, 0x69, 0x5e, 0xec], "fmadds fr2, fr30, fr4, fr13"); test_xenon_le(&[0xec, 0x21, 0x02, 0xfc], "fsqrt fr0, fr4"); test_xenon_le(&[0xfd, 0x6c, 0x52, 0xfc], "fnmsub. fr2, fr18, fr19, fr13"); test_xenon_le(&[0xfd, 0x2b, 0x52, 0xee], "fnmsubs. fr18, fr18, fr15, fr5"); test_xenon_le(&[0xff, 0x5f, 0x57, 0xee], "fnmadds. fr18, fr23, fr31, fr11"); test_xenon_le(&[0x2b, 0x1f, 0x00, 0xff], "fadd. fr24, fr0, fr3"); test_xenon_le(&[0x3f, 0xa0, 0xff, 0xff], "fnmadd. fr31, fr31, fr0, fr20"); test_xenon_le(&[0x65, 0x6b, 0x00, 0xff], "fdiv. fr24, fr0, fr13"); test_xenon_le(&[0xb3, 0x2a, 0xff, 0xfe], "fmul. fr23, fr31, fr10"); test_xenon_le(&[0x51, 0x48, 0xd6, 0xfe], "fneg. fr22, fr9"); test_xenon_le(&[0x90, 0x88, 0xff, 0xfc], "fmr fr7, fr17"); // HELP: does fsqrt exist on POWER/POWER2 or not? objdump says yes, but the RS/6000 Hardware // Technical Reference says no. AIX 5.3 says it's optional on PowerPC, and says nothing about // the POWER family architecture. so i think binutils is wrong on this one? test_invalid_under(&power1, &[0xec, 0x21, 0x02, 0xfc]); test_display_under(&p200, &[0x2b, 0x1f, 0x00, 0xff], "fadd. fr24, fr0, fr3"); test_invalid_under(&e500, &[0x2b, 0x1f, 0x00, 0xff]); test_invalid_under(&e500, &[0x90, 0x88, 0xff, 0xfc]); test_display_under(&p200, &[0x90, 0x88, 0xff, 0xfc], "fmr fr7, fr17"); // surprise! single-precision floats weren't supported in RS/6000? test_invalid_under(&power2, &[0x2f, 0x05, 0x7f, 0xff]); test_invalid_under(&power2, &[0x39, 0x6b, 0x47, 0xec]); test_invalid_under(&power2, &[0x3a, 0x69, 0x5e, 0xec]); test_display_under(&power2, &[0xfd, 0x6c, 0x52, 0xfc], "fnmsub. fr2, fr18, fr19, fr13"); test_invalid_under(&power2, &[0xfd, 0x2b, 0x52, 0xee]); test_invalid_under(&power2, &[0xff, 0x5f, 0x57, 0xee]); test_display_under(&power2, &[0x2b, 0x1f, 0x00, 0xff], "fadd. fr24, fr0, fr3"); test_display_under(&power2, &[0x3f, 0xa0, 0xff, 0xff], "fnmadd. fr31, fr31, fr0, fr20"); test_display_under(&power2, &[0x65, 0x6b, 0x00, 0xff], "fdiv. fr24, fr0, fr13"); test_display_under(&power2, &[0xb3, 0x2a, 0xff, 0xfe], "fmul. fr23, fr31, fr10"); test_display_under(&power2, &[0x51, 0x48, 0xd6, 0xfe], "fneg. fr22, fr9"); test_display_under(&power2, &[0x90, 0x88, 0xff, 0xfc], "fmr fr7, fr17"); test_xenon_le(&[0x40, 0x98, 0x04, 0xfc], "fcmpo cr0, fr4, fr19"); test_xenon_le(&[0x2f, 0x05, 0x00, 0x7f], "stfsx fr24, 0, r0"); test_xenon_le(&[0xae, 0x3d, 0x0a, 0x7c], "stfdx fr0, r10, r7"); test_xenon_le(&[0x6e, 0xfd, 0x07, 0x7c], "stfsux fr0, r7, r31"); test_xenon_le(&[0x6e, 0x3c, 0x0a, 0x7c], "lfsux fr0, r10, r7"); test_invalid_under(&e500, &[0x6e, 0x3c, 0x0a, 0x7c]); test_xenon_le(&[0xef, 0xa4, 0x59, 0x7c], "lfdux fr2, r25, r20"); test_xenon_le(&[0x2f, 0x04, 0x00, 0x7f], "lfsx fr24, 0, r0"); // frsqrte is in PPC, frsqrtes was added in Power v2.03 (not in Xenon) test_xenon_le(&[0x34, 0x00, 0x00, 0xfc], "frsqrte fr0, fr0"); test_xenon_le(&[0x34, 0xa5, 0xff, 0xff], "frsqrte fr31, fr20"); test_invalid_under(&e500, &[0x74, 0x51, 0x16, 0xee]); test_xenon_le(&[0x0c, 0xa9, 0xff, 0xff], "mtfsfi fpscrf7, 10"); test_xenon_le(&[0x0d, 0x41, 0xe3, 0xfd], "mtfsfi. fpscrf3, 4"); test_xenon_le(&[0x18, 0xf8, 0xff, 0xff], "frsp fr31, fr31"); test_xenon_le(&[0x19, 0xf8, 0xff, 0xff], "frsp. fr31, fr31"); test_xenon_le(&[0x1c, 0xf8, 0xff, 0xff], "fctiw fr31, fr31"); test_xenon_le(&[0x1d, 0xf8, 0xff, 0xff], "fctiw. fr31, fr31"); test_not_xenon_le(&[0x1c, 0x01, 0xff, 0xfc], "fctiwu fr7, fr0"); test_not_xenon_le(&[0x1d, 0x01, 0xff, 0xfc], "fctiwu. fr7, fr0"); test_not_xenon_le(&[0x1e, 0x01, 0xff, 0xfc], "fctiwuz fr7, fr0"); test_not_xenon_le(&[0x1f, 0x01, 0xff, 0xfc], "fctiwuz. fr7, fr0"); test_xenon_le(&[0x1e, 0xf8, 0xff, 0xff], "fctiwz fr31, fr31"); test_xenon_le(&[0x1f, 0xf8, 0xff, 0xff], "fctiwz. fr31, fr31"); test_xenon_le(&[0x5c, 0x7e, 0xa4, 0xfe], "fctid fr21, fr15"); test_xenon_le(&[0x5d, 0x7e, 0xa4, 0xfe], "fctid. fr21, fr15"); test_xenon_le(&[0x5e, 0x7e, 0xa4, 0xfe], "fctidz fr21, fr15"); test_xenon_le(&[0x5f, 0x7e, 0xa4, 0xfe], "fctidz. fr21, fr15"); test_xenon_le(&[0x9c, 0xfe, 0x10, 0xfd], "fcfid fr8, fr31"); test_xenon_le(&[0x4c, 0xc0, 0x82, 0xfd], "mtfsb1 12"); test_xenon_le(&[0x4d, 0xc0, 0x82, 0xfd], "mtfsb1. 12"); test_not_xenon_le(&[0x5c, 0x7f, 0xa4, 0xfe], "fctidu fr21, fr15"); test_not_xenon_le(&[0x5d, 0x7f, 0xa4, 0xfe], "fctidu. fr21, fr15"); test_not_xenon_le(&[0x5e, 0x7f, 0xa4, 0xfe], "fctiduz fr21, fr15"); test_not_xenon_le(&[0x5f, 0x7f, 0xa4, 0xfe], "fctiduz. fr21, fr15"); // instructions in the floating point space which were added after Xenon (Power 2.03, // generally) test_not_xenon_le(&[0x30, 0xe3, 0xff, 0xff], "fre fr31, fr28"); test_not_xenon_le(&[0x30, 0xa6, 0xff, 0xff], "fre fr31, fr20"); test_not_xenon_le(&[0x80, 0x6b, 0x00, 0xe0], "lfq fr0, 0x6b80"); test_not_xenon_le(&[0x46, 0x32, 0x47, 0xfd], "drrndq fr10, fr7, fr6, 1"); test_display_le(&[0x2e, 0x06, 0x00, 0x7c], "lfdpx fr0, 0, r0"); test_display_le(&[0x6e, 0x06, 0x00, 0x7c], "lfqux fr0, 0, r0"); test_display_le(&[0x2e, 0x07, 0x00, 0x7c], "stfdpx fr0, 0, r0"); } #[test] fn test_gekko_ps() { let gekko = InstDecoder::for_cpu(IsaVersion::Gekko).with_be(false); let all = InstDecoder::for_cpu(IsaVersion::All).with_be(false); test_display_under(&gekko, &[0x9c, 0xe0, 0x00, 0x10], "ps_madds0 fr0, fr0, fr2, fr28"); test_display_under(&gekko, &[0x9d, 0xe0, 0x00, 0x10], "ps_madds0. fr0, fr0, fr2, fr28"); test_display_under(&gekko, &[0x9e, 0xe0, 0x00, 0x10], "ps_madds1 fr0, fr0, fr2, fr28"); test_display_under(&gekko, &[0x9f, 0xe0, 0x00, 0x10], "ps_madds1. fr0, fr0, fr2, fr28"); test_display_under(&gekko, &[0x28, 0x4c, 0x1a, 0x10], "ps_sub fr0, fr26, fr9"); test_display_under(&gekko, &[0x29, 0x4c, 0x1a, 0x10], "ps_sub. fr0, fr26, fr9"); test_display_under(&gekko, &[0x2a, 0x4c, 0x1a, 0x10], "ps_add fr0, fr26, fr9"); test_display_under(&gekko, &[0x2b, 0x4c, 0x1a, 0x10], "ps_add. fr0, fr26, fr9"); test_display_under(&gekko, &[0x2e, 0x4c, 0x1a, 0x10], "ps_sel fr0, fr26, fr16, fr9"); test_display_under(&gekko, &[0x2f, 0x4c, 0x1a, 0x10], "ps_sel. fr0, fr26, fr16, fr9"); test_display_under(&gekko, &[0x30, 0xe1, 0x00, 0x10], "ps_res fr0, fr28"); test_display_under(&gekko, &[0x31, 0xe1, 0x00, 0x10], "ps_res. fr0, fr28"); test_display_under(&gekko, &[0x32, 0xe1, 0x00, 0x10], "ps_mul fr0, fr0, fr4"); test_display_under(&gekko, &[0x33, 0xe1, 0x00, 0x10], "ps_mul. fr0, fr0, fr4"); test_display_under(&gekko, &[0x34, 0xe1, 0x00, 0x10], "ps_rsqrte fr0, fr28"); test_display_under(&gekko, &[0x35, 0xe1, 0x00, 0x10], "ps_rsqrte. fr0, fr28"); test_display_under(&gekko, &[0x50, 0x20, 0x05, 0x10], "ps_neg fr0, fr4"); test_display_under(&gekko, &[0x51, 0x20, 0x05, 0x10], "ps_neg. fr0, fr4"); test_display_under(&gekko, &[0x90, 0x20, 0x05, 0x10], "ps_mr fr0, fr4"); test_display_under(&gekko, &[0x91, 0x20, 0x05, 0x10], "ps_mr. fr0, fr4"); test_display_under(&gekko, &[0x10, 0x21, 0x05, 0x10], "ps_nabs fr0, fr4"); test_display_under(&gekko, &[0x11, 0x21, 0x05, 0x10], "ps_nabs. fr0, fr4"); test_display_under(&gekko, &[0x10, 0x22, 0x05, 0x10], "ps_abs fr0, fr4"); test_display_under(&gekko, &[0x11, 0x22, 0x05, 0x10], "ps_abs. fr0, fr4"); test_display_under(&gekko, &[0x20, 0x1c, 0x05, 0x10], "ps_merge00 fr0, fr5, fr3"); test_display_under(&gekko, &[0x82, 0xd7, 0x00, 0xf0], "psq_st fr0, 0x782, 0x1, gqr5"); test_display_under(&gekko, &[0x82, 0xd7, 0x00, 0xf4], "psq_stu fr0, 0x782, 0x1, gqr5"); test_invalid_under(&all, &[0x82, 0xd7, 0x00, 0xf4]); test_invalid_under(&all, &[0x10, 0x00, 0x64, 0xf4]); test_display_under(&gekko, &[0xcf, 0xff, 0x15, 0x10], "psq_stux fr0, r21, r31, 0x1, gqr7"); // HELP: this could be a ps_cmpu0, maybe? ppcd would say as much, but dolphin rejects it. not // clear what an actual Gekko processor would do here! test_invalid_under(&gekko, &[0x00, 0x01, 0x00, 0x10]); test_invalid_under(&gekko, &[0xc1, 0xc2, 0x00, 0x10]); } #[test] fn test_vector() { test_display(&[0x10, 0x00, 0x02, 0x0C], "vspltb vr0, vr0, 0"); test_display(&[0x10, 0x50, 0x02, 0x0C], "vspltb vr2, vr0, 0"); test_display(&[0x10, 0x00, 0x61, 0x0A], "vrefp vr0, vr12"); test_display(&[0x13, 0xd6, 0xf1, 0x02], "vmaxsb vr30, vr22, vr30"); test_display(&[0x13, 0xf0, 0x02, 0x4c], "vsplth vr31, vr0, 0"); // TODO: LMA is not handled correctly, and this is an incorrect decode, but we shouldn't // currently panic... test_display(&[0x10, 0x00, 0x05, 0xd6], "vcmpgefp. vr0, vr0, vr0"); test_display(&[0x10, 0x1f, 0x03, 0x8c], "vspltisw vr0, -1"); } #[test] fn branches() { let decoder_p2 = InstDecoder::for_cpu(IsaVersion::RIOS2).with_be(false); let decoder_ppc = InstDecoder::for_cpu(IsaVersion::PowerPC).with_be(false); let decoder_xenon = InstDecoder::for_cpu(IsaVersion::Xenon).with_be(false); let p200_32b = InstDecoder::for_cpu(IsaVersion::V2_0_32b).with_be(false); let decoder_202 = InstDecoder::for_cpu(IsaVersion::V2_02).with_be(false); let e500 = InstDecoder::for_cpu(IsaVersion::e500).with_be(false); let e500mc = InstDecoder::for_cpu(IsaVersion::e500mc).with_be(false); let decoder_207 = InstDecoder::for_cpu(IsaVersion::V2_07).with_be(false); test_display_under_literal(&p200_32b, &[0x54, 0xff, 0xfc, 0x40], "bge+ cr7, $-0xac"); let inst = p200_32b.decode_slice(&[0x54, 0xff, 0xfc, 0x40]).unwrap(); // the rendered form, like above, includes processing the BO/BI fields into the in-line // condition+hint `ge+`. assert_eq!(inst.operand_count(), 3); test_display_under_literal(&p200_32b, &[0x54, 0xff, 0xdc, 0x40], "bge- cr7, $-0xac"); test_display_under_literal(&p200_32b, &[0x54, 0xff, 0xdc, 0x40], "bge- cr7, $-0xac"); test_display_under_literal(&e500, &[0x20, 0x08, 0x82, 0x4d], "beqlr-"); test_display_under_literal(&e500mc, &[0x20, 0x08, 0x82, 0x4d], "beqlr cr0, 1"); test_display_under_literal(&decoder_ppc, &[0x20, 0x10, 0x80, 0x4e], "blr"); test_display_under_literal(&decoder_202, &[0x20, 0x10, 0x80, 0x4e], "blr 2"); // there's a BH on v2.02 and later, so the operand count varies.. let inst = decoder_ppc.decode_slice(&[0x20, 0x10, 0x80, 0x4e]).unwrap(); assert_eq!(inst.operand_count(), 2); let inst = decoder_202.decode_slice(&[0x20, 0x10, 0x80, 0x4e]).unwrap(); assert_eq!(inst.operand_count(), 3); test_display_under_literal(&decoder_ppc, &[0x20, 0x0c, 0x80, 0x4e], "bctr"); test_display_under_literal(&decoder_202, &[0x20, 0x0c, 0x80, 0x4e], "bctr 1"); test_display_under_literal(&decoder_207, &[0x20, 0x00, 0x9e, 0x4c], "bnelr cr7"); test_display_under_literal(&decoder_207, &[0xf8, 0xff, 0x20, 0x43], "bdnz+ $-0x8"); test_display_under_literal(&decoder_p2, &[0x20, 0x38, 0x7d, 0x4c], "bdzflr 4*cr7+gt"); // BO is 0x14, so the branch is unconditional. BI and BH are ignored. test_display_under_literal(&decoder_207, &[0x20, 0x00, 0x89, 0x4e], "blr"); test_display_under_literal(&decoder_207, &[0x20, 0x08, 0x82, 0x4d], "beqlr cr0, 1"); test_display_le_literal(&[0x21, 0xc4, 0x84, 0x4e], "bctrl"); test_display_le_literal(&[0x21, 0x7c, 0x86, 0x4c], "bnectrl cr1, 3"); test_display_le_literal(&[0x21, 0x64, 0x86, 0x4c], "bnectrl cr1"); test_display_under_literal(&decoder_p2, &[0x20, 0x38, 0x7d, 0x4c], "bdzflr 4*cr7+gt"); test_display_under_literal(&decoder_ppc, &[0x20, 0x38, 0x7d, 0x4c], "bdzflr+ 4*cr7+gt"); test_display_under_literal(&decoder_xenon, &[0x20, 0x38, 0x7d, 0x4c], "bdzflr 4*cr7+gt"); test_display_under_literal(&decoder_207, &[0x20, 0x38, 0x7d, 0x4c], "bdzflr 4*cr7+gt, 3"); test_display_le(&[0xa0, 0xfe, 0xff, 0x4b], "b $-0x160"); // TODO: double check test_display_le(&[0x41, 0x9a, 0x09, 0x48], "bl $+0x99a40"); // test_display_le(&[0x48, 0x02, 0xbd, 0xd1], "bl $+0x2bdd0"); // test_display_le(&[0xd1, 0xbd, 0x02, 0x48], "bl $+0x2bdd0"); // test_display_le(&[0x4b, 0xf2, 0x45, 0x40], "bcla 2, 5, 0xfffff248"); // TODO: when do prediction bits become supported..? what ISA rev, in particular.. test_display_le(&[0x48, 0x01, 0xe0, 0x41], "blt+ $+0x148"); test_display_le(&[0x7f, 0x19, 0xc0, 0x40], "bgela- 0x197c"); test_display_le(&[0x38, 0x80, 0x00, 0x43], "bdnz- cr0, $-0x7fc8"); test_display_le(&[0x38, 0xe0, 0x09, 0x42], "bdnz cr2, $-0x1fc8"); test_display_le(&[0x60, 0x84, 0x54, 0x43], "bdz- cr5, $-0x7ba0"); test_display_le(&[0x4b, 0xf2, 0x45, 0x40], "bdzfla gt, cr1, 0xfffff248"); test_display_le(&[0x61, 0x6a, 0x00, 0x40], "bdnzl ge, $+0x6a60"); test_display_le(&[0x3b, 0x63, 0x00, 0x4a], "bla 0xfe006338"); } #[test] fn test_amazon() { let amazon = InstDecoder::for_cpu(IsaVersion::Amazon).with_be(false); let power2 = InstDecoder::for_cpu(IsaVersion::RIOS2).with_be(false); let p207 = InstDecoder::for_cpu(IsaVersion::V2_07).with_be(false); test_invalid_under(&power2, &[0xe3, 0x77, 0x2a, 0x79]); test_display_under(&amazon, &[0xe3, 0x77, 0x2a, 0x79], "rldicl. r10, r9, 0x2e, 0x3f"); test_display_under(&p207, &[0xe3, 0x77, 0x2a, 0x79], "rldicl. r10, r9, 0x2e, 0x3f"); } #[test] fn test_xenon() { let xenon = InstDecoder::for_cpu(IsaVersion::Xenon).with_be(false); let gekko = InstDecoder::for_cpu(IsaVersion::Gekko).with_be(false); let decoder_207 = InstDecoder::for_cpu(IsaVersion::V2_07).with_be(false); test_display_le(&[0x22, 0x00, 0x00, 0x44], "sc 1"); // these two are odd: the disassemblers in xenia, dolphin, etc, permit the aa bit to be clear, // but the Power ISA manuals are much more stringent. i've chosen to agree with xenia and // dolphin rather than objdump on these. so: // because `aa` bit is clear test_display_under(&xenon, &[0x48, 0x01, 0x45, 0x45], "sc 10"); // and gekko also allows a clear `aa` bit. test_display_under(&gekko, &[0x48, 0x01, 0x45, 0x45], "sc 10"); test_xenon_le(&[0x64, 0xe6, 0x00, 0x10], "vmsumubm vr0, vr0, vr28, vr25"); test_display_under(&xenon, &[0xec, 0xe1, 0x1b, 0x7c], "dcbtstct r27, r28, 0x0"); test_display_under(&decoder_207, &[0xec, 0xe1, 0x1b, 0x7c], "dcbtstct r27, r28, 0x0"); test_display_under(&decoder_207, &[0xec, 0x31, 0x00, 0x7e], "dcbtstt 0, r6"); test_not_xenon_le(&[0x90, 0xeb, 0xff, 0xfc], "frip fr7, fr29"); test_not_xenon_le(&[0xd0, 0x03, 0x01, 0xfc], "frim fr0, fr0"); test_not_xenon_le(&[0x51, 0x4b, 0xdf, 0xfe], "friz. fr22, fr9"); test_not_xenon_le(&[0x41, 0x99, 0x01, 0xfc], "ftsqrt cr0, fr19"); // xenia decodes this, unsure what hardware thinks. test_xenon_le(&[0x81, 0x53, 0x00, 0xe8], "ldu r0, 0x5380"); test_xenon_le(&[0x48, 0x06, 0x17, 0x11], "vsum4shs vr8, vr23, vr0"); } #[test] fn test_gekko() { let gekko = InstDecoder::for_cpu(IsaVersion::Gekko).with_be(false); let p207 = InstDecoder::for_cpu(IsaVersion::V2_07).with_be(false); test_invalid_under(&gekko, &[0xf5, 0xc5, 0x39, 0xf8]); test_display_under(&p207, &[0xf5, 0xc5, 0x39, 0xf8], "stdu r1, -0x3a0c(r25)"); test_not_gekko_le(&[0x24, 0xe0, 0xf5, 0x4f], "rfid"); test_not_gekko_le(&[0xac, 0x32, 0x9d, 0xed], "fsqrts fr12, fr6"); // dolphin/ppcd (gekko generally?) tolerates lk being any value here, objdump is stricter and // yax follows objdump elsewhere for simplicity. test_display_under(&gekko, &[0x29, 0x30, 0x00, 0x7c], "lwarx r0, 0, r6"); } #[test] fn test_deleted() { let decoder_p2 = InstDecoder::for_cpu(IsaVersion::RIOS2).with_be(false); let decoder_ppc = InstDecoder::for_cpu(IsaVersion::PowerPC).with_be(false); let decoder_xenon = InstDecoder::for_cpu(IsaVersion::Xenon).with_be(false); let decoder_207 = InstDecoder::for_cpu(IsaVersion::V2_07).with_be(false); test_display_under(&decoder_p2, &[0x3a, 0x7c, 0xba, 0x7c], "maskir r26, r5, r15"); test_invalid_under(&decoder_ppc, &[0x3a, 0x7c, 0xba, 0x7c]); test_invalid_under(&decoder_xenon, &[0x3a, 0x7c, 0xba, 0x7c]); test_invalid_under(&decoder_207, &[0x3a, 0x7c, 0xba, 0x7c]); } #[test] fn test_cache() { let decoder_power = InstDecoder::for_cpu(IsaVersion::RIOS).with_be(false); let decoder_amazon = InstDecoder::for_cpu(IsaVersion::Amazon).with_be(false); let decoder_e500 = InstDecoder::for_cpu(IsaVersion::e500).with_be(false); let decoder_a2 = InstDecoder::for_cpu(IsaVersion::A2).with_be(false); let decoder_ppc = InstDecoder::for_cpu(IsaVersion::PowerPC).with_be(false); let decoder_xenon = InstDecoder::for_cpu(IsaVersion::Xenon).with_be(false); let decoder_205 = InstDecoder::for_cpu(IsaVersion::V2_05).with_be(false); let decoder_207 = InstDecoder::for_cpu(IsaVersion::V2_07).with_be(false); test_display_under(&decoder_ppc, &[0xec, 0x31, 0x00, 0x7e], "dcbtst 0, r6"); test_display_under(&decoder_205, &[0xec, 0x31, 0x00, 0x7e], "dcbtstt 0, r6"); test_display_under(&decoder_207, &[0xec, 0x31, 0x00, 0x7e], "dcbtstt 0, r6"); test_display_under(&decoder_amazon, &[0x2c, 0x32, 0x03, 0x7c], "dcbt r3, r6, 0x0"); test_display_under(&decoder_ppc, &[0x2c, 0x32, 0x03, 0x7c], "dcbt r3, r6"); // so... Power v2.00 clearly says there's a two-bit `TH` field at this point. xenia does not // decode it. objdump does not decode it. it's a hint, so it seems plausible that everyone // simply ignores it?. test_display_under(&decoder_xenon, &[0x2c, 0x32, 0x03, 0x7c], "dcbt r3, r6, 0x0"); test_display_under(&decoder_207, &[0x2c, 0x32, 0x03, 0x7c], "dcbtct r3, r6, 0x0"); // objdump would tell you this should be "dcbtct r3, r6, 16", but the alias `dcbtt` was added // in the same version of Power that extended the hint field to 5 bits, and is the same version // that A2 is conformant to: Power v2.06. test_display_under(&decoder_207, &[0x2c, 0x32, 0x03, 0x7e], "dcbtt r3, r6"); test_display_under(&decoder_a2, &[0x2c, 0x32, 0x00, 0x7e], "dcbtt 0, r6"); test_invalid_under(&decoder_xenon, &[0xec, 0x85, 0x01, 0x7c]); test_display_under(&decoder_207, &[0xec, 0x85, 0x01, 0x7c], "dcba r1, r16"); test_display_under(&decoder_ppc, &[0xec, 0x1f, 0xf6, 0x7c], "dcbz r22, r3"); test_invalid_under(&decoder_xenon, &[0xec, 0x1f, 0xf6, 0x7c]); test_cell_le(&[0xec, 0x1f, 0xf6, 0x7c], "dcbz r22, r3"); test_display_under(&decoder_207, &[0xec, 0x1f, 0xf6, 0x7c], "dcbz r22, r3"); test_display_under(&decoder_xenon, &[0xed, 0x07, 0x28, 0x7c], "dcbz128 r8, r0"); test_display_under(&decoder_207, &[0xed, 0x07, 0x28, 0x7c], "dcbz r8, r0"); test_display_under(&decoder_ppc, &[0xac, 0x07, 0x40, 0x7c], "icbi 0, r0"); test_display_under(&decoder_xenon, &[0xac, 0x07, 0x40, 0x7c], "icbi 0, r0"); test_display_under(&decoder_207, &[0xac, 0x07, 0x40, 0x7c], "icbi 0, r0"); // test_display_under(&decoder_ppc, &[0xed, 0x41, 0x56, 0x7c], "dcbtst r22, r8"); test_display_under(&decoder_xenon, &[0xed, 0x41, 0x56, 0x7c], "dcbtstct r22, r8, 0x2"); test_display_under(&decoder_207, &[0xed, 0x41, 0x56, 0x7c], "dcbtstct r22, r8, 0x2"); test_not_xenon_le(&[0x24, 0x7b, 0x0a, 0x7c], "slbmte r0, r15"); test_not_xenon_le(&[0x64, 0x7b, 0x0a, 0x7c], "slbie r15"); test_display_under(&decoder_ppc, &[0xac, 0x00, 0x00, 0x7c], "dcbf 0, r0"); test_display_under(&decoder_xenon, &[0xac, 0x00, 0x00, 0x7c], "dcbf 0, r0"); test_display_under(&decoder_207, &[0xac, 0x00, 0x00, 0x7c], "dcbf 0, r0"); test_display_under(&decoder_ppc, &[0xec, 0x01, 0x00, 0x7c], "dcbtst 0, r0"); test_display_under(&decoder_xenon, &[0xec, 0x01, 0x00, 0x7c], "dcbtstct 0, r0, 0x0"); test_display_under(&decoder_207, &[0xec, 0x01, 0x00, 0x7c], "dcbtstct 0, r0, 0x0"); test_invalid_under(&decoder_power, &[0xec, 0x01, 0x00, 0x7c]); test_display_under(&decoder_ppc, &[0x2c, 0x02, 0x00, 0x7c], "dcbt 0, r0"); test_display_under(&decoder_xenon, &[0x2c, 0x02, 0x00, 0x7c], "dcbt 0, r0, 0x0"); test_display_under(&decoder_207, &[0x2c, 0x02, 0x00, 0x7c], "dcbtct 0, r0, 0x0"); test_display_under(&decoder_207, &[0x2c, 0x02, 0x00, 0x7e], "dcbtt 0, r0"); test_invalid_under(&decoder_ppc, &[0x4c, 0x01, 0x00, 0x7c]); test_display_under(&decoder_e500, &[0x4c, 0x29, 0x64, 0x7c], "dcbtls 0x3, r4, r5"); test_display_under(&decoder_a2, &[0x4c, 0x29, 0x64, 0x7c], "dcbtls 0x3, r4, r5"); test_display_under(&decoder_207, &[0x4c, 0x01, 0x00, 0x7c], "dcbtls 0x0, 0, r0"); } #[test] fn loadstore() { let baseline = InstDecoder::for_cpu(IsaVersion::RIOS).with_be(false); let default = InstDecoder::default().with_be(false); test_invalid_under(&baseline, &[0x38, 0x9f, 0x34, 0xe8]); // TODO: what does objdump say? // test_display_under(&power2, &[0x38, 0x9f, 0x34, 0xe8], "ld r1, -0x60c8(r20)"); test_display_le(&[0x38, 0x9f, 0x34, 0xe8], "ld r1, -0x60c8(r20)"); test_display_le(&[0xaa, 0xbc, 0xfd, 0x7f], "lswi r31, r29, 0x17"); test_display_le(&[0xaa, 0xad, 0xfd, 0x7f], "stswi r31, r29, 0x15"); test_invalid_under(&baseline, &[0x48, 0x1a, 0x05, 0xf9]); test_display_le(&[0x48, 0x1a, 0x05, 0xf9], "std r8, 0x1a48(r5)"); test_display_le(&[0xef, 0xfd, 0xf8, 0x7c], "stfdux fr7, r24, r31"); test_invalid_under(&default, &[0xee, 0x1b, 0x87, 0x7c]); test_invalid_under(&baseline, &[0xee, 0x1b, 0x87, 0x7c]); } #[test] fn muldiv() { test_display_le(&[0xd3, 0xff, 0x02, 0x7c], "divdo. r0, r2, r31"); test_display_le(&[0x93, 0x1c, 0x00, 0x7c], "mulhd. r0, r0, r3"); } #[test] fn test_bits() { test_display_le(&[0x90, 0x81, 0xff, 0x78], "rldcl r31, r7, r16, 6"); test_display_le(&[0xb1, 0x44, 0x00, 0x7a], "rldcl. r0, r16, r8, 50"); test_display_le(&[0xd2, 0xc1, 0x00, 0x78], "rldcr r0, r0, r24, 7"); test_display_le(&[0xb3, 0xdf, 0x00, 0x7a], "rldcr. r0, r16, r27, 62"); test_display_le(&[0xee, 0xc9, 0x66, 0x7a], "rldimi r6, r19, 57, 39"); test_display_le(&[0xd0, 0x14, 0x00, 0x7c], "nego r0, r0"); test_display_le(&[0xd0, 0x10, 0x00, 0x7c], "neg r0, r0"); } // yoinked from vmlinux-3.16.0-6-powerpc64le // address 2f2d0c (file offset 302d0c): #[test] fn from_linux() { test_display_le(&[0xac, 0x04, 0x20, 0x7c], "lwsync"); test_display_le(&[0x00, 0x00, 0x20, 0x39], "li r9, 0"); test_display_le(&[0x04, 0x00, 0xc2, 0x3c], "addis r6, r2, 4"); test_display_le(&[0x80, 0x1d, 0x26, 0x91], "stw r9, 0x1d80(r6)"); test_display_le(&[0x02, 0x00, 0xbe, 0xe8], "lwa r5, 0(r30)"); test_display_le(&[0x20, 0x00, 0x7b, 0x38], "addi r3, r27, 0x20"); test_display_le(&[0x01, 0x00, 0x80, 0x38], "li r4, 1"); test_display_le(&[0x78, 0x83, 0x1f, 0x7e], "mr r31, r16"); test_display_le(&[0x00, 0x00, 0x00, 0x3a], "li r16, 0"); test_display_le(&[0x69, 0xa3, 0x12, 0x48], "bl $+0x12a368"); test_display_le(&[0xa0, 0xfe, 0xff, 0x4b], "b $-0x160"); test_display_le(&[0x06, 0x00, 0xe2, 0x3c], "addis r7, r2, 6"); // test_display_le(&[0x48, 0x95, 0xc7, 0x3b], "addi r30, r7, 0x9548"); // test_display_le(&[0xac, 0x04, 0x00, 0x7c], "sync 0"); test_display_le(&[0xa6, 0x03, 0x08, 0x7c], "mtlr r0"); test_display_le(&[0x20, 0x00, 0x80, 0x4e], "blr"); test_display_le(&[0x00, 0x00, 0x42, 0x60], "ori r2, r2, 0"); test_display_le(&[0xb4, 0x07, 0x29, 0x7d], "extsw r9, r9"); test_display_le(&[0x24, 0x1f, 0x29, 0x79], "sldi r9, r9, 3"); test_display_le(&[0x79, 0x1b, 0x64, 0x7c], "mr. r4, r3"); test_display_le(&[0x81, 0xff, 0x21, 0xf8], "stdu r1, -0x80(r1)"); test_display_le(&[0x2c, 0xfd, 0x60, 0x7c], "stwbrx r3, 0, r31"); test_display_le(&[0x2c, 0x54, 0x20, 0x7d], "lwbrx r9, 0, r10"); test_display_le(&[0x00, 0x00, 0x63, 0x80], "lwz r3, 0(r3)"); test_display_le(&[0x01, 0x00, 0x83, 0x2b], "cmplwi cr7, r3, 0x1"); test_display_le(&[0x00, 0x00, 0x23, 0x2c], "cmpdi r3, 0"); test_display_le(&[0x44, 0x00, 0x29, 0x79], "clrrdi r9, r9, 62"); test_display_le(&[0x21, 0x00, 0x63, 0x78], "clrldi. r3, r3, 32"); test_display_le(&[0xe3, 0x77, 0x2a, 0x79], "rldicl. r10, r9, 0x2e, 0x3f"); test_display_le(&[0xa2, 0xf0, 0x29, 0x79], "rldicl r9, r9, 0x3e, 0x22"); test_display_le(&[0x00, 0x00, 0x00, 0x60], "nop"); test_display_le(&[0xa6, 0x02, 0x08, 0x7c], "mflr r0"); test_display_le(&[0xac, 0x04, 0x00 ,0x7c], "hwsync"); test_display_le(&[0xa8, 0xf8, 0x40, 0x7d], "ldarx r10, 0, r31, 0"); test_display_le(&[0x50, 0x50, 0x49, 0x7d], "subf r10, r9, r10"); test_display_le(&[0xad, 0xf9, 0x40, 0x7d], "stdcx. r10, 0, r31"); test_display_le(&[0x01, 0x00, 0x4a, 0x69], "xori r10, r10, 1"); test_display_le(&[0x00, 0x00, 0x0a, 0x0b], "tdnei r10, 0"); test_display_le(&[0x00, 0x00, 0x86, 0x08], "tdeqi r6, 0"); test_display_le(&[0x48, 0x00, 0x00, 0x08], "tdi 0, r0, 0x48"); test_display_le(&[0x74, 0x00, 0x63, 0x7c], "cntlzd r3, r3"); test_display_le(&[0x51, 0x38, 0x0a, 0x7d], "subf. r8, r10, r7"); test_display_le_literal(&[0x21, 0x04, 0x80, 0x4e], "bctrl"); } // an incomplete collection of assembler aliases. #[test] fn aliases() { // aka `nor r21, r26, r26` test_display_le(&[0xf8, 0xd0, 0x55, 0x7f], "not r21, r26"); // aka `mtspr 1, r0` test_display_le(&[0xa6, 0x03, 0x01, 0x7c], "mtxer r0"); // aka `mtspr 8, r0` test_display_le(&[0xa6, 0x03, 0x08, 0x7c], "mtlr r0"); // aka `mtspr 9, r0` test_display_le(&[0xa6, 0x03, 0x09, 0x7c], "mtctr r0"); // aka `rldicr r9, r9, 3, 0x39` test_display_le(&[0x24, 0x1f, 0x29, 0x79], "sldi r9, r9, 3"); test_display_le(&[0xc0, 0x04, 0x0a, 0x78], "clrldi r10, r0, 19"); // aka `rlwnm. r0, r0, r8, 0, 31` test_display_le(&[0x3f, 0x40, 0x00, 0x5c], "rotlw. r0, r0, r8"); // no alias when `me!=31` test_display_le(&[0x39, 0x40, 0x00, 0x5c], "rlwnm. r0, r0, r8, 0, 28"); // still no alias when `me!=31` test_display_le(&[0x7f, 0x7c, 0x58, 0x50], "rlwimi. r24, r2, 15, 17, 31"); } #[test] fn ppc_and_later() { // from v2.01 Book I Appendix F: /* cntlzd Count Leading Zeros Doubleword divd Divide Doubleword divdu Divide Doubleword Unsigned divw Divide Word divwu Divide Word Unsigned extsb Extend Sign Byte extsw Extend Sign Word fadds Floating Add Single fcfid Floating Convert From Integer Doubleword fctid Floating Convert To Integer Doubleword fctidz Floating Convert To Integer Doubleword with round toward Zero fctiw Floating Convert To Integer Word fctiwz Floating Convert To Integer Word with round toward Zero fdivs Floating Divide Single fmadds Floating Multiply-Add Single fmsubs Floating Multiply-Subtract Single fmuls Floating Multiply Single fnmadds Floating Negative Multiply-Add Single fnmsubs Floating Negative Multiply-Subtract Single fres Floating Reciprocal Estimate Single frsqrte Floating Reciprocal Square Root Estimate fsel Floating Select fsqrt[ s] Floating Square Root [Single] fsubs Floating Subtract Single ld Load Doubleword ldu Load Doubleword with Update ldux Load Doubleword with Update Indexed ldx Load Doubleword Indexed lwa Load Word Algebraic lwaux Load Word Algebraic with Update Indexed lwax Load Word Algebraic Indexed mfocrf Move From One Condition Register Field mtocrf Move To One Condition Register Field mulhd Multiply High Doubleword mulhdu Multiply High Doubleword Unsigned mulhw Multiply High Word mulhwu Multiply High Word Unsigned mulld Multiply Low Doubleword rldcl Rotate Left Doubleword then Clear Left rldcr Rotate Left Doubleword then Clear Right rldic Rotate Left Doubleword Immediate then Clear rldicl Rotate Left Doubleword Immediate then Clear Left rldicr Rotate Left Doubleword Immediate then Clear Right rldimi Rotate Left Doubleword Immediate then Mask Insert sld Shift Left Doubleword srad Shift Right Algebraic Doubleword sradi Shift Right Algebraic Doubleword Immediate srd Shift Right Doubleword std Store Doubleword stdu Store Doubleword with Update stdux Store Doubleword with Update Indexed stdx Store Doubleword Indexed stfiwx Store Floating-Point as Integer Word Indexed subf Subtract From td Trap Doubleword tdi Trap Doubleword Immediate */ test_display_le(&[0x26, 0x80, 0x90, 0x7d], "mfocrf r12, 0x8"); test_display_le(&[0x77, 0x4e, 0x08, 0x7c], "sradi. r8, r0, 41"); } #[test] fn test_shifts() { let power1 = InstDecoder::for_cpu(IsaVersion::RIOS).with_be(false); let power2 = InstDecoder::for_cpu(IsaVersion::RIOS2).with_be(false); let p205 = InstDecoder::for_cpu(IsaVersion::V2_05).with_be(false); test_display_le(&[0x30, 0x4e, 0x08, 0x7c], "sraw r8, r0, r9"); test_display_le(&[0x70, 0x4e, 0x08, 0x7c], "srawi r8, r0, 9"); test_display_le(&[0x77, 0x4e, 0x08, 0x7c], "sradi. r8, r0, 41"); test_display_under(&power1, &[0x3a, 0x28, 0x86, 0x58], "rlmi r6, r4, r5, 0x0, 0x1d"); test_display_under(&power2, &[0x3a, 0x28, 0x86, 0x58], "rlmi r6, r4, r5, 0x0, 0x1d"); test_invalid_under(&p205, &[0x3a, 0x28, 0x86, 0x58]); } #[test] fn misc_instr() { let power1 = InstDecoder::for_cpu(IsaVersion::RIOS).with_be(false); let e500 = InstDecoder::for_cpu(IsaVersion::e500).with_be(false); test_display_under(&e500, &[0x0c, 0x04, 0x00, 0x7c], "bblels"); test_display_le(&[0xac, 0x04, 0x00, 0x7c], "hwsync"); test_display_le(&[0xac, 0x04, 0x00, 0x7c], "hwsync"); test_display_le(&[0xac, 0x04, 0x40, 0x7c], "ptesync"); test_display_le(&[0xac, 0x04, 0x60, 0x7c], "sync 3"); test_display_le(&[0x8e, 0x50, 0x00, 0x7c], "lvewx vr0, 0, r10"); test_display_le(&[0x6c, 0xbb, 0x38, 0x7c], "ecowx r1, r24, r23"); test_display_le(&[0x6c, 0xba, 0x38, 0x7c], "eciwx r1, r24, r23"); test_display_le(&[0x00, 0x00, 0x70, 0x28], "cmpldi r16, 0"); test_display_under(&power1, &[0x64, 0x00, 0x00, 0x4c], "rfi"); test_invalid_under(&e500, &[0x00, 0x00, 0x00, 0xc0]); test_display_under(&power1, &[0x00, 0x00, 0x00, 0xc0], "lfs fr0, 0"); } #[test] fn misc_tlb() { let rios2 = InstDecoder::for_cpu(IsaVersion::RIOS2).with_be(false); let e500 = InstDecoder::for_cpu(IsaVersion::e500).with_be(false); let xenon = InstDecoder::for_cpu(IsaVersion::Xenon).with_be(false); let gekko = InstDecoder::for_cpu(IsaVersion::Gekko).with_be(false); let p202 = InstDecoder::for_cpu(IsaVersion::V2_02).with_be(false); let p207 = InstDecoder::for_cpu(IsaVersion::V2_07).with_be(false); test_display_le(&[0x64, 0xea, 0xdf, 0x7d], "tlbie r29, r14"); test_not_xenon_le(&[0x64, 0xea, 0xdf, 0x7d], "tlbie r29, r14"); // Xenia does not decode tlbie, presumably Xenon does not support it? test_invalid_under(&xenon, &[0x64, 0xea, 0xdf, 0x7d]); test_display_under(&gekko, &[0x64, 0xea, 0xdf, 0x7d], "tlbie r29"); test_display_under(&p202, &[0x64, 0xea, 0xdf, 0x7d], "tlbie r29, 0x0"); test_display_under(&p202, &[0x64, 0xea, 0xff, 0x7d], "tlbie r29, 0x1"); test_display_under(&p207, &[0x64, 0xea, 0xff, 0x7d], "tlbie r29, r15"); test_display_under(&rios2, &[0x64, 0x22, 0x03, 0x7c], "tlbi r3, r4"); test_display_under(&p202, &[0x64, 0x22, 0x03, 0x7c], "tlbie r4, 0x0"); test_invalid_under(&rios2, &[0x64, 0x07, 0x00, 0x7c]); test_display_under(&e500, &[0x64, 0x07, 0x00, 0x7c], "tlbre"); test_invalid_under(&rios2, &[0xa4, 0x07, 0x00, 0x7c]); test_display_under(&e500, &[0xa4, 0x07, 0x00, 0x7c], "tlbwe"); test_invalid_under(&rios2, &[0x24, 0x07, 0x00, 0x7c]); test_display_under(&e500, &[0x24, 0x07, 0x00, 0x7c], "tlbsx 0, r0"); } #[test] fn misc_tw() { test_display_le(&[0x08, 0xf8, 0x1f, 0x7d], "twgt r31, r31"); } #[test] fn test_power203() { let e500 = InstDecoder::for_cpu(IsaVersion::e500).with_be(false); let p202 = InstDecoder::for_cpu(IsaVersion::V2_02).with_be(false); let p203 = InstDecoder::for_cpu(IsaVersion::V2_03).with_be(false); let p300 = InstDecoder::for_cpu(IsaVersion::V3_0).with_be(false); test_display_under(&p202, &[0xac, 0x76, 0x1c, 0x7c], "eieio"); test_display_under(&p203, &[0xac, 0x76, 0x1c, 0x7c], "eieio"); test_display_under(&p203, &[0xac, 0x0e, 0x1c, 0x7c], "eieio"); test_display_under(&p203, &[0xac, 0x0e, 0x3c, 0x7c], "mbar 0x1"); test_display_under(&p300, &[0xac, 0x76, 0x1c, 0x7c], "eieio"); test_display_under(&e500, &[0x1e, 0x29, 0x64, 0x7c], "isel r3, r4, r5, crb4"); test_display_under(&p300, &[0x1e, 0x29, 0x64, 0x7c], "isel r3, r4, r5, crb4"); test_invalid_under(&p202, &[0x5e, 0x02, 0x00, 0x7c]); test_invalid_under(&p203, &[0x5e, 0x03, 0x00, 0x7c]); test_display_under(&p300, &[0x5e, 0x03, 0x00, 0x7c], "isel r0, 0, r0, crb13"); test_display_under(&p300, &[0x5f, 0x03, 0x00, 0x7c], "isel r0, 0, r0, crb13"); } #[test] fn test_power205() { let p202 = InstDecoder::for_cpu(IsaVersion::V2_02).with_be(false); let p205 = InstDecoder::for_cpu(IsaVersion::V2_05).with_be(false); let p300 = InstDecoder::for_cpu(IsaVersion::V3_0).with_be(false); test_display_under(&p202, &[0x28, 0x30, 0x00, 0x7c], "lwarx r0, 0, r6"); test_display_under(&p205, &[0x28, 0x30, 0x00, 0x7c], "lwarx r0, 0, r6, 0"); test_invalid_under(&p202, &[0x29, 0x30, 0x00, 0x7c]); test_display_under(&p205, &[0x29, 0x30, 0x00, 0x7c], "lwarx r0, 0, r6, 1"); test_display_under(&p300, &[0x29, 0x30, 0x00, 0x7c], "lwarx r0, 0, r6, 1"); test_display_under(&p202, &[0xa8, 0x30, 0x00, 0x7c], "ldarx r0, 0, r6"); test_display_under(&p205, &[0xa8, 0x30, 0x00, 0x7c], "ldarx r0, 0, r6, 0"); test_invalid_under(&p202, &[0xa9, 0x30, 0x00, 0x7c]); test_display_under(&p205, &[0xa9, 0x30, 0x00, 0x7c], "ldarx r0, 0, r6, 1"); test_display_under(&p300, &[0xa9, 0x30, 0x00, 0x7c], "ldarx r0, 0, r6, 1"); } #[test] fn test_e500mc() { let power2 = InstDecoder::for_cpu(IsaVersion::RIOS2).with_be(false); let p205 = InstDecoder::for_cpu(IsaVersion::V2_05).with_be(false); let e500mc = InstDecoder::for_cpu(IsaVersion::e500mc).with_be(false); let p300 = InstDecoder::for_cpu(IsaVersion::V3_0).with_be(false); let all = InstDecoder::for_cpu(IsaVersion::All).with_be(false); test_invalid_under(&power2, &[0xc6, 0x24, 0x00, 0x7c]); test_invalid_under(&p205, &[0xc6, 0x24, 0x00, 0x7c]); test_display_under(&e500mc, &[0xc6, 0x24, 0x00, 0x7c], "lddx r0, 0, r4"); test_invalid_under(&p300, &[0xc6, 0x24, 0x00, 0x7c]); test_display_under(&all, &[0xc6, 0x24, 0x00, 0x7c], "lddx r0, 0, r4"); } #[test] fn test_power300() { } #[test] fn test_transaction() { let p206 = InstDecoder::for_cpu(IsaVersion::V2_06).with_be(false); let p207 = InstDecoder::for_cpu(IsaVersion::V2_07).with_be(false); test_invalid_under(&p206, &[0x1d, 0x07, 0x03, 0x7c]); test_display_under(&p207, &[0x1d, 0x07, 0x03, 0x7c], "tabort. r3"); test_invalid_under(&p206, &[0x5d, 0x07, 0x03, 0x7c]); test_display_under(&p207, &[0x5d, 0x07, 0x03, 0x7c], "treclaim. r3"); test_invalid_under(&p206, &[0x5d, 0x07, 0x05, 0x7c]); test_display_under(&p207, &[0x5d, 0x07, 0x05, 0x7c], "treclaim. r5"); } #[test] fn from_linux_misc() { test_display_le(&[0x00, 0x00, 0x00, 0x60], "nop"); test_display_le(&[0x00, 0x02, 0x00, 0x00], "attn"); test_display_le(&[0x06, 0x01, 0x00, 0x7c], "wrtee r0"); test_display_le(&[0x08, 0x00, 0xe0, 0x7f], "trap"); test_display_le(&[0x08, 0x20, 0xe0, 0x7f], "tw 0x1f, r0, r4"); test_display_le(&[0x1c, 0x21, 0x00, 0x7c], "msgsndp r4"); test_display_le(&[0x1d, 0x07, 0x03, 0x7c], "tabort. r3"); test_display_le(&[0x22, 0x00, 0x00, 0x44], "sc 1"); test_display_le(&[0x24, 0x02, 0x00, 0x4c], "hrfid"); test_display_le(&[0x2c, 0x01, 0x00, 0x4c], "isync"); test_display_le(&[0x38, 0x4a, 0x49, 0x7d], "eqv r9, r10, r9"); test_display_le(&[0x38, 0xf2, 0xff, 0x7f], "eqv r31, r31, r30"); test_display_le(&[0x48, 0x00, 0x00, 0x08], "tdi 0, r0, 72"); test_display_le(&[0x4c, 0x00, 0x00, 0x24], "dozi r0, r0, 0x4c"); test_display_le(&[0x4c, 0x00, 0x00, 0x26], "dozi r16, r0, 0x4c"); test_display_le(&[0x5d, 0x07, 0x03, 0x7c], "treclaim. r3"); test_display_le(&[0x5d, 0x07, 0x05, 0x7c], "treclaim. r5"); // TODO: what is the "nap" instruction.. // test_display_le(&[0x64, 0x03, 0x00, 0x4c], "nap"); test_display_le(&[0x6c, 0x04, 0x00, 0x7c], "tlbsync"); // TODO: variance from binutils: dssall has a field which binutils omits if zero test_display_le(&[0x6c, 0x06, 0x00, 0x7e], "dssall 0x0"); test_display_le(&[0x9c, 0x21, 0x00, 0x7c], "msgsnd r4"); test_display_le(&[0xac, 0x04, 0x00, 0x7c], "hwsync"); test_display_le(&[0xac, 0x04, 0x40, 0x7c], "ptesync"); test_display_le(&[0xac, 0x06, 0x00, 0x7c], "eieio"); test_display_le(&[0xac, 0x1f, 0x06, 0x7c], "icbi r6, r3"); // TODO: first operand should be 0 if "r0" test_display_le(&[0xac, 0x37, 0x00, 0x7c], "icbi 0, r6"); test_display_le(&[0xdd, 0x07, 0x00, 0x7c], "trechkpt."); // TODO: should be printed as twui probably? test_display_le(&[0x00, 0x00, 0xe0, 0x0f], "twi 0x1f, r0, 0"); } #[test] fn control_reg() { test_display(&[0x4c, 0x0d, 0x51, 0x82], "crxor crb0, crb13, crb10"); test_display(&[0x4f, 0xde, 0xf2, 0x43], "crset crb30"); test_display(&[0xfc, 0xff, 0xa8, 0x80], "mcrfs cr1, fpscrf7"); test_display(&[0x7e, 0xe3, 0x14, 0x00], "mcrxr cr5"); test_display(&[0x4c, 0x42, 0x11, 0x82], "crclr crb2"); test_display(&[0x4f, 0xfa, 0xd0, 0x43], "crnot crb31, crb26"); test_display(&[0x4f, 0xf9, 0xcb, 0x83], "crmove crb31, crb25"); } #[test] fn ppc32_vse() { test_display(&[0x08, 0xa7, 0xff, 0xff], "tdlgei r7, -1"); test_display(&[0x08, 0xab, 0xff, 0xff], "tdlgei r11, -1"); test_display(&[0x08, 0xc8, 0x00, 0x00], "tdllei r8, 0"); test_display(&[0x08, 0xc9, 0x00, 0x00], "tdllei r9, 0"); test_display(&[0x08, 0xca, 0x00, 0x00], "tdllei r10, 0"); test_display(&[0x0c, 0xa3, 0xff, 0xff], "twlgei r3, -1"); test_display(&[0x0c, 0xa4, 0xff, 0xff], "twlgei r4, -1"); test_display(&[0x0c, 0xa5, 0xff, 0xff], "twlgei r5, -1"); test_display(&[0x0c, 0xa6, 0xff, 0xff], "twlgei r6, -1"); test_display(&[0x0c, 0xa7, 0xff, 0xff], "twlgei r7, -1"); test_display(&[0x0c, 0xa8, 0xff, 0xff], "twlgei r8, -1"); test_display(&[0x0c, 0xa9, 0xff, 0xff], "twlgei r9, -1"); test_display(&[0x0c, 0xaa, 0xff, 0xff], "twlgei r10, -1"); test_display(&[0x0c, 0xab, 0xff, 0xff], "twlgei r11, -1"); test_display(&[0x0c, 0xc3, 0x00, 0x00], "twllei r3, 0"); test_display(&[0x0c, 0xc4, 0x00, 0x00], "twllei r4, 0"); test_display(&[0x0c, 0xc5, 0x00, 0x00], "twllei r5, 0"); test_display(&[0x0c, 0xc6, 0x00, 0x00], "twllei r6, 0"); test_display(&[0x0c, 0xc7, 0x00, 0x00], "twllei r7, 0"); test_display(&[0x0c, 0xc8, 0x00, 0x00], "twllei r8, 0"); test_display(&[0x0c, 0xc9, 0x00, 0x00], "twllei r9, 0"); test_display(&[0x0c, 0xca, 0x00, 0x00], "twllei r10, 0"); test_display(&[0x0c, 0xcb, 0x00, 0x00], "twllei r11, 0"); test_display(&[0x0c, 0xd0, 0x00, 0x00], "twllei r16, 0"); test_display(&[0x0c, 0xd4, 0x00, 0x00], "twllei r20, 0"); test_display(&[0x0c, 0xd5, 0x00, 0x00], "twllei r21, 0"); test_display(&[0x0c, 0xd7, 0x00, 0x00], "twllei r23, 0"); test_display(&[0x0c, 0xd8, 0x00, 0x00], "twllei r24, 0"); test_display(&[0x0c, 0xd9, 0x00, 0x00], "twllei r25, 0"); test_display(&[0x0c, 0xda, 0x00, 0x00], "twllei r26, 0"); test_display(&[0x0c, 0xdb, 0x00, 0x00], "twllei r27, 0"); test_display(&[0x0c, 0xdc, 0x00, 0x00], "twllei r28, 0"); test_display(&[0x0c, 0xdd, 0x00, 0x00], "twllei r29, 0"); test_display(&[0x0c, 0xde, 0x00, 0x00], "twllei r30, 0"); test_display(&[0x0c, 0xdf, 0x00, 0x00], "twllei r31, 0"); test_display(&[0x0f, 0xe0, 0x00, 0x14], "twi 31, r0, 0x14"); test_display(&[0x0f, 0xe0, 0x00, 0x16], "twi 31, r0, 0x16"); } #[test] fn ppc32_mul() { test_display(&[0x7C, 0x63, 0x59, 0xD6], "mullw r3, r3, r11"); test_display(&[0x7C, 0x63, 0xD1, 0xD6], "mullw r3, r3, r26"); test_display(&[0x7C, 0x63, 0xD9, 0xD6], "mullw r3, r3, r27"); test_display(&[0x7C, 0x63, 0xE1, 0xD6], "mullw r3, r3, r28"); test_display(&[0x7C, 0x63, 0xF9, 0xD6], "mullw r3, r3, r31"); test_display(&[0x7C, 0x65, 0x59, 0xD6], "mullw r3, r5, r11"); test_display(&[0x7C, 0x68, 0x58, 0x96], "mulhw r3, r8, r11"); test_display(&[0x7C, 0x6A, 0x18, 0x96], "mulhw r3, r10, r3"); test_display(&[0x7C, 0x6A, 0x49, 0xD6], "mullw r3, r10, r9"); test_display(&[0x7C, 0x6A, 0x58, 0x96], "mulhw r3, r10, r11"); test_display(&[0x7C, 0x6A, 0x59, 0xD6], "mullw r3, r10, r11"); test_display(&[0x7C, 0x6A, 0xB1, 0xD6], "mullw r3, r10, r22"); test_display(&[0x7C, 0x6B, 0x41, 0xD6], "mullw r3, r11, r8"); test_display(&[0x7C, 0x6B, 0x49, 0xD6], "mullw r3, r11, r9"); test_display(&[0x7C, 0x6B, 0x51, 0xD6], "mullw r3, r11, r10"); test_display(&[0x7C, 0x6B, 0xB9, 0xD6], "mullw r3, r11, r23"); test_display(&[0x7C, 0x6B, 0xF1, 0xD6], "mullw r3, r11, r30"); test_display(&[0x7C, 0x75, 0x99, 0xD6], "mullw r3, r21, r19"); test_display(&[0x7C, 0x7C, 0xF1, 0xD6], "mullw r3, r28, r30"); test_display(&[0x7C, 0x7D, 0xE1, 0xD6], "mullw r3, r29, r28"); test_display(&[0x7C, 0x7E, 0xF1, 0xD6], "mullw r3, r30, r30"); test_display(&[0x7C, 0x7F, 0xF9, 0xD6], "mullw r3, r31, r31"); test_display(&[0x7C, 0x83, 0xE9, 0xD6], "mullw r4, r3, r29"); test_display(&[0x7C, 0x83, 0xF9, 0xD6], "mullw r4, r3, r31"); test_display(&[0x7C, 0x84, 0x19, 0xD6], "mullw r4, r4, r3"); test_display(&[0x7C, 0x84, 0x29, 0xD6], "mullw r4, r4, r5"); test_display(&[0x7C, 0x84, 0x49, 0xD6], "mullw r4, r4, r9"); test_display(&[0x7C, 0x84, 0x51, 0xD6], "mullw r4, r4, r10"); test_display(&[0x7C, 0x84, 0x59, 0xD6], "mullw r4, r4, r11"); test_display(&[0x7C, 0x84, 0xD1, 0xD6], "mullw r4, r4, r26"); test_display(&[0x7C, 0x84, 0xE1, 0xD6], "mullw r4, r4, r28"); test_display(&[0x7C, 0x84, 0xE9, 0xD6], "mullw r4, r4, r29"); test_display(&[0x7C, 0x85, 0x59, 0xD6], "mullw r4, r5, r11"); test_display(&[0x7C, 0x85, 0xA9, 0xD6], "mullw r4, r5, r21"); test_display(&[0x7C, 0x86, 0x39, 0xD6], "mullw r4, r6, r7"); test_display(&[0x7C, 0x88, 0x58, 0x96], "mulhw r4, r8, r11"); test_display(&[0x7C, 0x88, 0xF8, 0x96], "mulhw r4, r8, r31"); test_display(&[0x7C, 0x8A, 0x41, 0xD6], "mullw r4, r10, r8"); test_display(&[0x7C, 0x8A, 0x59, 0xD6], "mullw r4, r10, r11"); test_display(&[0x7C, 0x8A, 0xF1, 0xD6], "mullw r4, r10, r30"); test_display(&[0x7C, 0x8B, 0x39, 0xD6], "mullw r4, r11, r7"); test_display(&[0x7C, 0x8B, 0xE9, 0xD6], "mullw r4, r11, r29"); test_display(&[0x7C, 0x97, 0xB1, 0xD6], "mullw r4, r23, r22"); test_display(&[0x7C, 0x99, 0xC1, 0xD6], "mullw r4, r25, r24"); test_display(&[0x7C, 0x9B, 0xF1, 0xD6], "mullw r4, r27, r30"); test_display(&[0x7C, 0x9C, 0xF1, 0xD6], "mullw r4, r28, r30"); test_display(&[0x7C, 0x9D, 0x21, 0xD6], "mullw r4, r29, r4"); test_display(&[0x7C, 0x9D, 0xE1, 0xD6], "mullw r4, r29, r28"); test_display(&[0x7C, 0xA3, 0x29, 0xD6], "mullw r5, r3, r5"); test_display(&[0x7C, 0xA3, 0x59, 0xD6], "mullw r5, r3, r11"); test_display(&[0x7C, 0xA3, 0xF9, 0xD6], "mullw r5, r3, r31"); test_display(&[0x7C, 0xA4, 0x29, 0xD6], "mullw r5, r4, r5"); test_display(&[0x7C, 0xA4, 0x51, 0xD6], "mullw r5, r4, r10"); test_display(&[0x7C, 0xA5, 0x19, 0xD6], "mullw r5, r5, r3"); test_display(&[0x7C, 0xA5, 0x21, 0xD6], "mullw r5, r5, r4"); test_display(&[0x7C, 0xA5, 0x49, 0xD2], "mulld r5, r5, r9"); test_display(&[0x7C, 0xA5, 0x51, 0xD6], "mullw r5, r5, r10"); test_display(&[0x7C, 0xA5, 0x59, 0xD6], "mullw r5, r5, r11"); test_display(&[0x7C, 0xA5, 0xE1, 0xD6], "mullw r5, r5, r28"); test_display(&[0x7C, 0xA5, 0xE9, 0xD6], "mullw r5, r5, r29"); test_display(&[0x7C, 0xA6, 0x51, 0xD6], "mullw r5, r6, r10"); test_display(&[0x7C, 0xA7, 0x29, 0xD6], "mullw r5, r7, r5"); test_display(&[0x7C, 0xA7, 0x31, 0xD6], "mullw r5, r7, r6"); test_display(&[0x7C, 0xA7, 0x41, 0xD6], "mullw r5, r7, r8"); test_display(&[0x7C, 0xA7, 0x58, 0x16], "mulhwu r5, r7, r11"); test_display(&[0x7C, 0xA7, 0x59, 0xD6], "mullw r5, r7, r11"); test_display(&[0x7C, 0xA7, 0xD8, 0x16], "mulhwu r5, r7, r27"); test_display(&[0x7C, 0xA8, 0x58, 0x16], "mulhwu r5, r8, r11"); test_display(&[0x7C, 0xA8, 0x59, 0xD6], "mullw r5, r8, r11"); test_display(&[0x7C, 0xA8, 0xE1, 0xD6], "mullw r5, r8, r28"); test_display(&[0x7C, 0xA9, 0x31, 0xD6], "mullw r5, r9, r6"); test_display(&[0x7C, 0xA9, 0x41, 0xD6], "mullw r5, r9, r8"); test_display(&[0x7C, 0xA9, 0x51, 0xD6], "mullw r5, r9, r10"); test_display(&[0x7C, 0xA9, 0x59, 0xD6], "mullw r5, r9, r11"); test_display(&[0x7C, 0xA9, 0xD9, 0xD6], "mullw r5, r9, r27"); test_display(&[0x7C, 0xA9, 0xE0, 0x96], "mulhw r5, r9, r28"); test_display(&[0x7C, 0xAA, 0x31, 0xD6], "mullw r5, r10, r6"); test_display(&[0x7C, 0xAA, 0x39, 0xD6], "mullw r5, r10, r7"); test_display(&[0x7C, 0xAA, 0x49, 0xD6], "mullw r5, r10, r9"); test_display(&[0x7C, 0xAA, 0x59, 0xD6], "mullw r5, r10, r11"); test_display(&[0x7C, 0xAB, 0x29, 0xD6], "mullw r5, r11, r5"); test_display(&[0x7C, 0xAB, 0x51, 0xD6], "mullw r5, r11, r10"); test_display(&[0x7C, 0xAB, 0xE1, 0xD6], "mullw r5, r11, r28"); test_display(&[0x7C, 0xAB, 0xF1, 0xD6], "mullw r5, r11, r30"); test_display(&[0x7C, 0xB9, 0xC1, 0xD6], "mullw r5, r25, r24"); test_display(&[0x7C, 0xBA, 0xE1, 0xD6], "mullw r5, r26, r28"); test_display(&[0x7C, 0xBB, 0x29, 0xD6], "mullw r5, r27, r5"); test_display(&[0x7C, 0xBD, 0x59, 0xD6], "mullw r5, r29, r11"); test_display(&[0x7C, 0xBD, 0xF1, 0xD6], "mullw r5, r29, r30"); test_display(&[0x7C, 0xBE, 0x41, 0xD6], "mullw r5, r30, r8"); test_display(&[0x7C, 0xBE, 0x59, 0xD6], "mullw r5, r30, r11"); test_display(&[0x7C, 0xBE, 0xE9, 0xD6], "mullw r5, r30, r29"); test_display(&[0x7C, 0xBF, 0x29, 0xD6], "mullw r5, r31, r5"); test_display(&[0x7C, 0xBF, 0xE1, 0xD6], "mullw r5, r31, r28"); test_display(&[0x7C, 0xC4, 0x91, 0xD6], "mullw r6, r4, r18"); test_display(&[0x7C, 0xC6, 0x49, 0xD6], "mullw r6, r6, r9"); test_display(&[0x7C, 0xC6, 0x51, 0xD2], "mulld r6, r6, r10"); test_display(&[0x7C, 0xC6, 0x51, 0xD6], "mullw r6, r6, r10"); test_display(&[0x7C, 0xC6, 0x59, 0xD6], "mullw r6, r6, r11"); test_display(&[0x7C, 0xC6, 0x59, 0xD7], "mullw. r6, r6, r11"); test_display(&[0x7C, 0xC6, 0x71, 0xD6], "mullw r6, r6, r14"); test_display(&[0x7C, 0xC6, 0x79, 0xD6], "mullw r6, r6, r15"); test_display(&[0x7C, 0xC6, 0x81, 0xD6], "mullw r6, r6, r16"); test_display(&[0x7C, 0xC6, 0xE9, 0xD6], "mullw r6, r6, r29"); test_display(&[0x7C, 0xC7, 0x30, 0x96], "mulhw r6, r7, r6"); test_display(&[0x7C, 0xC7, 0x31, 0xD6], "mullw r6, r7, r6"); test_display(&[0x7C, 0xC7, 0x51, 0xD6], "mullw r6, r7, r10"); test_display(&[0x7C, 0xC7, 0xA9, 0xD6], "mullw r6, r7, r21"); test_display(&[0x7C, 0xC7, 0xE9, 0xD6], "mullw r6, r7, r29"); test_display(&[0x7C, 0xC8, 0x31, 0xD6], "mullw r6, r8, r6"); test_display(&[0x7C, 0xC8, 0x51, 0xD6], "mullw r6, r8, r10"); test_display(&[0x7C, 0xC8, 0x58, 0x96], "mulhw r6, r8, r11"); test_display(&[0x7C, 0xC8, 0xD0, 0x16], "mulhwu r6, r8, r26"); test_display(&[0x7C, 0xC9, 0x31, 0xD6], "mullw r6, r9, r6"); test_display(&[0x7C, 0xC9, 0x41, 0xD6], "mullw r6, r9, r8"); test_display(&[0x7C, 0xCA, 0x41, 0xD6], "mullw r6, r10, r8"); test_display(&[0x7C, 0xCA, 0x49, 0xD6], "mullw r6, r10, r9"); test_display(&[0x7C, 0xCA, 0xD9, 0xD6], "mullw r6, r10, r27"); test_display(&[0x7C, 0xCA, 0xE0, 0x96], "mulhw r6, r10, r28"); test_display(&[0x7C, 0xCB, 0x49, 0xD6], "mullw r6, r11, r9"); test_display(&[0x7C, 0xCB, 0x49, 0xD7], "mullw. r6, r11, r9"); test_display(&[0x7C, 0xD7, 0x49, 0xD6], "mullw r6, r23, r9"); test_display(&[0x7C, 0xD8, 0x49, 0xD6], "mullw r6, r24, r9"); test_display(&[0x7C, 0xD9, 0x31, 0xD6], "mullw r6, r25, r6"); test_display(&[0x7C, 0xDA, 0x51, 0xD6], "mullw r6, r26, r10"); test_display(&[0x7C, 0xE3, 0x89, 0xD6], "mullw r7, r3, r17"); test_display(&[0x7C, 0xE3, 0xE1, 0xD6], "mullw r7, r3, r28"); test_display(&[0x7C, 0xE4, 0x30, 0x16], "mulhwu r7, r4, r6"); test_display(&[0x7C, 0xE4, 0x39, 0xD6], "mullw r7, r4, r7"); test_display(&[0x7C, 0xE4, 0x49, 0xD6], "mullw r7, r4, r9"); test_display(&[0x7C, 0xE5, 0xD0, 0x16], "mulhwu r7, r5, r26"); test_display(&[0x7C, 0xE6, 0x39, 0xD6], "mullw r7, r6, r7"); test_display(&[0x7C, 0xE7, 0x21, 0xD6], "mullw r7, r7, r4"); test_display(&[0x7C, 0xE7, 0x28, 0x96], "mulhw r7, r7, r5"); test_display(&[0x7C, 0xE7, 0x29, 0xD6], "mullw r7, r7, r5"); test_display(&[0x7C, 0xE7, 0x30, 0x16], "mulhwu r7, r7, r6"); test_display(&[0x7C, 0xE7, 0x31, 0xD6], "mullw r7, r7, r6"); test_display(&[0x7C, 0xE7, 0x49, 0xD6], "mullw r7, r7, r9"); test_display(&[0x7C, 0xE7, 0x51, 0xD2], "mulld r7, r7, r10"); test_display(&[0x7C, 0xE7, 0x51, 0xD6], "mullw r7, r7, r10"); test_display(&[0x7C, 0xE7, 0x58, 0x96], "mulhw r7, r7, r11"); test_display(&[0x7C, 0xE7, 0x59, 0xD6], "mullw r7, r7, r11"); test_display(&[0x7C, 0xE7, 0xD9, 0xD6], "mullw r7, r7, r27"); test_display(&[0x7C, 0xE7, 0xE1, 0xD6], "mullw r7, r7, r28"); test_display(&[0x7C, 0xE7, 0xE9, 0xD6], "mullw r7, r7, r29"); test_display(&[0x7C, 0xE7, 0xF1, 0xD6], "mullw r7, r7, r30"); test_display(&[0x7C, 0xE8, 0x39, 0xD6], "mullw r7, r8, r7"); test_display(&[0x7C, 0xE8, 0x51, 0xD6], "mullw r7, r8, r10"); test_display(&[0x7C, 0xE8, 0x58, 0x96], "mulhw r7, r8, r11"); test_display(&[0x7C, 0xE8, 0xD1, 0xD6], "mullw r7, r8, r26"); test_display(&[0x7C, 0xE9, 0x29, 0xD6], "mullw r7, r9, r5"); test_display(&[0x7C, 0xE9, 0x30, 0x16], "mulhwu r7, r9, r6"); test_display(&[0x7C, 0xE9, 0x38, 0x96], "mulhw r7, r9, r7"); test_display(&[0x7C, 0xE9, 0x58, 0x96], "mulhw r7, r9, r11"); test_display(&[0x7C, 0xE9, 0xF1, 0xD6], "mullw r7, r9, r30"); test_display(&[0x7C, 0xEA, 0x39, 0xD6], "mullw r7, r10, r7"); test_display(&[0x7C, 0xEA, 0x41, 0xD6], "mullw r7, r10, r8"); test_display(&[0x7C, 0xEA, 0x80, 0x96], "mulhw r7, r10, r16"); test_display(&[0x7C, 0xEA, 0xA1, 0xD6], "mullw r7, r10, r20"); test_display(&[0x7C, 0xEA, 0xA8, 0x96], "mulhw r7, r10, r21"); test_display(&[0x7C, 0xEA, 0xD0, 0x96], "mulhw r7, r10, r26"); test_display(&[0x7C, 0xEA, 0xD1, 0xD6], "mullw r7, r10, r26"); test_display(&[0x7C, 0xEA, 0xE8, 0x96], "mulhw r7, r10, r29"); test_display(&[0x7C, 0xEB, 0x21, 0xD6], "mullw r7, r11, r4"); test_display(&[0x7C, 0xEB, 0x28, 0x96], "mulhw r7, r11, r5"); test_display(&[0x7C, 0xEB, 0x30, 0x96], "mulhw r7, r11, r6"); test_display(&[0x7C, 0xEB, 0x39, 0xD6], "mullw r7, r11, r7"); test_display(&[0x7C, 0xEB, 0x51, 0xD6], "mullw r7, r11, r10"); test_display(&[0x7C, 0xEB, 0xC0, 0x96], "mulhw r7, r11, r24"); test_display(&[0x7C, 0xEB, 0xD9, 0xD6], "mullw r7, r11, r27"); test_display(&[0x7C, 0xEB, 0xE0, 0x96], "mulhw r7, r11, r28"); test_display(&[0x7C, 0xF2, 0x49, 0xD6], "mullw r7, r18, r9"); test_display(&[0x7C, 0xF3, 0x49, 0xD6], "mullw r7, r19, r9"); test_display(&[0x7C, 0xF5, 0x49, 0xD6], "mullw r7, r21, r9"); test_display(&[0x7C, 0xF7, 0x49, 0xD6], "mullw r7, r23, r9"); test_display(&[0x7C, 0xF7, 0x58, 0x96], "mulhw r7, r23, r11"); test_display(&[0x7C, 0xF8, 0x49, 0xD6], "mullw r7, r24, r9"); test_display(&[0x7C, 0xF8, 0x58, 0x96], "mulhw r7, r24, r11"); test_display(&[0x7C, 0xF9, 0x49, 0xD6], "mullw r7, r25, r9"); test_display(&[0x7C, 0xF9, 0x58, 0x96], "mulhw r7, r25, r11"); test_display(&[0x7C, 0xFA, 0x39, 0xD6], "mullw r7, r26, r7"); test_display(&[0x7C, 0xFA, 0x49, 0xD6], "mullw r7, r26, r9"); test_display(&[0x7C, 0xFA, 0x58, 0x96], "mulhw r7, r26, r11"); test_display(&[0x7C, 0xFC, 0x51, 0xD6], "mullw r7, r28, r10"); test_display(&[0x7D, 0x03, 0x41, 0xD6], "mullw r8, r3, r8"); test_display(&[0x7D, 0x03, 0x49, 0xD6], "mullw r8, r3, r9"); test_display(&[0x7D, 0x03, 0xE9, 0xD6], "mullw r8, r3, r29"); test_display(&[0x7D, 0x05, 0x41, 0xD6], "mullw r8, r5, r8"); test_display(&[0x7D, 0x05, 0x59, 0xD6], "mullw r8, r5, r11"); test_display(&[0x7D, 0x06, 0x39, 0xD6], "mullw r8, r6, r7"); test_display(&[0x7D, 0x06, 0x40, 0x16], "mulhwu r8, r6, r8"); test_display(&[0x7D, 0x06, 0x41, 0xD6], "mullw r8, r6, r8"); test_display(&[0x7D, 0x06, 0x49, 0xD6], "mullw r8, r6, r9"); test_display(&[0x7D, 0x06, 0x51, 0xD6], "mullw r8, r6, r10"); test_display(&[0x7D, 0x06, 0x59, 0xD7], "mullw. r8, r6, r11"); test_display(&[0x7D, 0x06, 0xA1, 0xD6], "mullw r8, r6, r20"); test_display(&[0x7D, 0x06, 0xE1, 0xD6], "mullw r8, r6, r28"); test_display(&[0x7D, 0x06, 0xF9, 0xD6], "mullw r8, r6, r31"); test_display(&[0x7D, 0x07, 0x41, 0xD6], "mullw r8, r7, r8"); test_display(&[0x7D, 0x07, 0x49, 0xD6], "mullw r8, r7, r9"); test_display(&[0x7D, 0x07, 0x59, 0xD6], "mullw r8, r7, r11"); test_display(&[0x7D, 0x08, 0x19, 0xD6], "mullw r8, r8, r3"); test_display(&[0x7D, 0x08, 0x21, 0xD6], "mullw r8, r8, r4"); test_display(&[0x7D, 0x08, 0x29, 0xD6], "mullw r8, r8, r5"); test_display(&[0x7D, 0x08, 0x30, 0x96], "mulhw r8, r8, r6"); test_display(&[0x7D, 0x08, 0x31, 0xD6], "mullw r8, r8, r6"); test_display(&[0x7D, 0x08, 0x38, 0x16], "mulhwu r8, r8, r7"); test_display(&[0x7D, 0x08, 0x39, 0xD6], "mullw r8, r8, r7"); test_display(&[0x7D, 0x08, 0x49, 0xD6], "mullw r8, r8, r9"); test_display(&[0x7D, 0x08, 0x51, 0xD6], "mullw r8, r8, r10"); test_display(&[0x7D, 0x08, 0x58, 0x96], "mulhw r8, r8, r11"); test_display(&[0x7D, 0x08, 0x59, 0xD6], "mullw r8, r8, r11"); test_display(&[0x7D, 0x08, 0x89, 0xD6], "mullw r8, r8, r17"); test_display(&[0x7D, 0x08, 0x99, 0xD6], "mullw r8, r8, r19"); test_display(&[0x7D, 0x08, 0xA9, 0xD6], "mullw r8, r8, r21"); test_display(&[0x7D, 0x08, 0xB9, 0xD6], "mullw r8, r8, r23"); test_display(&[0x7D, 0x08, 0xC9, 0xD6], "mullw r8, r8, r25"); test_display(&[0x7D, 0x08, 0xD1, 0xD6], "mullw r8, r8, r26"); test_display(&[0x7D, 0x08, 0xD9, 0xD6], "mullw r8, r8, r27"); test_display(&[0x7D, 0x08, 0xE9, 0xD6], "mullw r8, r8, r29"); test_display(&[0x7D, 0x08, 0xF1, 0xD6], "mullw r8, r8, r30"); test_display(&[0x7D, 0x08, 0xF9, 0xD6], "mullw r8, r8, r31"); test_display(&[0x7D, 0x09, 0x20, 0x96], "mulhw r8, r9, r4"); test_display(&[0x7D, 0x09, 0x39, 0xD6], "mullw r8, r9, r7"); test_display(&[0x7D, 0x09, 0x40, 0x96], "mulhw r8, r9, r8"); test_display(&[0x7D, 0x09, 0x51, 0xD6], "mullw r8, r9, r10"); test_display(&[0x7D, 0x09, 0x59, 0xD6], "mullw r8, r9, r11"); test_display(&[0x7D, 0x09, 0x90, 0x16], "mulhwu r8, r9, r18"); test_display(&[0x7D, 0x09, 0xF1, 0xD6], "mullw r8, r9, r30"); test_display(&[0x7D, 0x0A, 0x29, 0xD6], "mullw r8, r10, r5"); test_display(&[0x7D, 0x0A, 0x38, 0x96], "mulhw r8, r10, r7"); test_display(&[0x7D, 0x0A, 0x41, 0xD6], "mullw r8, r10, r8"); test_display(&[0x7D, 0x0A, 0x49, 0xD6], "mullw r8, r10, r9"); test_display(&[0x7D, 0x0A, 0x59, 0xD6], "mullw r8, r10, r11"); test_display(&[0x7D, 0x0A, 0x80, 0x96], "mulhw r8, r10, r16"); test_display(&[0x7D, 0x0A, 0xA8, 0x96], "mulhw r8, r10, r21"); test_display(&[0x7D, 0x0A, 0xC1, 0xD6], "mullw r8, r10, r24"); test_display(&[0x7D, 0x0A, 0xD0, 0x96], "mulhw r8, r10, r26"); test_display(&[0x7D, 0x0A, 0xE0, 0x96], "mulhw r8, r10, r28"); test_display(&[0x7D, 0x0A, 0xE8, 0x96], "mulhw r8, r10, r29"); test_display(&[0x7D, 0x0A, 0xF0, 0x96], "mulhw r8, r10, r30"); test_display(&[0x7D, 0x0B, 0x19, 0xD6], "mullw r8, r11, r3"); test_display(&[0x7D, 0x0B, 0x21, 0xD6], "mullw r8, r11, r4"); test_display(&[0x7D, 0x0B, 0x40, 0x16], "mulhwu r8, r11, r8"); test_display(&[0x7D, 0x0B, 0x40, 0x96], "mulhw r8, r11, r8"); test_display(&[0x7D, 0x0B, 0x51, 0xD6], "mullw r8, r11, r10"); test_display(&[0x7D, 0x0B, 0xA8, 0x96], "mulhw r8, r11, r21"); test_display(&[0x7D, 0x0B, 0xD1, 0xD6], "mullw r8, r11, r26"); test_display(&[0x7D, 0x0B, 0xD9, 0xD6], "mullw r8, r11, r27"); test_display(&[0x7D, 0x0B, 0xE0, 0x96], "mulhw r8, r11, r28"); test_display(&[0x7D, 0x0B, 0xE8, 0x96], "mulhw r8, r11, r29"); test_display(&[0x7D, 0x1C, 0x41, 0xD6], "mullw r8, r28, r8"); test_display(&[0x7D, 0x1C, 0x59, 0xD6], "mullw r8, r28, r11"); test_display(&[0x7D, 0x1D, 0xF9, 0xD6], "mullw r8, r29, r31"); test_display(&[0x7D, 0x1E, 0x99, 0xD6], "mullw r8, r30, r19"); test_display(&[0x7D, 0x1F, 0x41, 0xD6], "mullw r8, r31, r8"); test_display(&[0x7D, 0x1F, 0xB8, 0x96], "mulhw r8, r31, r23"); test_display(&[0x7D, 0x1F, 0xD8, 0x96], "mulhw r8, r31, r27"); test_display(&[0x7D, 0x23, 0x48, 0x16], "mulhwu r9, r3, r9"); test_display(&[0x7D, 0x23, 0x49, 0xD6], "mullw r9, r3, r9"); test_display(&[0x7D, 0x23, 0xE0, 0x96], "mulhw r9, r3, r28"); test_display(&[0x7D, 0x24, 0x49, 0xD6], "mullw r9, r4, r9"); test_display(&[0x7D, 0x24, 0x51, 0xD6], "mullw r9, r4, r10"); test_display(&[0x7D, 0x24, 0x59, 0xD6], "mullw r9, r4, r11"); test_display(&[0x7D, 0x25, 0x49, 0xD6], "mullw r9, r5, r9"); test_display(&[0x7D, 0x25, 0x51, 0xD6], "mullw r9, r5, r10"); test_display(&[0x7D, 0x25, 0xE9, 0xD6], "mullw r9, r5, r29"); test_display(&[0x7D, 0x26, 0x39, 0xD6], "mullw r9, r6, r7"); test_display(&[0x7D, 0x26, 0x40, 0x16], "mulhwu r9, r6, r8"); test_display(&[0x7D, 0x26, 0x48, 0x16], "mulhwu r9, r6, r9"); test_display(&[0x7D, 0x26, 0x49, 0xD6], "mullw r9, r6, r9"); test_display(&[0x7D, 0x26, 0xC9, 0xD6], "mullw r9, r6, r25"); test_display(&[0x7D, 0x26, 0xD9, 0xD6], "mullw r9, r6, r27"); test_display(&[0x7D, 0x26, 0xE1, 0xD6], "mullw r9, r6, r28"); test_display(&[0x7D, 0x26, 0xE9, 0xD6], "mullw r9, r6, r29"); test_display(&[0x7D, 0x27, 0x40, 0x16], "mulhwu r9, r7, r8"); test_display(&[0x7D, 0x27, 0x41, 0xD6], "mullw r9, r7, r8"); test_display(&[0x7D, 0x27, 0x48, 0x16], "mulhwu r9, r7, r9"); test_display(&[0x7D, 0x27, 0x49, 0xD6], "mullw r9, r7, r9"); test_display(&[0x7D, 0x27, 0x59, 0xD6], "mullw r9, r7, r11"); test_display(&[0x7D, 0x27, 0xC0, 0x96], "mulhw r9, r7, r24"); test_display(&[0x7D, 0x27, 0xC9, 0xD6], "mullw r9, r7, r25"); test_display(&[0x7D, 0x27, 0xD1, 0xD6], "mullw r9, r7, r26"); test_display(&[0x7D, 0x27, 0xE0, 0x96], "mulhw r9, r7, r28"); test_display(&[0x7D, 0x27, 0xE1, 0xD6], "mullw r9, r7, r28"); test_display(&[0x7D, 0x28, 0x39, 0xD2], "mulld r9, r8, r7"); test_display(&[0x7D, 0x28, 0x48, 0x96], "mulhw r9, r8, r9"); test_display(&[0x7D, 0x28, 0x49, 0xD6], "mullw r9, r8, r9"); test_display(&[0x7D, 0x28, 0x59, 0xD6], "mullw r9, r8, r11"); test_display(&[0x7D, 0x29, 0x19, 0xD6], "mullw r9, r9, r3"); test_display(&[0x7D, 0x29, 0x21, 0xD6], "mullw r9, r9, r4"); test_display(&[0x7D, 0x29, 0x28, 0x96], "mulhw r9, r9, r5"); test_display(&[0x7D, 0x29, 0x29, 0xD6], "mullw r9, r9, r5"); test_display(&[0x7D, 0x29, 0x31, 0xD6], "mullw r9, r9, r6"); test_display(&[0x7D, 0x29, 0x38, 0x16], "mulhwu r9, r9, r7"); test_display(&[0x7D, 0x29, 0x39, 0xD6], "mullw r9, r9, r7"); test_display(&[0x7D, 0x29, 0x40, 0x16], "mulhwu r9, r9, r8"); test_display(&[0x7D, 0x29, 0x41, 0xD2], "mulld r9, r9, r8"); test_display(&[0x7D, 0x29, 0x41, 0xD6], "mullw r9, r9, r8"); test_display(&[0x7D, 0x29, 0x41, 0xD7], "mullw. r9, r9, r8"); test_display(&[0x7D, 0x29, 0x51, 0xD6], "mullw r9, r9, r10"); test_display(&[0x7D, 0x29, 0x58, 0x96], "mulhw r9, r9, r11"); test_display(&[0x7D, 0x29, 0x59, 0xD6], "mullw r9, r9, r11"); test_display(&[0x7D, 0x29, 0x71, 0xD6], "mullw r9, r9, r14"); test_display(&[0x7D, 0x29, 0x81, 0xD6], "mullw r9, r9, r16"); test_display(&[0x7D, 0x29, 0x99, 0xD6], "mullw r9, r9, r19"); test_display(&[0x7D, 0x29, 0xA9, 0xD6], "mullw r9, r9, r21"); test_display(&[0x7D, 0x29, 0xB1, 0xD6], "mullw r9, r9, r22"); test_display(&[0x7D, 0x29, 0xB9, 0xD6], "mullw r9, r9, r23"); test_display(&[0x7D, 0x29, 0xC9, 0xD6], "mullw r9, r9, r25"); test_display(&[0x7D, 0x29, 0xD1, 0xD6], "mullw r9, r9, r26"); test_display(&[0x7D, 0x29, 0xD9, 0xD6], "mullw r9, r9, r27"); test_display(&[0x7D, 0x29, 0xE1, 0xD6], "mullw r9, r9, r28"); test_display(&[0x7D, 0x29, 0xE9, 0xD6], "mullw r9, r9, r29"); test_display(&[0x7D, 0x29, 0xF1, 0xD6], "mullw r9, r9, r30"); test_display(&[0x7D, 0x29, 0xF8, 0x96], "mulhw r9, r9, r31"); test_display(&[0x7D, 0x29, 0xF9, 0xD6], "mullw r9, r9, r31"); test_display(&[0x7D, 0x2A, 0x30, 0x96], "mulhw r9, r10, r6"); test_display(&[0x7D, 0x2A, 0x38, 0x96], "mulhw r9, r10, r7"); test_display(&[0x7D, 0x2A, 0x39, 0xD6], "mullw r9, r10, r7"); test_display(&[0x7D, 0x2A, 0x40, 0x96], "mulhw r9, r10, r8"); test_display(&[0x7D, 0x2A, 0x48, 0x96], "mulhw r9, r10, r9"); test_display(&[0x7D, 0x2A, 0x49, 0xD6], "mullw r9, r10, r9"); test_display(&[0x7D, 0x2A, 0x58, 0x96], "mulhw r9, r10, r11"); test_display(&[0x7D, 0x2A, 0x59, 0xD6], "mullw r9, r10, r11"); test_display(&[0x7D, 0x2A, 0xD0, 0x96], "mulhw r9, r10, r26"); test_display(&[0x7D, 0x2A, 0xE0, 0x96], "mulhw r9, r10, r28"); test_display(&[0x7D, 0x2A, 0xE9, 0xD6], "mullw r9, r10, r29"); test_display(&[0x7D, 0x2B, 0x30, 0x96], "mulhw r9, r11, r6"); test_display(&[0x7D, 0x2B, 0x40, 0x96], "mulhw r9, r11, r8"); test_display(&[0x7D, 0x2B, 0x48, 0x96], "mulhw r9, r11, r9"); test_display(&[0x7D, 0x2B, 0x51, 0xD6], "mullw r9, r11, r10"); test_display(&[0x7D, 0x2B, 0x80, 0x96], "mulhw r9, r11, r16"); test_display(&[0x7D, 0x2B, 0xA8, 0x96], "mulhw r9, r11, r21"); test_display(&[0x7D, 0x2B, 0xC0, 0x96], "mulhw r9, r11, r24"); test_display(&[0x7D, 0x2B, 0xD0, 0x96], "mulhw r9, r11, r26"); test_display(&[0x7D, 0x2B, 0xE0, 0x96], "mulhw r9, r11, r28"); test_display(&[0x7D, 0x2B, 0xE1, 0xD6], "mullw r9, r11, r28"); test_display(&[0x7D, 0x2B, 0xE8, 0x96], "mulhw r9, r11, r29"); test_display(&[0x7D, 0x2B, 0xF0, 0x96], "mulhw r9, r11, r30"); test_display(&[0x7D, 0x2B, 0xF9, 0xD6], "mullw r9, r11, r31"); test_display(&[0x7D, 0x38, 0x31, 0xD6], "mullw r9, r24, r6"); test_display(&[0x7D, 0x39, 0x39, 0xD6], "mullw r9, r25, r7"); test_display(&[0x7D, 0x3B, 0x51, 0xD6], "mullw r9, r27, r10"); test_display(&[0x7D, 0x3B, 0xE1, 0xD6], "mullw r9, r27, r28"); test_display(&[0x7D, 0x3B, 0xE9, 0xD6], "mullw r9, r27, r29"); test_display(&[0x7D, 0x3C, 0x49, 0xD6], "mullw r9, r28, r9"); test_display(&[0x7D, 0x3C, 0x51, 0xD6], "mullw r9, r28, r10"); test_display(&[0x7D, 0x3C, 0xF1, 0xD6], "mullw r9, r28, r30"); test_display(&[0x7D, 0x3D, 0x59, 0xD6], "mullw r9, r29, r11"); test_display(&[0x7D, 0x3D, 0xE1, 0xD6], "mullw r9, r29, r28"); test_display(&[0x7D, 0x3E, 0x49, 0xD6], "mullw r9, r30, r9"); test_display(&[0x7D, 0x3F, 0x49, 0xD6], "mullw r9, r31, r9"); test_display(&[0x7D, 0x3F, 0x59, 0xD6], "mullw r9, r31, r11"); test_display(&[0x7D, 0x3F, 0xB1, 0xD6], "mullw r9, r31, r22"); test_display(&[0x7D, 0x3F, 0xF0, 0x96], "mulhw r9, r31, r30"); test_display(&[0x7D, 0x43, 0x38, 0x96], "mulhw r10, r3, r7"); test_display(&[0x7D, 0x43, 0x39, 0xD6], "mullw r10, r3, r7"); test_display(&[0x7D, 0x43, 0x51, 0xD6], "mullw r10, r3, r10"); test_display(&[0x7D, 0x43, 0xA1, 0xD6], "mullw r10, r3, r20"); test_display(&[0x7D, 0x43, 0xF1, 0xD6], "mullw r10, r3, r30"); test_display(&[0x7D, 0x44, 0x29, 0xD6], "mullw r10, r4, r5"); test_display(&[0x7D, 0x44, 0x38, 0x96], "mulhw r10, r4, r7"); test_display(&[0x7D, 0x44, 0x51, 0xD6], "mullw r10, r4, r10"); test_display(&[0x7D, 0x44, 0xC9, 0xD6], "mullw r10, r4, r25"); test_display(&[0x7D, 0x45, 0x41, 0xD6], "mullw r10, r5, r8"); test_display(&[0x7D, 0x45, 0x51, 0xD6], "mullw r10, r5, r10"); test_display(&[0x7D, 0x45, 0x59, 0xD6], "mullw r10, r5, r11"); test_display(&[0x7D, 0x45, 0xA1, 0xD6], "mullw r10, r5, r20"); test_display(&[0x7D, 0x46, 0x39, 0xD7], "mullw. r10, r6, r7"); test_display(&[0x7D, 0x46, 0x49, 0xD6], "mullw r10, r6, r9"); test_display(&[0x7D, 0x46, 0x51, 0xD6], "mullw r10, r6, r10"); test_display(&[0x7D, 0x46, 0x59, 0xD6], "mullw r10, r6, r11"); test_display(&[0x7D, 0x46, 0xD9, 0xD6], "mullw r10, r6, r27"); test_display(&[0x7D, 0x46, 0xF9, 0xD6], "mullw r10, r6, r31"); test_display(&[0x7D, 0x47, 0x29, 0xD6], "mullw r10, r7, r5"); test_display(&[0x7D, 0x47, 0x41, 0xD6], "mullw r10, r7, r8"); test_display(&[0x7D, 0x47, 0x49, 0xD6], "mullw r10, r7, r9"); test_display(&[0x7D, 0x47, 0x51, 0xD6], "mullw r10, r7, r10"); test_display(&[0x7D, 0x47, 0x59, 0xD6], "mullw r10, r7, r11"); test_display(&[0x7D, 0x47, 0x71, 0xD6], "mullw r10, r7, r14"); test_display(&[0x7D, 0x47, 0xD9, 0xD6], "mullw r10, r7, r27"); test_display(&[0x7D, 0x47, 0xE1, 0xD6], "mullw r10, r7, r28"); test_display(&[0x7D, 0x48, 0x29, 0xD6], "mullw r10, r8, r5"); test_display(&[0x7D, 0x48, 0x31, 0xD6], "mullw r10, r8, r6"); test_display(&[0x7D, 0x48, 0x48, 0x16], "mulhwu r10, r8, r9"); test_display(&[0x7D, 0x48, 0x50, 0x16], "mulhwu r10, r8, r10"); test_display(&[0x7D, 0x48, 0x51, 0xD6], "mullw r10, r8, r10"); test_display(&[0x7D, 0x48, 0x59, 0xD6], "mullw r10, r8, r11"); test_display(&[0x7D, 0x48, 0x91, 0xD6], "mullw r10, r8, r18"); test_display(&[0x7D, 0x48, 0xB9, 0xD6], "mullw r10, r8, r23"); test_display(&[0x7D, 0x48, 0xD1, 0xD6], "mullw r10, r8, r26"); test_display(&[0x7D, 0x48, 0xE9, 0xD6], "mullw r10, r8, r29"); test_display(&[0x7D, 0x49, 0x21, 0xD6], "mullw r10, r9, r4"); test_display(&[0x7D, 0x49, 0x39, 0xD6], "mullw r10, r9, r7"); test_display(&[0x7D, 0x49, 0x41, 0xD6], "mullw r10, r9, r8"); test_display(&[0x7D, 0x49, 0x50, 0x96], "mulhw r10, r9, r10"); test_display(&[0x7D, 0x49, 0x51, 0xD6], "mullw r10, r9, r10"); test_display(&[0x7D, 0x49, 0x59, 0xD6], "mullw r10, r9, r11"); test_display(&[0x7D, 0x49, 0xB1, 0xD6], "mullw r10, r9, r22"); test_display(&[0x7D, 0x49, 0xE1, 0xD2], "mulld r10, r9, r28"); test_display(&[0x7D, 0x49, 0xF1, 0xD6], "mullw r10, r9, r30"); test_display(&[0x7D, 0x4A, 0x19, 0xD6], "mullw r10, r10, r3"); test_display(&[0x7D, 0x4A, 0x21, 0xD6], "mullw r10, r10, r4"); test_display(&[0x7D, 0x4A, 0x28, 0x96], "mulhw r10, r10, r5"); test_display(&[0x7D, 0x4A, 0x29, 0xD6], "mullw r10, r10, r5"); test_display(&[0x7D, 0x4A, 0x30, 0x96], "mulhw r10, r10, r6"); test_display(&[0x7D, 0x4A, 0x31, 0xD6], "mullw r10, r10, r6"); test_display(&[0x7D, 0x4A, 0x38, 0x16], "mulhwu r10, r10, r7"); test_display(&[0x7D, 0x4A, 0x39, 0xD6], "mullw r10, r10, r7"); test_display(&[0x7D, 0x4A, 0x40, 0x16], "mulhwu r10, r10, r8"); test_display(&[0x7D, 0x4A, 0x40, 0x96], "mulhw r10, r10, r8"); test_display(&[0x7D, 0x4A, 0x41, 0xD2], "mulld r10, r10, r8"); test_display(&[0x7D, 0x4A, 0x41, 0xD6], "mullw r10, r10, r8"); test_display(&[0x7D, 0x4A, 0x48, 0x16], "mulhwu r10, r10, r9"); test_display(&[0x7D, 0x4A, 0x49, 0xD6], "mullw r10, r10, r9"); test_display(&[0x7D, 0x4A, 0x49, 0xD7], "mullw. r10, r10, r9"); test_display(&[0x7D, 0x4A, 0x51, 0xD6], "mullw r10, r10, r10"); test_display(&[0x7D, 0x4A, 0x58, 0x96], "mulhw r10, r10, r11"); test_display(&[0x7D, 0x4A, 0x59, 0xD2], "mulld r10, r10, r11"); test_display(&[0x7D, 0x4A, 0x59, 0xD6], "mullw r10, r10, r11"); test_display(&[0x7D, 0x4A, 0x70, 0x96], "mulhw r10, r10, r14"); test_display(&[0x7D, 0x4A, 0x79, 0xD6], "mullw r10, r10, r15"); test_display(&[0x7D, 0x4A, 0x81, 0xD6], "mullw r10, r10, r16"); test_display(&[0x7D, 0x4A, 0x89, 0xD6], "mullw r10, r10, r17"); test_display(&[0x7D, 0x4A, 0x91, 0xD6], "mullw r10, r10, r18"); test_display(&[0x7D, 0x4A, 0x99, 0xD6], "mullw r10, r10, r19"); test_display(&[0x7D, 0x4A, 0xB0, 0x96], "mulhw r10, r10, r22"); test_display(&[0x7D, 0x4A, 0xB1, 0xD6], "mullw r10, r10, r22"); test_display(&[0x7D, 0x4A, 0xB8, 0x96], "mulhw r10, r10, r23"); test_display(&[0x7D, 0x4A, 0xB9, 0xD6], "mullw r10, r10, r23"); test_display(&[0x7D, 0x4A, 0xC1, 0xD6], "mullw r10, r10, r24"); test_display(&[0x7D, 0x4A, 0xC9, 0xD6], "mullw r10, r10, r25"); test_display(&[0x7D, 0x4A, 0xD0, 0x96], "mulhw r10, r10, r26"); test_display(&[0x7D, 0x4A, 0xD1, 0xD6], "mullw r10, r10, r26"); test_display(&[0x7D, 0x4A, 0xD9, 0xD6], "mullw r10, r10, r27"); test_display(&[0x7D, 0x4A, 0xE1, 0xD6], "mullw r10, r10, r28"); test_display(&[0x7D, 0x4A, 0xE8, 0x96], "mulhw r10, r10, r29"); test_display(&[0x7D, 0x4A, 0xE9, 0xD6], "mullw r10, r10, r29"); test_display(&[0x7D, 0x4A, 0xF1, 0xD6], "mullw r10, r10, r30"); test_display(&[0x7D, 0x4A, 0xF8, 0x96], "mulhw r10, r10, r31"); test_display(&[0x7D, 0x4A, 0xF9, 0xD6], "mullw r10, r10, r31"); test_display(&[0x7D, 0x4B, 0x21, 0xD6], "mullw r10, r11, r4"); test_display(&[0x7D, 0x4B, 0x28, 0x16], "mulhwu r10, r11, r5"); test_display(&[0x7D, 0x4B, 0x30, 0x12], "mulhdu r10, r11, r6"); test_display(&[0x7D, 0x4B, 0x30, 0x16], "mulhwu r10, r11, r6"); test_display(&[0x7D, 0x4B, 0x30, 0x96], "mulhw r10, r11, r6"); test_display(&[0x7D, 0x4B, 0x38, 0x16], "mulhwu r10, r11, r7"); test_display(&[0x7D, 0x4B, 0x38, 0x96], "mulhw r10, r11, r7"); test_display(&[0x7D, 0x4B, 0x39, 0xD6], "mullw r10, r11, r7"); test_display(&[0x7D, 0x4B, 0x40, 0x16], "mulhwu r10, r11, r8"); test_display(&[0x7D, 0x4B, 0x41, 0xD6], "mullw r10, r11, r8"); test_display(&[0x7D, 0x4B, 0x48, 0x16], "mulhwu r10, r11, r9"); test_display(&[0x7D, 0x4B, 0x48, 0x96], "mulhw r10, r11, r9"); test_display(&[0x7D, 0x4B, 0x49, 0xD6], "mullw r10, r11, r9"); test_display(&[0x7D, 0x4B, 0x50, 0x16], "mulhwu r10, r11, r10"); test_display(&[0x7D, 0x4B, 0x50, 0x96], "mulhw r10, r11, r10"); test_display(&[0x7D, 0x4B, 0x51, 0xD6], "mullw r10, r11, r10"); test_display(&[0x7D, 0x4B, 0x59, 0xD6], "mullw r10, r11, r11"); test_display(&[0x7D, 0x4B, 0x78, 0x96], "mulhw r10, r11, r15"); test_display(&[0x7D, 0x4B, 0x80, 0x96], "mulhw r10, r11, r16"); test_display(&[0x7D, 0x4B, 0x81, 0xD6], "mullw r10, r11, r16"); test_display(&[0x7D, 0x4B, 0x88, 0x96], "mulhw r10, r11, r17"); test_display(&[0x7D, 0x4B, 0x89, 0xD6], "mullw r10, r11, r17"); test_display(&[0x7D, 0x4B, 0x90, 0x16], "mulhwu r10, r11, r18"); test_display(&[0x7D, 0x4B, 0xA1, 0xD6], "mullw r10, r11, r20"); test_display(&[0x7D, 0x4B, 0xA8, 0x96], "mulhw r10, r11, r21"); test_display(&[0x7D, 0x4B, 0xC9, 0xD6], "mullw r10, r11, r25"); test_display(&[0x7D, 0x4B, 0xD0, 0x96], "mulhw r10, r11, r26"); test_display(&[0x7D, 0x4B, 0xD1, 0xD6], "mullw r10, r11, r26"); test_display(&[0x7D, 0x4B, 0xD8, 0x16], "mulhwu r10, r11, r27"); test_display(&[0x7D, 0x4B, 0xD8, 0x96], "mulhw r10, r11, r27"); test_display(&[0x7D, 0x4B, 0xD9, 0xD6], "mullw r10, r11, r27"); test_display(&[0x7D, 0x4B, 0xE0, 0x96], "mulhw r10, r11, r28"); test_display(&[0x7D, 0x4B, 0xE1, 0xD6], "mullw r10, r11, r28"); test_display(&[0x7D, 0x4B, 0xE8, 0x96], "mulhw r10, r11, r29"); test_display(&[0x7D, 0x4B, 0xE9, 0xD6], "mullw r10, r11, r29"); test_display(&[0x7D, 0x4B, 0xF1, 0xD6], "mullw r10, r11, r30"); test_display(&[0x7D, 0x4B, 0xF8, 0x96], "mulhw r10, r11, r31"); test_display(&[0x7D, 0x4B, 0xF9, 0xD6], "mullw r10, r11, r31"); test_display(&[0x7D, 0x4F, 0x99, 0xD6], "mullw r10, r15, r19"); test_display(&[0x7D, 0x50, 0xC9, 0xD6], "mullw r10, r16, r25"); test_display(&[0x7D, 0x53, 0x51, 0xD6], "mullw r10, r19, r10"); test_display(&[0x7D, 0x53, 0xB1, 0xD6], "mullw r10, r19, r22"); test_display(&[0x7D, 0x54, 0x51, 0xD6], "mullw r10, r20, r10"); test_display(&[0x7D, 0x58, 0x38, 0x96], "mulhw r10, r24, r7"); test_display(&[0x7D, 0x59, 0x38, 0x96], "mulhw r10, r25, r7"); test_display(&[0x7D, 0x5A, 0x38, 0x96], "mulhw r10, r26, r7"); test_display(&[0x7D, 0x5A, 0xE1, 0xD6], "mullw r10, r26, r28"); test_display(&[0x7D, 0x5B, 0x38, 0x96], "mulhw r10, r27, r7"); test_display(&[0x7D, 0x5B, 0x39, 0xD6], "mullw r10, r27, r7"); test_display(&[0x7D, 0x5B, 0x49, 0xD6], "mullw r10, r27, r9"); test_display(&[0x7D, 0x5C, 0x38, 0x96], "mulhw r10, r28, r7"); test_display(&[0x7D, 0x5C, 0x51, 0xD6], "mullw r10, r28, r10"); test_display(&[0x7D, 0x5C, 0xB8, 0x16], "mulhwu r10, r28, r23"); test_display(&[0x7D, 0x5D, 0x31, 0xD6], "mullw r10, r29, r6"); test_display(&[0x7D, 0x5D, 0x38, 0x96], "mulhw r10, r29, r7"); test_display(&[0x7D, 0x5D, 0xC8, 0x96], "mulhw r10, r29, r25"); test_display(&[0x7D, 0x5E, 0x31, 0xD6], "mullw r10, r30, r6"); test_display(&[0x7D, 0x5E, 0x49, 0xD6], "mullw r10, r30, r9"); test_display(&[0x7D, 0x5E, 0x50, 0x16], "mulhwu r10, r30, r10"); test_display(&[0x7D, 0x5E, 0x51, 0xD6], "mullw r10, r30, r10"); test_display(&[0x7D, 0x5E, 0x59, 0xD6], "mullw r10, r30, r11"); test_display(&[0x7D, 0x5E, 0x99, 0xD6], "mullw r10, r30, r19"); test_display(&[0x7D, 0x5E, 0xD9, 0xD6], "mullw r10, r30, r27"); test_display(&[0x7D, 0x5F, 0x31, 0xD6], "mullw r10, r31, r6"); test_display(&[0x7D, 0x5F, 0x38, 0x96], "mulhw r10, r31, r7"); test_display(&[0x7D, 0x5F, 0x48, 0x96], "mulhw r10, r31, r9"); test_display(&[0x7D, 0x5F, 0x59, 0xD2], "mulld r10, r31, r11"); test_display(&[0x7D, 0x5F, 0xE9, 0xD6], "mullw r10, r31, r29"); test_display(&[0x7D, 0x63, 0x31, 0xD6], "mullw r11, r3, r6"); test_display(&[0x7D, 0x63, 0x49, 0xD6], "mullw r11, r3, r9"); test_display(&[0x7D, 0x63, 0x58, 0x16], "mulhwu r11, r3, r11"); test_display(&[0x7D, 0x63, 0x58, 0x96], "mulhw r11, r3, r11"); test_display(&[0x7D, 0x63, 0x59, 0xD6], "mullw r11, r3, r11"); test_display(&[0x7D, 0x63, 0xE0, 0x16], "mulhwu r11, r3, r28"); test_display(&[0x7D, 0x63, 0xE9, 0xD6], "mullw r11, r3, r29"); test_display(&[0x7D, 0x63, 0xF0, 0x96], "mulhw r11, r3, r30"); test_display(&[0x7D, 0x64, 0x31, 0xD6], "mullw r11, r4, r6"); test_display(&[0x7D, 0x64, 0x39, 0xD6], "mullw r11, r4, r7"); test_display(&[0x7D, 0x64, 0x41, 0xD6], "mullw r11, r4, r8"); test_display(&[0x7D, 0x64, 0x49, 0xD6], "mullw r11, r4, r9"); test_display(&[0x7D, 0x64, 0x50, 0x96], "mulhw r11, r4, r10"); test_display(&[0x7D, 0x64, 0x51, 0xD6], "mullw r11, r4, r10"); test_display(&[0x7D, 0x64, 0x59, 0xD6], "mullw r11, r4, r11"); test_display(&[0x7D, 0x64, 0xE9, 0xD6], "mullw r11, r4, r29"); test_display(&[0x7D, 0x65, 0x41, 0xD6], "mullw r11, r5, r8"); test_display(&[0x7D, 0x65, 0x49, 0xD6], "mullw r11, r5, r9"); test_display(&[0x7D, 0x65, 0x58, 0x96], "mulhw r11, r5, r11"); test_display(&[0x7D, 0x65, 0x59, 0xD6], "mullw r11, r5, r11"); test_display(&[0x7D, 0x65, 0xF1, 0xD6], "mullw r11, r5, r30"); test_display(&[0x7D, 0x66, 0x21, 0xD6], "mullw r11, r6, r4"); test_display(&[0x7D, 0x66, 0x39, 0xD6], "mullw r11, r6, r7"); test_display(&[0x7D, 0x66, 0x41, 0xD6], "mullw r11, r6, r8"); test_display(&[0x7D, 0x66, 0x51, 0xD6], "mullw r11, r6, r10"); test_display(&[0x7D, 0x66, 0x59, 0xD2], "mulld r11, r6, r11"); test_display(&[0x7D, 0x66, 0x59, 0xD6], "mullw r11, r6, r11"); test_display(&[0x7D, 0x66, 0xE1, 0xD6], "mullw r11, r6, r28"); test_display(&[0x7D, 0x67, 0x19, 0xD6], "mullw r11, r7, r3"); test_display(&[0x7D, 0x67, 0x29, 0xD6], "mullw r11, r7, r5"); test_display(&[0x7D, 0x67, 0x41, 0xD6], "mullw r11, r7, r8"); test_display(&[0x7D, 0x67, 0x49, 0xD6], "mullw r11, r7, r9"); test_display(&[0x7D, 0x67, 0x51, 0xD6], "mullw r11, r7, r10"); test_display(&[0x7D, 0x67, 0x58, 0x96], "mulhw r11, r7, r11"); test_display(&[0x7D, 0x67, 0x59, 0xD6], "mullw r11, r7, r11"); test_display(&[0x7D, 0x67, 0xC9, 0xD6], "mullw r11, r7, r25"); test_display(&[0x7D, 0x68, 0x29, 0xD6], "mullw r11, r8, r5"); test_display(&[0x7D, 0x68, 0x49, 0xD6], "mullw r11, r8, r9"); test_display(&[0x7D, 0x68, 0x50, 0x16], "mulhwu r11, r8, r10"); test_display(&[0x7D, 0x68, 0x51, 0xD6], "mullw r11, r8, r10"); test_display(&[0x7D, 0x68, 0x58, 0x96], "mulhw r11, r8, r11"); test_display(&[0x7D, 0x68, 0x59, 0xD6], "mullw r11, r8, r11"); test_display(&[0x7D, 0x68, 0xD1, 0xD6], "mullw r11, r8, r26"); test_display(&[0x7D, 0x68, 0xE9, 0xD6], "mullw r11, r8, r29"); test_display(&[0x7D, 0x68, 0xF1, 0xD6], "mullw r11, r8, r30"); test_display(&[0x7D, 0x68, 0xF9, 0xD6], "mullw r11, r8, r31"); test_display(&[0x7D, 0x69, 0x21, 0xD6], "mullw r11, r9, r4"); test_display(&[0x7D, 0x69, 0x29, 0xD6], "mullw r11, r9, r5"); test_display(&[0x7D, 0x69, 0x31, 0xD6], "mullw r11, r9, r6"); test_display(&[0x7D, 0x69, 0x41, 0xD6], "mullw r11, r9, r8"); test_display(&[0x7D, 0x69, 0x58, 0x96], "mulhw r11, r9, r11"); test_display(&[0x7D, 0x69, 0x59, 0xD2], "mulld r11, r9, r11"); test_display(&[0x7D, 0x69, 0x59, 0xD6], "mullw r11, r9, r11"); test_display(&[0x7D, 0x69, 0x71, 0xD6], "mullw r11, r9, r14"); test_display(&[0x7D, 0x69, 0xA1, 0xD6], "mullw r11, r9, r20"); test_display(&[0x7D, 0x69, 0xB9, 0xD6], "mullw r11, r9, r23"); test_display(&[0x7D, 0x69, 0xD9, 0xD6], "mullw r11, r9, r27"); test_display(&[0x7D, 0x69, 0xE0, 0x96], "mulhw r11, r9, r28"); test_display(&[0x7D, 0x69, 0xE1, 0xD6], "mullw r11, r9, r28"); test_display(&[0x7D, 0x69, 0xE9, 0xD6], "mullw r11, r9, r29"); test_display(&[0x7D, 0x69, 0xF0, 0x96], "mulhw r11, r9, r30"); test_display(&[0x7D, 0x69, 0xF1, 0xD6], "mullw r11, r9, r30"); test_display(&[0x7D, 0x69, 0xF9, 0xD6], "mullw r11, r9, r31"); test_display(&[0x7D, 0x6A, 0x21, 0xD6], "mullw r11, r10, r4"); test_display(&[0x7D, 0x6A, 0x38, 0x16], "mulhwu r11, r10, r7"); test_display(&[0x7D, 0x6A, 0x38, 0x96], "mulhw r11, r10, r7"); test_display(&[0x7D, 0x6A, 0x39, 0xD2], "mulld r11, r10, r7"); test_display(&[0x7D, 0x6A, 0x39, 0xD6], "mullw r11, r10, r7"); test_display(&[0x7D, 0x6A, 0x40, 0x96], "mulhw r11, r10, r8"); test_display(&[0x7D, 0x6A, 0x48, 0x16], "mulhwu r11, r10, r9"); test_display(&[0x7D, 0x6A, 0x48, 0x96], "mulhw r11, r10, r9"); test_display(&[0x7D, 0x6A, 0x49, 0xD6], "mullw r11, r10, r9"); test_display(&[0x7D, 0x6A, 0x58, 0x16], "mulhwu r11, r10, r11"); test_display(&[0x7D, 0x6A, 0x58, 0x96], "mulhw r11, r10, r11"); test_display(&[0x7D, 0x6A, 0x59, 0xD6], "mullw r11, r10, r11"); test_display(&[0x7D, 0x6A, 0xA1, 0xD6], "mullw r11, r10, r20"); test_display(&[0x7D, 0x6A, 0xC1, 0xD6], "mullw r11, r10, r24"); test_display(&[0x7D, 0x6A, 0xC8, 0x16], "mulhwu r11, r10, r25"); test_display(&[0x7D, 0x6A, 0xC9, 0xD6], "mullw r11, r10, r25"); test_display(&[0x7D, 0x6A, 0xD8, 0x16], "mulhwu r11, r10, r27"); test_display(&[0x7D, 0x6A, 0xD8, 0x96], "mulhw r11, r10, r27"); test_display(&[0x7D, 0x6A, 0xE8, 0x96], "mulhw r11, r10, r29"); test_display(&[0x7D, 0x6A, 0xF0, 0x96], "mulhw r11, r10, r30"); test_display(&[0x7D, 0x6A, 0xF1, 0xD6], "mullw r11, r10, r30"); test_display(&[0x7D, 0x6A, 0xF8, 0x96], "mulhw r11, r10, r31"); test_display(&[0x7D, 0x6A, 0xF9, 0xD6], "mullw r11, r10, r31"); test_display(&[0x7D, 0x6B, 0x19, 0xD6], "mullw r11, r11, r3"); test_display(&[0x7D, 0x6B, 0x21, 0xD6], "mullw r11, r11, r4"); test_display(&[0x7D, 0x6B, 0x28, 0x96], "mulhw r11, r11, r5"); test_display(&[0x7D, 0x6B, 0x29, 0xD6], "mullw r11, r11, r5"); test_display(&[0x7D, 0x6B, 0x30, 0x96], "mulhw r11, r11, r6"); test_display(&[0x7D, 0x6B, 0x31, 0xD6], "mullw r11, r11, r6"); test_display(&[0x7D, 0x6B, 0x38, 0x96], "mulhw r11, r11, r7"); test_display(&[0x7D, 0x6B, 0x39, 0xD2], "mulld r11, r11, r7"); test_display(&[0x7D, 0x6B, 0x39, 0xD6], "mullw r11, r11, r7"); test_display(&[0x7D, 0x6B, 0x40, 0x16], "mulhwu r11, r11, r8"); test_display(&[0x7D, 0x6B, 0x40, 0x96], "mulhw r11, r11, r8"); test_display(&[0x7D, 0x6B, 0x41, 0xD2], "mulld r11, r11, r8"); test_display(&[0x7D, 0x6B, 0x41, 0xD6], "mullw r11, r11, r8"); test_display(&[0x7D, 0x6B, 0x48, 0x16], "mulhwu r11, r11, r9"); test_display(&[0x7D, 0x6B, 0x48, 0x96], "mulhw r11, r11, r9"); test_display(&[0x7D, 0x6B, 0x49, 0xD2], "mulld r11, r11, r9"); test_display(&[0x7D, 0x6B, 0x49, 0xD6], "mullw r11, r11, r9"); test_display(&[0x7D, 0x6B, 0x50, 0x16], "mulhwu r11, r11, r10"); test_display(&[0x7D, 0x6B, 0x50, 0x96], "mulhw r11, r11, r10"); test_display(&[0x7D, 0x6B, 0x51, 0xD2], "mulld r11, r11, r10"); test_display(&[0x7D, 0x6B, 0x51, 0xD6], "mullw r11, r11, r10"); test_display(&[0x7D, 0x6B, 0x51, 0xD7], "mullw. r11, r11, r10"); test_display(&[0x7D, 0x6B, 0x59, 0xD6], "mullw r11, r11, r11"); test_display(&[0x7D, 0x6B, 0x70, 0x96], "mulhw r11, r11, r14"); test_display(&[0x7D, 0x6B, 0x79, 0xD6], "mullw r11, r11, r15"); test_display(&[0x7D, 0x6B, 0x81, 0xD6], "mullw r11, r11, r16"); test_display(&[0x7D, 0x6B, 0x89, 0xD6], "mullw r11, r11, r17"); test_display(&[0x7D, 0x6B, 0x91, 0xD6], "mullw r11, r11, r18"); test_display(&[0x7D, 0x6B, 0x99, 0xD6], "mullw r11, r11, r19"); test_display(&[0x7D, 0x6B, 0xA1, 0xD6], "mullw r11, r11, r20"); test_display(&[0x7D, 0x6B, 0xB0, 0x16], "mulhwu r11, r11, r22"); test_display(&[0x7D, 0x6B, 0xB1, 0xD6], "mullw r11, r11, r22"); test_display(&[0x7D, 0x6B, 0xB9, 0xD6], "mullw r11, r11, r23"); test_display(&[0x7D, 0x6B, 0xC0, 0x16], "mulhwu r11, r11, r24"); test_display(&[0x7D, 0x6B, 0xC1, 0xD6], "mullw r11, r11, r24"); test_display(&[0x7D, 0x6B, 0xC8, 0x96], "mulhw r11, r11, r25"); test_display(&[0x7D, 0x6B, 0xC9, 0xD6], "mullw r11, r11, r25"); test_display(&[0x7D, 0x6B, 0xD0, 0x96], "mulhw r11, r11, r26"); test_display(&[0x7D, 0x6B, 0xD1, 0xD6], "mullw r11, r11, r26"); test_display(&[0x7D, 0x6B, 0xD8, 0x16], "mulhwu r11, r11, r27"); test_display(&[0x7D, 0x6B, 0xD9, 0xD6], "mullw r11, r11, r27"); test_display(&[0x7D, 0x6B, 0xE0, 0x96], "mulhw r11, r11, r28"); test_display(&[0x7D, 0x6B, 0xE1, 0xD6], "mullw r11, r11, r28"); test_display(&[0x7D, 0x6B, 0xE8, 0x96], "mulhw r11, r11, r29"); test_display(&[0x7D, 0x6B, 0xE9, 0xD6], "mullw r11, r11, r29"); test_display(&[0x7D, 0x6B, 0xF0, 0x96], "mulhw r11, r11, r30"); test_display(&[0x7D, 0x6B, 0xF1, 0xD6], "mullw r11, r11, r30"); test_display(&[0x7D, 0x6B, 0xF8, 0x96], "mulhw r11, r11, r31"); test_display(&[0x7D, 0x6B, 0xF9, 0xD6], "mullw r11, r11, r31"); test_display(&[0x7D, 0x6E, 0xE9, 0xD6], "mullw r11, r14, r29"); test_display(&[0x7D, 0x72, 0xA9, 0xD6], "mullw r11, r18, r21"); test_display(&[0x7D, 0x73, 0xC9, 0xD6], "mullw r11, r19, r25"); test_display(&[0x7D, 0x73, 0xE9, 0xD6], "mullw r11, r19, r29"); test_display(&[0x7D, 0x75, 0x59, 0xD6], "mullw r11, r21, r11"); test_display(&[0x7D, 0x75, 0xD1, 0xD6], "mullw r11, r21, r26"); test_display(&[0x7D, 0x76, 0x41, 0xD6], "mullw r11, r22, r8"); test_display(&[0x7D, 0x76, 0xD9, 0xD6], "mullw r11, r22, r27"); test_display(&[0x7D, 0x77, 0x58, 0x16], "mulhwu r11, r23, r11"); test_display(&[0x7D, 0x77, 0x58, 0x96], "mulhw r11, r23, r11"); test_display(&[0x7D, 0x77, 0x59, 0xD6], "mullw r11, r23, r11"); test_display(&[0x7D, 0x79, 0x59, 0xD6], "mullw r11, r25, r11"); test_display(&[0x7D, 0x79, 0xD1, 0xD6], "mullw r11, r25, r26"); test_display(&[0x7D, 0x79, 0xE9, 0xD6], "mullw r11, r25, r29"); test_display(&[0x7D, 0x7A, 0xB9, 0xD6], "mullw r11, r26, r23"); test_display(&[0x7D, 0x7B, 0x51, 0xD6], "mullw r11, r27, r10"); test_display(&[0x7D, 0x7B, 0x59, 0xD6], "mullw r11, r27, r11"); test_display(&[0x7D, 0x7B, 0x89, 0xD6], "mullw r11, r27, r17"); test_display(&[0x7D, 0x7B, 0xD1, 0xD6], "mullw r11, r27, r26"); test_display(&[0x7D, 0x7B, 0xE1, 0xD6], "mullw r11, r27, r28"); test_display(&[0x7D, 0x7B, 0xE9, 0xD6], "mullw r11, r27, r29"); test_display(&[0x7D, 0x7C, 0x50, 0x96], "mulhw r11, r28, r10"); test_display(&[0x7D, 0x7C, 0xD9, 0xD7], "mullw. r11, r28, r27"); test_display(&[0x7D, 0x7C, 0xE9, 0xD6], "mullw r11, r28, r29"); test_display(&[0x7D, 0x7C, 0xF9, 0xD6], "mullw r11, r28, r31"); test_display(&[0x7D, 0x7D, 0x29, 0xD6], "mullw r11, r29, r5"); test_display(&[0x7D, 0x7D, 0x58, 0x96], "mulhw r11, r29, r11"); test_display(&[0x7D, 0x7D, 0xC0, 0x16], "mulhwu r11, r29, r24"); test_display(&[0x7D, 0x7D, 0xD0, 0x96], "mulhw r11, r29, r26"); test_display(&[0x7D, 0x7D, 0xD1, 0xD6], "mullw r11, r29, r26"); test_display(&[0x7D, 0x7D, 0xD9, 0xD6], "mullw r11, r29, r27"); test_display(&[0x7D, 0x7D, 0xF0, 0x96], "mulhw r11, r29, r30"); test_display(&[0x7D, 0x7E, 0x40, 0x96], "mulhw r11, r30, r8"); test_display(&[0x7D, 0x7E, 0x41, 0xD6], "mullw r11, r30, r8"); test_display(&[0x7D, 0x7E, 0x59, 0xD6], "mullw r11, r30, r11"); test_display(&[0x7D, 0x7E, 0x81, 0xD6], "mullw r11, r30, r16"); test_display(&[0x7D, 0x7E, 0x99, 0xD6], "mullw r11, r30, r19"); test_display(&[0x7D, 0x7E, 0xD0, 0x96], "mulhw r11, r30, r26"); test_display(&[0x7D, 0x7E, 0xD1, 0xD6], "mullw r11, r30, r26"); test_display(&[0x7D, 0x7E, 0xE0, 0x96], "mulhw r11, r30, r28"); test_display(&[0x7D, 0x7E, 0xE1, 0xD6], "mullw r11, r30, r28"); test_display(&[0x7D, 0x7E, 0xE8, 0x96], "mulhw r11, r30, r29"); test_display(&[0x7D, 0x7E, 0xE9, 0xD6], "mullw r11, r30, r29"); test_display(&[0x7D, 0x7E, 0xE9, 0xD7], "mullw. r11, r30, r29"); test_display(&[0x7D, 0x7E, 0xF9, 0xD6], "mullw r11, r30, r31"); test_display(&[0x7D, 0x7F, 0x29, 0xD6], "mullw r11, r31, r5"); test_display(&[0x7D, 0x7F, 0x51, 0xD6], "mullw r11, r31, r10"); test_display(&[0x7D, 0x7F, 0x59, 0xD6], "mullw r11, r31, r11"); test_display(&[0x7D, 0x7F, 0xC1, 0xD6], "mullw r11, r31, r24"); test_display(&[0x7D, 0x7F, 0xC9, 0xD6], "mullw r11, r31, r25"); test_display(&[0x7D, 0x7F, 0xE1, 0xD6], "mullw r11, r31, r28"); test_display(&[0x7D, 0x7F, 0xE8, 0x96], "mulhw r11, r31, r29"); test_display(&[0x7D, 0x7F, 0xF0, 0x96], "mulhw r11, r31, r30"); test_display(&[0x7D, 0xE9, 0x39, 0xD6], "mullw r15, r9, r7"); test_display(&[0x7E, 0x08, 0x51, 0xD6], "mullw r16, r8, r10"); test_display(&[0x7E, 0x2B, 0x89, 0xD6], "mullw r17, r11, r17"); test_display(&[0x7E, 0x58, 0x58, 0x96], "mulhw r18, r24, r11"); test_display(&[0x7E, 0x6B, 0x49, 0xD6], "mullw r19, r11, r9"); test_display(&[0x7E, 0x99, 0x58, 0x96], "mulhw r20, r25, r11"); test_display(&[0x7E, 0xA9, 0xA1, 0xD6], "mullw r21, r9, r20"); test_display(&[0x7E, 0xB7, 0x58, 0x96], "mulhw r21, r23, r11"); test_display(&[0x7E, 0xB9, 0x58, 0x96], "mulhw r21, r25, r11"); test_display(&[0x7E, 0xCB, 0x51, 0xD6], "mullw r22, r11, r10"); test_display(&[0x7E, 0xDD, 0xD9, 0xD6], "mullw r22, r29, r27"); test_display(&[0x7E, 0xE9, 0x51, 0xD6], "mullw r23, r9, r10"); test_display(&[0x7E, 0xEB, 0xA9, 0xD6], "mullw r23, r11, r21"); test_display(&[0x7E, 0xF5, 0xE9, 0xD6], "mullw r23, r21, r29"); test_display(&[0x7E, 0xF8, 0x58, 0x96], "mulhw r23, r24, r11"); test_display(&[0x7E, 0xFA, 0x58, 0x96], "mulhw r23, r26, r11"); test_display(&[0x7E, 0xFB, 0xF9, 0xD6], "mullw r23, r27, r31"); test_display(&[0x7F, 0x05, 0x49, 0xD6], "mullw r24, r5, r9"); test_display(&[0x7F, 0x06, 0x21, 0xD6], "mullw r24, r6, r4"); test_display(&[0x7F, 0x0A, 0x29, 0xD6], "mullw r24, r10, r5"); test_display(&[0x7F, 0x0A, 0x59, 0xD6], "mullw r24, r10, r11"); test_display(&[0x7F, 0x0B, 0x41, 0xD6], "mullw r24, r11, r8"); test_display(&[0x7F, 0x19, 0x58, 0x96], "mulhw r24, r25, r11"); test_display(&[0x7F, 0x19, 0xB1, 0xD6], "mullw r24, r25, r22"); test_display(&[0x7F, 0x1A, 0x58, 0x96], "mulhw r24, r26, r11"); test_display(&[0x7F, 0x23, 0xC9, 0xD6], "mullw r25, r3, r25"); test_display(&[0x7F, 0x24, 0x39, 0xD6], "mullw r25, r4, r7"); test_display(&[0x7F, 0x26, 0x21, 0xD6], "mullw r25, r6, r4"); test_display(&[0x7F, 0x28, 0x49, 0xD6], "mullw r25, r8, r9"); test_display(&[0x7F, 0x2B, 0x51, 0xD6], "mullw r25, r11, r10"); test_display(&[0x7F, 0x2B, 0xD9, 0xD6], "mullw r25, r11, r27"); test_display(&[0x7F, 0x36, 0xF9, 0xD6], "mullw r25, r22, r31"); test_display(&[0x7F, 0x39, 0x59, 0xD6], "mullw r25, r25, r11"); test_display(&[0x7F, 0x3A, 0x58, 0x96], "mulhw r25, r26, r11"); test_display(&[0x7F, 0x3B, 0x51, 0xD6], "mullw r25, r27, r10"); test_display(&[0x7F, 0x44, 0x39, 0xD6], "mullw r26, r4, r7"); test_display(&[0x7F, 0x45, 0xE1, 0xD6], "mullw r26, r5, r28"); test_display(&[0x7F, 0x4A, 0xE1, 0xD6], "mullw r26, r10, r28"); test_display(&[0x7F, 0x4B, 0x49, 0xD6], "mullw r26, r11, r9"); test_display(&[0x7F, 0x4B, 0xC9, 0xD6], "mullw r26, r11, r25"); test_display(&[0x7F, 0x4B, 0xD1, 0xD6], "mullw r26, r11, r26"); test_display(&[0x7F, 0x57, 0x58, 0x96], "mulhw r26, r23, r11"); test_display(&[0x7F, 0x57, 0x99, 0xD6], "mullw r26, r23, r19"); test_display(&[0x7F, 0x58, 0xD9, 0xD6], "mullw r26, r24, r27"); test_display(&[0x7F, 0x5A, 0x21, 0xD6], "mullw r26, r26, r4"); test_display(&[0x7F, 0x5A, 0xC9, 0xD6], "mullw r26, r26, r25"); test_display(&[0x7F, 0x5D, 0xF1, 0xD6], "mullw r26, r29, r30"); test_display(&[0x7F, 0x5E, 0xC8, 0x16], "mulhwu r26, r30, r25"); test_display(&[0x7F, 0x64, 0x58, 0x96], "mulhw r27, r4, r11"); test_display(&[0x7F, 0x69, 0x39, 0xD6], "mullw r27, r9, r7"); test_display(&[0x7F, 0x69, 0x59, 0xD6], "mullw r27, r9, r11"); test_display(&[0x7F, 0x69, 0xE9, 0xD6], "mullw r27, r9, r29"); test_display(&[0x7F, 0x6A, 0x29, 0xD6], "mullw r27, r10, r5"); test_display(&[0x7F, 0x6A, 0x59, 0xD6], "mullw r27, r10, r11"); test_display(&[0x7F, 0x6B, 0x51, 0xD2], "mulld r27, r11, r10"); test_display(&[0x7F, 0x6B, 0xF1, 0xD6], "mullw r27, r11, r30"); test_display(&[0x7F, 0x77, 0x19, 0xD6], "mullw r27, r23, r3"); test_display(&[0x7F, 0x79, 0xC1, 0xD7], "mullw. r27, r25, r24"); test_display(&[0x7F, 0x7A, 0xF1, 0xD6], "mullw r27, r26, r30"); test_display(&[0x7F, 0x7F, 0x41, 0xD6], "mullw r27, r31, r8"); test_display(&[0x7F, 0x85, 0x58, 0x96], "mulhw r28, r5, r11"); test_display(&[0x7F, 0x85, 0xE1, 0xD6], "mullw r28, r5, r28"); test_display(&[0x7F, 0x89, 0x39, 0xD6], "mullw r28, r9, r7"); test_display(&[0x7F, 0x8A, 0x59, 0xD6], "mullw r28, r10, r11"); test_display(&[0x7F, 0x8A, 0xD1, 0xD6], "mullw r28, r10, r26"); test_display(&[0x7F, 0x8B, 0x71, 0xD6], "mullw r28, r11, r14"); test_display(&[0x7F, 0x8B, 0xA1, 0xD6], "mullw r28, r11, r20"); test_display(&[0x7F, 0x8B, 0xE1, 0xD6], "mullw r28, r11, r28"); test_display(&[0x7F, 0x96, 0x99, 0xD6], "mullw r28, r22, r19"); test_display(&[0x7F, 0x9A, 0x51, 0xD6], "mullw r28, r26, r10"); test_display(&[0x7F, 0x9A, 0xF9, 0xD6], "mullw r28, r26, r31"); test_display(&[0x7F, 0x9C, 0x59, 0xD6], "mullw r28, r28, r11"); test_display(&[0x7F, 0xA4, 0xD9, 0xD6], "mullw r29, r4, r27"); test_display(&[0x7F, 0xA4, 0xF1, 0xD6], "mullw r29, r4, r30"); test_display(&[0x7F, 0xA5, 0x58, 0x96], "mulhw r29, r5, r11"); test_display(&[0x7F, 0xA9, 0x58, 0x96], "mulhw r29, r9, r11"); test_display(&[0x7F, 0xAA, 0x59, 0xD6], "mullw r29, r10, r11"); test_display(&[0x7F, 0xAB, 0x39, 0xD6], "mullw r29, r11, r7"); test_display(&[0x7F, 0xAB, 0x41, 0xD6], "mullw r29, r11, r8"); test_display(&[0x7F, 0xAB, 0x51, 0xD6], "mullw r29, r11, r10"); test_display(&[0x7F, 0xAB, 0x79, 0xD6], "mullw r29, r11, r15"); test_display(&[0x7F, 0xAB, 0xD1, 0xD6], "mullw r29, r11, r26"); test_display(&[0x7F, 0xAB, 0xE9, 0xD6], "mullw r29, r11, r29"); test_display(&[0x7F, 0xB4, 0xE1, 0xD6], "mullw r29, r20, r28"); test_display(&[0x7F, 0xBC, 0xE1, 0xD6], "mullw r29, r28, r28"); test_display(&[0x7F, 0xBD, 0x21, 0xD2], "mulld r29, r29, r4"); test_display(&[0x7F, 0xBD, 0x41, 0xD6], "mullw r29, r29, r8"); test_display(&[0x7F, 0xBD, 0xE1, 0xD6], "mullw r29, r29, r28"); test_display(&[0x7F, 0xC4, 0x29, 0xD6], "mullw r30, r4, r5"); test_display(&[0x7F, 0xC6, 0x58, 0x96], "mulhw r30, r6, r11"); test_display(&[0x7F, 0xC8, 0x58, 0x96], "mulhw r30, r8, r11"); test_display(&[0x7F, 0xC8, 0x59, 0xD6], "mullw r30, r8, r11"); test_display(&[0x7F, 0xC9, 0x51, 0xD6], "mullw r30, r9, r10"); test_display(&[0x7F, 0xCA, 0x49, 0xD6], "mullw r30, r10, r9"); test_display(&[0x7F, 0xCA, 0xF0, 0x16], "mulhwu r30, r10, r30"); test_display(&[0x7F, 0xCB, 0x19, 0xD6], "mullw r30, r11, r3"); test_display(&[0x7F, 0xD3, 0xF1, 0xD6], "mullw r30, r19, r30"); test_display(&[0x7F, 0xDA, 0xB1, 0xD6], "mullw r30, r26, r22"); test_display(&[0x7F, 0xDB, 0xF1, 0xD6], "mullw r30, r27, r30"); test_display(&[0x7F, 0xDC, 0xD9, 0xD6], "mullw r30, r28, r27"); test_display(&[0x7F, 0xDD, 0xE1, 0xD6], "mullw r30, r29, r28"); test_display(&[0x7F, 0xDD, 0xF1, 0xD6], "mullw r30, r29, r30"); test_display(&[0x7F, 0xDE, 0x29, 0xD6], "mullw r30, r30, r5"); test_display(&[0x7F, 0xDE, 0xD8, 0x96], "mulhw r30, r30, r27"); test_display(&[0x7F, 0xDE, 0xE9, 0xD6], "mullw r30, r30, r29"); test_display(&[0x7F, 0xE3, 0x21, 0xD7], "mullw. r31, r3, r4"); test_display(&[0x7F, 0xE5, 0x31, 0xD6], "mullw r31, r5, r6"); test_display(&[0x7F, 0xE7, 0x58, 0x96], "mulhw r31, r7, r11"); test_display(&[0x7F, 0xE8, 0x59, 0xD6], "mullw r31, r8, r11"); test_display(&[0x7F, 0xEB, 0x51, 0xD6], "mullw r31, r11, r10"); test_display(&[0x7F, 0xF2, 0xD1, 0xD6], "mullw r31, r18, r26"); test_display(&[0x7F, 0xF8, 0xD9, 0xD6], "mullw r31, r24, r27"); test_display(&[0x7F, 0xFB, 0xC9, 0xD6], "mullw r31, r27, r25"); test_display(&[0x7F, 0xFE, 0xF1, 0xD6], "mullw r31, r30, r30"); test_display(&[0x7F, 0xFF, 0x41, 0xD6], "mullw r31, r31, r8"); test_display(&[0x7F, 0xFF, 0xF1, 0xD6], "mullw r31, r31, r30"); } #[test] fn ppc64_general() { test_display_under( &InstDecoder::ppc64le(), &[0x3d, 0x60, 0x82, 0x70], "andi. r2, r4, 0x603d"); test_display_under( &InstDecoder::ppc64le(), &[0x41, 0x99, 0x01, 0xc0], "lfs f0, -26303(r1)"); } #[test] fn ppc32_ext() { test_display(&[0x7C, 0x6B, 0x07, 0x34], "extsh r11, r3"); test_display(&[0x7C, 0x6B, 0x07, 0x35], "extsh. r11, r3"); test_display(&[0x7C, 0x6B, 0x07, 0x74], "extsb r11, r3"); test_display(&[0x7C, 0x6B, 0x07, 0xB4], "extsw r11, r3"); test_display(&[0x7F, 0x0A, 0x07, 0x34], "extsh r10, r24"); test_display(&[0x7F, 0x0A, 0x07, 0xB4], "extsw r10, r24"); test_display(&[0x7F, 0x0B, 0x07, 0x34], "extsh r11, r24"); test_display(&[0x7F, 0x0B, 0x07, 0x35], "extsh. r11, r24"); test_display(&[0x7F, 0xAB, 0x07, 0x75], "extsb. r11, r29"); test_display(&[0x7F, 0xAB, 0x07, 0xB4], "extsw r11, r29"); test_display(&[0x7F, 0xBF, 0x07, 0x75], "extsb. r31, r29"); test_display(&[0x7F, 0xCB, 0x07, 0x34], "extsh r11, r30"); test_display(&[0x7F, 0xCB, 0x07, 0x74], "extsb r11, r30"); test_display(&[0x7F, 0xCB, 0x07, 0x75], "extsb. r11, r30"); test_display(&[0x7F, 0xCB, 0x07, 0xB4], "extsw r11, r30"); test_display(&[0x7F, 0xCF, 0x07, 0x34], "extsh r15, r30"); test_display(&[0x7F, 0xDE, 0x07, 0xB4], "extsw r30, r30"); test_display(&[0x7F, 0xDF, 0x07, 0x34], "extsh r31, r30"); test_display(&[0x7F, 0xDF, 0x07, 0x74], "extsb r31, r30"); test_display(&[0x7F, 0xE3, 0x07, 0x34], "extsh r3, r31"); test_display(&[0x7F, 0xE4, 0x07, 0x34], "extsh r4, r31"); test_display(&[0x7F, 0xE4, 0x07, 0x74], "extsb r4, r31"); test_display(&[0x7F, 0xE5, 0x07, 0x34], "extsh r5, r31"); test_display(&[0x7F, 0xE9, 0x07, 0xB4], "extsw r9, r31"); test_display(&[0x7F, 0xEA, 0x07, 0x34], "extsh r10, r31"); test_display(&[0x7F, 0xEA, 0x07, 0x74], "extsb r10, r31"); test_display(&[0x7F, 0xEA, 0x07, 0xB4], "extsw r10, r31"); test_display(&[0x7F, 0xFF, 0x07, 0x34], "extsh r31, r31"); test_display(&[0x7F, 0xFF, 0x07, 0x74], "extsb r31, r31"); test_display(&[0x7F, 0xFF, 0x07, 0xB4], "extsw r31, r31"); } #[test] fn ppc32_rots() { test_display(&[0x51, 0x69, 0x42, 0x1E], "rlwimi r9, r11, 8, 8, 15"); test_display(&[0x51, 0x69, 0x44, 0x2E], "rlwimi r9, r11, 8, 16, 23"); test_display(&[0x51, 0x69, 0x80, 0x1E], "rlwimi r9, r11, 16, 0, 15"); test_display(&[0x51, 0x69, 0x80, 0x5E], "rlwimi r9, r11, 16, 1, 15"); test_display(&[0x50, 0x00, 0xE1, 0x3B], "rlwimi. r0, r0, 28, 4, 29"); test_display(&[0x54, 0xC8, 0xBF, 0xFE], "rlwinm r8, r6, 23, 31, 31"); test_display(&[0x54, 0xC8, 0xDF, 0xFE], "rlwinm r8, r6, 27, 31, 31"); test_display(&[0x54, 0xC8, 0xEF, 0x7A], "rlwinm r8, r6, 29, 29, 29"); test_display(&[0x54, 0xC9, 0x00, 0x01], "clrrwi. r9, r6, 31"); test_display(&[0x54, 0xC9, 0x00, 0x26], "clrrwi r9, r6, 12"); test_display(&[0x55, 0x43, 0x00, 0x2A], "clrrwi r3, r10, 10"); // seems like tools do not want to print `clrrwi r3, r10, 0`. test_display(&[0x55, 0x43, 0x00, 0x3E], "rlwinm r3, r10, 0, 0, 31"); test_display(&[0x55, 0x6B, 0x00, 0x00], "clrrwi r11, r11, 31"); test_display(&[0x55, 0x6B, 0x00, 0x01], "clrrwi. r11, r11, 31"); test_display(&[0x55, 0x6B, 0x00, 0x0E], "clrrwi r11, r11, 24"); test_display(&[0x55, 0x6B, 0x00, 0x16], "clrrwi r11, r11, 20"); test_display(&[0x55, 0x6B, 0x00, 0x1A], "clrrwi r11, r11, 18"); test_display(&[0x55, 0x6B, 0x00, 0x1E], "clrrwi r11, r11, 16"); test_display(&[0x55, 0x6B, 0x00, 0x1F], "clrrwi. r11, r11, 16"); test_display(&[0x55, 0x6B, 0x00, 0x20], "clrrwi r11, r11, 15"); test_display(&[0x55, 0x6B, 0x00, 0x22], "clrrwi r11, r11, 14"); test_display(&[0x55, 0x6B, 0x00, 0x26], "clrrwi r11, r11, 12"); test_display(&[0x55, 0x6B, 0x00, 0x27], "clrrwi. r11, r11, 12"); test_display(&[0x55, 0x6B, 0x00, 0x2A], "clrrwi r11, r11, 10"); test_display(&[0x55, 0x6B, 0x00, 0x2C], "clrrwi r11, r11, 9"); test_display(&[0x55, 0x6B, 0x00, 0x2E], "clrrwi r11, r11, 8"); test_display(&[0x55, 0x6B, 0x00, 0x30], "clrrwi r11, r11, 7"); test_display(&[0x55, 0x6B, 0x00, 0x31], "clrrwi. r11, r11, 7"); test_display(&[0x55, 0x6B, 0x00, 0x32], "clrrwi r11, r11, 6"); test_display(&[0x55, 0x6B, 0x00, 0x34], "clrrwi r11, r11, 5"); test_display(&[0x55, 0x6B, 0x00, 0x35], "clrrwi. r11, r11, 5"); test_display(&[0x55, 0x6B, 0x00, 0x36], "clrrwi r11, r11, 4"); test_display(&[0x55, 0x6B, 0x00, 0x38], "clrrwi r11, r11, 3"); test_display(&[0x55, 0x6B, 0x00, 0x3A], "clrrwi r11, r11, 2"); test_display(&[0x55, 0x6B, 0x00, 0x3C], "clrrwi r11, r11, 1"); test_display(&[0x55, 0x6B, 0x00, 0x3D], "clrrwi. r11, r11, 1"); test_display(&[0x56, 0x6B, 0x07, 0xFE], "clrlwi r11, r19, 31"); test_display(&[0x56, 0x6B, 0x07, 0xFF], "clrlwi. r11, r19, 31"); test_display(&[0x57, 0x4A, 0x00, 0x30], "clrrwi r10, r26, 7"); test_display(&[0x57, 0x4A, 0x04, 0x3E], "clrlwi r10, r26, 16"); test_display(&[0x57, 0x4A, 0x06, 0x3E], "clrlwi r10, r26, 24"); test_display(&[0x57, 0xAB, 0x00, 0x00], "clrrwi r11, r29, 31"); test_display(&[0x57, 0xAB, 0x00, 0x04], "clrrwi r11, r29, 29"); test_display(&[0x57, 0xAB, 0x00, 0x31], "clrrwi. r11, r29, 7"); test_display(&[0x57, 0xAB, 0x00, 0x3C], "clrrwi r11, r29, 1"); test_display(&[0x57, 0xEA, 0x10, 0x3E], "rotlwi r10, r31, 2"); test_display(&[0x60, 0x00, 0x00, 0x00], "nop"); test_display(&[0x69, 0x29, 0x20, 0x00], "xori r9, r9, 8192"); test_display(&[0x6A, 0xF7, 0x00, 0x01], "xori r23, r23, 1"); test_display(&[0x6B, 0x6B, 0x00, 0x0F], "xori r11, r27, 15"); test_display(&[0x6B, 0xBD, 0x00, 0x01], "xori r29, r29, 1"); test_display(&[0x6B, 0xC5, 0x00, 0x01], "xori r5, r30, 1"); test_display(&[0x6B, 0xCB, 0x00, 0x01], "xori r11, r30, 1"); test_display(&[0x6D, 0x46, 0xAE, 0xA9], "xoris r6, r10, 44713"); test_invalid(&[0x7c, 0x08, 0xf2, 0xfe]); test_invalid(&[0x7c, 0x08, 0xf3, 0x3f]); test_invalid(&[0x7c, 0x08, 0xf3, 0x7F]); test_invalid(&[0x7c, 0x08, 0xfa, 0xbf]); test_display(&[0x79, 0x2A, 0x00, 0x0E], "rldimi r10, r9, 32, 0"); test_display(&[0x55, 0x0A, 0x40, 0x1E], "rlwinm r10, r8, 8, 0, 15"); test_display(&[0x55, 0x0A, 0x40, 0x3E], "rotlwi r10, r8, 8"); test_display(&[0x55, 0x0A, 0x50, 0x3E], "rotlwi r10, r8, 10"); test_display(&[0x55, 0x0A, 0x53, 0x2A], "rlwinm r10, r8, 10, 12, 21"); test_display(&[0x7B, 0xFF, 0x00, 0x20], "rldicl r31, r31, 0, 32"); test_display(&[0x7B, 0xFF, 0x0F, 0xA4], "rldicr r31, r31, 1, 62"); test_display(&[0x7B, 0xCA, 0xE6, 0x22], "rldicl r10, r30, 60, 56"); test_display(&[0x7B, 0xCB, 0x00, 0x20], "rldicl r11, r30, 0, 32"); test_display(&[0x7B, 0xCB, 0x05, 0x20], "rldicl r11, r30, 0, 52"); test_display(&[0x7B, 0xCB, 0x83, 0xE4], "rldicr r11, r30, 16, 47"); test_display(&[0x79, 0x8C, 0x9F, 0xE6], "rldicr r12, r12, 51, 63"); test_display(&[0x79, 0x8C, 0xA7, 0xE6], "rldicr r12, r12, 52, 63"); test_display(&[0x79, 0x8C, 0xAF, 0xE4], "rldicr r12, r12, 21, 63"); test_display(&[0x78, 0x63, 0x00, 0x20], "rldicl r3, r3, 0, 32"); test_display(&[0x78, 0x63, 0xAB, 0x02], "rldicl r3, r3, 53, 12"); test_display(&[0x78, 0x63, 0xE8, 0xA4], "rldicr r3, r3, 29, 34"); test_display(&[0x57, 0xFF, 0xFF, 0xFE], "rlwinm r31, r31, 31, 31, 31"); test_display(&[0x57, 0xFF, 0x15, 0xFA], "rlwinm r31, r31, 2, 23, 29"); test_display(&[0x57, 0xFF, 0x18, 0x3E], "rotlwi r31, r31, 3"); test_display(&[0x57, 0xFF, 0x20, 0x3E], "rotlwi r31, r31, 4"); test_display(&[0x57, 0xFF, 0x23, 0x36], "rlwinm r31, r31, 4, 12, 27"); test_display(&[0x57, 0xFF, 0x07, 0xFA], "rlwinm r31, r31, 0, 31, 29"); test_display(&[0x57, 0xFF, 0x07, 0xFE], "clrlwi r31, r31, 31"); test_display(&[0x57, 0xFF, 0x10, 0x3E], "rotlwi r31, r31, 2"); test_display(&[0x57, 0xFF, 0x06, 0x7E], "clrlwi r31, r31, 25"); test_display(&[0x57, 0xFE, 0x00, 0x30], "clrrwi r30, r31, 7"); test_display(&[0x57, 0xEB, 0x7F, 0xFE], "rlwinm r11, r31, 15, 31, 31"); test_display(&[0x57, 0xEB, 0x86, 0x3E], "rlwinm r11, r31, 16, 24, 31"); test_display(&[0x57, 0xEB, 0x07, 0xFE], "clrlwi r11, r31, 31"); test_display(&[0x57, 0xEB, 0x07, 0xFF], "clrlwi. r11, r31, 31"); test_display(&[0x57, 0xEB, 0x07, 0x3F], "clrlwi. r11, r31, 28"); test_display(&[0x57, 0xEB, 0x07, 0x7A], "rlwinm r11, r31, 0, 29, 29"); test_display(&[0x57, 0xEB, 0x07, 0x7B], "rlwinm. r11, r31, 0, 29, 29"); test_display(&[0x57, 0xEB, 0x07, 0xBC], "rlwinm r11, r31, 0, 30, 30"); test_display(&[0x57, 0xEB, 0x07, 0xBD], "rlwinm. r11, r31, 0, 30, 30"); test_display(&[0x57, 0xEB, 0x07, 0xBE], "clrlwi r11, r31, 30"); test_display(&[0x57, 0xEB, 0x07, 0xBF], "clrlwi. r11, r31, 30"); test_display(&[0x57, 0xEB, 0x00, 0x00], "clrrwi r11, r31, 31"); test_display(&[0x57, 0xDE, 0x06, 0x3F], "clrlwi. r30, r30, 24"); test_display(&[0x57, 0xDE, 0x07, 0xFA], "rlwinm r30, r30, 0, 31, 29"); test_display(&[0x57, 0xAB, 0x08, 0x3E], "rotlwi r11, r29, 1"); test_display(&[0x57, 0xAB, 0x10, 0x3E], "rotlwi r11, r29, 2"); } #[test] fn test_power_as() { let power1 = InstDecoder::for_cpu(IsaVersion::RIOS).with_be(false); let power_as = InstDecoder::for_cpu(IsaVersion::Amazon).with_be(false); let p202 = InstDecoder::for_cpu(IsaVersion::V2_02).with_be(false); test_invalid_under(&power1, &[0x24, 0x5b, 0x00, 0x7c]); test_display_under(&power_as, &[0x24, 0x5b, 0x00, 0x7c], "slbmte r0, r11"); test_display_under(&p202, &[0x24, 0x5b, 0x00, 0x7c], "slbmte r0, r11"); test_invalid_under(&power1, &[0x64, 0x5b, 0x00, 0x7c]); test_display_under(&power_as, &[0x64, 0x5b, 0x00, 0x7c], "slbie r11"); // because 2.02 supports SLB (non-AS) test_display_under(&p202, &[0x64, 0x5b, 0x00, 0x7c], "slbie r11"); test_invalid_under(&power1, &[0xa6, 0x1e, 0x00, 0x7c]); test_display_under(&power_as, &[0xa6, 0x1e, 0x00, 0x7c], "slbmfev r0, r3"); test_display_under(&p202, &[0xa6, 0x1e, 0x00, 0x7c], "slbmfev r0, r3"); test_invalid_under(&power1, &[0x26, 0x1f, 0x00, 0x7c]); test_display_under(&power_as, &[0x26, 0x1f, 0x00, 0x7c], "slbmfee r0, r3"); test_display_under(&p202, &[0x26, 0x1f, 0x00, 0x7c], "slbmfee r0, r3"); } #[test] fn test_le_power2() { let power1 = InstDecoder::for_cpu(IsaVersion::RIOS).with_be(false); let power2 = InstDecoder::for_cpu(IsaVersion::RIOS2).with_be(false); let p202 = InstDecoder::for_cpu(IsaVersion::V2_02).with_be(false); let p205 = InstDecoder::for_cpu(IsaVersion::V2_05).with_be(false); let p207 = InstDecoder::for_cpu(IsaVersion::V2_07).with_be(false); test_display_under(&power1, &[0x22, 0x00, 0x00, 0x44], "svca 8"); test_display_under(&power1, &[0xa8, 0x30, 0x00, 0x44], "svc 5, 3, 2"); test_display_under(&power1, &[0xa9, 0x30, 0x00, 0x44], "svcl 5, 3, 2"); test_invalid_under(&power1, &[0x2e, 0x26, 0x64, 0x7c]); test_display_under(&power2, &[0x2e, 0x26, 0x64, 0x7c], "lfqx fr3, r4, r4"); test_invalid_under(&p202, &[0x2e, 0x26, 0x64, 0x7c]); test_display_under(&p205, &[0x2e, 0x26, 0x44, 0x7c], "lfdpx fr2, r4, r4"); test_invalid_under(&power1, &[0x6e, 0x26, 0x64, 0x7c]); test_display_under(&power2, &[0x6e, 0x26, 0x64, 0x7c], "lfqux fr3, r4, r4"); test_invalid_under(&p202, &[0x6e, 0x26, 0x64, 0x7c]); test_invalid_under(&p205, &[0x6e, 0x26, 0x44, 0x7c]); test_invalid_under(&power1, &[0x2e, 0x27, 0x64, 0x7c]); test_display_under(&power2, &[0x2e, 0x27, 0x64, 0x7c], "stfqx fr3, r4, r4"); test_invalid_under(&p202, &[0x2e, 0x27, 0x64, 0x7c]); test_display_under(&p205, &[0x2e, 0x27, 0x44, 0x7c], "stfdpx fr2, r4, r4"); test_invalid_under(&power1, &[0x10, 0x00, 0xc4, 0xe4]); test_display_under(&power2, &[0x10, 0x00, 0xc4, 0xe4], "lfqu fr6, 0x10(r4)"); test_invalid_under(&p202, &[0x10, 0x00, 0xc4, 0xe4]); test_display_under(&p205, &[0x10, 0x00, 0xc4, 0xe4], "lfdp fr6, 0x10(r4)"); test_invalid_under(&p202, &[0x10, 0x00, 0x44, 0xe4]); test_display_under(&p205, &[0x10, 0x00, 0x44, 0xe4], "lfdp fr2, 0x10(r4)"); test_invalid_under(&p205, &[0x12, 0x00, 0x44, 0xe4]); test_invalid_under(&power1, &[0x10, 0x00, 0x64, 0xf0]); test_display_under(&power2, &[0x10, 0x00, 0x64, 0xf0], "stfq fr3, 0x10(r4)"); test_invalid_under(&p202, &[0x10, 0x00, 0x64, 0xf0]); test_invalid_under(&p205, &[0x10, 0x00, 0x64, 0xf0]); // IncompleteDecoder test_invalid_under(&power1, &[0x10, 0x00, 0xc4, 0xf4]); test_display_under(&power2, &[0x10, 0x00, 0xc4, 0xf4], "stfqu fr6, 0x10(r4)"); test_invalid_under(&p202, &[0x10, 0x00, 0xc4, 0xf4]); test_display_under(&p205, &[0x10, 0x00, 0xc4, 0xf4], "stfdp fr6, 0x10(r4)"); test_display_under(&p207, &[0x10, 0x00, 0x44, 0xf4], "stfdp fr2, 0x10(r4)"); test_display_under(&power1, &[0x10, 0x00, 0x64, 0xe0], "lfq fr3, 0x10(r4)"); test_display_under(&power2, &[0x10, 0x00, 0x64, 0xe0], "lfq fr3, 0x10(r4)"); test_invalid_under(&p202, &[0x10, 0x00, 0x64, 0xe0]); test_display_under(&power1, &[0x26, 0x04, 0x00, 0x7c], "clcs r0, r0"); test_display_under(&power2, &[0x26, 0x04, 0x00, 0x7c], "clcs r0, r0"); test_invalid_under(&p202, &[0x26, 0x04, 0x00, 0x7c]); test_display_under(&power1, &[0xe6, 0x04, 0x00, 0x7c], "mfsri r0, r0, r0"); test_display_under(&power2, &[0xe6, 0x04, 0x00, 0x7c], "mfsri r0, r0, r0"); test_invalid_under(&p202, &[0xe6, 0x04, 0x00, 0x7c]); test_display_under(&power1, &[0xec, 0x04, 0x00, 0x7c], "dclst r0, r0"); test_display_under(&power2, &[0xec, 0x04, 0x00, 0x7c], "dclst r0, r0"); test_invalid_under(&p202, &[0xec, 0x04, 0x00, 0x7c]); test_display_under(&power1, &[0x31, 0x45, 0x00, 0x7c], "srq. r0, r0, r8"); test_display_under(&power2, &[0x31, 0x45, 0x00, 0x7c], "srq. r0, r0, r8"); test_invalid_under(&p202, &[0x31, 0x45, 0x00, 0x7c]); test_display_under(&power1, &[0x33, 0x45, 0x00, 0x7c], "sre. r0, r0, r8"); test_display_under(&power2, &[0x33, 0x45, 0x00, 0x7c], "sre. r0, r0, r8"); test_invalid_under(&p202, &[0x33, 0x45, 0x00, 0x7c]); test_display_under(&power1, &[0x71, 0x45, 0x00, 0x7c], "sriq. r0, r0, 0x8"); test_display_under(&power2, &[0x71, 0x45, 0x00, 0x7c], "sriq. r0, r0, 0x8"); test_invalid_under(&p202, &[0x71, 0x45, 0x00, 0x7c]); test_display_under(&power1, &[0xb1, 0x45, 0x00, 0x7c], "srlq. r0, r0, r8"); test_display_under(&power2, &[0xb1, 0x45, 0x00, 0x7c], "srlq. r0, r0, r8"); test_invalid_under(&p202, &[0xb1, 0x45, 0x00, 0x7c]); test_display_under(&power1, &[0xb3, 0x45, 0x00, 0x7c], "sreq. r0, r0, r8"); test_display_under(&power2, &[0xb3, 0x45, 0x00, 0x7c], "sreq. r0, r0, r8"); test_invalid_under(&p202, &[0xb3, 0x45, 0x00, 0x7c]); test_display_under(&power1, &[0x71, 0x07, 0x00, 0x7c], "sraiq. r0, r0, 0x0"); test_display_under(&power2, &[0x71, 0x07, 0x00, 0x7c], "sraiq. r0, r0, 0x0"); test_invalid_under(&p202, &[0x71, 0x07, 0x00, 0x7c]); test_display_under(&power1, &[0xf1, 0x45, 0x00, 0x7c], "srliq. r0, r0, 0x8"); test_display_under(&power2, &[0xf1, 0x45, 0x00, 0x7c], "srliq. r0, r0, 0x8"); test_invalid_under(&p202, &[0xf1, 0x45, 0x00, 0x7c]); test_display_under(&power1, &[0xec, 0x18, 0x00, 0x7c], "clf r0, r3"); test_display_under(&power2, &[0xec, 0x18, 0x00, 0x7c], "clf r0, r3"); test_invalid_under(&p202, &[0xf1, 0x45, 0x00, 0x7c]); test_display_under(&power1, &[0x31, 0x59, 0x00, 0x7c], "slq. r0, r0, r11"); test_display_under(&power2, &[0x31, 0x59, 0x00, 0x7c], "slq. r0, r0, r11"); test_invalid_under(&p202, &[0x31, 0x59, 0x00, 0x7c]); test_display_under(&power1, &[0x33, 0x59, 0x00, 0x7c], "sle. r0, r0, r11"); test_display_under(&power2, &[0x33, 0x59, 0x00, 0x7c], "sle. r0, r0, r11"); test_invalid_under(&p202, &[0x33, 0x59, 0x00, 0x7c]); test_display_under(&power1, &[0xb3, 0x59, 0x00, 0x7c], "sleq. r0, r0, r11"); test_display_under(&power2, &[0xb3, 0x59, 0x00, 0x7c], "sleq. r0, r0, r11"); test_invalid_under(&p202, &[0xb3, 0x59, 0x00, 0x7c]); test_display_under(&power1, &[0x33, 0x5c, 0x00, 0x7c], "rrib. r0, r0, r11"); test_display_under(&power2, &[0x33, 0x5c, 0x00, 0x7c], "rrib. r0, r0, r11"); test_invalid_under(&p202, &[0x33, 0x5c, 0x00, 0x7c]); test_display_under(&power1, &[0x11, 0x2e, 0x00, 0x7c], "dozo. r0, r0, r5"); test_display_under(&power2, &[0x11, 0x2e, 0x00, 0x7c], "dozo. r0, r0, r5"); test_invalid_under(&p202, &[0x11, 0x2e, 0x00, 0x7c]); test_display_under(&power1, &[0x4c, 0x00, 0x00, 0x24], "dozi r0, r0, 76"); test_display_under(&power2, &[0x4c, 0x00, 0x00, 0x24], "dozi r0, r0, 76"); test_invalid_under(&p202, &[0x4c, 0x00, 0x00, 0x24]); test_display_under(&power1, &[0x2b, 0x0a, 0x00, 0x7c], "lscbx. r0, 0, r1"); test_display_under(&power2, &[0x2b, 0x0a, 0x00, 0x7c], "lscbx. r0, 0, r1"); test_invalid_under(&p202, &[0x2b, 0x0a, 0x00, 0x7c]); // TODO: actual testcases for these // test_invalid_under(&power1, &[0x2e, 0x97, 0x00, 0x7c]); // test_display_under(&power2, &[0x2e, 0x97, 0x00, 0x7c], "rac r0, r0, r2"); // test_invalid_under(&p202, &[0x2e, 0x97, 0x00, 0x7c]); } #[test] fn ppc32_move_reg() { test_invalid(&[0x7f, 0x9e, 0xd9, 0x20]); let gekko = InstDecoder::for_cpu(IsaVersion::Gekko).with_be(false); let cell = InstDecoder::for_cpu(IsaVersion::Cell).with_be(false); let xenon = InstDecoder::for_cpu(IsaVersion::Xenon).with_be(false); let p202 = InstDecoder::for_cpu(IsaVersion::V2_02).with_be(false); let p207 = InstDecoder::for_cpu(IsaVersion::V2_07).with_be(false); test_display_under(&gekko, &[0x20, 0xd9, 0x9e, 0x7f], "mtcrf 0xed, r28"); test_invalid_under(&p202, &[0x20, 0xd9, 0x9e, 0x7f]); test_invalid_under(&p207, &[0x20, 0xd9, 0x9e, 0x7f]); test_display_under(&gekko, &[0x26, 0x80, 0x70, 0x7c], "mfcr r3"); //"mfocrf r3, 8"); test_display_under(&p202, &[0x26, 0x80, 0x70, 0x7c], "mfocrf r3, 0x8"); test_display_under(&p207, &[0x26, 0x80, 0x70, 0x7c], "mfocrf r3, 0x8"); test_invalid_under(&gekko, &[0xa4, 0x00, 0x00, 0x7c]); test_display_under(&p202, &[0xa4, 0x00, 0x00, 0x7c], "mtsrd 0, r0"); test_display_under(&p207, &[0xa4, 0x00, 0x00, 0x7c], "mtsrd 0, r0"); test_display_under(&p207, &[0xa4, 0x00, 0x11, 0x7c], "mtsrd 1, r0"); test_display_under(&gekko, &[0x27, 0x08, 0xb8, 0x7d], "mfcr r13"); test_display_under(&p202, &[0x27, 0x08, 0xb8, 0x7d], "mfocrf r13, 0x80"); test_display_under(&p207, &[0x27, 0x08, 0xb8, 0x7d], "mfocrf r13, 0x80"); test_display_under(&gekko, &[0x27, 0xf8, 0x7f, 0x7f], "mfcr r27"); test_display(&[0x7F, 0x50, 0x18, 0x26], "mfocrf r26, 0x1"); test_display(&[0x7C, 0x08, 0x02, 0xA6], "mflr r0"); test_display(&[0x7D, 0x88, 0x02, 0xA6], "mflr r12"); test_display(&[0x7F, 0xe8, 0x02, 0xA6], "mflr r31"); test_display(&[0x7C, 0x08, 0x03, 0xA6], "mtlr r0"); test_display(&[0x7D, 0x88, 0x03, 0xA6], "mtlr r12"); test_display(&[0x7F, 0xE8, 0x03, 0xA6], "mtlr r31"); test_display(&[0x7C, 0x09, 0x03, 0xA6], "mtctr r0"); test_display(&[0x7C, 0xC9, 0x03, 0xA6], "mtctr r6"); test_display(&[0x7E, 0x09, 0x03, 0xA6], "mtctr r16"); test_display(&[0x7E, 0x49, 0x03, 0xA6], "mtctr r18"); test_display(&[0x7F, 0xC9, 0x03, 0xA6], "mtctr r30"); test_display(&[0x7F, 0xE9, 0x03, 0xA6], "mtctr r31"); test_display(&[0x7C, 0x60, 0x00, 0xA6], "mfmsr r3"); test_display(&[0x7D, 0x60, 0x00, 0xA6], "mfmsr r11"); test_display_under(&cell, &[0x64, 0x01, 0x41, 0x7d], "mtmsrd r10, 1"); test_display_under(&xenon, &[0x64, 0x01, 0x41, 0x7d], "mtmsree r10"); test_display(&[0x7C, 0x80, 0x00, 0x26], "mfcr r4"); test_display(&[0x7D, 0x60, 0x00, 0x26], "mfcr r11"); test_display(&[0x7C, 0x8F, 0xF1, 0x20], "mtcr r4"); test_display(&[0x7C, 0xAF, 0xF1, 0x20], "mtcr r5"); test_display(&[0x7C, 0xC1, 0x03, 0xA6], "mtxer r6"); test_display(&[0x7C, 0xD0, 0x20, 0x26], "mfocrf r6, 0x2"); test_display(&[0x7D, 0x70, 0x20, 0x26], "mfocrf r11, 0x2"); test_display(&[0x7D, 0x4C, 0x42, 0xE6], "mftb r10, 0x10c"); test_display(&[0x7D, 0x6C, 0x42, 0xE6], "mftb r11, 0x10c"); test_display(&[0x7F, 0xAC, 0x42, 0xE6], "mftb r29, 0x10c"); test_display(&[0xFC, 0x00, 0x04, 0x8E], "mffs fr0"); test_display(&[0xFD, 0xFE, 0x05, 0x8E], "mtfsf 0xff, fr0"); test_display(&[0xFD, 0xFE, 0x0D, 0x8E], "mtfsf 0xff, fr1"); test_display(&[0x7C, 0x0D, 0xAA, 0xE6], "mftb r0, 0x2ad"); test_display_le(&[0xa6, 0xea, 0x0b, 0x7c], "mfspr r0, spr939"); test_display_le(&[0xa6, 0xeb, 0x0b, 0x7c], "mtspr spr939, r0"); test_display_le(&[0x04, 0x06, 0xe0, 0x13], "mfvscr vr31"); } #[test] fn ppc32_cntlz() { test_display(&[0x7C, 0x63, 0x00, 0x34], "cntlzw r3, r3"); test_display(&[0x7C, 0x64, 0x00, 0x34], "cntlzw r4, r3"); test_display(&[0x7C, 0x65, 0x00, 0x34], "cntlzw r5, r3"); test_display(&[0x7C, 0x65, 0x00, 0x74], "cntlzd r5, r3"); test_display(&[0x7C, 0x66, 0x00, 0x34], "cntlzw r6, r3"); test_display(&[0x7C, 0x69, 0x00, 0x34], "cntlzw r9, r3"); test_display(&[0x7C, 0x6B, 0x00, 0x34], "cntlzw r11, r3"); test_display(&[0x7F, 0x8B, 0x00, 0x74], "cntlzd r11, r28"); test_display(&[0x7F, 0x9A, 0x00, 0x34], "cntlzw r26, r28"); } #[test] fn ppc32_cmp() { test_display(&[0x28, 0x05, 0x00, 0x00], "cmplwi r5, 0"); test_display(&[0x28, 0x05, 0x00, 0x80], "cmplwi r5, 128"); test_display(&[0x28, 0x05, 0x04, 0x00], "cmplwi r5, 1024"); test_display(&[0x28, 0x06, 0x00, 0x00], "cmplwi r6, 0"); test_display(&[0x28, 0x06, 0x00, 0x04], "cmplwi r6, 4"); test_display(&[0x2F, 0x1F, 0x2E, 0x50], "cmpwi cr6, r31, 11856"); test_display(&[0x2F, 0x1F, 0xFF, 0xF1], "cmpwi cr6, r31, 65521"); test_display(&[0x2F, 0x1F, 0xFF, 0xFB], "cmpwi cr6, r31, 65531"); test_display(&[0x2F, 0x1F, 0xFF, 0xFC], "cmpwi cr6, r31, 65532"); test_display(&[0x2F, 0x1F, 0xFF, 0xFD], "cmpwi cr6, r31, 65533"); test_display(&[0x2F, 0x1F, 0xFF, 0xFE], "cmpwi cr6, r31, 65534"); test_display(&[0x2F, 0x1F, 0xFF, 0xFF], "cmpwi cr6, r31, 65535"); test_display(&[0x2F, 0x2B, 0x00, 0x08], "cmpdi cr6, r11, 8"); test_display(&[0x2F, 0x2B, 0x00, 0x0A], "cmpdi cr6, r11, 10"); test_display(&[0x2F, 0x2B, 0x00, 0x64], "cmpdi cr6, r11, 100"); test_display(&[0x2F, 0x2B, 0x03, 0xE8], "cmpdi cr6, r11, 1000"); test_display(&[0x2F, 0x2B, 0xFF, 0xFF], "cmpdi cr6, r11, 65535"); test_display(&[0x2F, 0x3A, 0x00, 0x00], "cmpdi cr6, r26, 0"); test_display(&[0x2F, 0x3A, 0xFF, 0xFF], "cmpdi cr6, r26, 65535"); test_display(&[0x2F, 0x3B, 0x00, 0x00], "cmpdi cr6, r27, 0"); test_display(&[0x2F, 0x3B, 0xFF, 0xFF], "cmpdi cr6, r27, 65535"); test_display(&[0x2F, 0x3E, 0x00, 0x00], "cmpdi cr6, r30, 0"); test_display(&[0x2F, 0x3E, 0x10, 0x00], "cmpdi cr6, r30, 4096"); test_display(&[0x7C, 0x03, 0x20, 0x00], "cmpw r3, r4"); test_display(&[0x7C, 0x04, 0x28, 0x00], "cmpw r4, r5"); test_display(&[0x7F, 0x1F, 0xE0, 0x00], "cmpw cr6, r31, r28"); test_display(&[0x7F, 0x1F, 0xE0, 0x40], "cmplw cr6, r31, r28"); test_display(&[0x7F, 0x1F, 0xE8, 0x00], "cmpw cr6, r31, r29"); test_display(&[0x7F, 0x1F, 0xE8, 0x40], "cmplw cr6, r31, r29"); test_display(&[0x7F, 0x1F, 0xF0, 0x00], "cmpw cr6, r31, r30"); test_display(&[0x7F, 0x1F, 0xF0, 0x40], "cmplw cr6, r31, r30"); test_display(&[0x7F, 0x36, 0x58, 0x00], "cmpd cr6, r22, r11"); test_display(&[0x7F, 0x3C, 0x40, 0x40], "cmpld cr6, r28, r8"); test_display(&[0x7F, 0x3F, 0x50, 0x40], "cmpld cr6, r31, r10"); test_display(&[0x7F, 0x3F, 0x58, 0x40], "cmpld cr6, r31, r11"); test_display(&[0x7F, 0x3F, 0xD8, 0x00], "cmpd cr6, r31, r27"); } #[test] fn ppc32_add() { test_display(&[0x35, 0x6B, 0xFF, 0xFE], "addic. r11, r11, -2"); test_display(&[0x35, 0x6B, 0xFF, 0xFF], "addic. r11, r11, -1"); test_display(&[0x35, 0x77, 0x00, 0x01], "addic. r11, r23, 1"); test_display(&[0x35, 0x7A, 0x00, 0x03], "addic. r11, r26, 3"); test_display(&[0x37, 0xDE, 0xF0, 0x00], "addic. r30, r30, -4096"); test_display(&[0x37, 0xDE, 0xFF, 0xFF], "addic. r30, r30, -1"); test_display(&[0x37, 0xEF, 0xFF, 0xFF], "addic. r31, r15, -1"); test_display(&[0x37, 0xFF, 0xFF, 0xFF], "addic. r31, r31, -1"); test_display(&[0x38, 0x05, 0x00, 0x01], "addi r0, r5, 1"); test_display(&[0x38, 0x0B, 0x0F, 0xFF], "addi r0, r11, 4095"); test_display(&[0x39, 0x44, 0x2F, 0x48], "addi r10, r4, 12104"); test_display(&[0x39, 0x44, 0x37, 0xF1], "addi r10, r4, 14321"); test_display(&[0x39, 0x7F, 0x00, 0x54], "addi r11, r31, 84"); test_display(&[0x39, 0x7F, 0x00, 0x58], "addi r11, r31, 88"); test_display(&[0x3B, 0xE9, 0x01, 0x78], "addi r31, r9, 376"); test_display(&[0x3B, 0xE9, 0x03, 0x18], "addi r31, r9, 792"); test_display(&[0x3B, 0xE9, 0x03, 0x50], "addi r31, r9, 848"); test_display(&[0x3B, 0xE9, 0x0F, 0x6C], "addi r31, r9, 3948"); test_display(&[0x3B, 0xE9, 0x25, 0xDC], "addi r31, r9, 9692"); test_display(&[0x3B, 0xE9, 0x2A, 0x64], "addi r31, r9, 10852"); test_display(&[0x3B, 0xE9, 0x53, 0xA0], "addi r31, r9, 21408"); test_display(&[0x3B, 0xFF, 0x00, 0x01], "addi r31, r31, 1"); test_display(&[0x3B, 0xFF, 0x00, 0x02], "addi r31, r31, 2"); test_display(&[0x3B, 0xFF, 0x00, 0x03], "addi r31, r31, 3"); test_display(&[0x3B, 0xFF, 0x65, 0x10], "addi r31, r31, 25872"); test_display(&[0x3B, 0xFF, 0x7A, 0x00], "addi r31, r31, 31232"); test_display(&[0x3B, 0xFF, 0x7C, 0x08], "addi r31, r31, 31752"); // addi rT, rA, -X is aliased into subi rT, rA, X. this is the case for the // remaining "addi" tests. // aka "addi r0, r5, -1024" test_display(&[0x38, 0x05, 0xFC, 0x00], "subi r0, r5, 1024"); test_display(&[0x3B, 0xE9, 0x81, 0x30], "subi r31, r9, 32464"); test_display(&[0x3B, 0xE9, 0x91, 0x30], "subi r31, r9, 28368"); test_display(&[0x3B, 0xE9, 0x92, 0xE0], "subi r31, r9, 27936"); test_display(&[0x3B, 0xE9, 0xAB, 0x7C], "subi r31, r9, 21636"); test_display(&[0x3B, 0xE9, 0xB4, 0xE0], "subi r31, r9, 19232"); test_display(&[0x3B, 0xE9, 0xCC, 0x18], "subi r31, r9, 13288"); test_display(&[0x3B, 0xE9, 0xE3, 0x68], "subi r31, r9, 7320"); test_display(&[0x3B, 0xE9, 0xED, 0xA8], "subi r31, r9, 4696"); test_display(&[0x3B, 0xE9, 0xFE, 0xB8], "subi r31, r9, 328"); test_display(&[0x3B, 0xE9, 0xFF, 0xF8], "subi r31, r9, 8"); test_display(&[0x3B, 0xFF, 0x80, 0x00], "subi r31, r31, 32768"); test_display(&[0x3B, 0xFF, 0xF9, 0xC8], "subi r31, r31, 1592"); test_display(&[0x3B, 0xFF, 0xFC, 0x40], "subi r31, r31, 960"); test_display(&[0x3B, 0xFF, 0xFC, 0x98], "subi r31, r31, 872"); test_display(&[0x3B, 0xFF, 0xFD, 0x60], "subi r31, r31, 672"); test_display(&[0x3B, 0xFF, 0xFE, 0xA8], "subi r31, r31, 344"); test_display(&[0x3B, 0xFF, 0xFF, 0xC0], "subi r31, r31, 64"); test_display(&[0x3B, 0xFF, 0xFF, 0xCC], "subi r31, r31, 52"); test_display(&[0x3B, 0xFF, 0xFF, 0xD0], "subi r31, r31, 48"); test_display(&[0x3B, 0xFF, 0xFF, 0xD8], "subi r31, r31, 40"); test_display(&[0x3B, 0xFF, 0xFF, 0xE8], "subi r31, r31, 24"); test_display(&[0x3B, 0xFF, 0xFF, 0xEC], "subi r31, r31, 20"); test_display(&[0x3B, 0xFF, 0xFF, 0xF0], "subi r31, r31, 16"); test_display(&[0x3B, 0xFF, 0xFF, 0xF4], "subi r31, r31, 12"); test_display(&[0x3B, 0xFF, 0xFF, 0xF8], "subi r31, r31, 8"); test_display(&[0x3C, 0x6B, 0x00, 0x01], "addis r3, r11, 1"); test_display(&[0x3C, 0x6B, 0x00, 0x02], "addis r3, r11, 2"); test_display(&[0x3C, 0x6B, 0x00, 0x03], "addis r3, r11, 3"); test_display(&[0x3C, 0x6B, 0x00, 0x06], "addis r3, r11, 6"); test_display(&[0x3C, 0x6E, 0x00, 0x03], "addis r3, r14, 3"); test_display(&[0x3D, 0x6B, 0x00, 0x01], "addis r11, r11, 1"); test_display(&[0x3D, 0x6B, 0x00, 0x02], "addis r11, r11, 2"); test_display(&[0x3D, 0x6B, 0x00, 0x03], "addis r11, r11, 3"); test_display(&[0x3D, 0x6B, 0x00, 0x04], "addis r11, r11, 4"); test_display(&[0x3D, 0x6B, 0x00, 0x06], "addis r11, r11, 6"); test_display(&[0x3D, 0x6B, 0x00, 0x09], "addis r11, r11, 9"); test_display(&[0x3D, 0x6B, 0x00, 0x0B], "addis r11, r11, 11"); test_display(&[0x3D, 0x6B, 0x00, 0x10], "addis r11, r11, 16"); test_display(&[0x3D, 0x6B, 0x05, 0x26], "addis r11, r11, 1318"); test_display(&[0x3D, 0x6B, 0x3C, 0x6F], "addis r11, r11, 15471"); test_display(&[0x3D, 0x6B, 0x40, 0x00], "addis r11, r11, 16384"); // same aliasing situation as addi above. test_display(&[0x3C, 0x6A, 0xDE, 0xAE], "subis r3, r10, 8530"); test_display(&[0x3C, 0x6B, 0xC0, 0x00], "subis r3, r11, 16384"); test_display(&[0x3C, 0x6B, 0xFF, 0xFF], "subis r3, r11, 1"); test_display(&[0x3D, 0x6B, 0xC0, 0x00], "subis r11, r11, 16384"); test_display(&[0x3D, 0x6B, 0xC9, 0xCF], "subis r11, r11, 13873"); test_display(&[0x7D, 0x4A, 0xFA, 0x14], "add r10, r10, r31"); test_display(&[0x7D, 0x4A, 0xFA, 0x15], "add. r10, r10, r31"); test_display(&[0x7D, 0x4B, 0x01, 0x94], "addze r10, r11"); test_display(&[0x7D, 0x4B, 0x1A, 0x14], "add r10, r11, r3"); test_display(&[0x7D, 0x4B, 0x52, 0x14], "add r10, r11, r10"); test_display(&[0x7D, 0x4B, 0x52, 0x15], "add. r10, r11, r10"); test_display(&[0x7D, 0x4B, 0x72, 0x14], "add r10, r11, r14"); test_display(&[0x7D, 0x6B, 0x01, 0x94], "addze r11, r11"); test_display(&[0x7D, 0x6B, 0x01, 0x95], "addze. r11, r11"); test_display(&[0x7D, 0x6B, 0x1A, 0x14], "add r11, r11, r3"); test_display(&[0x7D, 0x6B, 0x4A, 0x14], "add r11, r11, r9"); test_display(&[0x7D, 0x6B, 0x4A, 0x15], "add. r11, r11, r9"); test_display(&[0x7D, 0x6B, 0x52, 0x14], "add r11, r11, r10"); test_display(&[0x7D, 0x6B, 0x52, 0x15], "add. r11, r11, r10"); test_display(&[0x7D, 0x6B, 0x62, 0x14], "add r11, r11, r12"); test_display(&[0x7D, 0x6B, 0xE2, 0x14], "add r11, r11, r28"); test_display(&[0x7D, 0x6B, 0xE2, 0x15], "add. r11, r11, r28"); test_display(&[0x7D, 0x6B, 0xEA, 0x14], "add r11, r11, r29"); test_display(&[0x7E, 0x88, 0x4A, 0x14], "add r20, r8, r9"); test_display(&[0x7E, 0x89, 0x01, 0x94], "addze r20, r9"); test_display(&[0x7E, 0x89, 0x42, 0x14], "add r20, r9, r8"); test_display(&[0x7E, 0x89, 0x52, 0x14], "add r20, r9, r10"); test_display(&[0x7F, 0x4A, 0xFA, 0x14], "add r26, r10, r31"); test_display(&[0x7F, 0x4B, 0x01, 0x94], "addze r26, r11"); test_display(&[0x7F, 0x4B, 0x01, 0x95], "addze. r26, r11"); test_display(&[0x7F, 0x4B, 0x1A, 0x14], "add r26, r11, r3"); test_display(&[0x7F, 0x6B, 0x01, 0x94], "addze r27, r11"); test_display(&[0x7F, 0x6B, 0x01, 0x95], "addze. r27, r11"); test_display(&[0x7F, 0x6B, 0x1A, 0x14], "add r27, r11, r3"); test_display(&[0x7F, 0xE5, 0x01, 0x94], "addze r31, r5"); test_display(&[0x7F, 0xE5, 0x3A, 0x14], "add r31, r5, r7"); test_display(&[0x7F, 0xE5, 0xFA, 0x14], "add r31, r5, r31"); test_display(&[0x7F, 0xFF, 0x01, 0x94], "addze r31, r31"); test_display(&[0x7F, 0xFF, 0xEA, 0x14], "add r31, r31, r29"); test_display(&[0x7F, 0xFF, 0xF2, 0x14], "add r31, r31, r30"); } #[test] fn ppc32_div() { test_display(&[0x7C, 0x63, 0x33, 0x96], "divwu r3, r3, r6"); test_display(&[0x7C, 0x64, 0x5B, 0xD6], "divw r3, r4, r11"); test_display(&[0x7C, 0x6A, 0x23, 0xD6], "divw r3, r10, r4"); test_display(&[0x7C, 0x6A, 0x4B, 0xD2], "divd r3, r10, r9"); test_display(&[0x7C, 0x6A, 0x5B, 0x92], "divdu r3, r10, r11"); test_display(&[0x7C, 0xC8, 0x5B, 0xD6], "divw r6, r8, r11"); test_display(&[0x7C, 0xC9, 0x53, 0x96], "divwu r6, r9, r10"); test_display(&[0x7C, 0xC9, 0x5B, 0xD6], "divw r6, r9, r11"); test_display(&[0x7C, 0xCB, 0x4B, 0xD2], "divd r6, r11, r9"); test_display(&[0x7C, 0xCB, 0x4B, 0xD6], "divw r6, r11, r9"); test_display(&[0x7D, 0x44, 0x53, 0x96], "divwu r10, r4, r10"); test_display(&[0x7D, 0x44, 0x53, 0x97], "divwu. r10, r4, r10"); test_display(&[0x7D, 0x44, 0x5B, 0x96], "divwu r10, r4, r11"); test_display(&[0x7D, 0x7B, 0xE3, 0x96], "divwu r11, r27, r28"); test_display(&[0x7D, 0x7B, 0xE3, 0x97], "divwu. r11, r27, r28"); test_display(&[0x7D, 0x7C, 0xEB, 0x96], "divwu r11, r28, r29"); test_display(&[0x7D, 0x7D, 0x5B, 0x96], "divwu r11, r29, r11"); test_display(&[0x7F, 0xEB, 0xE3, 0x96], "divwu r31, r11, r28"); test_display(&[0x7F, 0xFE, 0x5B, 0xD6], "divw r31, r30, r11"); } #[test] fn xenia_compare() { test_xenon_le(&[0x71, 0x6b, 0xff, 0xef], "fres. fr31, fr13"); test_display(&[0xd2, 0x00, 0xe3, 0xb3], "stfs fr16, -0x1c4d"); test_display(&[0xd5, 0xbe, 0x20, 0x48], "stfsu fr13, 0x2048(r30)"); test_display(&[0xdd, 0x94, 0x0d, 0x48], "stfdu fr12, 0xd48(r20)"); test_display(&[0xd9, 0x95, 0xf1, 0x4b], "stfd fr12, -0xeb5(r21)"); test_display(&[0xc8, 0x05, 0x7f, 0x91], "lfd fr0, 0x7f91(r5)"); test_display(&[0xcc, 0x00, 0x81, 0xc3], "lfdu fr0, -0x7e3d"); test_display(&[0xc4, 0xff, 0x2b, 0xc0], "lfsu fr7, 0x2bc0(r31)"); // xenia would call this "addis r7, r31, -0xb5", but we know about assembler aliases :3 test_display(&[0x3c, 0xff, 0xff, 0x4b], "subis r7, r31, 181"); // and same but "addis -0x170' vs "subis 368" test_display(&[0x3c, 0xff, 0xfe, 0x90], "subis r7, r31, 368"); test_display_vmx128(&[0x15, 0x5a, 0x69, 0x7d], "vnmsubfp128 vr106, vr58, vr106, vr45"); test_display_vmx128(&[0x18, 0x58, 0xa0, 0xff], "vslw128 vr98, vr56, vr116"); test_display_vmx128(&[0x18, 0x01, 0x83, 0x80], "vupkhsb128 vr0, vr16"); test_display_vmx128(&[0x18, 0x03, 0x7f, 0xc1], "vupklsb128 vr0, vr47"); test_xenon_le(&[0x80, 0x44, 0x14, 0x10], "vsubuwm vr0, vr20, vr8"); test_xenon_le(&[0x40, 0x98, 0x02, 0x10], "vadduhm vr0, vr2, vr19"); test_xenon_le(&[0x80, 0x74, 0x00, 0x10], "vsubuwm vr0, vr0, vr14"); test_display_vmx128(&[0x10, 0xca, 0xa0, 0xfd], "vsldoi128 vr102, vr42, vr52, 3"); test_display_vmx128(&[0x10, 0xca, 0xa0, 0xfd], "vsldoi128 vr102, vr42, vr52, 3"); test_display_vmx128(&[0x10, 0x01, 0xc1, 0x83], "stvewx128 vr0, r1, r24"); test_display_vmx128(&[0x7c, 0x00, 0x06, 0x0e], "lvlxl vr0, 0, r0"); test_display_vmx128(&[0x7c, 0x00, 0x06, 0x4e], "lvrxl vr0, 0, r0"); // under any decoder, really, but.. let decoder_all = InstDecoder::for_cpu(IsaVersion::All).with_be(false); let decoder_p201 = InstDecoder::for_cpu(IsaVersion::V2_01).with_be(false); let decoder_xenon = InstDecoder::for_cpu(IsaVersion::Xenon).with_be(false); let decoder_amazon = InstDecoder::for_cpu(IsaVersion::Amazon).with_be(false); test_invalid_under(&decoder_xenon, &[0x81, 0x2b, 0x00, 0x10]); test_invalid_under(&decoder_all, &[0x81, 0x2b, 0x00, 0x10]); test_display_under(&decoder_all, &[0x0e, 0x06, 0x00, 0x7c], "stvepxl vr0, 0, r0"); test_display_under(&decoder_all, &[0x4e, 0x06, 0x00, 0x7c], "stvepx vr0, 0, r0"); test_not_xenon_le(&[0xe4, 0x31, 0x0a, 0x7c], "mtsrin r0, r6"); test_not_xenon_le(&[0xe4, 0x30, 0x0a, 0x7c], "mtsrdin r0, r6"); test_not_xenon_le(&[0x6c, 0xbb, 0x38, 0x7c], "ecowx r1, r24, r23"); test_not_xenon_le(&[0x6c, 0xba, 0x38, 0x7c], "eciwx r1, r24, r23"); test_not_xenon_le(&[0x64, 0xba, 0x38, 0x7c], "tlbie r23, r1"); test_not_xenon_le(&[0xe4, 0xba, 0x38, 0x7c], "tlbia"); test_not_xenon_le(&[0x6c, 0xbc, 0x38, 0x7c], "tlbsync"); test_xenon_le(&[0xce, 0x6a, 0x11, 0x7c], "lvxl vr0, r17, r13"); test_xenon_le(&[0xce, 0x6b, 0x11, 0x7c], "stvxl vr0, r17, r13"); test_xenon_le(&[0x75, 0xf0, 0x0e, 0x7c], "cntlzd. r14, r0"); test_display_under(&decoder_xenon, &[0x2c, 0xd1, 0x0e, 0x7c], "stwcx. r0, r14, r26"); test_display_under(&decoder_all, &[0x2c, 0xd1, 0x0e, 0x7c], "stwcx. r0, r14, r26"); test_invalid_under(&InstDecoder::for_cpu(IsaVersion::PowerPC).with_be(false), &[0x2c, 0xd1, 0x0e, 0x7c]); test_xenon_le(&[0x2d, 0xd1, 0x0e, 0x7c], "stwcx. r0, r14, r26"); test_xenon_le(&[0x30, 0x7c, 0x0e, 0x7c], "srw r14, r0, r15"); test_xenon_le(&[0x31, 0x38, 0x09, 0x7c], "slw. r9, r0, r7"); test_xenon_le(&[0xae, 0xf7, 0x0b, 0x7c], "stfiwx fr0, r11, r30"); test_display_under(&decoder_xenon, &[0x24, 0xb1, 0x0c, 0x7c], "mtmsr r0"); test_display_under(&decoder_all, &[0x24, 0xb1, 0x0c, 0x7c], "mtmsr r0"); test_display_under(&decoder_xenon, &[0x64, 0x39, 0x0c, 0x7c], "mtmsrd r0"); test_display_under(&decoder_all, &[0x64, 0x39, 0x0c, 0x7c], "mtmsrd r0"); test_display_under(&decoder_amazon, &[0x64, 0x01, 0x41, 0x7d], "mtmsrd r10, 1"); test_display_under(&decoder_xenon, &[0x64, 0x01, 0x41, 0x7d], "mtmsree r10"); test_display_under(&decoder_p201, &[0x64, 0x01, 0x41, 0x7d], "mtmsrd r10, 1"); test_display_under(&decoder_xenon, &[0xac, 0x04, 0x00 ,0x7c], "sync"); test_display_under(&decoder_all, &[0xac, 0x04, 0x00 ,0x7c], "hwsync"); test_xenon_le(&[0x88, 0x60, 0x0d, 0x7c], "td 0, r13, r12"); test_xenon_le(&[0x8f, 0x05, 0xfe, 0xfd], "mtfsf. 0xff, fr0"); test_xenon_le(&[0x8f, 0x1c, 0x02, 0xfe], "mffs. fr16"); test_display_under(&decoder_xenon, &[0x8f, 0x55, 0x05, 0xfc], "mtfsf. 2, fr10"); test_display_under(&decoder_all, &[0x8f, 0x55, 0x05, 0xfc], "mtfsf. 2, fr10, 0, 1"); } #[test] fn cell_compare() { test_cell_le(&[0xac, 0x1a, 0x25, 0x7c], "dst r5, r3, 1"); test_cell_le(&[0xac, 0x1a, 0x25, 0x7e], "dstt r5, r3, 1"); test_cell_le(&[0xec, 0x1a, 0x25, 0x7c], "dstst r5, r3, 1"); test_cell_le(&[0xec, 0x1a, 0x25, 0x7e], "dststt r5, r3, 1"); test_cell_le(&[0x6c, 0x1e, 0x25, 0x7c], "dss 1"); test_cell_le(&[0x6c, 0x1e, 0x25, 0x7e], "dssall 1"); // the Cell Broadband Engine Architecture allegedly mentions running hrfid, and objdump // supports it, so this all substantiates the notion that the PS3 operates runs a hypervisor // and applications are guests in it. so hrfid works, but wouldn't run in the unprivileged // context. test_cell_le(&[0x24, 0x02, 0x00, 0x4c], "hrfid"); } #[test] fn ppc32_loads() { let rios = InstDecoder::for_cpu(IsaVersion::RIOS).with_be(false); let p203 = InstDecoder::for_cpu(IsaVersion::V2_03).with_be(false); test_display(&[0x7c, 0x64, 0x26, 0x6e], "lfqux fr3, r4, r4"); test_display(&[0x81, 0x66, 0x01, 0x24], "lwz r11, 0x124(r6)"); test_display(&[0x7C, 0x00, 0x1C, 0x0E], "lvlx vr0, 0, r3"); test_display(&[0x7C, 0x00, 0x20, 0x0C], "lvsl vr0, 0, r4"); test_display(&[0x7C, 0x34, 0x10, 0x0C], "lvsl vr1, r20, r2"); test_display(&[0x7C, 0x00, 0x50, 0x8E], "lvewx vr0, 0, r10"); test_display(&[0x7F, 0xFF, 0x00, 0x0E], "lvebx vr31, r31, r0"); test_display(&[0x7C, 0x05, 0x54, 0x2E], "lfsx fr0, r5, r10"); test_display(&[0x7C, 0x0A, 0xF4, 0xAE], "lfdx fr0, r10, r30"); test_display(&[0x7C, 0x0A, 0xFC, 0x2E], "lfsx fr0, r10, r31"); test_display(&[0x7C, 0x0B, 0x1C, 0x2E], "lfsx fr0, r11, r3"); test_display(&[0x7C, 0x0B, 0x1C, 0x4E], "lvrx vr0, r11, r3"); test_display(&[0x7C, 0x0C, 0x00, 0x2E], "lwzx r0, r12, r0"); // this should be "lx" but it's really just a mnemonic difference across POWER/POWER2 and later // implementations. so we'll accept lwzx here.. test_display_under(&rios, &[0x2e, 0x28, 0x64, 0x7c], "lwzx r3, r4, r5"); test_display(&[0x7C, 0x0C, 0x02, 0x2E], "lhzx r0, r12, r0"); test_display(&[0x7C, 0x0C, 0x50, 0xAE], "lbzx r0, r12, r10"); test_display(&[0x7C, 0x1A, 0xCC, 0x4E], "lvrx vr0, r26, r25"); test_display(&[0x7C, 0x20, 0x04, 0xAC], "lwsync"); test_display(&[0x7C, 0x20, 0x20, 0xCE], "lvx vr1, 0, r4"); test_display(&[0x7C, 0x3F, 0x9C, 0x2E], "lfsx fr1, r31, r19"); test_display(&[0x7C, 0x40, 0x44, 0x0E], "lvlx vr2, 0, r8"); test_display(&[0x7C, 0x40, 0x58, 0x8E], "lvewx vr2, 0, r11"); test_display(&[0x7C, 0x44, 0x34, 0x2E], "lfsx fr2, r4, r6"); test_display(&[0x7C, 0x46, 0x20, 0xCE], "lvx vr2, r6, r4"); // lwarx (and others) get an EH hint in 2.05, so test both forms here.. test_display_under(&p203, &[0x28, 0x50, 0x60, 0x7C], "lwarx r3, 0, r10"); test_display(&[0x7C, 0x60, 0x50, 0x28], "lwarx r3, 0, r10, 0"); test_display(&[0x7C, 0x60, 0x50, 0x8E], "lvewx vr3, 0, r10"); test_display(&[0x7C, 0x60, 0x5C, 0x2C], "lwbrx r3, 0, r11"); test_display(&[0x7C, 0x61, 0x60, 0x2E], "lwzx r3, r1, r12"); test_display(&[0x7C, 0x61, 0x62, 0x2E], "lhzx r3, r1, r12"); test_display(&[0x7C, 0x63, 0x40, 0xAE], "lbzx r3, r3, r8"); test_display(&[0x7C, 0x63, 0x48, 0x2A], "ldx r3, r3, r9"); test_display(&[0x7C, 0x80, 0xE8, 0x4C], "lvsr vr4, 0, r29"); test_display(&[0x7C, 0x80, 0xF0, 0x4C], "lvsr vr4, 0, r30"); test_display(&[0x7C, 0x88, 0x20, 0xCE], "lvx vr4, r8, r4"); test_display(&[0x7C, 0x88, 0x38, 0xAE], "lbzx r4, r8, r7"); test_display(&[0x7C, 0x88, 0x48, 0x2E], "lwzx r4, r8, r9"); test_display(&[0x7C, 0x88, 0x4C, 0x2E], "lfsx fr4, r8, r9"); test_display(&[0x7C, 0xA0, 0x7C, 0x2C], "lwbrx r5, 0, r15"); // lwarx (and others) get an EH hint in 2.05, so test both forms here.. test_display_under(&p203, &[0x28, 0xF0, 0xA0, 0x7C], "lwarx r5, 0, r30"); test_display(&[0x7C, 0xA0, 0xF0, 0x28], "lwarx r5, 0, r30, 0"); test_display(&[0x7C, 0xA0, 0xF0, 0x8E], "lvewx vr5, 0, r30"); test_display(&[0x7C, 0xA0, 0xF4, 0x0E], "lvlx vr5, 0, r30"); test_display(&[0x7C, 0xA0, 0xF8, 0x0C], "lvsl vr5, 0, r31"); test_display(&[0x7D, 0x9F, 0x4C, 0x2E], "lfsx fr12, r31, r9"); test_display(&[0x7D, 0x9F, 0x54, 0x2E], "lfsx fr12, r31, r10"); test_display(&[0x7D, 0x9F, 0x5C, 0x2E], "lfsx fr12, r31, r11"); test_display(&[0x7D, 0xA0, 0x1C, 0x0E], "lvlx vr13, 0, r3"); test_display(&[0x7D, 0xA0, 0x20, 0x0C], "lvsl vr13, 0, r4"); test_display(&[0x7F, 0xFF, 0xE0, 0x2E], "lwzx r31, r31, r28"); test_display(&[0x7F, 0xFF, 0xF0, 0x2E], "lwzx r31, r31, r30"); test_display(&[0x7F, 0xFF, 0xF4, 0x2E], "lfsx fr31, r31, r30"); test_display(&[0x80, 0x01, 0x00, 0x08], "lwz r0, 8(r1)"); test_display(&[0x80, 0x03, 0x01, 0x38], "lwz r0, 138h(r3)"); test_display(&[0x80, 0x61, 0x44, 0x70], "lwz r3, 4470h(r1)"); test_display(&[0x83, 0x7D, 0x00, 0x08], "lwz r27, 8(r29)"); test_display(&[0x83, 0xFF, 0xBD, 0x0C], "lwz r31, -42F4h(r31)"); test_display(&[0x84, 0x04, 0x00, 0x10], "lwzu r0, 10h(r4)"); test_display(&[0x84, 0x0B, 0xF0, 0x00], "lwzu r0, -1000h(r11)"); test_display(&[0x84, 0xE4, 0x00, 0x04], "lwzu r7, 4(r4)"); test_display(&[0x85, 0x3B, 0x00, 0x04], "lwzu r9, 4(r27)"); test_display(&[0x85, 0x5D, 0x00, 0x04], "lwzu r10, 4(r29)"); test_display(&[0x88, 0x04, 0x00, 0x00], "lbz r0, 0(r4)"); test_display(&[0x88, 0x04, 0xFF, 0xFF], "lbz r0, -1(r4)"); test_display(&[0x88, 0x61, 0x00, 0x50], "lbz r3, 50h(r1)"); test_display(&[0x88, 0x61, 0x00, 0x51], "lbz r3, 51h(r1)"); test_display(&[0x8B, 0xFF, 0x00, 0xFF], "lbz r31, 0FFh(r31)"); test_display(&[0x8C, 0xA3, 0x00, 0x01], "lbzu r5, 1(r3)"); test_display(&[0x8C, 0xA9, 0x00, 0x01], "lbzu r5, 1(r9)"); test_display(&[0x8C, 0xC3, 0x00, 0x01], "lbzu r6, 1(r3)"); test_display(&[0x8C, 0xC4, 0x00, 0x01], "lbzu r6, 1(r4)"); test_display(&[0x8C, 0xE4, 0x00, 0x01], "lbzu r7, 1(r4)"); test_display(&[0x8D, 0x04, 0x00, 0x01], "lbzu r8, 1(r4)"); test_display(&[0x8D, 0x0A, 0x00, 0x01], "lbzu r8, 1(r10)"); test_display(&[0xA0, 0x61, 0x00, 0x16], "lhz r3, 16h(r1)"); test_display(&[0xA0, 0x61, 0x00, 0x50], "lhz r3, 50h(r1)"); test_display(&[0xA0, 0x61, 0x00, 0x52], "lhz r3, 52h(r1)"); test_display(&[0xA3, 0xFF, 0x00, 0x0A], "lhz r31, 0Ah(r31)"); test_display(&[0xA3, 0xFF, 0x00, 0x20], "lhz r31, 20h(r31)"); test_display(&[0xA8, 0xBE, 0x00, 0x00], "lha r5, 0(r30)"); test_display(&[0xA8, 0xDF, 0x00, 0x24], "lha r6, 24h(r31)"); test_display(&[0xAA, 0xDD, 0x00, 0x06], "lha r22, 6(r29)"); test_display(&[0xAB, 0x4B, 0x00, 0x00], "lha r26, 0(r11)"); test_display(&[0xC0, 0x01, 0x00, 0x14], "lfs fr0, 14h(r1)"); test_display(&[0xC0, 0x01, 0x00, 0x1C], "lfs fr0, 1Ch(r1)"); test_display(&[0xC3, 0x7D, 0x00, 0x08], "lfs fr27, 8(r29)"); test_display(&[0xC3, 0x7D, 0x00, 0x10], "lfs fr27, 10h(r29)"); test_display(&[0xC3, 0xFF, 0x01, 0x74], "lfs fr31, 174h(r31)"); test_display(&[0xC8, 0x01, 0x00, 0x58], "lfd fr0, 58h(r1)"); test_display(&[0xC8, 0x01, 0x00, 0x60], "lfd fr0, 60h(r1)"); test_display(&[0xC9, 0x0B, 0x00, 0x70], "lfd fr8, 70h(r11)"); test_display(&[0xCB, 0xEC, 0xFF, 0xF8], "lfd fr31, -8(r12)"); test_display(&[0xCB, 0xFF, 0xFF, 0xF8], "lfd fr31, -8(r31)"); test_display(&[0xE8, 0x24, 0x00, 0x20], "ld r1, 20h(r4)"); test_display(&[0xE8, 0x27, 0x00, 0x90], "ld r1, 90h(r7)"); test_display(&[0xE8, 0xA1, 0x00, 0x50], "ld r5, 50h(r1)"); test_display(&[0xE8, 0xA1, 0x00, 0x52], "lwa r5, 50h(r1)"); test_display(&[0xE8, 0xAB, 0xFF, 0xFA], "lwa r5, -8(r11)"); test_display(&[0xE8, 0xAF, 0x00, 0x00], "ld r5, 0(r15)"); test_display(&[0xE8, 0xE4, 0x00, 0x00], "ld r7, 0(r4)"); test_display(&[0xE8, 0xE4, 0x00, 0x09], "ldu r7, 8(r4)"); } #[test] fn ppc32_vmx128() { test_display_vmx128(&[0x18, 0xC0, 0xFA, 0xC3], "vminfp128 vr6, vr0, vr127"); test_display_vmx128(&[0x10, 0x00, 0xA0, 0xC3], "lvx128 vr0, 0, r20"); test_display_vmx128(&[0x10, 0x01, 0x30, 0xCB], "lvx128 vr64, r1, r6"); test_display_vmx128(&[0x10, 0x01, 0x60, 0xC3], "lvx128 vr0, r1, r12"); test_display_vmx128(&[0x10, 0x03, 0x20, 0xC3], "lvx128 vr0, r3, r4"); test_display_vmx128(&[0x10, 0x03, 0x38, 0xCB], "lvx128 vr64, r3, r7"); test_display_vmx128(&[0x10, 0x03, 0x38, 0xCF], "lvx128 vr96, r3, r7"); test_display_vmx128(&[0x10, 0x03, 0x5A, 0xCB], "lvxl128 vr64, r3, r11"); test_display_vmx128(&[0x10, 0x03, 0x5A, 0xCF], "lvxl128 vr96, r3, r11"); test_display_vmx128(&[0x10, 0x03, 0xE8, 0xC3], "lvx128 vr0, r3, r29"); test_display_vmx128(&[0x10, 0x03, 0xF8, 0xC3], "lvx128 vr0, r3, r31"); test_display_vmx128(&[0x10, 0x28, 0x5A, 0xCB], "lvxl128 vr65, r8, r11"); test_display_vmx128(&[0x10, 0x28, 0x5A, 0xCF], "lvxl128 vr97, r8, r11"); test_display_vmx128(&[0x10, 0x2B, 0x60, 0xCB], "lvx128 vr65, r11, r12"); test_display_vmx128(&[0x10, 0x2B, 0x60, 0xCF], "lvx128 vr97, r11, r12"); test_display_vmx128(&[0x10, 0x46, 0x20, 0xC3], "lvx128 vr2, r6, r4"); test_display_vmx128(&[0x10, 0x46, 0x20, 0xC7], "lvx128 vr34, r6, r4"); test_display_vmx128(&[0x10, 0x49, 0x5A, 0xCB], "lvxl128 vr66, r9, r11"); test_display_vmx128(&[0x10, 0x49, 0x5A, 0xCF], "lvxl128 vr98, r9, r11"); test_display_vmx128(&[0x10, 0x4B, 0x60, 0xCB], "lvx128 vr66, r11, r12"); test_display_vmx128(&[0x10, 0x4B, 0x60, 0xCF], "lvx128 vr98, r11, r12"); test_display_vmx128(&[0x10, 0x4B, 0x90, 0xC3], "lvx128 vr2, r11, r18"); test_display_vmx128(&[0x10, 0x6A, 0x5A, 0xCB], "lvxl128 vr67, r10, r11"); test_display_vmx128(&[0x10, 0x6A, 0x5A, 0xCF], "lvxl128 vr99, r10, r11"); test_display_vmx128(&[0x10, 0x83, 0x38, 0xCB], "lvx128 vr68, r3, r7"); test_display_vmx128(&[0x10, 0x83, 0x38, 0xCF], "lvx128 vr100, r3, r7"); test_display_vmx128(&[0x10, 0x83, 0x5A, 0xCB], "lvxl128 vr68, r3, r11"); test_display_vmx128(&[0x10, 0x83, 0x5A, 0xCF], "lvxl128 vr100, r3, r11"); test_display_vmx128(&[0x11, 0x5F, 0xE0, 0xC3], "lvx128 vr10, r31, r28"); test_display_vmx128(&[0x11, 0x5F, 0xE8, 0xC3], "lvx128 vr10, r31, r29"); test_display_vmx128(&[0x11, 0x60, 0x18, 0xC3], "lvx128 vr11, 0, r3"); test_display_vmx128(&[0x11, 0x60, 0x20, 0xC3], "lvx128 vr11, 0, r4"); test_display_vmx128(&[0x13, 0xC9, 0x5A, 0xCF], "lvxl128 vr126, r9, r11"); test_display_vmx128(&[0x13, 0xE0, 0x40, 0xCF], "lvx128 vr127, 0, r8"); test_display_vmx128(&[0x13, 0xE0, 0x44, 0x07], "lvlx128 vr63, 0, r8"); test_display_vmx128(&[0x13, 0xE0, 0x48, 0xCF], "lvx128 vr127, 0, r9"); test_display_vmx128(&[0x13, 0xFF, 0xE8, 0xCF], "lvx128 vr127, r31, r29"); test_display_vmx128(&[0x10, 0x00, 0x00, 0xCE], "vpkuwus vr0, vr0, vr0"); test_display_vmx128(&[0x10, 0x00, 0x01, 0xCA], "vlogefp vr0, vr0"); test_display_vmx128(&[0x10, 0x00, 0x01, 0xCE], "vpkswss vr0, vr0, vr0"); test_display_vmx128(&[0x10, 0x00, 0x02, 0x0C], "vspltb vr0, vr0, 0"); test_display_vmx128(&[0x10, 0x50, 0x02, 0x0C], "vspltb vr2, vr0, 0"); test_display_vmx128(&[0x10, 0x00, 0x61, 0x0A], "vrefp vr0, vr12"); test_display_vmx128(&[0x13, 0xd6, 0xf1, 0x02], "vmaxsb vr30, vr22, vr30"); test_display_vmx128(&[0x10, 0x00, 0x61, 0x82], "vmaxsw vr0, vr0, vr12"); test_display_vmx128(&[0x10, 0x00, 0x62, 0x0A], "vrfin vr0, vr12"); test_display_vmx128(&[0x10, 0x00, 0x63, 0x84], "vsraw vr0, vr0, vr12"); test_display_vmx128(&[0x10, 0x00, 0x64, 0x86], "vcmpequw. vr0, vr0, vr12"); test_display_vmx128(&[0x10, 0x00, 0x68, 0x40], "vadduhm vr0, vr0, vr13"); test_display_vmx128(&[0x10, 0x00, 0x69, 0x8A], "vexptefp vr0, vr13"); test_display_vmx128(&[0x10, 0x00, 0x6A, 0x4C], "vsplth vr0, vr13, 0"); test_display_vmx128(&[0x10, 0x00, 0x6B, 0x84], "vsraw vr0, vr0, vr13"); test_display_vmx128(&[0x10, 0x00, 0x6C, 0x40], "vsubuhm vr0, vr0, vr13"); test_display_vmx128(&[0x10, 0x08, 0x01, 0x4C], "vmrglh vr0, vr8, vr0"); test_display_vmx128(&[0x10, 0x0B, 0x02, 0x80], "vadduws vr0, vr11, vr0"); test_display_vmx128(&[0x10, 0x0C, 0x01, 0x04], "vslb vr0, vr12, vr0"); test_display_vmx128(&[0x10, 0x0C, 0x05, 0xC6], "vcmpgefp. vr0, vr12, vr0"); test_display_vmx128(&[0x10, 0x10, 0x03, 0x8A], "vctuxs vr0, vr0, 16"); test_display_vmx128(&[0x10, 0x40, 0x22, 0x0E], "vupkhsb vr2, vr4"); test_display_vmx128(&[0x10, 0x40, 0x51, 0x8A], "vexptefp vr2, vr10"); test_display_vmx128(&[0x10, 0x40, 0x61, 0xCA], "vlogefp vr2, vr12"); test_display_vmx128(&[0x10, 0x40, 0xF2, 0x0E], "vupkhsb vr2, vr30"); test_display_vmx128(&[0x10, 0x4D, 0x01, 0xC6], "vcmpgefp vr2, vr13, vr0"); test_display_vmx128(&[0x10, 0x60, 0xEA, 0x8E], "vupklsb vr3, vr29"); test_display_vmx128(&[0x10, 0x64, 0x68, 0x0C], "vmrghb vr3, vr4, vr13"); test_display_vmx128(&[0x10, 0x84, 0x69, 0x0C], "vmrglb vr4, vr4, vr13"); test_display_vmx128(&[0x10, 0x8D, 0x25, 0x02], "vavgsb vr4, vr13, vr4"); test_display_vmx128(&[0x10, 0x00, 0x04, 0x82], "vavguw vr0, vr0, vr0"); test_display_vmx128(&[0x10, 0xA0, 0x1A, 0x8E], "vupklsb vr5, vr3"); test_display_vmx128(&[0x10, 0xC0, 0x62, 0x0E], "vupkhsb vr6, vr12"); test_display_vmx128(&[0x10, 0xCC, 0x59, 0x8C], "vmrglw vr6, vr12, vr11"); test_display_vmx128(&[0x10, 0xE0, 0x3A, 0x4C], "vsplth vr7, vr7, 0"); test_display_vmx128(&[0x11, 0x00, 0x41, 0x0A], "vrefp vr8, vr8"); test_display_vmx128(&[0x11, 0x00, 0x45, 0x42], "vavgsh vr8, vr0, vr8"); test_display_vmx128(&[0x11, 0x20, 0x02, 0x4A], "vrfiz vr9, vr0"); test_display_vmx128(&[0x11, 0x28, 0x4D, 0xC6], "vcmpgefp. vr9, vr8, vr9"); test_display_vmx128(&[0x11, 0x2D, 0x4A, 0xC4], "vsr vr9, vr13, vr9"); test_display_vmx128(&[0x11, 0x2D, 0x60, 0x4A], "vsubfp vr9, vr13, vr12"); test_display_vmx128(&[0x11, 0x40, 0x01, 0x0A], "vrefp vr10, vr0"); test_display_vmx128(&[0x11, 0x40, 0x52, 0x4A], "vrfiz vr10, vr10"); test_display_vmx128(&[0x11, 0x40, 0x62, 0xCA], "vrfim vr10, vr12"); test_display_vmx128(&[0x11, 0x4B, 0x21, 0x84], "vslw vr10, vr11, vr4"); test_display_vmx128(&[0x11, 0x4B, 0x41, 0x2C], "vsldoi vr10, vr11, vr8, 4"); test_display_vmx128(&[0x11, 0x60, 0x01, 0x0A], "vrefp vr11, vr0"); test_display_vmx128(&[0x11, 0x62, 0x4C, 0x04], "vand vr11, vr2, vr9"); test_display_vmx128(&[0x11, 0x68, 0x38, 0x0A], "vaddfp vr11, vr8, vr7"); test_display_vmx128(&[0x11, 0x6A, 0x6C, 0x0A], "vmaxfp vr11, vr10, vr13"); test_display_vmx128(&[0x11, 0x6C, 0x5A, 0xC4], "vsr vr11, vr12, vr11"); test_display_vmx128(&[0x11, 0x6D, 0x04, 0x0A], "vmaxfp vr11, vr13, vr0"); test_display_vmx128(&[0x11, 0x6D, 0x64, 0x4A], "vminfp vr11, vr13, vr12"); test_display_vmx128(&[0x11, 0x7F, 0x03, 0x8C], "vspltisw vr11, -0x1"); test_display_vmx128(&[0x11, 0x80, 0x41, 0x4A], "vrsqrtefp vr12, vr8"); test_display_vmx128(&[0x11, 0x80, 0x52, 0x46], "vcmpgtuh vr12, vr0, vr10"); test_display_vmx128(&[0x11, 0x80, 0x62, 0x0A], "vrfin vr12, vr12"); test_display_vmx128(&[0x11, 0x80, 0x6E, 0xC6], "vcmpgtfp. vr12, vr0, vr13"); test_display_vmx128(&[0x11, 0x81, 0x03, 0x0C], "vspltisb vr12, 1"); test_display_vmx128(&[0x11, 0x84, 0x03, 0x8C], "vspltisw vr12, 4"); test_display_vmx128(&[0x11, 0x88, 0x1C, 0x44], "vandc vr12, vr8, vr3"); test_display_vmx128(&[0x11, 0x89, 0x6A, 0xAA], "vsel vr12, vr9, vr13, vr10"); test_display_vmx128(&[0x11, 0x8A, 0x4C, 0x84], "vor vr12, vr10, vr9"); test_display_vmx128(&[0x11, 0x8A, 0x6A, 0xC6], "vcmpgtfp vr12, vr10, vr13"); test_display_vmx128(&[0x11, 0x8B, 0x62, 0xC4], "vsr vr12, vr11, vr12"); test_display_vmx128(&[0x11, 0x8D, 0x5C, 0x04], "vand vr12, vr13, vr11"); test_display_vmx128(&[0x11, 0x9E, 0xF8, 0x00], "vaddubm vr12, vr30, vr31"); test_display_vmx128(&[0x11, 0xA0, 0x5A, 0x46], "vcmpgtuh vr13, vr0, vr11"); test_display_vmx128(&[0x11, 0xA0, 0x61, 0x4A], "vrsqrtefp vr13, vr12"); test_display_vmx128(&[0x11, 0xA0, 0x64, 0x4A], "vminfp vr13, vr0, vr12"); test_display_vmx128(&[0x11, 0xA0, 0x6B, 0x8A], "vctuxs vr13, vr13, 0"); test_display_vmx128(&[0x11, 0xA1, 0x10, 0x8C], "vmrghw vr13, vr1, vr2"); test_display_vmx128(&[0x11, 0xA5, 0x54, 0xC4], "vxor vr13, vr5, vr10"); test_display_vmx128(&[0x11, 0xA7, 0x03, 0x0C], "vspltisb vr13, 7"); test_display_vmx128(&[0x11, 0xA9, 0x02, 0xC6], "vcmpgtfp vr13, vr9, vr0"); test_display_vmx128(&[0x11, 0xA9, 0x59, 0xC6], "vcmpgefp vr13, vr9, vr11"); test_display_vmx128(&[0x11, 0xAB, 0x04, 0x86], "vcmpequw. vr13, vr11, vr0"); test_display_vmx128(&[0x11, 0xAB, 0x51, 0x8C], "vmrglw vr13, vr11, vr10"); test_display_vmx128(&[0x11, 0xAD, 0x60, 0x40], "vadduhm vr13, vr13, vr12"); test_display_vmx128(&[0x13, 0x00, 0x3A, 0xCE], "vupklsh vr24, vr7"); test_display_vmx128(&[0x13, 0x1F, 0x5B, 0x0A], "vcfux vr24, vr11, 31"); test_display_vmx128(&[0x13, 0x4F, 0x70, 0x4C], "vmrghh vr26, vr15, vr14"); test_display_vmx128(&[0x13, 0x60, 0xD3, 0xCA], "vctsxs vr27, vr26, 0"); test_display_vmx128(&[0x13, 0x73, 0x90, 0x4C], "vmrghh vr27, vr19, vr18"); test_display_vmx128(&[0x13, 0xA0, 0x62, 0x4E], "vupkhsh vr29, vr12"); test_display_vmx128(&[0x13, 0xA7, 0x2A, 0x84], "vsrw vr29, vr7, vr5"); test_display_vmx128(&[0x13, 0xAC, 0x48, 0x80], "vadduwm vr29, vr12, vr9"); test_display_vmx128(&[0x13, 0xB8, 0x00, 0x00], "vaddubm vr29, vr24, vr0"); test_display_vmx128(&[0x13, 0xC6, 0x2A, 0x84], "vsrw vr30, vr6, vr5"); test_display_vmx128(&[0x13, 0xC8, 0x53, 0x4A], "vcfsx vr30, vr10, 8"); test_display_vmx128(&[0x13, 0xCB, 0x69, 0x6E], "vmaddfp vr30, vr11, vr5, vr13"); test_display_vmx128(&[0x13, 0xD9, 0x00, 0x00], "vaddubm vr30, vr25, vr0"); test_display_vmx128(&[0x13, 0xE0, 0x01, 0x04], "vslb vr31, vr0, vr0"); test_display_vmx128(&[0x13, 0xE0, 0x48, 0xC6], "vcmpeqfp vr31, vr0, vr9"); test_display_vmx128(&[0x13, 0xE2, 0x2A, 0x8C], "vspltw vr31, vr5, 2"); test_display_vmx128(&[0x13, 0xE9, 0x01, 0x2B], "vperm vr31, vr9, vr0, vr4"); test_display_vmx128(&[0x13, 0xE9, 0x61, 0x6B], "vperm vr31, vr9, vr12, vr5"); test_display_vmx128(&[0x13, 0xEC, 0x59, 0xEB], "vperm vr31, vr12, vr11, vr7"); test_display_vmx128(&[0x13, 0xEC, 0x62, 0x2C], "vsldoi vr31, vr12, vr12, 8"); test_display_vmx128(&[0x13, 0xFC, 0xBC, 0xEF], "vnmsubfp vr31, vr28, vr19, vr23"); test_display_vmx128(&[0x13, 0xFF, 0x60, 0xAC], "vsldoi vr31, vr31, vr12, 2"); test_display_vmx128(&[0x13, 0xFF, 0xBA, 0xAE], "vmaddfp vr31, vr31, vr10, vr23"); test_display_vmx128(&[0x14, 0x00, 0xF9, 0xD3], "vmsum4fp128 vr0, vr0, vr127"); test_display_vmx128(&[0x14, 0x06, 0x61, 0x90], "vmsum3fp128 vr0, vr6, vr12"); test_display_vmx128(&[0x14, 0x1C, 0xED, 0x33], "vmaddcfp128 vr0, vr124, vr0, vr125"); test_display_vmx128(&[0x14, 0x3E, 0xEF, 0x33], "vxor128 vr1, vr126, vr125"); test_display_vmx128(&[0x14, 0x68, 0x01, 0x90], "vmsum3fp128 vr3, vr8, vr0"); test_display_vmx128(&[0x15, 0x4C, 0xF0, 0xD3], "vmaddfp128 vr10, vr12, vr126, vr10"); test_display_vmx128(&[0x15, 0x8A, 0xD2, 0x13], "vand128 vr12, vr10, vr122"); test_display_vmx128(&[0x15, 0xAD, 0xE8, 0x13], "vaddfp128 vr13, vr13, vr125"); test_display_vmx128(&[0x15, 0xB7, 0xBE, 0xD2], "vor128 vr13, vr87, vr87"); test_display_vmx128(&[0x15, 0xBC, 0xED, 0x33], "vmaddcfp128 vr13, vr124, vr13, vr125"); test_display_vmx128(&[0x15, 0xBF, 0x05, 0xB0], "vmsum3fp128 vr13, vr127, vr0"); test_display_vmx128(&[0x15, 0xBF, 0x56, 0x30], "vand128 vr13, vr127, vr10"); test_display_vmx128(&[0x15, 0xBF, 0x65, 0x30], "vmaddcfp128 vr13, vr127, vr13, vr12"); test_display_vmx128(&[0x15, 0xBF, 0xFF, 0x33], "vxor128 vr13, vr127, vr127"); test_display_vmx128(&[0x17, 0x7B, 0xE0, 0x25], "vperm128 vr59, vr59, vr60, vr0"); test_display_vmx128(&[0x17, 0x9E, 0x04, 0x3C], "vaddfp128 vr124, vr126, vr0"); test_display_vmx128(&[0x17, 0xBE, 0x04, 0x7C], "vsubfp128 vr125, vr126, vr0"); test_display_vmx128(&[0x17, 0xBE, 0x4C, 0x7C], "vsubfp128 vr125, vr126, vr9"); test_display_vmx128(&[0x17, 0xBF, 0xFE, 0xFF], "vor128 vr125, vr127, vr127"); test_display_vmx128(&[0x17, 0xC0, 0x58, 0x9C], "vmulfp128 vr126, vr0, vr11"); test_display_vmx128(&[0x17, 0xC0, 0x61, 0x1C], "vmaddcfp128 vr126, vr0, vr126, vr12"); test_display_vmx128(&[0x17, 0xC0, 0x6B, 0x5C], "vsel128 vr126, vr0, vr13, vr126"); test_display_vmx128(&[0x17, 0xDC, 0x04, 0xFC], "vmaddfp128 vr126, vr124, vr0, vr126"); test_display_vmx128(&[0x17, 0xE0, 0x68, 0x5C], "vsubfp128 vr127, vr0, vr13"); test_display_vmx128(&[0x17, 0xEB, 0x00, 0x1C], "vaddfp128 vr127, vr11, vr0"); test_display_vmx128(&[0x17, 0xEB, 0x5A, 0xDC], "vor128 vr127, vr11, vr11"); test_display_vmx128(&[0x17, 0xED, 0x03, 0x1C], "vxor128 vr127, vr13, vr0"); test_display_vmx128(&[0x17, 0xFD, 0x01, 0xC4], "vperm128 vr63, vr29, vr0, vr7"); test_display_vmx128(&[0x17, 0xFD, 0x5D, 0xF0], "vmsum4fp128 vr31, vr125, vr11"); test_display_vmx128(&[0x17, 0xFE, 0xE4, 0x7F], "vsubfp128 vr127, vr126, vr124"); test_display_vmx128(&[0x17, 0xFF, 0x00, 0x01], "vperm128 vr31, vr31, vr32, vr0"); test_display_vmx128(&[0x17, 0xFF, 0x61, 0xD0], "vmsum4fp128 vr31, vr31, vr12"); test_display_vmx128(&[0x17, 0xFF, 0x6C, 0xBC], "vmulfp128 vr127, vr127, vr13"); test_display_vmx128(&[0x17, 0xFF, 0xD8, 0x90], "vmulfp128 vr31, vr31, vr27"); test_display_vmx128(&[0x18, 0x0D, 0x0E, 0xD0], "vpkd3d128 vr0, vr1, 3, 1, 3"); test_display_vmx128(&[0x18, 0x1E, 0x04, 0xA0], "vcmpgefp128 vr0, vr126, vr0"); test_display_vmx128(&[0x18, 0x1E, 0x6C, 0xA0], "vcmpgefp128 vr0, vr126, vr13"); test_display_vmx128(&[0x18, 0x88, 0xFB, 0x43], "vmrglw128 vr4, vr8, vr127"); test_display_vmx128(&[0x18, 0xFE, 0xE7, 0x63], "vmrglw128 vr7, vr126, vr124"); test_display_vmx128(&[0x19, 0x00, 0xFA, 0x83], "vmaxfp128 vr8, vr0, vr127"); test_display_vmx128(&[0x19, 0x36, 0x66, 0x90], "vpkd3d128 vr9, vr12, 5, 2, 2"); test_display_vmx128(&[0x19, 0x5F, 0xFC, 0x23], "vcmpeqfp128 vr10, vr127, vr127"); test_display_vmx128(&[0x19, 0x61, 0x06, 0xD0], "vpkd3d128 vr11, vr0, 0, 1, 3"); test_display_vmx128(&[0x19, 0x8A, 0x6E, 0xD0], "vpkd3d128 vr12, vr13, 2, 2, 3"); test_display_vmx128(&[0x19, 0x9F, 0x6E, 0xE0], "vminfp128 vr12, vr127, vr13"); test_display_vmx128(&[0x19, 0xA0, 0xFA, 0xC3], "vminfp128 vr13, vr0, vr127"); test_display_vmx128(&[0x19, 0xA0, 0xFB, 0x73], "vrfin128 vr13, vr127"); test_display_vmx128(&[0x19, 0xA1, 0x06, 0xD0], "vpkd3d128 vr13, vr0, 0, 1, 3"); test_display_vmx128(&[0x19, 0xA1, 0xFF, 0x33], "vspltw128 vr13, vr127, 1"); test_display_vmx128(&[0x19, 0xA3, 0xC7, 0x32], "vspltw128 vr13, vr88, 3"); test_display_vmx128(&[0x19, 0xA3, 0xDF, 0x32], "vspltw128 vr13, vr91, 3"); test_display_vmx128(&[0x19, 0xAD, 0xFA, 0x43], "vcmpequw128. vr13, vr13, vr127"); test_display_vmx128(&[0x19, 0xAE, 0x5E, 0xD0], "vpkd3d128 vr13, vr11, 3, 2, 3"); test_display_vmx128(&[0x19, 0xB6, 0x06, 0x90], "vpkd3d128 vr13, vr0, 5, 2, 2"); test_display_vmx128(&[0x19, 0xB9, 0xBF, 0x23], "vmrghw128 vr13, vr121, vr119"); test_display_vmx128(&[0x19, 0xBF, 0x6C, 0xA0], "vcmpgefp128 vr13, vr127, vr13"); test_display_vmx128(&[0x19, 0xBF, 0x6E, 0xA0], "vmaxfp128 vr13, vr127, vr13"); test_display_vmx128(&[0x1B, 0x60, 0x63, 0x0C], "vmrghw128 vr123, vr0, vr12"); test_display_vmx128(&[0x1B, 0x80, 0x6B, 0x0C], "vmrghw128 vr124, vr0, vr13"); test_display_vmx128(&[0x1B, 0x89, 0x6B, 0x0C], "vmrghw128 vr124, vr9, vr13"); test_display_vmx128(&[0x1B, 0xA0, 0xFA, 0xFB], "vcuxwfp128 vr93, vr127, 0"); test_display_vmx128(&[0x1B, 0xBA, 0xD3, 0x5F], "vpermwi128 vr125, vr122, 186"); test_display_vmx128(&[0x1B, 0xC0, 0x07, 0x7C], "vspltisw128 vr126, 0"); test_display_vmx128(&[0x1B, 0xDF, 0x07, 0x7C], "vspltisw128 vr126, -1"); test_display_vmx128(&[0x1B, 0xC0, 0x17, 0xA4], "vupkhsb128 vr62, vr2"); test_display_vmx128(&[0x1B, 0xC0, 0x27, 0xE4], "vupklsb128 vr62, vr4"); test_display_vmx128(&[0x1B, 0xC7, 0xF2, 0xB5], "vcsxwfp128 vr62, vr62, 7"); test_display_vmx128(&[0x1B, 0xC7, 0xFA, 0xB1], "vcsxwfp128 vr30, vr63, 7"); test_display_vmx128(&[0x1B, 0xD4, 0xEF, 0xF0], "vupkd3d128 vr30, vr29, 5"); test_display_vmx128(&[0x1B, 0xDE, 0x6E, 0xAC], "vmaxfp128 vr126, vr126, vr13"); // test_display_vmx128(&[0x1B, 0xE0, 0x1F, 0xE4], "vupklsh128 vr63, vr3"); // TODO: missing? test_display_vmx128(&[0x1B, 0xE0, 0x6F, 0x3C], "vspltw128 vr127, vr13, 0"); test_display_vmx128(&[0x1B, 0xE1, 0x27, 0x34], "vspltw128 vr63, vr4, 1"); test_display_vmx128(&[0x1B, 0xE1, 0x5A, 0xD0], "vpermwi128 vr31, vr11, 97"); test_display_vmx128(&[0x1B, 0xE2, 0x57, 0x5C], "vrlimi128 vr127, vr10, 2, 1"); test_display_vmx128(&[0x1B, 0xE4, 0x07, 0xFC], "vupkd3d128 vr127, vr0, 1"); test_display_vmx128(&[0x1B, 0xE4, 0x8F, 0xD0], "vrlimi128 vr31, vr17, 4, 3"); test_display_vmx128(&[0x1B, 0xE6, 0x02, 0xCC], "vminfp128 vr127, vr6, vr0"); test_display_vmx128(&[0x1B, 0xE7, 0x6B, 0x1C], "vpermwi128 vr127, vr13, 135"); test_display_vmx128(&[0x1B, 0xE8, 0x07, 0x50], "vrlimi128 vr31, vr0, 8, 1"); test_display_vmx128(&[0x1B, 0xFF, 0x06, 0xEC], "vminfp128 vr127, vr127, vr0"); test_display_vmx128(&[0x1B, 0xFF, 0xFA, 0xB5], "vcsxwfp128 vr63, vr63, 31"); } #[test] fn test_opcodes() { assert_eq!(Opcode::EQV.to_string(), "eqv"); assert_eq!(Opcode::CRXOR.to_string(), "crxor"); assert_eq!(Opcode::DRSP.to_string(), "drsp"); assert_eq!(Opcode::DQUA.to_string(), "dqua"); assert_eq!(Opcode::TRECLAIM.to_string(), "treclaim"); }