use super::ppc_register_info::*;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum PpcOpcode {
ADD = 0,
ADDI,
SUBF,
MULLW,
MULLD,
DIVW,
DIVD,
NEG,
AND,
ANDC,
OR,
ORC,
XOR,
NAND,
NOR,
EQV,
EXTSB,
EXTSH,
EXTSW,
CNTLZW,
CNTLZD,
SLW,
SRW,
SRAW,
SLD,
SRD,
SRAD,
RLDICL,
RLDICR,
RLDIMI,
LWZ,
LWZU,
STW,
STWU,
LD,
LDU,
STD,
STDU,
LHZ,
LHA,
LBZ,
STH,
STB,
LMW,
STMW,
B,
BL,
BA,
BLA,
BC,
BCL,
BCTR,
BCLR,
BCCTR,
CMPW,
CMPD,
CMPWI,
CMPDI,
CRAND,
CROR,
CRXOR,
CRNAND,
CRNOR,
CREQV,
CRANDC,
CRORC,
MCRF,
MFCR,
MTCRF,
FADD,
FSUB,
FMUL,
FDIV,
FMADD,
FMSUB,
FNMADD,
FNMSUB,
FCMPU,
FCTIWZ,
FCFID,
LD64,
STD64,
LDARX,
STDCX,
MFSPR,
MTSPR,
LVX,
STVX,
VADDFP,
VMADDFP,
XXSPLTIB,
XXLXOR,
XVMADDADP,
NOP,
LI,
LIS,
MR,
MTLR,
MFLR,
MTCTR,
MFCTR,
CMPI,
CMPLI,
BDNZ,
BDZ,
XXMFACC,
XXMTACC,
XXSETACCZ,
XVI4GER,
XVI8GER,
XVI16GER,
XVF32GER,
XVF64GER,
PMXVI4GER8,
PMXVI8GER4,
PMXVF32GER,
PMXVF64GER,
XXMFACC_INTER4,
XXMFACC_INTER8,
XXMTACC_INTER4,
XXMTACC_INTER8,
PLD,
PSTD,
PLWZ,
PSTW,
PLI,
PADDI,
PADDIS,
PSUBIS,
PLFS,
PLFD,
PSTFS,
PSTFD,
PLHA,
PLHZ,
PLWA,
XSADDSP,
XSSUBSP,
XSMULSP,
XSDIVSP,
XSADDDP,
XSSUBDP,
XSMULDP,
XSDIVDP,
XSMADDASP,
XSMADDMSP,
XSMSUBASP,
XSMSUBMSP,
XSMADDADP,
XSMADDMDP,
XSMSUBADP,
XSMSUBMDP,
XVADDSP,
XVSUBSP,
XVMULSP,
XVDIVSP,
XVADDDP,
XVSUBDP,
XVMULDP,
XVDIVDP,
XVMADDASP,
XVMADDMSP,
XVMSUBASP,
XVMSUBMSP,
XVMADDMDP,
XVMSUBADP,
XVMSUBMDP,
DADD,
DSUB,
DMUL,
DDIV,
DCMPU,
DTSTDC,
DTSTDG,
FADD_BFP,
FSUB_BFP,
FMUL_BFP,
FDIV_BFP,
FSQRT_BFP,
FMADD_BFP,
FMSUB_BFP,
FNMADD_BFP,
FNMSUB_BFP,
FRSP,
FRDP,
FRIM,
FRIP,
FRIZ,
FRIN,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PpcOperandType {
RegDef,
RegUse1,
RegUse2,
RegBase,
RegStore,
Imm16,
UImm16,
Shamt,
BranchOffset,
JumpTarget,
FpReg,
CrField,
VrReg,
}
#[derive(Debug, Clone)]
pub struct PpcInstrDesc {
pub opcode: PpcOpcode,
pub mnemonic: String,
pub is_terminator: bool,
pub is_branch: bool,
pub is_call: bool,
pub is_return: bool,
pub may_load: bool,
pub may_store: bool,
pub has_side_effects: bool,
pub is_compare: bool,
pub is_commutative: bool,
pub is_cond_branch: bool,
pub operand_types: Vec<PpcOperandType>,
pub mc_opcode: u32,
}
pub struct PpcInstrInfo {
pub desc_map: HashMap<PpcOpcode, PpcInstrDesc>,
}
impl PpcInstrInfo {
pub fn new() -> Self {
let mut info = PpcInstrInfo {
desc_map: HashMap::new(),
};
info.register_all();
info
}
pub fn get_desc(&self, opcode: PpcOpcode) -> Option<&PpcInstrDesc> {
self.desc_map.get(&opcode)
}
pub fn get_mnemonic(&self, opcode: PpcOpcode) -> String {
self.desc_map
.get(&opcode)
.map(|d| d.mnemonic.clone())
.unwrap_or_else(|| "INVALID".into())
}
fn add(
&mut self,
opcode: PpcOpcode,
mnemonic: &str,
is_terminator: bool,
is_branch: bool,
is_call: bool,
is_return: bool,
may_load: bool,
may_store: bool,
has_side_effects: bool,
is_compare: bool,
is_commutative: bool,
is_cond_branch: bool,
operand_types: Vec<PpcOperandType>,
mc_opcode: u32,
) {
self.desc_map.insert(
opcode,
PpcInstrDesc {
opcode,
mnemonic: mnemonic.to_string(),
is_terminator,
is_branch,
is_call,
is_return,
may_load,
may_store,
has_side_effects,
is_compare,
is_commutative,
is_cond_branch,
operand_types,
mc_opcode,
},
);
}
fn register_all(&mut self) {
use PpcOperandType::*;
let r_alu = vec![RegDef, RegUse1, RegUse2];
self.add(
PpcOpcode::ADD,
"add",
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
r_alu.clone(),
0x1F,
);
self.add(
PpcOpcode::SUBF,
"subf",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
r_alu.clone(),
0x1F,
);
self.add(
PpcOpcode::MULLW,
"mullw",
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
r_alu.clone(),
0x1F,
);
self.add(
PpcOpcode::MULLD,
"mulld",
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
r_alu.clone(),
0x1F,
);
self.add(
PpcOpcode::DIVW,
"divw",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
r_alu.clone(),
0x1F,
);
self.add(
PpcOpcode::DIVD,
"divd",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
r_alu.clone(),
0x1F,
);
self.add(
PpcOpcode::AND,
"and",
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
r_alu.clone(),
0x1F,
);
self.add(
PpcOpcode::OR,
"or",
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
r_alu.clone(),
0x1F,
);
self.add(
PpcOpcode::XOR,
"xor",
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
r_alu.clone(),
0x1F,
);
self.add(
PpcOpcode::NOR,
"nor",
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
r_alu.clone(),
0x1F,
);
self.add(
PpcOpcode::ANDC,
"andc",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
r_alu.clone(),
0x1F,
);
self.add(
PpcOpcode::SLW,
"slw",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
r_alu.clone(),
0x1F,
);
self.add(
PpcOpcode::SRW,
"srw",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
r_alu.clone(),
0x1F,
);
self.add(
PpcOpcode::SRAW,
"sraw",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
r_alu.clone(),
0x1F,
);
let i_imm = vec![RegDef, RegUse1, Imm16];
self.add(
PpcOpcode::ADDI,
"addi",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
i_imm.clone(),
0x0E,
);
let i_load = vec![RegDef, RegBase, Imm16];
self.add(
PpcOpcode::LWZ,
"lwz",
false,
false,
false,
false,
true,
false,
false,
false,
false,
false,
i_load.clone(),
0x20,
);
self.add(
PpcOpcode::LBZ,
"lbz",
false,
false,
false,
false,
true,
false,
false,
false,
false,
false,
i_load.clone(),
0x22,
);
self.add(
PpcOpcode::LHZ,
"lhz",
false,
false,
false,
false,
true,
false,
false,
false,
false,
false,
i_load.clone(),
0x28,
);
self.add(
PpcOpcode::LHA,
"lha",
false,
false,
false,
false,
true,
false,
false,
false,
false,
false,
i_load.clone(),
0x2A,
);
self.add(
PpcOpcode::LD,
"ld",
false,
false,
false,
false,
true,
false,
false,
false,
false,
false,
i_load.clone(),
0x3A,
);
self.add(
PpcOpcode::LDU,
"ldu",
false,
false,
false,
false,
true,
false,
false,
false,
false,
false,
i_load.clone(),
0x3A,
);
let i_store = vec![RegStore, RegBase, Imm16];
self.add(
PpcOpcode::STW,
"stw",
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
i_store.clone(),
0x24,
);
self.add(
PpcOpcode::STB,
"stb",
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
i_store.clone(),
0x26,
);
self.add(
PpcOpcode::STH,
"sth",
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
i_store.clone(),
0x2C,
);
self.add(
PpcOpcode::STD,
"std",
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
i_store.clone(),
0x3E,
);
self.add(
PpcOpcode::STDU,
"stdu",
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
i_store.clone(),
0x3E,
);
let b_target = vec![BranchOffset];
self.add(
PpcOpcode::B,
"b",
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
b_target.clone(),
0x12,
);
self.add(
PpcOpcode::BL,
"bl",
true,
true,
true,
false,
false,
false,
false,
false,
false,
false,
b_target.clone(),
0x12,
);
let b_cond = vec![CrField, BranchOffset];
self.add(
PpcOpcode::BC,
"bc",
true,
true,
false,
false,
false,
false,
false,
false,
false,
true,
b_cond.clone(),
0x10,
);
self.add(
PpcOpcode::BCLR,
"bclr",
true,
true,
false,
true,
false,
false,
false,
false,
false,
false,
vec![CrField],
0x13,
);
self.add(
PpcOpcode::BCTR,
"bctr",
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
vec![],
0x13,
);
let cmp_reg = vec![CrField, RegUse1, RegUse2];
self.add(
PpcOpcode::CMPW,
"cmpw",
false,
false,
false,
false,
false,
false,
false,
true,
true,
false,
cmp_reg.clone(),
0x1F,
);
self.add(
PpcOpcode::CMPD,
"cmpd",
false,
false,
false,
false,
false,
false,
false,
true,
true,
false,
cmp_reg.clone(),
0x1F,
);
let cmp_imm = vec![CrField, RegUse1, Imm16];
self.add(
PpcOpcode::CMPWI,
"cmpwi",
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
cmp_imm.clone(),
0x0B,
);
self.add(
PpcOpcode::CMPDI,
"cmpdi",
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
cmp_imm.clone(),
0x0B,
);
let f_alu = vec![FpReg, FpReg, FpReg];
self.add(
PpcOpcode::FADD,
"fadd",
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
f_alu.clone(),
0x3F,
);
self.add(
PpcOpcode::FSUB,
"fsub",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
f_alu.clone(),
0x3F,
);
self.add(
PpcOpcode::FMUL,
"fmul",
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
f_alu.clone(),
0x3F,
);
self.add(
PpcOpcode::FDIV,
"fdiv",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
f_alu.clone(),
0x3F,
);
self.add(
PpcOpcode::FMADD,
"fmadd",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
vec![FpReg, FpReg, FpReg, FpReg],
0x3F,
);
self.add(
PpcOpcode::NOP,
"nop",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
vec![],
0x18,
);
self.add(
PpcOpcode::LI,
"li",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
vec![RegDef, Imm16],
0x0E,
);
self.add(
PpcOpcode::LIS,
"lis",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
vec![RegDef, Imm16],
0x0F,
);
self.add(
PpcOpcode::MR,
"mr",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
vec![RegDef, RegUse1],
0x1F,
);
self.add(
PpcOpcode::MTLR,
"mtlr",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
vec![RegUse1],
0x1F,
);
self.add(
PpcOpcode::MFLR,
"mflr",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
vec![RegDef],
0x1F,
);
self.add(
PpcOpcode::MTCTR,
"mtctr",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
vec![RegUse1],
0x1F,
);
self.add(
PpcOpcode::MFCTR,
"mfctr",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
vec![RegDef],
0x1F,
);
self.add(
PpcOpcode::CMPI,
"cmpi",
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
vec![RegUse1, RegUse2],
0x0B,
);
let v_alu = vec![VrReg, VrReg, VrReg];
self.add(
PpcOpcode::VADDFP,
"vaddfp",
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
v_alu.clone(),
0x04,
);
self.add(
PpcOpcode::VMADDFP,
"vmaddfp",
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
vec![VrReg, VrReg, VrReg, VrReg],
0x04,
);
for (mn, op) in &[
("xxmfacc", PpcOpcode::XXMFACC),
("xxmtacc", PpcOpcode::XXMTACC),
("xxsetaccz", PpcOpcode::XXSETACCZ),
("xvi4ger", PpcOpcode::XVI4GER),
("xvi8ger", PpcOpcode::XVI8GER),
("xvi16ger", PpcOpcode::XVI16GER),
("xvf32ger", PpcOpcode::XVF32GER),
("xvf64ger", PpcOpcode::XVF64GER),
("pmxvi4ger8", PpcOpcode::PMXVI4GER8),
("pmxvi8ger4", PpcOpcode::PMXVI8GER4),
("pmxvf32ger", PpcOpcode::PMXVF32GER),
("pmxvf64ger", PpcOpcode::PMXVF64GER),
] {
self.add(
*op,
mn,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
vec![],
0x04,
);
}
let prefixed: Vec<(&str, PpcOpcode, bool, bool)> = vec![
("pld", PpcOpcode::PLD, true, false),
("pstd", PpcOpcode::PSTD, false, true),
("plwz", PpcOpcode::PLWZ, true, false),
("pstw", PpcOpcode::PSTW, false, true),
("pli", PpcOpcode::PLI, false, false),
("paddi", PpcOpcode::PADDI, false, false),
("paddis", PpcOpcode::PADDIS, false, false),
("psubis", PpcOpcode::PSUBIS, false, false),
("plfs", PpcOpcode::PLFS, true, false),
("plfd", PpcOpcode::PLFD, true, false),
("pstfs", PpcOpcode::PSTFS, false, true),
("pstfd", PpcOpcode::PSTFD, false, true),
("plha", PpcOpcode::PLHA, true, false),
("plhz", PpcOpcode::PLHZ, true, false),
("plwa", PpcOpcode::PLWA, true, false),
];
for (mn, op, ld, st) in prefixed {
self.add(
op,
mn,
false,
false,
false,
false,
false,
false,
false,
ld,
st,
false,
vec![RegDef, Imm16],
0x01,
);
}
let vsx_simple: Vec<(&str, PpcOpcode)> = vec![
("xsaddsp", PpcOpcode::XSADDSP),
("xssubsp", PpcOpcode::XSSUBSP),
("xsmulsp", PpcOpcode::XSMULSP),
("xsdivsp", PpcOpcode::XSDIVSP),
("xsadddp", PpcOpcode::XSADDDP),
("xssubdp", PpcOpcode::XSSUBDP),
("xsmuldp", PpcOpcode::XSMULDP),
("xsdivdp", PpcOpcode::XSDIVDP),
("xsmaddasp", PpcOpcode::XSMADDASP),
("xsmaddmsp", PpcOpcode::XSMADDMSP),
("xsmsubasp", PpcOpcode::XSMSUBASP),
("xsmsubmsp", PpcOpcode::XSMSUBMSP),
("xsmaddadp", PpcOpcode::XSMADDADP),
("xsmaddmdp", PpcOpcode::XSMADDMDP),
("xsmsubadp", PpcOpcode::XSMSUBADP),
("xsmsubmdp", PpcOpcode::XSMSUBMDP),
("xvaddsp", PpcOpcode::XVADDSP),
("xvsubsp", PpcOpcode::XVSUBSP),
("xvmulsp", PpcOpcode::XVMULSP),
("xvdivsp", PpcOpcode::XVDIVSP),
("xvadddp", PpcOpcode::XVADDDP),
("xvsubdp", PpcOpcode::XVSUBDP),
("xvmuldp", PpcOpcode::XVMULDP),
("xvdivdp", PpcOpcode::XVDIVDP),
("xvmaddasp", PpcOpcode::XVMADDASP),
("xvmaddmsp", PpcOpcode::XVMADDMSP),
("xvmsubasp", PpcOpcode::XVMSUBASP),
("xvmsubmsp", PpcOpcode::XVMSUBMSP),
("xvmaddadp", PpcOpcode::XVMADDADP),
("xvmaddmdp", PpcOpcode::XVMADDMDP),
("xvmsubadp", PpcOpcode::XVMSUBADP),
("xvmsubmdp", PpcOpcode::XVMSUBMDP),
];
for (mn, op) in vsx_simple {
self.add(
op,
mn,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
vec![VrReg, VrReg, VrReg],
0x04,
);
}
for (mn, op) in &[
("dadd", PpcOpcode::DADD),
("dsub", PpcOpcode::DSUB),
("dmul", PpcOpcode::DMUL),
("ddiv", PpcOpcode::DDIV),
("dcmpu", PpcOpcode::DCMPU),
("dtstdc", PpcOpcode::DTSTDC),
("dtstdg", PpcOpcode::DTSTDG),
] {
self.add(
*op,
mn,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
vec![RegDef, RegUse1, RegUse2],
0x3F,
);
}
for (mn, op) in &[
("fadd", PpcOpcode::FADD_BFP),
("fsub", PpcOpcode::FSUB_BFP),
("fmul", PpcOpcode::FMUL_BFP),
("fdiv", PpcOpcode::FDIV_BFP),
("fsqrt", PpcOpcode::FSQRT_BFP),
("fmadd", PpcOpcode::FMADD_BFP),
("fmsub", PpcOpcode::FMSUB_BFP),
("fnmadd", PpcOpcode::FNMADD_BFP),
("fnmsub", PpcOpcode::FNMSUB_BFP),
("frsp", PpcOpcode::FRSP),
("frdp", PpcOpcode::FRDP),
("frim", PpcOpcode::FRIM),
("frip", PpcOpcode::FRIP),
("friz", PpcOpcode::FRIZ),
("frin", PpcOpcode::FRIN),
] {
self.add(
*op,
mn,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
vec![RegDef, RegUse1],
0x3F,
);
}
}
pub fn is_terminator(&self, opcode: PpcOpcode) -> bool {
self.desc_map
.get(&opcode)
.map(|d| d.is_terminator)
.unwrap_or(false)
}
pub fn is_branch(&self, opcode: PpcOpcode) -> bool {
self.desc_map
.get(&opcode)
.map(|d| d.is_branch)
.unwrap_or(false)
}
pub fn is_call(&self, opcode: PpcOpcode) -> bool {
self.desc_map
.get(&opcode)
.map(|d| d.is_call)
.unwrap_or(false)
}
pub fn is_return(&self, opcode: PpcOpcode) -> bool {
self.desc_map
.get(&opcode)
.map(|d| d.is_return)
.unwrap_or(false)
}
pub fn may_load(&self, opcode: PpcOpcode) -> bool {
self.desc_map
.get(&opcode)
.map(|d| d.may_load)
.unwrap_or(false)
}
pub fn may_store(&self, opcode: PpcOpcode) -> bool {
self.desc_map
.get(&opcode)
.map(|d| d.may_store)
.unwrap_or(false)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_all_opcodes_registered() {
let info = PpcInstrInfo::new();
assert!(info.get_desc(PpcOpcode::ADD).is_some());
assert!(info.get_desc(PpcOpcode::LWZ).is_some());
assert!(info.get_desc(PpcOpcode::STW).is_some());
assert!(info.get_desc(PpcOpcode::B).is_some());
assert!(info.get_desc(PpcOpcode::BL).is_some());
assert!(info.get_desc(PpcOpcode::BCLR).is_some());
assert!(info.get_desc(PpcOpcode::NOP).is_some());
}
#[test]
fn test_mnemonics() {
let info = PpcInstrInfo::new();
assert_eq!(info.get_mnemonic(PpcOpcode::ADD), "add");
assert_eq!(info.get_mnemonic(PpcOpcode::LWZ), "lwz");
assert_eq!(info.get_mnemonic(PpcOpcode::STW), "stw");
assert_eq!(info.get_mnemonic(PpcOpcode::B), "b");
assert_eq!(info.get_mnemonic(PpcOpcode::BL), "bl");
assert_eq!(info.get_mnemonic(PpcOpcode::BCLR), "bclr");
assert_eq!(info.get_mnemonic(PpcOpcode::NOP), "nop");
assert_eq!(info.get_mnemonic(PpcOpcode::LI), "li");
}
#[test]
fn test_terminators() {
let info = PpcInstrInfo::new();
assert!(info.is_terminator(PpcOpcode::B));
assert!(info.is_terminator(PpcOpcode::BCLR));
assert!(!info.is_terminator(PpcOpcode::ADD));
}
#[test]
fn test_calls() {
let info = PpcInstrInfo::new();
assert!(info.is_call(PpcOpcode::BL));
assert!(!info.is_call(PpcOpcode::B));
}
#[test]
fn test_returns() {
let info = PpcInstrInfo::new();
assert!(info.is_return(PpcOpcode::BCLR));
}
#[test]
fn test_load_store() {
let info = PpcInstrInfo::new();
assert!(info.may_load(PpcOpcode::LWZ));
assert!(info.may_load(PpcOpcode::LD));
assert!(info.may_store(PpcOpcode::STW));
assert!(info.may_store(PpcOpcode::STD));
}
#[test]
fn test_compare() {
let info = PpcInstrInfo::new();
let desc = info.get_desc(PpcOpcode::CMPW).unwrap();
assert!(desc.is_compare);
assert!(desc.is_commutative);
}
#[test]
fn test_pseudo() {
let info = PpcInstrInfo::new();
assert!(info.get_desc(PpcOpcode::NOP).is_some());
assert!(info.get_desc(PpcOpcode::LI).is_some());
assert!(info.get_desc(PpcOpcode::MR).is_some());
assert!(info.get_desc(PpcOpcode::MTLR).is_some());
}
#[test]
fn test_fpu() {
let info = PpcInstrInfo::new();
assert_eq!(info.get_mnemonic(PpcOpcode::FADD), "fadd");
assert_eq!(info.get_mnemonic(PpcOpcode::FSUB), "fsub");
}
#[test]
fn test_vmx() {
let info = PpcInstrInfo::new();
assert!(info.get_desc(PpcOpcode::VADDFP).is_some());
assert!(info.get_desc(PpcOpcode::VMADDFP).is_some());
}
}