1use 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
10pub 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
19pub struct M680xInsnDetail<'a>(pub(crate) &'a cs_m680x);
21
22impl_PartialEq_repr_fields!(M680xInsnDetail<'a> [ 'a ];
23 operands, flags
24);
25
26const 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 => is_first_op_in_mnem = M680X_FIRST_OP_IN_MNEM;
37
38 => is_second_op_in_mnem = M680X_SECOND_OP_IN_MNEM;
40);
41
42#[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_reg
76 );
77
78 define_m680x_register_option_getter!(
79 => offset_reg
81 );
82
83 pub fn offset(&self) -> i16 {
85 self.0.offset
86 }
87
88 pub fn offset_addr(&self) -> u16 {
92 self.0.offset_addr
93 }
94
95 pub fn offset_bits(&self) -> u8 {
97 self.0.offset_bits
98 }
99
100 pub fn inc_dec(&self) -> i8 {
109 self.0.inc_dec
110 }
111}
112
113const 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_indirect = M680X_IDX_INDIRECT;
125
126 => is_no_comma = M680X_IDX_NO_COMMA;
128
129 => is_post_inc_dec = M680X_IDX_POST_INC_DEC;
131);
132
133#[derive(Clone, Debug, Eq, PartialEq)]
135pub enum M680xOperandType {
136 Reg(RegId),
138
139 Imm(i32),
141
142 Indexed(M680xOpIdx),
144
145 Extended {
147 address: u16,
149
150 indirect: bool,
152 },
153
154 Direct {
156 direct_addr: u8,
158 },
159
160 Relative {
162 address: u16,
164
165 offset: i16,
167 },
168
169 Constant(u8),
173
174 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#[derive(Clone, Debug, Default, Eq, PartialEq)]
228pub struct M680xOperand {
229 pub op_type: M680xOperandType,
231
232 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}