msp430_asm/
emulate.rs

1use crate::instruction::Instruction;
2use crate::operand::{Operand, OperandWidth};
3
4use crate::two_operand::*;
5use std::fmt;
6
7/// All instructions that can emulate an instruction implement Emulate so
8/// that the decoding step can determine if a decoded instruction emulates
9/// another
10pub trait Emulate {
11    fn emulate(&self) -> Option<Instruction>;
12}
13
14/// All emulated instructions implement this trait to provide a common
15/// interface and polymorphism
16pub trait Emulated {
17    /// Return the mnemonic for the instruction. This is operand width aware
18    fn mnemonic(&self) -> &str;
19    /// Returns the destination operand
20    fn destination(&self) -> &Option<Operand>;
21    /// Returns the size of the instruction (in bytes). This should defer to
22    /// the original instruction due to the fact that emulation is a lossy
23    /// process
24    fn size(&self) -> usize;
25    /// Returns the operand width if one is specified
26    fn operand_width(&self) -> &Option<OperandWidth>;
27}
28
29macro_rules! emulated {
30    ($t:ident, $n:expr, $o:ident) => {
31        #[derive(Debug, Clone, Copy, PartialEq)]
32        pub struct $t {
33            destination: Option<Operand>,
34            operand_width: Option<OperandWidth>,
35            // we need to store the original instruction because emulation
36            // does not keep the original source and destination which makes
37            // it a lossy process. There are certain instructions where the
38            // source could use different addressing modes or that can be
39            // assembled in multiple ways
40            // (eg. mov #0, r15; [using immediate 0x0000 or constant #0])
41            original: $o,
42        }
43
44        impl $t {
45            pub fn new(
46                destination: Option<Operand>,
47                operand_width: Option<OperandWidth>,
48                original: $o,
49            ) -> $t {
50                $t {
51                    destination,
52                    operand_width,
53                    original,
54                }
55            }
56        }
57
58        impl Emulated for $t {
59            fn mnemonic(&self) -> &str {
60                match self.operand_width {
61                    Some(OperandWidth::Word) | None => $n,
62                    Some(OperandWidth::Byte) => concat!($n, ".b"),
63                }
64            }
65
66            fn destination(&self) -> &Option<Operand> {
67                &self.destination
68            }
69
70            fn size(&self) -> usize {
71                self.original.size()
72            }
73
74            fn operand_width(&self) -> &Option<OperandWidth> {
75                &self.operand_width
76            }
77        }
78
79        impl fmt::Display for $t {
80            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81                if self.destination.is_none() && self.operand_width.is_none() {
82                    write!(f, "{}", $n)
83                } else {
84                    write!(f, "{} {}", self.mnemonic(), self.destination.unwrap())
85                }
86            }
87        }
88    };
89}
90
91emulated!(Adc, "adc", Addc);
92emulated!(Br, "br", Mov);
93emulated!(Clr, "clr", Mov);
94emulated!(Clrc, "clrc", Bic);
95emulated!(Clrn, "clrn", Bic);
96emulated!(Clrz, "clrz", Bic);
97emulated!(Dadc, "dadc", Dadd);
98emulated!(Dec, "dec", Sub);
99emulated!(Decd, "decd", Sub);
100emulated!(Dint, "dint", Bic);
101emulated!(Eint, "eint", Bis);
102emulated!(Inc, "inc", Add);
103emulated!(Incd, "incd", Add);
104emulated!(Inv, "inv", Xor);
105emulated!(Nop, "nop", Mov);
106emulated!(Pop, "pop", Mov);
107emulated!(Ret, "ret", Mov);
108emulated!(Rla, "rla", Add);
109emulated!(Rlc, "rlc", Addc);
110emulated!(Sbc, "sbc", Subc);
111emulated!(Setc, "setc", Bis);
112emulated!(Setn, "Setn", Bis);
113emulated!(Setz, "setz", Bis);
114emulated!(Tst, "tst", Cmp);