msp430_asm/
two_operand.rs

1use std::fmt;
2
3use crate::emulate;
4use crate::emulate::Emulate;
5use crate::instruction::Instruction;
6use crate::operand::{Operand, OperandWidth};
7
8/// All two operand instructions implement this trait to provide a common
9/// interface and polymorphism
10pub trait TwoOperand {
11    /// Return the mnemonic for the instruction. This is operand width aware
12    fn mnemonic(&self) -> &str;
13    /// Returns the source operand
14    fn source(&self) -> &Operand;
15    /// Returns the destination operand
16    fn destination(&self) -> &Operand;
17    /// Returns the size of the instruction (in bytes)
18    fn size(&self) -> usize;
19    /// Returns the operand width
20    fn operand_width(&self) -> &OperandWidth;
21}
22
23macro_rules! two_operand {
24    ($t:ident, $n:expr) => {
25        #[derive(Debug, Clone, Copy, PartialEq)]
26        pub struct $t {
27            source: Operand,
28            operand_width: OperandWidth,
29            destination: Operand,
30        }
31
32        impl $t {
33            pub fn new(source: Operand, operand_width: OperandWidth, destination: Operand) -> $t {
34                $t {
35                    source,
36                    operand_width,
37                    destination,
38                }
39            }
40        }
41
42        impl TwoOperand for $t {
43            fn mnemonic(&self) -> &str {
44                match self.operand_width {
45                    OperandWidth::Word => $n,
46                    OperandWidth::Byte => concat!($n, ".b"),
47                }
48            }
49
50            fn source(&self) -> &Operand {
51                &self.source
52            }
53
54            fn destination(&self) -> &Operand {
55                &self.destination
56            }
57
58            fn size(&self) -> usize {
59                2 + self.source.size() + self.destination.size()
60            }
61
62            fn operand_width(&self) -> &OperandWidth {
63                &self.operand_width
64            }
65        }
66
67        impl fmt::Display for $t {
68            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69                write!(
70                    f,
71                    "{} {}, {}",
72                    self.mnemonic(),
73                    self.source,
74                    self.destination
75                )
76            }
77        }
78    };
79}
80
81two_operand!(Mov, "mov");
82
83impl Emulate for Mov {
84    fn emulate(&self) -> Option<Instruction> {
85        if self.source == Operand::Constant(0) && self.destination == Operand::RegisterDirect(3) {
86            return Some(Instruction::Nop(emulate::Nop::new(None, None, *self)));
87        }
88
89        if self.source == Operand::Constant(0) || self.source == Operand::Immediate(0) {
90            if let Operand::RegisterDirect(_) = self.destination {
91                return Some(Instruction::Clr(emulate::Clr::new(
92                    Some(self.destination),
93                    None,
94                    *self,
95                )));
96            }
97        }
98
99        if self.source == Operand::RegisterIndirectAutoIncrement(1) {
100            if self.destination == Operand::RegisterDirect(0) {
101                return Some(Instruction::Ret(emulate::Ret::new(None, None, *self)));
102            } else {
103                return Some(Instruction::Pop(emulate::Pop::new(
104                    Some(self.destination),
105                    Some(self.operand_width),
106                    *self,
107                )));
108            }
109        }
110
111        if self.destination == Operand::RegisterDirect(0) {
112            return Some(Instruction::Br(emulate::Br::new(
113                Some(self.source),
114                None,
115                *self,
116            )));
117        }
118
119        None
120    }
121}
122
123two_operand!(Add, "add");
124
125impl Emulate for Add {
126    fn emulate(&self) -> Option<Instruction> {
127        if self.source == Operand::Constant(1) {
128            Some(Instruction::Inc(emulate::Inc::new(
129                Some(self.destination),
130                None,
131                *self,
132            )))
133        } else if self.source == Operand::Constant(2) {
134            Some(Instruction::Incd(emulate::Incd::new(
135                Some(self.destination),
136                None,
137                *self,
138            )))
139        } else if self.source == self.destination {
140            Some(Instruction::Rla(emulate::Rla::new(
141                Some(self.destination),
142                Some(self.operand_width),
143                *self,
144            )))
145        } else {
146            None
147        }
148    }
149}
150
151two_operand!(Addc, "addc");
152
153impl Emulate for Addc {
154    fn emulate(&self) -> Option<Instruction> {
155        if self.source == Operand::Constant(0) {
156            Some(Instruction::Adc(emulate::Adc::new(
157                Some(self.destination),
158                Some(self.operand_width),
159                *self,
160            )))
161        } else if self.source == self.destination {
162            Some(Instruction::Rlc(emulate::Rlc::new(
163                Some(self.destination),
164                Some(self.operand_width),
165                *self,
166            )))
167        } else {
168            None
169        }
170    }
171}
172
173two_operand!(Subc, "subc");
174
175impl Emulate for Subc {
176    fn emulate(&self) -> Option<Instruction> {
177        if self.source == Operand::Constant(0) {
178            Some(Instruction::Sbc(emulate::Sbc::new(
179                Some(self.destination),
180                Some(self.operand_width),
181                *self,
182            )))
183        } else {
184            None
185        }
186    }
187}
188
189two_operand!(Sub, "sub");
190
191impl Emulate for Sub {
192    fn emulate(&self) -> Option<Instruction> {
193        if self.source == Operand::Constant(1) {
194            Some(Instruction::Dec(emulate::Dec::new(
195                Some(self.destination),
196                Some(self.operand_width),
197                *self,
198            )))
199        } else if self.source == Operand::Constant(2) {
200            Some(Instruction::Decd(emulate::Decd::new(
201                Some(self.destination),
202                Some(self.operand_width),
203                *self,
204            )))
205        } else {
206            None
207        }
208    }
209}
210
211two_operand!(Cmp, "cmp");
212
213impl Emulate for Cmp {
214    fn emulate(&self) -> Option<Instruction> {
215        if self.source == Operand::Constant(0) {
216            Some(Instruction::Tst(emulate::Tst::new(
217                Some(self.destination),
218                Some(self.operand_width),
219                *self,
220            )))
221        } else {
222            None
223        }
224    }
225}
226
227two_operand!(Dadd, "dadd");
228
229impl Emulate for Dadd {
230    fn emulate(&self) -> Option<Instruction> {
231        if self.source == Operand::Constant(0) {
232            Some(Instruction::Dadc(emulate::Dadc::new(
233                Some(self.destination),
234                Some(self.operand_width),
235                *self,
236            )))
237        } else {
238            None
239        }
240    }
241}
242
243two_operand!(Bit, "bit");
244two_operand!(Bic, "bic");
245
246impl Emulate for Bic {
247    fn emulate(&self) -> Option<Instruction> {
248        if self.destination == Operand::RegisterDirect(2) {
249            match self.source {
250                Operand::Constant(1) => {
251                    return Some(Instruction::Clrc(emulate::Clrc::new(None, None, *self)))
252                }
253                Operand::Constant(2) => {
254                    return Some(Instruction::Clrn(emulate::Clrn::new(None, None, *self)))
255                }
256                Operand::Constant(4) => {
257                    return Some(Instruction::Clrz(emulate::Clrz::new(None, None, *self)))
258                }
259                Operand::Constant(8) => {
260                    return Some(Instruction::Dint(emulate::Dint::new(None, None, *self)))
261                }
262                _ => {}
263            }
264        }
265
266        None
267    }
268}
269
270two_operand!(Bis, "bis");
271
272impl Emulate for Bis {
273    fn emulate(&self) -> Option<Instruction> {
274        if self.destination == Operand::RegisterDirect(2) {
275            match self.source {
276                Operand::Constant(1) => {
277                    return Some(Instruction::Setc(emulate::Setc::new(None, None, *self)))
278                }
279                Operand::Constant(2) => {
280                    return Some(Instruction::Setz(emulate::Setz::new(None, None, *self)))
281                }
282                Operand::Constant(4) => {
283                    return Some(Instruction::Setn(emulate::Setn::new(None, None, *self)))
284                }
285                Operand::Constant(8) => {
286                    return Some(Instruction::Eint(emulate::Eint::new(None, None, *self)))
287                }
288                _ => {}
289            }
290        }
291
292        None
293    }
294}
295
296two_operand!(Xor, "xor");
297
298impl Emulate for Xor {
299    fn emulate(&self) -> Option<Instruction> {
300        if self.source == Operand::Constant(-1) {
301            Some(Instruction::Inv(emulate::Inv::new(
302                Some(self.destination),
303                Some(self.operand_width),
304                *self,
305            )))
306        } else {
307            None
308        }
309    }
310}
311
312two_operand!(And, "and");