armv4t/
operation.rs

1use types::{MultiplyFlags, TransferFlags};
2
3descriminant! {
4    #[doc = "
5Condition codes for controlling execution
6
7Variants, values and conditions are as follows:
8
9| Variant       | Value | Conditions                |
10|---------------|-------|---------------------------|
11| `Equal`       | `0x0` | `Z == true`               |
12| `NotEqual`    | `0x1` | `Z == false`              |
13| `UnsignedGTE` | `0x2` | `C == true`               |
14| `UnsignedLT`  | `0x3` | `C == false`              |
15| `Negative`    | `0x4` | `N == true`               |
16| `Positive`    | `0x5` | `N == false`              |
17| `Overflow`    | `0x6` | `V == true`               |
18| `NoOverflow`  | `0x7` | `V == false`              |
19| `UnsignedGT`  | `0x8` | `C == true && Z == false` |
20| `UnsignedLTE` | `0x9` | `C == false && Z == true` |
21| `SignedGTE`   | `0xa` | `N == V`                  |
22| `SignedLT`    | `0xb` | `N != V`                  |
23| `SignedGT`    | `0xc` | `Z == false && N == V`    |
24| `SignedLTE`   | `0xd` | `Z == true || N != V`     |
25| `Always`      | `0xe` | -                         |"]
26    #[derive(Clone, Copy, Debug, PartialEq)]
27    pub enum Condition<u32> {
28        #[doc = "Equal"]
29        Equal = 0x0,
30        #[doc = "Not equal"]
31        NotEqual = 0x1,
32        #[doc = "Greater than or equal (unsigned)"]
33        UnsignedGTE = 0x2,
34        #[doc = "Less than (unsigned)"]
35        UnsignedLT = 0x3,
36        #[doc = "Negative"]
37        Negative = 0x4,
38        #[doc = "Positive or zero"]
39        Positive = 0x5,
40        #[doc = "Overflow"]
41        Overflow = 0x6,
42        #[doc = "No overflow"]
43        NoOverflow = 0x7,
44        #[doc = "Greater than (unsigned)"]
45        UnsignedGT = 0x8,
46        #[doc = "Less than or equal (unsigned)"]
47        UnsignedLTE = 0x9,
48        #[doc = "Greater than or equal (signed)"]
49        SignedGTE = 0xa,
50        #[doc = "Less than (signed)"]
51        SignedLT = 0xb,
52        #[doc = "Greater than (signed)"]
53        SignedGT = 0xc,
54        #[doc = "Less than or equal (signed)"]
55        SignedLTE = 0xd,
56        #[doc = "Always"]
57        Always = 0xe
58    }
59}
60
61/// A collection of registers associated with an operation.
62#[derive(Clone, Copy, Debug, Default, PartialEq)]
63pub struct Registers {
64    /// The `d` register
65    pub d: u8,
66    /// The `h` register
67    pub h: u8,
68    /// The `l` register
69    pub l: u8,
70    /// The `m` register
71    pub m: u8,
72    /// The `n` register
73    pub n: u8,
74    /// The `s` register
75    pub s: u8,
76}
77
78/// A wrapper around a boolean that specifies whether to set condition
79/// codes.
80#[derive(Clone, Copy, Debug, PartialEq)]
81pub struct SetFlags(pub bool);
82
83impl From<bool> for SetFlags {
84    fn from(flag: bool) -> Self {
85        SetFlags(flag)
86    }
87}
88
89/// A wrapper around a boolean that specifies whether to set r14 on
90/// branching.
91#[derive(Clone, Copy, Debug, PartialEq)]
92pub struct Link(pub bool);
93
94impl From<bool> for Link {
95    fn from(flag: bool) -> Self {
96        Link(flag)
97    }
98}
99
100/// Processor operations
101///
102/// Operations that the processor can perform.
103#[derive(Clone, Copy, Debug, PartialEq)]
104pub enum Operation {
105    /// Data processing
106    ///
107    /// Perform an arithmetic or logical calculation on data contained
108    /// in registers or encoded in the instruction.
109    Alu(DataOp, SetFlags, Registers, Shift),
110    /// Status register transfer
111    ///
112    /// Perform a transfer of a value between a register and a status
113    /// register.
114    ///
115    /// __NOTE:__ The u8 member is the mask of the portions of the
116    /// status register that should be transferred.
117    StatusTransfer(TransferFlags, u8, Registers, Shift),
118    /// Multiply
119    ///
120    /// Perform integer multiplication on data contained in registers.
121    Multiply(MultiplyFlags, Registers),
122    /// Multiply long
123    ///
124    /// Perform integer multiplication on data contained in registers,
125    /// producing a 64-bit result.
126    MultiplyLong(MultiplyFlags, Registers),
127    /// Single Data Swap
128    ///
129    /// Perform a swap between a register and a memory address.
130    SingleDataSwap(TransferFlags, Registers),
131    /// Branch and Exchange
132    ///
133    /// Perform a branch by setting the program counter. The instruction
134    /// set can also be changed based on the contents of the new PC.
135    BranchExchange(Registers),
136    /// Halfword and signed data transfer
137    ///
138    /// Perform a transfer of a halfword, byte, signed halfword, or
139    /// signed halfword value between a register and memory.
140    HalfwordDataTransfer(TransferFlags, Registers, Shift),
141    /// Single data transfer
142    ///
143    /// Perform a transfer of a word, or byte value between a register
144    /// and memory.
145    SingleDataTransfer(TransferFlags, Registers, Shift),
146    /// Undefined
147    ///
148    /// Execute the undefined instruction trap.
149    Undefined,
150    /// Block data transfer
151    ///
152    /// Perform a transfer of a subset of visible registers between the
153    /// register bank and memory.
154    BlockDataTransfer(TransferFlags, Registers, u16),
155    /// Conditional branch
156    ///
157    /// Perform a branch by adding an offset to the program counter.
158    Branch(Condition, Link, i32),
159    /// Coprocessor data transfer
160    ///
161    /// Perform a transfer between a subset of a coprocessor's registers
162    /// and memory.
163    ///
164    /// __NOTE:__ The u8 member is the coprocessor number and the u32
165    /// member is the offset.
166    CoprocessorDataTransfer(TransferFlags, u8, Registers, u32),
167    /// Coprocessor data operation
168    ///
169    /// Perform a request for an operation on a coprocessor.
170    ///
171    /// __NOTE:__ The u8 members are, in order: coprocessor number,
172    /// coprocessor opcode, coprocessor information.
173    CoprocessorDataOperation(u8, u8, u8, Registers),
174    /// Coprocessor register transfer
175    ///
176    /// Perform a transfer between an ARM register and a coprocessor
177    /// register, with an optional transformation.
178    ///
179    /// __NOTE:__ The u8 members are, in order: coprocessor number,
180    /// coprocessor opcode, coprocessor information.
181    CoprocessorRegisterTransfer(TransferFlags, u8, u8, u8, Registers),
182    /// Software interrupt
183    ///
184    /// Execute the software interrupt trap.
185    SoftwareInterrupt(u32),
186}
187
188descriminant! {
189    #[doc = "
190Arithmetic/logical operations
191
192Variants, values and operations are as follows:
193
194| Variant | Value | Operation & Flags                       |
195|---------|-------|-----------------------------------------|
196| `And`   | `0x0` | `lhs & rhs` sets N, Z; shift sets C     |
197| `Eor`   | `0x1` | `lhs ^ rhs` sets N, Z, shift sets C     |
198| `Sub`   | `0x2` | `lhs - rhs` sets N, Z, C, V             |
199| `Rsb`   | `0x3` | `rhs - lhs` sets N, Z, C, V             |
200| `Add`   | `0x4` | `lhs + rhs` sets N, Z, C, V             |
201| `Adc`   | `0x5` | `lhs + rhs + carry` sets N, Z, C, V     |
202| `Sbc`   | `0x6` | `lhs - rhs - 1 + carry` sets N, Z, C, V |
203| `Rsc`   | `0x7` | `rhs - lhs - 1 + carry` sets N, Z, C, V |
204| `Tst`   | `0x8` | `lhs & rhs` sets N, Z; shift sets C     |
205| `Teq`   | `0x9` | `lhs ^ rhs` sets N, Z; shift sets C     |
206| `Cmp`   | `0xa` | `lhs - rhs` sets N, Z, C, V             |
207| `Cmn`   | `0xb` | `lhs + rhs` sets N, Z, C, V             |
208| `Orr`   | `0xc` | `lhs | rhs` sets N, Z; shift sets C     |
209| `Mov`   | `0xd` | `rhs` sets N, Z; shift sets C           |
210| `Bic`   | `0xe` | `lhs & !rhs` sets N, Z; shift sets C    |
211| `Mvn`   | `0xf` | `!rhs` sets N, Z; shift sets C          |"]
212    #[derive(Clone, Copy, Debug, PartialEq)]
213    pub enum DataOp<u32> {
214        #[doc = "And"]
215        And = 0x0,
216        #[doc = "Exclusive or"]
217        Eor = 0x1,
218        #[doc = "Subtract"]
219        Sub = 0x2,
220        #[doc = "Reverse subtract"]
221        Rsb = 0x3,
222        #[doc = "Add"]
223        Add = 0x4,
224        #[doc = "Add with carry"]
225        Adc = 0x5,
226        #[doc = "Subtract with carry"]
227        Sbc = 0x6,
228        #[doc = "Reverse subtract with carry"]
229        Rsc = 0x7,
230        #[doc = "Test"]
231        Tst = 0x8,
232        #[doc = "Test equal"]
233        Teq = 0x9,
234        #[doc = "Compare"]
235        Cmp = 0xa,
236        #[doc = "Compare negative"]
237        Cmn = 0xb,
238        #[doc = "Or"]
239        Orr = 0xc,
240        #[doc = "Move"]
241        Mov = 0xd,
242        #[doc = "Bit clear"]
243        Bic = 0xe,
244        #[doc = "Move negative"]
245        Mvn = 0xf
246    }
247}
248
249/// Barrel shift operations
250///
251/// Shift types are encoded as follows:
252///
253///  - `0b00`: logical left
254///  - `0b01`: logical right
255///  - `0b10`: arithmetic right
256///  - `0b11`: rotate right
257#[derive(Clone, Copy, Debug, PartialEq)]
258pub enum Shift {
259    /// Immediate value
260    ///
261    /// The value in the instruction is used unmodified.
262    Immediate {
263        /// Value
264        value: u32,
265    },
266    /// Immediate shifted register
267    ///
268    /// The value in register `rm` is shifted by the amount given in the
269    /// amount field.
270    ImmediateShiftedRegister {
271        /// Amount to shift the base value
272        amount: u8,
273        /// Type of shift to perform
274        shift: u8,
275        /// Register containing base value
276        m: u8
277    },
278    /// Register shifted register
279    ///
280    /// The value in register `rm` is shifted by the amount given in
281    /// register `rs`.
282    RegisterShiftedRegister {
283        /// Register containing the amount to shift
284        s: u8,
285        /// Type of shift to perform
286        shift: u8,
287        /// Register containing base value
288        m: u8
289    },
290    /// Rotated immediate value
291    ///
292    /// The immediate value is rotated by twice the amount given in the
293    /// rotate field.
294    RotatedImmediate {
295        /// Amount to rotate divided by two
296        rotation: u8,
297        /// Value to rotate
298        immediate: u8
299    },
300}