lemurs_8080/chip/execution/
mod.rs1use crate::prelude::*;
2use core::num::NonZeroU8;
3use super::access::{*, Register::*, Byte::*, Double::*, Internal::*, Word::*};
4
5pub mod opcode;
6use opcode::{Op, Op::*};
7
8#[cfg(feature="open")]
9pub(super) type OpOutcome = Result<Option<NonZeroU8>, String>;
10#[cfg(not(feature="open"))]
11pub(super) type OpOutcome = Option<NonZeroU8>;
12
13impl<H: Harness + ?Sized, C: BorrowMut<H>> Machine<H, C> {
14 fn from_pc(&self) -> impl Iterator<Item=u8> + '_ {
15 let mut start = self.chip.pc;
16 core::iter::from_fn(move || {let val = self.read(start).0; start += 1; Some(Wrapping(val))})
17 }
18
19 #[doc(hidden)]
20 #[cfg(feature="open")]
21 pub fn execute(&mut self) -> OpOutcome {
22 if !self.chip.active { return Ok(NonZeroU8::new(1)) };
23 let (op, len) = Op::extract(self.from_pc())
24 .map_err(|e| panic!("Couldn't extract opcode from {e:X} at {:#06X}", self.chip.pc)).unwrap();
25 self.chip.pc += len as raw::u16;
26 let outcome = {
27 let (chip, bus) = self.split_mut();
28 op.execute_on(chip, bus)
29 };
30 if outcome.is_err() {
31 self.chip.active = false;
32 };
33 let (chip, bus) = self.split_mut();
34 if let Some(action) = bus.did_execute(chip, op)? {
35 action.execute_on(chip, bus).unwrap();
36 if action == Halt { return Ok(None); }
37 }
38 outcome
39 }
40
41 #[cfg(any(not(feature="open"), doc))]
53 pub fn execute(&mut self) -> OpOutcome {
54 if !self.chip.active { return NonZeroU8::new(1) };
55 let (op, len) = Op::extract(self.from_pc())
56 .map_err(|e| panic!("Couldn't extract opcode from {e:X?}")).unwrap();
57 self.chip.pc += len as raw::u16;
58 let elapsed = {
59 let (chip, board) = self.split_mut();
60 op.execute_on(chip, board)
61 };
62 if elapsed.is_none() { self.chip.active = false; }
63 elapsed
64 }
65
66 pub fn interrupt(&mut self, op: Op) -> Result<bool, opcode::Error> {
76 if op.len() == 1 {
77 Ok(self.chip.interrupts && {
78 self.chip.active = true;
79 self.chip.interrupts = false;
80 let _ = op.execute_on(&mut self.chip, self.board.borrow_mut());
81 true
82 })
83 } else {
84 Err(opcode::Error::NotUsable(op))
85 }
86 }
87
88 pub fn reset_to(&mut self, index: usize) -> Result<bool, opcode::OutOfRange> {
92 match index {
93 0..=7 => Ok(self.interrupt(Reset{vector: index as raw::u8}).ok().unwrap()),
94 _ => Err(opcode::OutOfRange)
95 }
96 }
97}
98
99fn subtract(base: u8, by: u8) -> (u8, bool, bool) {
100 let value = (!by) + Wrapping(1);
101 let aux = base ^ value;
102 let (value, carry) = base.0.overflowing_add(value.0);
103 (Wrapping(value), by.0 != 0 && !carry, (value ^ aux.0) & 0x10 != 0)
104}
105
106macro_rules! byte {
107 {$chip:expr, $from:ident, $bus:expr, $onboard: expr, $external: expr} => {
108 match $chip.resolve($from) {
109 Single(register) => ($chip[register], $onboard),
110 Byte::RAM(address) => ($bus.read(address), $external),
111 _ => unreachable!()
112 }
113 };
114}
115
116impl Op {
117 #[cfg_attr(debug_assertions, allow(unreachable_patterns))]
118 fn execute_on<H: Harness + ?Sized>(self, chip: &mut State, mut bus: impl DerefMut<Target = H>) -> OpOutcome {
119 let cycles = match self {
120 Add { from, carry } => {
121 let (value, time) = byte!{chip, from, bus, 4, 7};
122 AddTo{value, carry}.execute_on(chip, bus)?;
123 time
124 }
125 AddTo { value, carry } => {
126 let carry_in = chip.c && carry;
127 let accumulator = &mut chip[A];
128 let aux = *accumulator ^ value;
129 let (value, carry) = accumulator.0.overflowing_add(value.0.wrapping_add(carry_in as raw::u8));
130 let value = Wrapping(value);
131 *accumulator = value;
132 *chip.update_flags() = carry;
133 chip.a = (value ^ aux).0 & 0x10 != 0;
134 7
135 }
136 And{from} => {
137 let (value, time) = byte!{chip, from, bus, 4, 7};
138 AndWith{value}.execute_on(chip, bus)?;
139 time
140 }
141 AndWith { value } => {
142 chip[A] &= value;
143 *chip.update_flags() = false;
144 7
145 }
146 Call{sub} => {
147 bus.write_word(chip.push(), chip.pc);
148 chip.pc = sub;
149 17
150 }
151 CallIf(test, sub) => if test.approves(chip) {
152 Call{sub}.execute_on(chip, bus)?;
153 17
154 } else {
155 11
156 }
157 CarryFlag(set) => {
158 chip.c = set || !chip.c;
159 4
160 }
161 Compare{from} => {
162 let (value, time) = byte!{chip, from, bus, 4, 7};
163 CompareWith { value }.execute_on(chip, bus)?;
164 time
165 }
166 CompareWith{value} => {
167 let (value, carry, aux) = subtract(chip[A], value);
168 *chip.update_flags_for(value) = carry;
169 chip.a = aux;
170 7
171 }
172 ComplementAccumulator => {
173 chip[A] = !chip[A];
174 4
175 }
176 DecimalAddAdjust => {
177 let aux = if chip[A].0 & 0x0F > 0x09 {
178 chip[A] += 0x06;
179 true
180 } else {
181 if chip.a { chip[A] = chip[A] + Wrapping(6); }
182 false
183 };
184 let carry = if chip[A] >> 4 > Wrapping(0x09) {
185 chip[A] += 0x06 << 4;
186 true
187 } else {
188 if chip.c { chip[A] += 0x06 << 4; }
189 false
190 };
191 *chip.update_flags() = carry;
192 chip.a = aux;
193 4
194 }
195 DecrementByte { register } => {
196 let (value, time) = match chip.resolve(register) {
197 Single(reg) => { chip[reg] -= 1; (chip[reg], 5)}
198 Byte::RAM(address) => {
199 let value = bus.read(address) - Wrapping(1);
200 bus.write(address, value);
201 (value, 10)
202 }
203 _ => unreachable!()
204 };
205 *chip.update_flags_for(value) = false;
206 chip.a = (value ^ (value + Wrapping(1))).0 & 0x10 != 0;
207 time
208 }
209 DecrementWord{register} => {
210 chip[register] -= 1;
211 5
212 }
213 DoubleAdd { register } => {
214 let (value, carry) = chip[HL].0.overflowing_add(chip[register].0);
215 (chip[HL], chip.c) = (Wrapping(value), carry);
216 10
217 }
218 ExchangeDoubleWithHilo => {
219 (chip[DE], chip[HL]) = (chip[HL], chip[DE]);
220 5
221 }
222 ExchangeTopWithHilo => {
223 let out = chip[HL];
224 chip[HL] = bus.read_word(chip.sp);
225 bus.write_word(chip.sp, out);
226 18
227 }
228 ExclusiveOr { from } => {
229 let (value, time) = byte!(chip, from, bus, 4, 7);
230 ExclusiveOrWith{value}.execute_on(chip, bus)?;
231 time
232 }
233 ExclusiveOrWith { value } => {
234 chip[A] ^= value;
235 *chip.update_flags() = false;
236 7
237 }
238 Halt => {
239 chip.active = false;
240 7
241 }
242 In(port) => {
243 chip[A] = bus.input(port);
244 10
245 }
246 IncrementByte { register } => {
247 let (value, time) = match chip.resolve(register) {
248 Single(reg) => { chip[reg] += 1; (chip[reg], 5)}
249 Byte::RAM(address) => {
250 let value = bus.read(address) + Wrapping(1);
251 bus.write(address, value);
252 (value, 10)
253 }
254 _ => unreachable!()
255 };
256 *chip.update_flags_for(value) = false;
257 chip.a = (value ^ (value - Wrapping(1))).0 & 0x10 != 0;
258 time
259 }
260 IncrementWord { register } => {
261 chip[register] += 1;
262 5
263 }
264 Interrupts(active) => {
265 chip.interrupts = active;
266 4
267 }
268 Jump{to} => {
269 chip.pc = to;
270 10
271 }
272 JumpIf(test, addr) => {
273 if test.approves(chip) { chip.pc = addr; }
274 10
275 }
276 LoadAccumulator{address} => {
277 chip[A] = bus.read(address);
278 13
279 }
280 LoadAccumulatorIndirect { register } => {
281 chip[A] = bus.read(chip[register]);
282 7
283 }
284 LoadExtendedWith { to, value } => {
285 chip[to] = value;
286 10
287 }
288 LoadHilo{address} => {
289 chip[HL] = bus.read_word(address);
290 16
291 }
292 Move{to, from} => {
293 let (to, from) = (chip.resolve(to), chip.resolve(from));
294 match (to, from) {
295 (Single(to), Single(from)) => {
296 chip[to] = chip[from];
297 5
298 }
299 (Byte::RAM(address), Single(from)) => {
300 bus.write(address, chip[from]);
301 7
302 }
303 (Single(to), Byte::RAM(address)) => {
304 chip[to] = bus.read(address);
305 7
306 }
307 _ => unreachable!()
308 }
309 }
310 MoveData { value, to } => {
311 match chip.resolve(to) {
312 Single(register) => { chip[register] = value; 7 },
313 Byte::RAM(address) => { bus.write(address, value); 10},
314 _ => unreachable!()
315 }
316 }
317 Or{from} => {
318 let (value, time) = byte!{chip, from, bus, 4, 7};
319 OrWith{value}.execute_on(chip, bus)?;
320 time
321 }
322 OrWith{value} => {
323 chip[A] |= value;
324 *chip.update_flags() = false;
325 7
326 }
327 Out(port) => {
328 bus.output(port, chip[A]);
329 10
330 }
331 Pop(target) => {
332 match target {
333 OnBoard(internal) => chip[internal] = bus.read_word(chip.pop()),
334 ProgramStatus => {
335 let [accumulator, status] = bus.read_word(chip.pop()).0.to_le_bytes();
336 chip[A] = Wrapping(accumulator);
337 chip.extract_flags(status);
338 }
339 _ => unreachable!()
340 };
341 10
342 }
343 ProgramCounterFromHilo => {
344 chip[ProgramCounter] = chip[HL];
345 5
346 }
347 Push (source) => {
348 let source = match source {
349 OnBoard(internal) => chip[internal],
350 ProgramStatus => chip.status(),
351 _ => unreachable!()
352 };
353 bus.write_word(chip.push(), source);
354 11
355 }
356 Reset{vector} => {
357 bus.write_word(chip.push(), chip.pc);
358 chip.pc = Wrapping(vector as raw::u16 * 8);
359 11
360 }
361 Return => {
362 chip.pc = bus.read_word(chip.pop());
363 10
364 }
365 ReturnIf(test) => {
366 if test.approves(chip) {
367 Return.execute_on(chip, bus)?;
368 11
369 } else {
370 5
371 }
372 }
373 RotateAccumulatorLeft => {
374 let bits = chip[A].0 as raw::u16 | if chip.c { 0x8000 } else { 0x0000 };
375 let [bits, carry] = bits.rotate_left(1).to_le_bytes();
376 chip.c = carry != 0;
377 chip[A] = Wrapping(bits);
378 4
379 }
380 RotateAccumulatorRight => {
381 let bits = chip[A].0 as raw::u16 | if chip.c { 0x0100 } else { 0x0000 };
382 let [bits, carry] = bits.rotate_right(1).to_le_bytes();
383 chip.c = carry != 0;
384 chip[A] = Wrapping(bits);
385 4
386 }
387 RotateLeftCarrying => {
388 let accumulator = chip[A].0;
389 chip.c = accumulator & 0x80 != 0;
390 chip[A] = Wrapping(accumulator.rotate_left(1));
391 4
392 }
393 RotateRightCarrying => {
394 let accumulator = chip[A].0;
395 chip.c = accumulator & 0x01 != 0;
396 chip[A] = Wrapping(accumulator.rotate_right(1));
397 4
398 }
399 StackPointerFromHilo => {
400 chip[StackPointer] = chip[HL];
401 5
402 }
403 StoreAccumulator { address } => {
404 bus.write(address, chip[A]);
405 13
406 }
407 StoreAccumulatorIndirect { register } => {
408 bus.write(chip[register], chip[A]);
409 7
410 }
411 StoreHilo{ address } => {
412 bus.write_word(address, chip[HL]);
413 16
414 }
415 Subtract { from, carry } => {
416 let (value, time) = byte!{chip, from, bus, 4, 7};
417 SubtractBy{value, carry}.execute_on(chip, bus)?;
418 time
419 }
420 SubtractBy{ value, carry } => {
421 let (value, carry, aux) = subtract(chip[A], value + Wrapping((chip.c && carry) as raw::u8));
422 chip[A] = value;
423 *chip.update_flags() = carry;
424 chip.a = aux;
425 7
426 }
427 NOP(n) => n,
428 #[cfg(debug_assertions)]
429 _ => unimplemented!("Op {self:?} not implemented yet")
430 };
431 let cycles = NonZeroU8::new(cycles);
432 #[cfg(feature="open")]
433 let cycles = Ok(cycles);
434 cycles
435 }
436}
437
438#[cfg(test)]
439mod tests;