use core::convert::From;
use core::{fmt, slice};
use capstone_sys::{
cs_m680x, cs_m680x_op, m680x_op_ext, m680x_op_idx, m680x_op_rel, m680x_op_type,
};
pub use capstone_sys::m680x_insn as M680xInsn;
pub use capstone_sys::m680x_reg as M680xReg;
pub use crate::arch::arch_builder::m680x::*;
use crate::arch::DetailsArchInsn;
use crate::instruction::{RegId, RegIdInt};
pub struct M680xInsnDetail<'a>(pub(crate) &'a cs_m680x);
impl_PartialEq_repr_fields!(M680xInsnDetail<'a> [ 'a ];
operands, flags
);
const M680X_FIRST_OP_IN_MNEM: u8 = 1;
const M680X_SECOND_OP_IN_MNEM: u8 = 2;
define_impl_bitmask!(
impl M680xInsnDetail<'a>;
flags: u8 = { |self_: &M680xInsnDetail| self_.0.flags }
test_mod = test_M680xInsnDetail;
=> is_first_op_in_mnem = M680X_FIRST_OP_IN_MNEM;
=> is_second_op_in_mnem = M680X_SECOND_OP_IN_MNEM;
);
#[derive(Clone, Debug)]
pub struct M680xOpIdx(pub(crate) m680x_op_idx);
impl_PartialEq_repr_fields!(M680xOpIdx [ ];
base_reg, offset_reg, offset, offset_addr, offset_bits, inc_dec, flags
);
impl Eq for M680xOpIdx {}
macro_rules! define_m680x_register_option_getter {
(
$( #[$enum_attr:meta] )*
=> $field:ident
) => {
$( #[$enum_attr] )*
pub fn $field(&self) -> Option<RegId> {
if (self.0).$field == M680xReg::M680X_REG_INVALID {
None
} else {
Some(RegId((self.0).$field as RegIdInt))
}
}
}
}
impl M680xOpIdx {
fn new(op_idx: &m680x_op_idx) -> Self {
M680xOpIdx(*op_idx)
}
define_m680x_register_option_getter!(
=> base_reg
);
define_m680x_register_option_getter!(
=> offset_reg
);
pub fn offset(&self) -> i16 {
self.0.offset
}
pub fn offset_addr(&self) -> u16 {
self.0.offset_addr
}
pub fn offset_bits(&self) -> u8 {
self.0.offset_bits
}
pub fn inc_dec(&self) -> i8 {
self.0.inc_dec
}
}
const M680X_IDX_INDIRECT: u8 = 1;
const M680X_IDX_NO_COMMA: u8 = 2;
const M680X_IDX_POST_INC_DEC: u8 = 4;
define_impl_bitmask!(
impl M680xOpIdx<>;
flags: u8 = { |self_: &M680xOpIdx| self_.0.flags }
test_mod = test_M680xOpIdx;
=> is_indirect = M680X_IDX_INDIRECT;
=> is_no_comma = M680X_IDX_NO_COMMA;
=> is_post_inc_dec = M680X_IDX_POST_INC_DEC;
);
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum M680xOperandType {
Reg(RegId),
Imm(i32),
Indexed(M680xOpIdx),
Extended {
address: u16,
indirect: bool,
},
Direct {
direct_addr: u8,
},
Relative {
address: u16,
offset: i16,
},
Constant(u8),
Invalid,
}
impl Default for M680xOperandType {
fn default() -> Self {
M680xOperandType::Invalid
}
}
impl<'a> From<&'a cs_m680x_op> for M680xOperand {
fn from(op: &cs_m680x_op) -> M680xOperand {
let op_type = match op.type_ {
m680x_op_type::M680X_OP_REGISTER => {
M680xOperandType::Reg(RegId(unsafe { op.__bindgen_anon_1.reg } as RegIdInt))
}
m680x_op_type::M680X_OP_IMMEDIATE => {
M680xOperandType::Imm(unsafe { op.__bindgen_anon_1.imm })
}
m680x_op_type::M680X_OP_INDEXED => {
M680xOperandType::Indexed(M680xOpIdx::new(unsafe { &op.__bindgen_anon_1.idx }))
}
m680x_op_type::M680X_OP_EXTENDED => {
let op_ext: m680x_op_ext = unsafe { op.__bindgen_anon_1.ext };
M680xOperandType::Extended {
address: op_ext.address,
indirect: op_ext.indirect,
}
}
m680x_op_type::M680X_OP_DIRECT => M680xOperandType::Direct {
direct_addr: unsafe { op.__bindgen_anon_1.direct_addr },
},
m680x_op_type::M680X_OP_RELATIVE => {
let op_rel: m680x_op_rel = unsafe { op.__bindgen_anon_1.rel };
M680xOperandType::Relative {
address: op_rel.address,
offset: op_rel.offset,
}
}
m680x_op_type::M680X_OP_CONSTANT => {
M680xOperandType::Constant(unsafe { op.__bindgen_anon_1.const_val })
}
m680x_op_type::M680X_OP_INVALID => M680xOperandType::Invalid,
};
M680xOperand {
op_type,
size: op.size,
}
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct M680xOperand {
pub op_type: M680xOperandType,
pub size: u8,
}
def_arch_details_struct!(
InsnDetail = M680xInsnDetail;
Operand = M680xOperand;
OperandIterator = M680xOperandIterator;
OperandIteratorLife = M680xOperandIterator<'a>;
[ pub struct M680xOperandIterator<'a>(slice::Iter<'a, cs_m680x_op>); ]
cs_arch_op = cs_m680x_op;
cs_arch = cs_m680x;
);
#[cfg(test)]
mod test {
use super::*;
use capstone_sys::*;
#[test]
fn m680x_op_type() {
let op_base = cs_m680x_op {
type_: m680x_op_type::M680X_OP_INVALID,
__bindgen_anon_1: cs_m680x_op__bindgen_ty_1 { reg: 0 },
size: 1,
access: 0,
};
assert_eq!(
M680xOperand::from(&op_base).op_type,
M680xOperandType::Invalid
);
assert_eq!(
M680xOperand::from(&cs_m680x_op {
type_: m680x_op_type::M680X_OP_REGISTER,
__bindgen_anon_1: cs_m680x_op__bindgen_ty_1 {
reg: M680xReg::M680X_REG_E
},
..op_base
})
.op_type,
M680xOperandType::Reg(RegId(M680xReg::M680X_REG_E as RegIdInt))
);
assert_eq!(
M680xOperand::from(&cs_m680x_op {
type_: m680x_op_type::M680X_OP_CONSTANT,
__bindgen_anon_1: cs_m680x_op__bindgen_ty_1 { const_val: 42 },
..op_base
})
.op_type,
M680xOperandType::Constant(42)
);
assert_eq!(
M680xOperand::from(&cs_m680x_op {
type_: m680x_op_type::M680X_OP_IMMEDIATE,
__bindgen_anon_1: cs_m680x_op__bindgen_ty_1 { imm: 1037 },
..op_base
})
.op_type,
M680xOperandType::Imm(1037)
);
assert_eq!(
M680xOperand::from(&cs_m680x_op {
type_: m680x_op_type::M680X_OP_DIRECT,
__bindgen_anon_1: cs_m680x_op__bindgen_ty_1 { direct_addr: 67 },
..op_base
})
.op_type,
M680xOperandType::Direct { direct_addr: 67 }
);
assert_eq!(
M680xOperand::from(&cs_m680x_op {
type_: m680x_op_type::M680X_OP_EXTENDED,
__bindgen_anon_1: cs_m680x_op__bindgen_ty_1 {
ext: m680x_op_ext {
address: 45876,
indirect: true,
}
},
..op_base
})
.op_type,
M680xOperandType::Extended {
address: 45876,
indirect: true
}
);
let base_reg = m680x_reg::M680X_REG_A;
let offset_reg = m680x_reg::M680X_REG_B;
let offset = 5;
let offset_addr = 0x1337;
let offset_bits = 4;
let inc_dec = -3;
let cs_op_idx = m680x_op_idx {
base_reg,
offset_reg,
offset,
offset_addr,
offset_bits,
inc_dec,
flags: 7,
};
assert_eq!(
M680xOperand::from(&cs_m680x_op {
type_: m680x_op_type::M680X_OP_INDEXED,
__bindgen_anon_1: cs_m680x_op__bindgen_ty_1 { idx: cs_op_idx },
..op_base
})
.op_type,
M680xOperandType::Indexed(M680xOpIdx(cs_op_idx))
);
}
#[test]
fn op_idx() {
let base_reg = m680x_reg::M680X_REG_A;
let offset_reg = m680x_reg::M680X_REG_B;
let offset = 5;
let offset_addr = 0x1337;
let offset_bits = 4;
let inc_dec = -3;
let mut idx = M680xOpIdx(m680x_op_idx {
base_reg,
offset_reg,
offset,
offset_addr,
offset_bits,
inc_dec,
flags: 7,
});
assert_eq!(idx.base_reg(), Some(RegId(base_reg as RegIdInt)));
assert_eq!(idx.offset_reg(), Some(RegId(offset_reg as RegIdInt)));
assert_eq!(idx.offset(), offset);
assert_eq!(idx.offset_addr(), offset_addr);
assert_eq!(idx.offset_bits(), offset_bits);
assert_eq!(idx.inc_dec(), inc_dec);
assert!(idx.is_indirect());
assert!(idx.is_no_comma());
assert!(idx.is_post_inc_dec());
idx.0.flags = 5;
assert!(idx.is_indirect());
assert!(!idx.is_no_comma());
assert!(idx.is_post_inc_dec());
}
}