capstone_git/arch/
m680x.rs

1//! Contains m680x-specific types
2
3use core::convert::From;
4use core::{fmt, slice};
5
6use capstone_sys::{
7    cs_m680x, cs_m680x_op, m680x_op_ext, m680x_op_idx, m680x_op_rel, m680x_op_type,
8};
9
10// XXX todo(tmfink): create rusty versions
11pub use capstone_sys::m680x_insn as M680xInsn;
12pub use capstone_sys::m680x_reg as M680xReg;
13
14pub use crate::arch::arch_builder::m680x::*;
15use crate::arch::DetailsArchInsn;
16use crate::instruction::{RegId, RegIdInt};
17
18
19/// Contains M680X-specific details for an instruction
20pub struct M680xInsnDetail<'a>(pub(crate) &'a cs_m680x);
21
22impl_PartialEq_repr_fields!(M680xInsnDetail<'a> [ 'a ];
23    operands, flags
24);
25
26// M680X instruction flags
27const M680X_FIRST_OP_IN_MNEM: u8 = 1;
28const M680X_SECOND_OP_IN_MNEM: u8 = 2;
29
30define_impl_bitmask!(
31    impl M680xInsnDetail<'a>;
32    flags: u8 = { |self_: &M680xInsnDetail| self_.0.flags }
33    test_mod = test_M680xInsnDetail;
34
35    /// The first (register) operand is part of the instruction mnemonic
36    => is_first_op_in_mnem = M680X_FIRST_OP_IN_MNEM;
37
38    /// The second (register) operand is part of the instruction mnemonic
39    => is_second_op_in_mnem = M680X_SECOND_OP_IN_MNEM;
40);
41
42/// Instruction's operand referring to indexed addressing
43#[derive(Clone, Debug)]
44pub struct M680xOpIdx(pub(crate) m680x_op_idx);
45
46impl_PartialEq_repr_fields!(M680xOpIdx [ ];
47    base_reg, offset_reg, offset, offset_addr, offset_bits, inc_dec, flags
48);
49
50impl Eq for M680xOpIdx {}
51
52macro_rules! define_m680x_register_option_getter {
53    (
54        $( #[$enum_attr:meta] )*
55        => $field:ident
56    ) => {
57        $( #[$enum_attr] )*
58        pub fn $field(&self) -> Option<RegId> {
59            if (self.0).$field == M680xReg::M680X_REG_INVALID {
60                None
61            } else {
62                Some(RegId((self.0).$field as RegIdInt))
63            }
64        }
65    }
66}
67
68impl M680xOpIdx {
69    fn new(op_idx: &m680x_op_idx) -> Self {
70        M680xOpIdx(*op_idx)
71    }
72
73    define_m680x_register_option_getter!(
74        /// Base register
75        => base_reg
76    );
77
78    define_m680x_register_option_getter!(
79        /// Offset register
80        => offset_reg
81    );
82
83    /// 5-,8- or 16-bit offset
84    pub fn offset(&self) -> i16 {
85        self.0.offset
86    }
87
88    /// Offset address
89    ///
90    /// if base_reg == M680X_REG_PC, then calculated as offset + PC
91    pub fn offset_addr(&self) -> u16 {
92        self.0.offset_addr
93    }
94
95    /// Offset bits
96    pub fn offset_bits(&self) -> u8 {
97        self.0.offset_bits
98    }
99
100    /// Increment or decrement value
101    ///
102    /// - `0`: no inc-/decrement
103    /// - `1 .. 8`: increment by `1 .. 8`
104    /// - `-1 .. -8`: decrement by `1 .. 8`
105    ///
106    /// if flag `M680X_IDX_POST_INC_DEC` set it is post
107    /// inc-/decrement, otherwise pre inc-/decrement.
108    pub fn inc_dec(&self) -> i8 {
109        self.0.inc_dec
110    }
111}
112
113// Comes from M680X_IDX_* #defines
114const M680X_IDX_INDIRECT: u8 = 1;
115const M680X_IDX_NO_COMMA: u8 = 2;
116const M680X_IDX_POST_INC_DEC: u8 = 4;
117
118define_impl_bitmask!(
119    impl M680xOpIdx<>;
120    flags: u8 = { |self_: &M680xOpIdx| self_.0.flags }
121    test_mod = test_M680xOpIdx;
122
123    /// Is index indirect?
124    => is_indirect = M680X_IDX_INDIRECT;
125
126    /// Is there no comma?
127    => is_no_comma = M680X_IDX_NO_COMMA;
128
129    /// Is index indirect?
130    => is_post_inc_dec = M680X_IDX_POST_INC_DEC;
131);
132
133/// M680X operand
134#[derive(Clone, Debug, Eq, PartialEq)]
135pub enum M680xOperandType {
136    /// Register
137    Reg(RegId),
138
139    /// Immediate
140    Imm(i32),
141
142    /// Indexed addressing operand
143    Indexed(M680xOpIdx),
144
145    /// Extended addressing operand
146    Extended {
147        /// Absolute address
148        address: u16,
149
150        /// Whether extended indirect addressing
151        indirect: bool,
152    },
153
154    /// Direct addressing operand
155    Direct {
156        /// Direct address (lower 8-bit)
157        direct_addr: u8,
158    },
159
160    /// Relative addressing operand
161    Relative {
162        /// Absolute address
163        address: u16,
164
165        /// Offset/displacement value
166        offset: i16,
167    },
168
169    /// Constant operand (displayed as number only)
170    ///
171    /// Used e.g. for a bit index or page number.
172    Constant(u8),
173
174    /// Invalid
175    Invalid,
176}
177
178impl Default for M680xOperandType {
179    fn default() -> Self {
180        M680xOperandType::Invalid
181    }
182}
183
184impl From<&cs_m680x_op> for M680xOperand {
185    fn from(op: &cs_m680x_op) -> M680xOperand {
186        let op_type = match op.type_ {
187            m680x_op_type::M680X_OP_REGISTER => {
188                M680xOperandType::Reg(RegId(unsafe { op.__bindgen_anon_1.reg } as RegIdInt))
189            }
190            m680x_op_type::M680X_OP_IMMEDIATE => {
191                M680xOperandType::Imm(unsafe { op.__bindgen_anon_1.imm })
192            }
193            m680x_op_type::M680X_OP_INDEXED => {
194                M680xOperandType::Indexed(M680xOpIdx::new(unsafe { &op.__bindgen_anon_1.idx }))
195            }
196            m680x_op_type::M680X_OP_EXTENDED => {
197                let op_ext: m680x_op_ext = unsafe { op.__bindgen_anon_1.ext };
198                M680xOperandType::Extended {
199                    address: op_ext.address,
200                    indirect: op_ext.indirect,
201                }
202            }
203            m680x_op_type::M680X_OP_DIRECT => M680xOperandType::Direct {
204                direct_addr: unsafe { op.__bindgen_anon_1.direct_addr },
205            },
206            m680x_op_type::M680X_OP_RELATIVE => {
207                let op_rel: m680x_op_rel = unsafe { op.__bindgen_anon_1.rel };
208                M680xOperandType::Relative {
209                    address: op_rel.address,
210                    offset: op_rel.offset,
211                }
212            }
213            m680x_op_type::M680X_OP_CONSTANT => {
214                M680xOperandType::Constant(unsafe { op.__bindgen_anon_1.const_val })
215            }
216            m680x_op_type::M680X_OP_INVALID => M680xOperandType::Invalid,
217        };
218
219        M680xOperand {
220            op_type,
221            size: op.size,
222        }
223    }
224}
225
226/// M680X operand
227#[derive(Clone, Debug, Default, Eq, PartialEq)]
228pub struct M680xOperand {
229    /// Operand type
230    pub op_type: M680xOperandType,
231
232    /// Size of this operand in bytes
233    pub size: u8,
234}
235
236def_arch_details_struct!(
237    InsnDetail = M680xInsnDetail;
238    Operand = M680xOperand;
239    OperandIterator = M680xOperandIterator;
240    OperandIteratorLife = M680xOperandIterator<'a>;
241    [ pub struct M680xOperandIterator<'a>(slice::Iter<'a, cs_m680x_op>); ]
242    cs_arch_op = cs_m680x_op;
243    cs_arch = cs_m680x;
244);
245
246#[cfg(test)]
247mod test {
248    use super::*;
249    use capstone_sys::*;
250
251    #[test]
252    fn m680x_op_type() {
253        let op_base = cs_m680x_op {
254            type_: m680x_op_type::M680X_OP_INVALID,
255            __bindgen_anon_1: cs_m680x_op__bindgen_ty_1 { reg: 0 },
256            size: 1,
257            access: 0,
258        };
259
260        assert_eq!(
261            M680xOperand::from(&op_base).op_type,
262            M680xOperandType::Invalid
263        );
264        assert_eq!(
265            M680xOperand::from(&cs_m680x_op {
266                type_: m680x_op_type::M680X_OP_REGISTER,
267                __bindgen_anon_1: cs_m680x_op__bindgen_ty_1 {
268                    reg: M680xReg::M680X_REG_E
269                },
270                ..op_base
271            })
272            .op_type,
273            M680xOperandType::Reg(RegId(M680xReg::M680X_REG_E as RegIdInt))
274        );
275        assert_eq!(
276            M680xOperand::from(&cs_m680x_op {
277                type_: m680x_op_type::M680X_OP_CONSTANT,
278                __bindgen_anon_1: cs_m680x_op__bindgen_ty_1 { const_val: 42 },
279                ..op_base
280            })
281            .op_type,
282            M680xOperandType::Constant(42)
283        );
284        assert_eq!(
285            M680xOperand::from(&cs_m680x_op {
286                type_: m680x_op_type::M680X_OP_IMMEDIATE,
287                __bindgen_anon_1: cs_m680x_op__bindgen_ty_1 { imm: 1037 },
288                ..op_base
289            })
290            .op_type,
291            M680xOperandType::Imm(1037)
292        );
293        assert_eq!(
294            M680xOperand::from(&cs_m680x_op {
295                type_: m680x_op_type::M680X_OP_DIRECT,
296                __bindgen_anon_1: cs_m680x_op__bindgen_ty_1 { direct_addr: 67 },
297                ..op_base
298            })
299            .op_type,
300            M680xOperandType::Direct { direct_addr: 67 }
301        );
302        assert_eq!(
303            M680xOperand::from(&cs_m680x_op {
304                type_: m680x_op_type::M680X_OP_EXTENDED,
305                __bindgen_anon_1: cs_m680x_op__bindgen_ty_1 {
306                    ext: m680x_op_ext {
307                        address: 45876,
308                        indirect: true,
309                    }
310                },
311                ..op_base
312            })
313            .op_type,
314            M680xOperandType::Extended {
315                address: 45876,
316                indirect: true
317            }
318        );
319
320        let base_reg = m680x_reg::M680X_REG_A;
321        let offset_reg = m680x_reg::M680X_REG_B;
322        let offset = 5;
323        let offset_addr = 0x1337;
324        let offset_bits = 4;
325        let inc_dec = -3;
326        let cs_op_idx = m680x_op_idx {
327            base_reg,
328            offset_reg,
329            offset,
330            offset_addr,
331            offset_bits,
332            inc_dec,
333            flags: 7,
334        };
335        assert_eq!(
336            M680xOperand::from(&cs_m680x_op {
337                type_: m680x_op_type::M680X_OP_INDEXED,
338                __bindgen_anon_1: cs_m680x_op__bindgen_ty_1 { idx: cs_op_idx },
339                ..op_base
340            })
341            .op_type,
342            M680xOperandType::Indexed(M680xOpIdx(cs_op_idx))
343        );
344    }
345
346    #[test]
347    fn op_idx() {
348        let base_reg = m680x_reg::M680X_REG_A;
349        let offset_reg = m680x_reg::M680X_REG_B;
350        let offset = 5;
351        let offset_addr = 0x1337;
352        let offset_bits = 4;
353        let inc_dec = -3;
354
355        let mut idx = M680xOpIdx(m680x_op_idx {
356            base_reg,
357            offset_reg,
358            offset,
359            offset_addr,
360            offset_bits,
361            inc_dec,
362            flags: 7,
363        });
364
365        assert_eq!(idx.base_reg(), Some(RegId(base_reg as RegIdInt)));
366        assert_eq!(idx.offset_reg(), Some(RegId(offset_reg as RegIdInt)));
367        assert_eq!(idx.offset(), offset);
368        assert_eq!(idx.offset_addr(), offset_addr);
369        assert_eq!(idx.offset_bits(), offset_bits);
370        assert_eq!(idx.inc_dec(), inc_dec);
371        assert!(idx.is_indirect());
372        assert!(idx.is_no_comma());
373        assert!(idx.is_post_inc_dec());
374
375        idx.0.flags = 5;
376        assert!(idx.is_indirect());
377        assert!(!idx.is_no_comma());
378        assert!(idx.is_post_inc_dec());
379    }
380}