msp430_asm/
operand.rs

1use std::fmt;
2
3use crate::DecodeError;
4use crate::Result;
5
6/// Represents a source or destination operand. This represents all
7/// addressing mode represented by AS/AD with their corresponding register
8/// pairs. In msp430 the valid destination operands are a subset of the
9/// source operands. Due to cases in the implementation where it is necessary
10/// to sometimes use a source as a destination (br emulated instruction) or
11/// compare a source and a destination rather than create separate types for
12/// source and destination they share one. The enforcement that a valid
13/// destination is specified, as all operands are valid for source, is left
14/// to the implementation of the decoding logic or assembling logic.
15#[derive(Debug, Clone, Copy, PartialEq)]
16pub enum Operand {
17    /// The operand is stored in the register
18    RegisterDirect(u8),
19    /// The operand is stored at the offset of the address specified in the
20    /// register.
21    ///
22    /// This requires an additional word
23    Indexed((u8, i16)),
24    /// The operand is stored at the address that is in the register
25    ///
26    /// This requires an additional word
27    RegisterIndirect(u8),
28    /// The operand is stored at the address that is in the register and the
29    /// register is autoincremented by one word
30    RegisterIndirectAutoIncrement(u8),
31    /// The operand is the value of the following word relative to PC
32    ///
33    /// This requires an additional word
34    Symbolic(i16),
35    /// The operand is the immediate value following the instruction word
36    ///
37    /// This requires an additional word
38    Immediate(u16),
39    /// The operand is stored at the address specified by the immediate value
40    /// after the instruction word
41    ///
42    /// This requires an additional word
43    Absolute(u16),
44    /// The operand is a constant value specified by the combination of
45    /// register (SR or CG) and the addressing mode
46    Constant(i8),
47}
48
49impl Operand {
50    pub fn size(&self) -> usize {
51        match self {
52            Self::RegisterDirect(_) => 0,
53            Self::Indexed(_) => 2,
54            Self::RegisterIndirect(_) => 0,
55            Self::RegisterIndirectAutoIncrement(_) => 0,
56            Self::Symbolic(_) => 2,
57            Self::Immediate(_) => 2,
58            Self::Absolute(_) => 2,
59            Self::Constant(_) => 0,
60        }
61    }
62}
63
64impl fmt::Display for Operand {
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66        match self {
67            Self::RegisterDirect(r) => match r {
68                0 => write!(f, "pc"),
69                1 => write!(f, "sp"),
70                2 => write!(f, "sr"),
71                3 => write!(f, "cg"),
72                _ => write!(f, "r{}", r),
73            },
74            Self::Indexed((r, i)) => match r {
75                1 => {
76                    if *i >= 0 {
77                        write!(f, "{:#x}(sp)", i)
78                    } else {
79                        write!(f, "-{:#x}(sp)", -i)
80                    }
81                }
82                3 => {
83                    if *i >= 0 {
84                        write!(f, "{:#x}(cg)", i)
85                    } else {
86                        write!(f, "-{:#x}(cg)", -i)
87                    }
88                }
89                4..=15 => {
90                    if *i >= 0 {
91                        write!(f, "{:#x}(r{})", i, r)
92                    } else {
93                        write!(f, "-{:#x}(r{})", -i, r)
94                    }
95                }
96                _ => unreachable!(),
97            },
98            Self::RegisterIndirect(r) => {
99                if *r == 1 {
100                    write!(f, "@sp")
101                } else {
102                    write!(f, "@r{}", r)
103                }
104            }
105            Self::RegisterIndirectAutoIncrement(r) => {
106                if *r == 1 {
107                    write!(f, "@sp+")
108                } else {
109                    write!(f, "@r{}+", r)
110                }
111            }
112            Self::Symbolic(i) => {
113                if *i >= 0 {
114                    write!(f, "#{:#x}(pc)", i)
115                } else {
116                    write!(f, "#-{:#x}(pc)", -i)
117                }
118            }
119            Self::Immediate(i) => {
120                if *i & 0x8000 == 0 {
121                    write!(f, "#{:#x}", i)
122                } else {
123                    write!(f, "#-{:#x}", *i as i16)
124                }
125            }
126            Self::Absolute(a) => write!(f, "&{:#x}", a),
127            Self::Constant(i) => {
128                if *i >= 0 {
129                    write!(f, "#{:#x}", i)
130                } else {
131                    write!(f, "#-{:#x}", -i)
132                }
133            }
134        }
135    }
136}
137
138/// Specifies whether the operand (source or destination) will be used as a
139/// byte or a word.
140///
141/// The operand itself is always stored as a word for alignment reasons
142#[derive(Debug, Clone, Copy, PartialEq)]
143pub enum OperandWidth {
144    Byte,
145    Word,
146}
147
148impl From<u8> for OperandWidth {
149    fn from(val: u8) -> Self {
150        match val {
151            0 => OperandWidth::Word,
152            1 => OperandWidth::Byte,
153            _ => unreachable!(),
154        }
155    }
156}
157
158/// Parses a source operand from an input stream. This is only used for AS
159/// modes where the source operand is stored as an additional word of data.
160/// Otherwise the source operand can be fully decoded from just reading the
161/// the instruction word
162pub fn parse_source(register: u8, source: u16, data: &[u8]) -> Result<(Operand, &[u8])> {
163    match source {
164        0 => match register {
165            3 => Ok((Operand::Constant(0), data)),
166            0..=2 | 4..=15 => Ok((Operand::RegisterDirect(register), data)),
167            _ => Err(DecodeError::InvalidSource((source, register))),
168        },
169        1 => match register {
170            0 => {
171                if data.len() < 2 {
172                    Err(DecodeError::MissingSource)
173                } else {
174                    let (bytes, remaining_data) = data.split_at(std::mem::size_of::<u16>());
175                    let second_word = i16::from_le_bytes(bytes.try_into().unwrap());
176                    Ok((Operand::Symbolic(second_word), remaining_data))
177                }
178            }
179            2 => {
180                if data.len() < 2 {
181                    Err(DecodeError::MissingSource)
182                } else {
183                    let (bytes, remaining_data) = data.split_at(std::mem::size_of::<u16>());
184                    let second_word = u16::from_le_bytes(bytes.try_into().unwrap());
185                    Ok((Operand::Absolute(second_word), remaining_data))
186                }
187            }
188            3 => Ok((Operand::Constant(1), data)),
189            1 | 4..=15 => {
190                if data.len() < 2 {
191                    Err(DecodeError::MissingSource)
192                } else {
193                    let (bytes, remaining_data) = data.split_at(std::mem::size_of::<u16>());
194                    let second_word = i16::from_le_bytes(bytes.try_into().unwrap());
195                    Ok((Operand::Indexed((register, second_word)), remaining_data))
196                }
197            }
198            _ => Err(DecodeError::InvalidSource((source, register))),
199        },
200        2 => match register {
201            2 => Ok((Operand::Constant(4), data)),
202            3 => Ok((Operand::Constant(2), data)),
203            0..=1 | 4..=15 => Ok((Operand::RegisterIndirect(register), data)),
204            _ => Err(DecodeError::InvalidSource((source, register))),
205        },
206        3 => match register {
207            0 => {
208                if data.len() < 2 {
209                    Err(DecodeError::MissingSource)
210                } else {
211                    let (bytes, remaining_data) = data.split_at(std::mem::size_of::<u16>());
212                    let second_word = u16::from_le_bytes(bytes.try_into().unwrap());
213                    Ok((Operand::Immediate(second_word), remaining_data))
214                }
215            }
216            2 => Ok((Operand::Constant(8), data)),
217            3 => Ok((Operand::Constant(-1), data)),
218            1 | 4..=15 => Ok((Operand::RegisterIndirectAutoIncrement(register), data)),
219            _ => Err(DecodeError::InvalidSource((source, register))),
220        },
221        _ => Err(DecodeError::InvalidSource((source, register))),
222    }
223}
224
225/// Parses a destination operand from an input stream. This is only used for
226/// AD modes where the destination operand is stored as an additional word
227/// of data. Otherwise the destination operand can be fully decoded from just
228/// reading the the instruction word
229pub fn parse_destination(register: u8, source: u16, data: &[u8]) -> Result<Operand> {
230    match source {
231        0 => Ok(Operand::RegisterDirect(register)),
232        1 => {
233            if data.len() < 2 {
234                Err(DecodeError::MissingDestination)
235            } else {
236                let (bytes, _) = data[0..2].split_at(std::mem::size_of::<u16>());
237                let raw_operand = u16::from_le_bytes(bytes.try_into().unwrap());
238                let index = raw_operand;
239                match register {
240                    0 => Ok(Operand::Symbolic(index as i16)),
241                    2 => Ok(Operand::Absolute(raw_operand)),
242                    1 | 3..=15 => Ok(Operand::Indexed((register, index as i16))),
243                    _ => Err(DecodeError::InvalidDestination((source, register))),
244                }
245            }
246        }
247        _ => Err(DecodeError::InvalidDestination((source, register))),
248    }
249}
250
251#[cfg(test)]
252mod tests {
253    use super::*;
254
255    #[test]
256    fn source_pc_symbolic() {
257        let data = [0x2, 0x0];
258        let source = parse_source(0, 1, &data);
259        assert_eq!(source, Ok((Operand::Symbolic(2), &data[2..])));
260    }
261
262    #[test]
263    fn source_pc_symbolic_missing_data() {
264        let data = [];
265        let source = parse_source(0, 1, &data);
266        assert_eq!(source, Err(DecodeError::MissingSource))
267    }
268
269    #[test]
270    fn source_pc_immediate() {
271        let data = [0x2, 0x0];
272        let source = parse_source(0, 3, &data);
273        assert_eq!(source, Ok((Operand::Immediate(2), &data[2..])));
274    }
275
276    #[test]
277    fn source_pc_immediate_high_bit() {
278        let data = [0xfe, 0xff];
279        let source = parse_source(0, 3, &data);
280        assert_eq!(source, Ok((Operand::Immediate(65534), &data[2..])));
281    }
282
283    #[test]
284    fn source_pc_immediate_missing_data() {
285        let data = [];
286        let source = parse_source(0, 3, &data);
287        assert_eq!(source, Err(DecodeError::MissingSource))
288    }
289
290    #[test]
291    fn source_pc_invalid_source() {
292        let data = [0xfe, 0xff];
293        let source = parse_source(0, 5, &data);
294        assert_eq!(source, Err(DecodeError::InvalidSource((5, 0))));
295    }
296
297    #[test]
298    fn source_sr_absolute() {
299        let data = [0x2, 0x0];
300        let source = parse_source(2, 1, &data);
301        assert_eq!(source, Ok((Operand::Absolute(2), &data[2..])));
302    }
303
304    #[test]
305    fn source_sr_absolute_missing_data() {
306        let data = [];
307        let source = parse_source(2, 1, &data);
308        assert_eq!(source, Err(DecodeError::MissingSource));
309    }
310
311    #[test]
312    fn source_sr_constant_four() {
313        let data = [];
314        let source = parse_source(2, 2, &data);
315        assert_eq!(source, Ok((Operand::Constant(4), &data[..])));
316    }
317
318    #[test]
319    fn source_sr_constant_eight() {
320        let data = [];
321        let source = parse_source(2, 3, &data);
322        assert_eq!(source, Ok((Operand::Constant(8), &data[..])));
323    }
324
325    #[test]
326    fn source_sr_invalid_source() {
327        let data = [];
328        let source = parse_source(2, 4, &data);
329        assert_eq!(source, Err(DecodeError::InvalidSource((4, 2))));
330    }
331
332    #[test]
333    fn source_cg_zero() {
334        let data = [];
335        let source = parse_source(3, 0, &data);
336        assert_eq!(source, Ok((Operand::Constant(0), &data[..])));
337    }
338
339    #[test]
340    fn source_cg_one() {
341        let data = [];
342        let source = parse_source(3, 1, &data);
343        assert_eq!(source, Ok((Operand::Constant(1), &data[..])));
344    }
345
346    #[test]
347    fn source_cg_two() {
348        let data = [];
349        let source = parse_source(3, 2, &data);
350        assert_eq!(source, Ok((Operand::Constant(2), &data[..])));
351    }
352
353    #[test]
354    fn source_cg_negative_one() {
355        let data = [];
356        let source = parse_source(3, 3, &data);
357        assert_eq!(source, Ok((Operand::Constant(-1), &data[..])));
358    }
359
360    #[test]
361    fn source_cg_invalid_source() {
362        let data = [];
363        let source = parse_source(3, 4, &data);
364        assert_eq!(source, Err(DecodeError::InvalidSource((4, 3))));
365    }
366
367    #[test]
368    fn source_gp_register_direct() {
369        let data = [];
370        let source = parse_source(9, 0, &data);
371        assert_eq!(source, Ok((Operand::RegisterDirect(9), &data[..])));
372    }
373
374    #[test]
375    fn source_gp_register_indexed() {
376        let data = [0x2, 0x0];
377        let source = parse_source(9, 1, &data);
378        assert_eq!(source, Ok((Operand::Indexed((9, 2)), &data[2..])));
379    }
380
381    #[test]
382    fn source_gp_register_indexed_negative() {
383        let data = [0xfd, 0xff];
384        let source = parse_source(9, 1, &data);
385        assert_eq!(source, Ok((Operand::Indexed((9, -3)), &data[2..])));
386    }
387
388    #[test]
389    fn source_gp_register_indirect() {
390        let data = [];
391        let source = parse_source(9, 2, &data);
392        assert_eq!(source, Ok((Operand::RegisterIndirect(9), &data[..])));
393    }
394
395    #[test]
396    fn source_gp_register_indirect_auto_increment() {
397        let data = [];
398        let source = parse_source(9, 3, &data);
399        assert_eq!(
400            source,
401            Ok((Operand::RegisterIndirectAutoIncrement(9), &data[..]))
402        );
403    }
404
405    #[test]
406    fn source_gp_invalid_source() {
407        let data = [];
408        let source = parse_source(9, 4, &data);
409        assert_eq!(source, Err(DecodeError::InvalidSource((4, 9))));
410    }
411
412    #[test]
413    fn destination_register_direct() {
414        let data = [];
415        let destination = parse_destination(9, 0, &data);
416        assert_eq!(destination, Ok(Operand::RegisterDirect(9)));
417    }
418
419    #[test]
420    fn destination_register_indexed() {
421        let data = [0x2, 0x0];
422        let destination = parse_destination(9, 1, &data);
423        assert_eq!(destination, Ok(Operand::Indexed((9, 2))));
424    }
425
426    #[test]
427    fn destination_register_indexed_negative() {
428        let data = [0xfe, 0xff];
429        let destination = parse_destination(9, 1, &data);
430        assert_eq!(destination, Ok(Operand::Indexed((9, -2))));
431    }
432
433    #[test]
434    fn destination_register_symbolic() {
435        let data = [0x2, 0x0];
436        let destination = parse_destination(0, 1, &data);
437        assert_eq!(destination, Ok(Operand::Symbolic(2)));
438    }
439
440    #[test]
441    fn destination_register_symbolic_negative() {
442        let data = [0xfe, 0xff];
443        let destination = parse_destination(0, 1, &data);
444        assert_eq!(destination, Ok(Operand::Symbolic(-2)));
445    }
446
447    #[test]
448    fn destination_register_absolute() {
449        let data = [0x2, 0x0];
450        let destination = parse_destination(2, 1, &data);
451        assert_eq!(destination, Ok(Operand::Absolute(2)));
452    }
453
454    #[test]
455    fn destination_invalid_source() {
456        let data = [];
457        let destination = parse_destination(9, 3, &data);
458        assert_eq!(destination, Err(DecodeError::InvalidDestination((3, 9))));
459    }
460}