1use std::fmt;
2
3use crate::emulate;
4use crate::emulate::Emulate;
5use crate::instruction::Instruction;
6use crate::operand::{Operand, OperandWidth};
7
8pub trait TwoOperand {
11 fn mnemonic(&self) -> &str;
13 fn source(&self) -> &Operand;
15 fn destination(&self) -> &Operand;
17 fn size(&self) -> usize;
19 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");