capstone_git/arch/
tms320c64x.rs

1//! Contains tms320c64x-specific types
2
3use core::convert::From;
4use core::{cmp, fmt, slice};
5use core::ffi::c_int;
6
7use capstone_sys::{
8    cs_tms320c64x, cs_tms320c64x_op, tms320c64x_funit, tms320c64x_mem_dir, tms320c64x_mem_disp,
9    tms320c64x_mem_mod, tms320c64x_op_mem, tms320c64x_op_type,
10};
11
12// XXX todo(tmfink): create rusty versions
13pub use capstone_sys::tms320c64x_insn as Tms320c64xInsn;
14pub use capstone_sys::tms320c64x_insn_group as Tms320c64xInsnGroup;
15pub use capstone_sys::tms320c64x_reg as Tms320c64xReg;
16
17pub use crate::arch::arch_builder::tms320c64x::*;
18use crate::instruction::{RegId, RegIdInt};
19
20
21/// Contains TMS320C64X-specific details for an instruction
22pub struct Tms320c64xInsnDetail<'a>(pub(crate) &'a cs_tms320c64x);
23
24define_cs_enum_wrapper_reverse!(
25    [
26        /// TMS320C64X Functional Unit
27        => Tms320c64xFuntionalUnit = tms320c64x_funit,
28    ]
29    /// Invalid or unspecified
30    => Invalid = TMS320C64X_FUNIT_INVALID;
31    /// D
32    => D = TMS320C64X_FUNIT_D;
33    /// L
34    => L = TMS320C64X_FUNIT_L;
35    /// M
36    => M = TMS320C64X_FUNIT_M;
37    /// S
38    => S = TMS320C64X_FUNIT_S;
39    /// NO
40    => No = TMS320C64X_FUNIT_NO;
41);
42
43impl Tms320c64xInsnDetail<'_> {
44    /// Whether condition is zero
45    pub fn is_condition_zero(&self) -> bool {
46        self.0.condition.zero != 0
47    }
48
49    /// Condition register
50    pub fn condition_reg(&self) -> RegId {
51        RegId(self.0.condition.reg as RegIdInt)
52    }
53
54    /// Functional unit
55    pub fn functional_unit(&self) -> Tms320c64xFuntionalUnit {
56        Tms320c64xFuntionalUnit::from_u32(self.0.funit.unit)
57            .unwrap_or(Tms320c64xFuntionalUnit::Invalid)
58    }
59
60    /// Functional unit side
61    pub fn functional_unit_side(&self) -> u8 {
62        self.0.funit.side as u8
63    }
64
65    /// Functional unit cross path
66    pub fn functional_unit_cross_path(&self) -> i8 {
67        // todo(tmfink): capstone bug where cs_tms320c64x.funit.crosspath is stored as unsigned
68        // instead of signed
69        self.0.funit.crosspath as i8
70    }
71
72    /// Instruction parallel
73    pub fn parallel(&self) -> i8 {
74        self.0.parallel as c_int as i8
75    }
76}
77
78impl_PartialEq_repr_fields!(Tms320c64xInsnDetail<'a> [ 'a ];
79    is_condition_zero, condition_reg, functional_unit, functional_unit_side,
80    functional_unit_cross_path, parallel
81);
82
83/// TMS320C64X operand
84#[derive(Clone, Debug, Eq, PartialEq)]
85pub enum Tms320c64xOperand {
86    /// Register
87    Reg(RegId),
88
89    /// Immediate
90    Imm(i32),
91
92    /// Memory
93    Mem(Tms320c64xOpMem),
94
95    /// Pair of registers
96    RegPair(RegId, RegId),
97
98    /// Invalid
99    Invalid,
100}
101
102impl Default for Tms320c64xOperand {
103    fn default() -> Self {
104        Tms320c64xOperand::Invalid
105    }
106}
107
108define_cs_enum_wrapper_reverse!(
109    [
110        /// TMS320C64X Memory Operand modification
111        => Tms320c64xMemDisplayType = tms320c64x_mem_disp,
112    ]
113    /// Invalid or unspecified
114    => Invalid = TMS320C64X_MEM_DISP_INVALID;
115    /// Constant
116    => Constant = TMS320C64X_MEM_DISP_CONSTANT;
117    /// Regiter
118    => Register = TMS320C64X_MEM_DISP_REGISTER;
119);
120
121/// TMS320C64X Operand Memory Display
122#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
123pub enum Tms320c64xMemDisplay {
124    /// Invalid or unspecified
125    Invalid,
126
127    /// Constant
128    Constant(u32),
129
130    /// Register
131    Register(RegId),
132}
133
134define_cs_enum_wrapper_reverse!(
135    [
136        /// TMS320C64X Memory Operand direction
137        => Tms320c64xMemDirection = tms320c64x_mem_dir,
138    ]
139    /// Invalid or unspecified
140    => Invalid = TMS320C64X_MEM_DIR_INVALID;
141    /// Forward
142    => Forward = TMS320C64X_MEM_DIR_FW;
143    /// Backward
144    => Backward = TMS320C64X_MEM_DIR_BW;
145);
146
147define_cs_enum_wrapper_reverse!(
148    [
149        /// TMS320C64X Memory Operand modification
150        => Tms320c64xMemModify = tms320c64x_mem_mod,
151    ]
152    /// Invalid or unspecified
153    => Invalid = TMS320C64X_MEM_MOD_INVALID;
154    /// No
155    => No = TMS320C64X_MEM_MOD_NO;
156    /// Pre
157    => Pre = TMS320C64X_MEM_MOD_PRE;
158    /// Post
159    => Post = TMS320C64X_MEM_MOD_POST;
160);
161
162/// TMS320C64X memory operand
163#[derive(Debug, Copy, Clone)]
164pub struct Tms320c64xOpMem(pub(crate) tms320c64x_op_mem);
165
166/// todo(tmfink): add all getters
167impl Tms320c64xOpMem {
168    /// Base register
169    pub fn base(&self) -> RegId {
170        RegId(self.0.base as RegIdInt)
171    }
172
173    /// Disp value (type depends on display_type)
174    fn disp(&self) -> u32 {
175        self.0.disp as u32
176    }
177
178    /// Unit of base and offset register
179    pub fn unit(&self) -> u32 {
180        self.0.unit as u32
181    }
182
183    /// Offset scaled
184    pub fn scaled(&self) -> u32 {
185        self.0.scaled as u32
186    }
187
188    /// Displacement type
189    fn display_type(&self) -> Tms320c64xMemDisplayType {
190        Tms320c64xMemDisplayType::from_u32(self.0.disptype as u32)
191            .unwrap_or(Tms320c64xMemDisplayType::Invalid)
192    }
193
194    /// Display
195    pub fn display(&self) -> Tms320c64xMemDisplay {
196        match self.display_type() {
197            Tms320c64xMemDisplayType::Invalid => Tms320c64xMemDisplay::Invalid,
198            Tms320c64xMemDisplayType::Constant => Tms320c64xMemDisplay::Constant(self.disp()),
199            Tms320c64xMemDisplayType::Register => {
200                Tms320c64xMemDisplay::Register(RegId(self.disp() as RegIdInt))
201            }
202        }
203    }
204
205    /// Direction
206    pub fn direction(&self) -> Tms320c64xMemDirection {
207        Tms320c64xMemDirection::from_u32(self.0.direction as u32)
208            .unwrap_or(Tms320c64xMemDirection::Invalid)
209    }
210
211    /// Modification
212    pub fn modify(&self) -> Tms320c64xMemModify {
213        Tms320c64xMemModify::from_u32(self.0.modify as u32).unwrap_or(Tms320c64xMemModify::Invalid)
214    }
215}
216
217impl_PartialEq_repr_fields!(Tms320c64xOpMem;
218    base, disp, unit, scaled, display_type, direction, modify
219);
220
221impl cmp::Eq for Tms320c64xOpMem {}
222
223impl From<&cs_tms320c64x_op> for Tms320c64xOperand {
224    fn from(insn: &cs_tms320c64x_op) -> Tms320c64xOperand {
225        match insn.type_ {
226            tms320c64x_op_type::TMS320C64X_OP_REG => {
227                Tms320c64xOperand::Reg(RegId(unsafe { insn.__bindgen_anon_1.reg } as RegIdInt))
228            }
229            tms320c64x_op_type::TMS320C64X_OP_IMM => {
230                Tms320c64xOperand::Imm(unsafe { insn.__bindgen_anon_1.imm } as i32)
231            }
232            tms320c64x_op_type::TMS320C64X_OP_MEM => {
233                Tms320c64xOperand::Mem(Tms320c64xOpMem(unsafe { insn.__bindgen_anon_1.mem }))
234            }
235            tms320c64x_op_type::TMS320C64X_OP_REGPAIR => {
236                let reg = unsafe { insn.__bindgen_anon_1.reg };
237                // todo(tmfink): bug in capstone?
238                Tms320c64xOperand::RegPair(RegId((reg as RegIdInt) + 1), RegId(reg as RegIdInt))
239            }
240            tms320c64x_op_type::TMS320C64X_OP_INVALID => Tms320c64xOperand::Invalid,
241        }
242    }
243}
244
245def_arch_details_struct!(
246    InsnDetail = Tms320c64xInsnDetail;
247    Operand = Tms320c64xOperand;
248    OperandIterator = Tms320c64xOperandIterator;
249    OperandIteratorLife = Tms320c64xOperandIterator<'a>;
250    [ pub struct Tms320c64xOperandIterator<'a>(slice::Iter<'a, cs_tms320c64x_op>); ]
251    cs_arch_op = cs_tms320c64x_op;
252    cs_arch = cs_tms320c64x;
253);
254
255#[cfg(test)]
256mod test {
257    use super::*;
258    use capstone_sys::*;
259    use core::ffi::{c_int, c_uint};
260
261    const OP_MEM_ZERO: tms320c64x_op_mem = tms320c64x_op_mem {
262        base: 0,
263        disp: 0,
264        unit: 0,
265        scaled: 0,
266        disptype: 0,
267        direction: 0,
268        modify: 0,
269    };
270
271    #[test]
272    fn tms320c64x_insn_detail() {
273        let op = cs_tms320c64x_op {
274            type_: tms320c64x_op_type::TMS320C64X_OP_IMM,
275            __bindgen_anon_1: cs_tms320c64x_op__bindgen_ty_1 { imm: 0 },
276        };
277        let cs_insn = cs_tms320c64x {
278            op_count: 0,
279            operands: [op; 8],
280            condition: cs_tms320c64x__bindgen_ty_1 {
281                reg: tms320c64x_reg::TMS320C64X_REG_GPLYA as c_uint,
282                zero: 1,
283            },
284            funit: cs_tms320c64x__bindgen_ty_2 {
285                unit: tms320c64x_funit::TMS320C64X_FUNIT_L as c_uint,
286                side: 18,
287                crosspath: -1 as c_int as c_uint,
288            },
289            parallel: 1,
290        };
291        let d = Tms320c64xInsnDetail(&cs_insn);
292
293        assert!(d.is_condition_zero());
294        assert_eq!(
295            d.condition_reg(),
296            RegId(Tms320c64xReg::TMS320C64X_REG_GPLYA as RegIdInt)
297        );
298        assert_eq!(d.functional_unit(), Tms320c64xFuntionalUnit::L);
299        assert_eq!(d.functional_unit_side(), 18);
300        assert_eq!(d.functional_unit_cross_path(), -1);
301        assert_eq!(d.parallel(), 1);
302    }
303
304    #[test]
305    fn tms320c64x_op_from() {
306        let op = cs_tms320c64x_op {
307            type_: tms320c64x_op_type::TMS320C64X_OP_INVALID,
308            __bindgen_anon_1: cs_tms320c64x_op__bindgen_ty_1 { reg: 0 },
309        };
310        assert_eq!(
311            Tms320c64xOperand::from(&op),
312            Tms320c64xOperand::Invalid
313        );
314    }
315
316    #[test]
317    fn op_mem() {
318        // display type
319        assert_eq!(
320            Tms320c64xOpMem(OP_MEM_ZERO).display(),
321            Tms320c64xMemDisplay::Invalid
322        );
323        assert_eq!(
324            Tms320c64xOpMem(tms320c64x_op_mem {
325                disptype: 999,
326                ..OP_MEM_ZERO
327            })
328            .display(),
329            Tms320c64xMemDisplay::Invalid
330        );
331        assert_eq!(
332            Tms320c64xOpMem(tms320c64x_op_mem {
333                disptype: tms320c64x_mem_disp::TMS320C64X_MEM_DISP_CONSTANT as c_uint,
334                disp: 3133789374,
335                ..OP_MEM_ZERO
336            })
337            .display(),
338            Tms320c64xMemDisplay::Constant(3133789374)
339        );
340        assert_eq!(
341            Tms320c64xOpMem(tms320c64x_op_mem {
342                disptype: tms320c64x_mem_disp::TMS320C64X_MEM_DISP_REGISTER as c_uint,
343                disp: tms320c64x_reg::TMS320C64X_REG_A13 as c_uint,
344                ..OP_MEM_ZERO
345            })
346            .display(),
347            Tms320c64xMemDisplay::Register(RegId(Tms320c64xReg::TMS320C64X_REG_A13 as RegIdInt))
348        );
349
350        // Simple getters
351        assert_eq!(
352            Tms320c64xOpMem(tms320c64x_op_mem {
353                base: tms320c64x_reg::TMS320C64X_REG_A13 as c_uint,
354                ..OP_MEM_ZERO
355            })
356            .base(),
357            RegId(Tms320c64xReg::TMS320C64X_REG_A13 as RegIdInt)
358        );
359        assert_eq!(
360            Tms320c64xOpMem(tms320c64x_op_mem {
361                unit: 29393 as c_uint,
362                ..OP_MEM_ZERO
363            })
364            .unit(),
365            29393
366        );
367        assert_eq!(
368            Tms320c64xOpMem(tms320c64x_op_mem {
369                scaled: 29393 as c_uint,
370                ..OP_MEM_ZERO
371            })
372            .scaled(),
373            29393
374        );
375        assert_eq!(
376            Tms320c64xOpMem(tms320c64x_op_mem {
377                direction: tms320c64x_mem_dir::TMS320C64X_MEM_DIR_FW as c_uint,
378                ..OP_MEM_ZERO
379            })
380            .direction(),
381            Tms320c64xMemDirection::Forward,
382        );
383        assert_eq!(
384            Tms320c64xOpMem(tms320c64x_op_mem {
385                modify: tms320c64x_mem_mod::TMS320C64X_MEM_MOD_PRE as c_uint,
386                ..OP_MEM_ZERO
387            })
388            .modify(),
389            Tms320c64xMemModify::Pre,
390        );
391    }
392}