1use core::panic;
2use std::{
3 mem,
4 ops::{Deref, DerefMut},
5 sync::{
6 mpsc::{Receiver, Sender},
7 Mutex, OnceLock,
8 },
9 thread,
10 time::{Duration, SystemTime, UNIX_EPOCH},
11};
12
13use std::sync::mpsc::channel;
14
15pub static INTERRUPT_SENDER: OnceLock<Mutex<Sender<(u8, bool)>>> = OnceLock::new();
17
18pub static PAUSE_SENDER: OnceLock<Mutex<Sender<()>>> = OnceLock::new();
20
21use crate::{
22 condition_codes::ConditionCodes, IoCallbacks, MemoryOutOfBounds, Result, CLOCK_CYCLES,
23};
24
25#[repr(C)]
26pub struct Cpu8080<'a> {
27 ram: &'a mut [u8],
28 rom: &'a [u8],
29 sp: u16,
30 pc: u16,
31 reg_a: u8,
32 reg_b: u8,
33 reg_c: u8,
34 reg_d: u8,
35 reg_e: u8,
36 reg_h: u8,
37 reg_l: u8,
38 conditon_codes: ConditionCodes,
39 interrupt_enabled: bool,
40 io_callbacks: IoCallbacks,
41 interrupt_receiver: Receiver<(u8, bool)>,
42 pause_receiver: Receiver<()>,
43}
44
45macro_rules! generate_move_from_mem {
46 ( $( ($func:ident, $reg:ident) ),* ) => {
47 $(
48 fn $func(&mut self) -> Result<()> {
49 let mem_addr = u16::from_le_bytes([self.reg_l, self.reg_h]);
50 Ok(self.$reg = self.load_byte_from_memory(mem_addr.into())?)
51 }
52 )*
53 };
54}
55
56macro_rules! generate_store_reg_to_ram {
57 ( $( ($func:ident, $reg:ident) ),* ) => {
58 $(
59 fn $func(&mut self) -> Result<()> {
60 let mem_addr = u16::from_le_bytes([self.reg_l, self.reg_h]);
61 self.store_to_ram(mem_addr.into(), self.$reg)
62 }
63 )*
64 };
65}
66
67macro_rules! generate_jump_on_condition {
68 ( $( ($jump:ident, $condition:ident) ),* ) => {
69 $(
70 fn $jump(&mut self, $condition: bool) -> Result<()> {
71 if $condition {
72 self.jmp()?;
73 } else {
74 self.pc += 2;
75 }
76 Ok(())
77 }
78 )*
79 };
80}
81
82macro_rules! generate_call_on_condition {
83 ( $( ($call:ident, $condition:ident) ),* ) => {
84 $(
85 fn $call(&mut self, $condition: bool) -> Result<()> {
86 if $condition {
87 self.call()?;
88 } else {
89 self.pc += 2;
90 }
91 Ok(())
92 }
93 )*
94 };
95}
96
97macro_rules! generate_return_on_condition {
98 ( $( ($ret:ident, $condition:ident) ),* ) => {
99 $(
100 fn $ret(&mut self, $condition: bool) -> Result<()> {
101 if $condition {
102 self.ret()?;
103 }
104 Ok(())
105 }
106 )*
107 };
108}
109
110macro_rules! generate_load_data_into_reg_pair {
111 ( $( ($func:ident, $reg_hi:ident, $reg_lo:ident) ),* ) => {
112 $(
113 fn $func(&mut self) -> Result<()> {
114 [self.$reg_lo, self.$reg_hi] = self.load_d16_operand()?;
115 self.pc += 2;
116 Ok(())
117 }
118 )*
119 };
120}
121
122macro_rules! generate_inc_dec_reg_pair {
123 ( $( ($func:ident, $reg_hi:ident, $reg_lo:ident, $value:expr) ),* ) => {
124 $(
125 fn $func(&mut self) {
126 let pair_value = u16::from_le_bytes([self.$reg_lo, self.$reg_hi]) as u32;
127 let value = $value as u32;
128 [_, _, self.$reg_hi, self.$reg_lo] = (pair_value + value).to_be_bytes();
129 }
130 )*
131 };
132}
133
134macro_rules! generate_inc_dec_reg {
135 ( $( ($func:ident, $reg:ident, $value:expr) ),* ) => {
136 $(
137 fn $func(&mut self) {
138 self.$reg = self.set_condition_bits(self.$reg.into(), $value.into()) as u8;
139 }
140 )*
141 };
142}
143
144macro_rules! pop_to_reg_pair {
145 ( $( ($func:ident, $reg_hi:ident, $reg_lo:ident) ),* ) => {
146 $(
147 fn $func(&mut self) -> Result<()> {
148 let addr_lo = self.load_byte_from_memory(self.sp.into())?;
149 let addr_hi = self.load_byte_from_memory((self.sp + 1).into())?;
150 (self.$reg_lo, self.$reg_hi) = (addr_lo, addr_hi);
151 self.sp += 2;
152 Ok(())
153 }
154 )*
155 };
156}
157
158macro_rules! push_to_reg_pair {
159 ( $( ($func:ident, $reg_hi:ident, $reg_lo:ident) ),* ) => {
160 $(
161 fn $func(&mut self) -> Result<()> {
162 self.store_to_ram((self.sp - 1).into(), self.$reg_hi)?;
163 self.store_to_ram((self.sp - 2).into(), self.$reg_lo)?;
164 self.sp -= 2;
165 Ok(())
166 }
167 )*
168 };
169}
170
171impl<'a> Cpu8080<'a> {
172 pub fn new(rom: &'a [u8], ram: &'a mut [u8], io_callbacks: IoCallbacks) -> Self {
173 let (interrupt_sender, interrupt_receiver) = channel();
174 INTERRUPT_SENDER.set(Mutex::new(interrupt_sender)).unwrap();
175 let (pause_sender, pause_receiver) = channel();
176 PAUSE_SENDER.set(Mutex::new(pause_sender)).unwrap();
177 Cpu8080 {
178 reg_a: 0,
179 reg_b: 0,
180 reg_c: 0,
181 reg_d: 0,
182 reg_e: 0,
183 reg_h: 0,
184 reg_l: 0,
185 sp: 0,
186 pc: 0,
187 rom,
188 ram,
189 conditon_codes: ConditionCodes::default(),
190 interrupt_enabled: false,
191 io_callbacks,
192 interrupt_receiver,
193 pause_receiver,
194 }
195 }
196
197 fn add(&mut self, reg: u8) {
198 let result = self.set_condition_bits(self.reg_a.into(), reg.into());
199 self.set_carry(result > u8::MAX.into());
200 self.reg_a = result as u8;
201 }
202
203 fn sub(&mut self, reg: u8) {
204 let result = self.set_condition_bits(self.reg_a.into(), reg.wrapping_neg().into());
205 self.set_carry(self.reg_a < reg);
206 self.reg_a = result as u8;
207 }
208
209 fn adc(&mut self, reg: u8) {
210 let carry = if self.conditon_codes.is_carry_set() {
211 1
212 } else {
213 0
214 };
215 let result = self.set_condition_bits(self.reg_a.into(), reg as u16 + carry);
216 self.set_carry(result > u8::MAX.into());
217 self.reg_a = result as u8;
218 }
219
220 fn sbb(&mut self, reg: u8) {
221 let carry: u8 = if self.conditon_codes.is_carry_set() {
222 1
223 } else {
224 0
225 };
226 let result = self.set_condition_bits(
227 self.reg_a.into(),
228 reg.wrapping_neg() as u16 + carry.wrapping_neg() as u16,
229 );
230 self.set_carry(self.reg_a < reg);
231 self.reg_a = result as u8;
232 }
233
234 fn set_condition_bits(&mut self, value1: u16, value2: u16) -> u16 {
235 let result = value1 + value2;
237 let lsb = result as u8;
238 self.set_zero(lsb == 0);
239 self.set_sign(lsb >= 0x80);
240 self.set_parity(lsb.count_ones() % 2 == 0);
241 let aux_carry = result & 0xf;
242 if aux_carry < (value1 & 0xf) && aux_carry < (value2 & 0xf) {
243 self.conditon_codes.set_aux_carry()
244 } else {
245 self.conditon_codes.reset_aux_carry()
246 }
247 result
248 }
249
250 fn set_zero(&mut self, is_zero: bool) {
251 if is_zero {
252 self.conditon_codes.set_zero()
253 } else {
254 self.conditon_codes.reset_zero()
255 }
256 }
257
258 fn set_parity(&mut self, is_parity_set: bool) {
259 if is_parity_set {
260 self.conditon_codes.set_parity()
261 } else {
262 self.conditon_codes.reset_parity()
263 }
264 }
265
266 fn set_sign(&mut self, is_sign_set: bool) {
267 if is_sign_set {
268 self.conditon_codes.set_sign()
269 } else {
270 self.conditon_codes.reset_sign()
271 }
272 }
273
274 fn set_carry(&mut self, is_carry: bool) {
275 if is_carry {
276 self.conditon_codes.set_carry();
277 } else {
278 self.conditon_codes.reset_carry();
279 }
280 }
281
282 fn dad(&mut self, value: u16) {
283 let hl = u16::from_le_bytes([self.reg_l, self.reg_h]) as u32;
284 let hl = hl + value as u32;
285 [self.reg_h, self.reg_l] = (hl as u16).to_be_bytes();
286 self.set_carry(hl > u16::MAX.into());
287 }
288
289 fn rlc(&mut self) {
290 self.reg_a = self.reg_a.rotate_left(1);
291 let carry = self.reg_a & 0x1;
292 self.set_carry(carry == 1);
293 }
294
295 fn rrc(&mut self) {
296 let carry = self.reg_a & 0x1;
297 self.reg_a = self.reg_a.rotate_right(1);
298 self.set_carry(carry == 1);
299 }
300
301 fn ral(&mut self) {
302 let carry = self.reg_a >= 0x80;
303 self.reg_a <<= 1;
304 self.reg_a |= self.conditon_codes.is_carry_set() as u8;
305 self.set_carry(carry);
306 }
307
308 fn rar(&mut self) {
309 let carry = self.reg_a & 0x1;
310 self.reg_a >>= 1;
311 self.reg_a |= (self.conditon_codes.is_carry_set() as u8) << 7;
312 self.set_carry(carry == 1);
313 }
314
315 fn load_byte_from_memory(&self, addr: usize) -> Result<u8> {
317 if addr >= self.rom.len() {
318 Ok(*self
319 .ram
320 .get(addr - self.rom.len())
321 .ok_or(MemoryOutOfBounds)?)
322 } else {
323 Ok(*self.rom.get(addr).ok_or(MemoryOutOfBounds)?)
324 }
325 }
326
327 fn store_to_ram(&mut self, addr: usize, value: u8) -> Result<()> {
329 if let Some(content) = self.ram.get_mut(addr - self.rom.len()) {
330 *content = value
331 }
332 Ok(())
333 }
334
335 fn adi(&mut self) -> Result<()> {
336 let imm = self.load_d8_operand()?;
337 self.add(imm);
338 Ok(())
339 }
340
341 fn aci(&mut self) -> Result<()> {
342 let imm = self.load_d8_operand()?;
343 self.adc(imm);
344 Ok(())
345 }
346
347 fn add_m(&mut self) -> Result<()> {
348 let mem_addr = u16::from_le_bytes([self.reg_l, self.reg_h]);
349 let value = self.load_byte_from_memory(mem_addr.into())?;
350 self.add(value);
351 Ok(())
352 }
353
354 fn sub_m(&mut self) -> Result<()> {
355 let mem_addr = u16::from_le_bytes([self.reg_l, self.reg_h]);
356 let value = self.load_byte_from_memory(mem_addr.into())?;
357 self.sub(value);
358 Ok(())
359 }
360
361 fn adc_m(&mut self) -> Result<()> {
362 let mem_addr = u16::from_le_bytes([self.reg_l, self.reg_h]);
363 let value = self.load_byte_from_memory(mem_addr.into())?;
364 self.adc(value);
365 Ok(())
366 }
367
368 fn sbb_m(&mut self) -> Result<()> {
369 let mem_addr = u16::from_le_bytes([self.reg_l, self.reg_h]);
370 let value = self.load_byte_from_memory(mem_addr.into())?;
371 self.sbb(value);
372 Ok(())
373 }
374
375 fn sui(&mut self) -> Result<()> {
376 let imm = self.load_d8_operand()?;
377 self.sub(imm);
378 Ok(())
379 }
380
381 fn sbi(&mut self) -> Result<()> {
382 let imm = self.load_d8_operand()?;
383 self.sbb(imm);
384 Ok(())
385 }
386
387 fn and(&mut self, value: u8) {
388 self.reg_a &= value;
389 self.logical_condtion_set();
390 }
391
392 fn ani(&mut self) -> Result<()> {
393 let value = self.load_d8_operand()?;
394 self.and(value);
395 Ok(())
396 }
397
398 fn ana_m(&mut self) -> Result<()> {
399 let mem_addr = u16::from_le_bytes([self.reg_l, self.reg_h]);
400 let value = self.load_byte_from_memory(mem_addr.into())?;
401 self.and(value);
402 Ok(())
403 }
404
405 fn xor(&mut self, value: u8) {
406 self.reg_a ^= value;
407 self.logical_condtion_set();
408 }
409
410 fn xri(&mut self) -> Result<()> {
411 let value = self.load_d8_operand()?;
412 self.xor(value);
413 Ok(())
414 }
415
416 fn xra_m(&mut self) -> Result<()> {
417 let mem_addr = u16::from_le_bytes([self.reg_l, self.reg_h]);
418 let value = self.load_byte_from_memory(mem_addr.into())?;
419 self.xor(value);
420 Ok(())
421 }
422
423 fn logical_condtion_set(&mut self) {
424 self.set_carry(false); self.set_zero(self.reg_a == 0);
426 self.set_sign(self.reg_a >= 0x80);
427 self.conditon_codes.reset_aux_carry();
428 self.set_parity(self.reg_a.count_ones() % 2 == 0);
429 }
430
431 fn or(&mut self, value: u8) {
432 self.reg_a |= value;
433 self.logical_condtion_set();
434 }
435
436 fn ori(&mut self) -> Result<()> {
437 let value = self.load_d8_operand()?;
438 self.or(value);
439 Ok(())
440 }
441
442 fn ora_m(&mut self) -> Result<()> {
443 let mem_addr = u16::from_le_bytes([self.reg_l, self.reg_h]);
444 let value = self.load_byte_from_memory(mem_addr.into())?;
445 self.or(value);
446 Ok(())
447 }
448
449 fn cmp(&mut self, value: u8) {
450 let _ = self.set_condition_bits(self.reg_a.into(), value.wrapping_neg().into());
451 self.set_carry(self.reg_a < value);
452 }
453
454 fn cmp_m(&mut self) -> Result<()> {
455 let mem_addr = u16::from_le_bytes([self.reg_l, self.reg_h]);
456 let value = self.load_byte_from_memory(mem_addr.into())?;
457 self.cmp(value);
458 Ok(())
459 }
460
461 fn cpi(&mut self) -> Result<()> {
462 let value = self.load_d8_operand()?;
463 self.cmp(value);
464 Ok(())
465 }
466
467 generate_inc_dec_reg_pair![
468 (inx_b, reg_b, reg_c, 1),
469 (inx_d, reg_d, reg_e, 1),
470 (inx_h, reg_h, reg_l, 1),
471 (dcx_b, reg_b, reg_c, 1u16.wrapping_neg()),
472 (dcx_d, reg_d, reg_e, 1u16.wrapping_neg()),
473 (dcx_h, reg_h, reg_l, 1u16.wrapping_neg())
474 ];
475
476 generate_inc_dec_reg![
477 (inr_b, reg_b, 1u8),
478 (inr_c, reg_c, 1u8),
479 (inr_d, reg_d, 1u8),
480 (inr_e, reg_e, 1u8),
481 (inr_h, reg_h, 1u8),
482 (inr_l, reg_l, 1u8),
483 (inr_a, reg_a, 1u8),
484 (dcr_b, reg_b, 1u8.wrapping_neg()),
485 (dcr_c, reg_c, 1u8.wrapping_neg()),
486 (dcr_d, reg_d, 1u8.wrapping_neg()),
487 (dcr_e, reg_e, 1u8.wrapping_neg()),
488 (dcr_h, reg_h, 1u8.wrapping_neg()),
489 (dcr_l, reg_l, 1u8.wrapping_neg()),
490 (drc_a, reg_a, 1u8.wrapping_neg())
491 ];
492
493 fn inr_m(&mut self) -> Result<()> {
494 let addr: usize = u16::from_le_bytes([self.reg_l, self.reg_h]).into();
495 let value = self.set_condition_bits(self.load_byte_from_memory(addr)?.into(), 1) as u8;
496 self.store_to_ram(addr, value)?;
497 Ok(())
498 }
499
500 fn dcr_m(&mut self) -> Result<()> {
501 let addr: usize = u16::from_le_bytes([self.reg_l, self.reg_h]).into();
502 let value = self.set_condition_bits(
503 self.load_byte_from_memory(addr)?.into(),
504 1u8.wrapping_neg().into(),
505 ) as u8;
506 self.store_to_ram(addr, value)?;
507 Ok(())
508 }
509
510 generate_move_from_mem![
511 (move_from_mem_to_b, reg_b),
512 (move_from_mem_to_c, reg_c),
513 (move_from_mem_to_d, reg_d),
514 (move_from_mem_to_e, reg_e),
515 (move_from_mem_to_l, reg_l),
516 (move_from_mem_to_h, reg_h),
517 (move_from_mem_to_a, reg_a)
518 ];
519
520 generate_store_reg_to_ram![
521 (store_reg_b_to_ram, reg_b),
522 (store_reg_c_to_ram, reg_c),
523 (store_reg_d_to_ram, reg_d),
524 (store_reg_e_to_ram, reg_e),
525 (store_reg_l_to_ram, reg_l),
526 (store_reg_h_to_ram, reg_h),
527 (store_reg_a_to_ram, reg_a)
528 ];
529
530 generate_load_data_into_reg_pair![
531 (load_data_into_reg_pair_b, reg_b, reg_c),
532 (load_data_into_reg_pair_d, reg_d, reg_e),
533 (load_data_into_reg_pair_h, reg_h, reg_l)
534 ];
535
536 pub fn run(&mut self) -> Result<()> {
537 #[cfg(feature = "bdos_mock")]
538 {
539 self.pc = 0x100
540 }
541 let mut start = SystemTime::now()
545 .duration_since(UNIX_EPOCH)
546 .unwrap()
547 .as_micros();
548 let mut circles = 0;
549 #[cfg(not(feature = "bdos_mock"))]
550 let mut pause = true;
551 while self.pc < self.rom.len() as u16 {
552 #[cfg(not(feature = "bdos_mock"))]
553 if pause {
554 self.pause_receiver.recv().unwrap();
555 pause = false
556 } else if self.pause_receiver.try_recv().is_ok() {
557 pause = true
558 }
559 circles += self.execute()?;
560 if let Ok((irq_no, allow_nested_interrupt)) = self.interrupt_receiver.try_recv() {
561 if self.interrupt_enabled {
562 self.rst(irq_no)?;
563 circles += CLOCK_CYCLES[0xc7_usize] as u64
564 }
565 self.interrupt_enabled = allow_nested_interrupt
566 }
567 if circles >= 16666 {
568 let time_spent = SystemTime::now()
569 .duration_since(UNIX_EPOCH)
570 .unwrap()
571 .as_micros()
572 - start;
573 if time_spent < circles as u128 / 2 {
574 thread::sleep(Duration::from_micros(circles / 2 - time_spent as u64))
575 }
576 circles = 0;
577 start = SystemTime::now()
578 .duration_since(UNIX_EPOCH)
579 .unwrap()
580 .as_micros();
581 }
582 }
583 Ok(())
584 }
585
586 pub fn get_ram(&self) -> &[u8] {
587 self.ram
588 }
589
590 fn execute(&mut self) -> Result<u64> {
591 let opcode = self.load_byte_from_memory(self.pc.into())?;
592 #[cfg(feature = "bdos_mock")]
593 if self.pc == 5 {
594 self.call_bdos()?;
595 self.pc -= 1;
596 } else if self.pc == 0 {
597 println!("RE-ENTRY TO CP/M WARM BOOT, exiting...");
598 std::process::exit(0)
599 }
600
601 self.pc += 1;
602 match opcode {
603 0x00 | 0x08 | 0x10 | 0x18 | 0x20 | 0x28 | 0x30 | 0x38 | 0x40 | 0x49 | 0x52 | 0x5b
604 | 0x64 | 0x6d | 0x7f | 0xcb | 0xd9 | 0xdd | 0xed | 0xfd => (),
605 0x01 => self.load_data_into_reg_pair_b()?,
606 0x02 => self.store_to_ram(
607 u16::from_le_bytes([self.reg_c, self.reg_b]).into(),
608 self.reg_a,
609 )?,
610 0x03 => self.inx_b(),
611 0x04 => self.inr_b(),
612 0x05 => self.dcr_b(),
613 0x06 => self.reg_b = self.load_d8_operand()?,
614 0x07 => self.rlc(),
615 0x09 => self.dad(u16::from_le_bytes([self.reg_c, self.reg_b])),
616 0x0a => {
617 self.reg_a =
618 self.load_byte_from_memory(u16::from_le_bytes([self.reg_c, self.reg_b]).into())?
619 }
620 0x0b => self.dcx_b(),
621 0x0c => self.inr_c(),
622 0x0d => self.dcr_c(),
623 0x0e => self.reg_c = self.load_d8_operand()?,
624 0x0f => self.rrc(),
625 0x11 => self.load_data_into_reg_pair_d()?,
626 0x12 => self.store_to_ram(
627 u16::from_le_bytes([self.reg_e, self.reg_d]).into(),
628 self.reg_a,
629 )?,
630 0x13 => self.inx_d(),
631 0x14 => self.inr_d(),
632 0x15 => self.dcr_d(),
633 0x16 => self.reg_d = self.load_d8_operand()?,
634 0x17 => self.ral(),
635 0x19 => self.dad(u16::from_le_bytes([self.reg_e, self.reg_d])),
636 0x1a => {
637 self.reg_a =
638 self.load_byte_from_memory(u16::from_le_bytes([self.reg_e, self.reg_d]).into())?
639 }
640 0x1b => self.dcx_d(),
641 0x1c => self.inr_e(),
642 0x1d => self.dcr_e(),
643 0x1e => self.reg_e = self.load_d8_operand()?,
644 0x1f => self.rar(),
645 0x21 => self.load_data_into_reg_pair_h()?,
646 0x22 => self.shld()?,
647 0x23 => self.inx_h(),
648 0x24 => self.inr_h(),
649 0x25 => self.dcr_h(),
650 0x26 => self.reg_h = self.load_d8_operand()?,
651 0x27 => self.daa(),
652 0x29 => self.dad(u16::from_le_bytes([self.reg_l, self.reg_h])),
653 0x2a => self.lhld()?,
654 0x2b => self.dcx_h(),
655 0x2c => self.inr_l(),
656 0x2d => self.dcr_l(),
657 0x2e => self.reg_l = self.load_d8_operand()?,
658 0x2f => self.reg_a = !self.reg_a,
659 0x31 => self.load_stack_pointer_from_operand()?,
660 0x32 => self.sta()?,
661 0x33 => self.sp += 1,
662 0x34 => self.inr_m()?,
663 0x35 => self.dcr_m()?,
664 0x36 => {
665 let imm = self.load_d8_operand()?;
666 self.store_to_ram(u16::from_le_bytes([self.reg_l, self.reg_h]).into(), imm)?
667 }
668 0x37 => self.conditon_codes.set_carry(),
669 0x39 => self.dad(self.sp),
670 0x3a => self.lda()?,
671 0x3b => self.sp -= 1,
672 0x3c => self.inr_a(),
673 0x3d => self.drc_a(),
674 0x3e => self.reg_a = self.load_d8_operand()?,
675 0x3f => self.set_carry(!self.conditon_codes.is_carry_set()),
676 0x41 => self.reg_b = self.reg_c,
677 0x42 => self.reg_b = self.reg_d,
678 0x43 => self.reg_b = self.reg_e,
679 0x44 => self.reg_b = self.reg_h,
680 0x45 => self.reg_b = self.reg_l,
681 0x46 => self.move_from_mem_to_b()?,
682 0x47 => self.reg_b = self.reg_a,
683 0x48 => self.reg_c = self.reg_b,
684 0x4a => self.reg_c = self.reg_d,
685 0x4b => self.reg_c = self.reg_e,
686 0x4c => self.reg_c = self.reg_h,
687 0x4d => self.reg_c = self.reg_l,
688 0x4e => self.move_from_mem_to_c()?,
689 0x4f => self.reg_c = self.reg_a,
690 0x50 => self.reg_d = self.reg_b,
691 0x51 => self.reg_d = self.reg_c,
692 0x53 => self.reg_d = self.reg_e,
693 0x54 => self.reg_d = self.reg_h,
694 0x55 => self.reg_d = self.reg_l,
695 0x56 => self.move_from_mem_to_d()?,
696 0x57 => self.reg_d = self.reg_a,
697 0x58 => self.reg_e = self.reg_b,
698 0x59 => self.reg_e = self.reg_c,
699 0x5a => self.reg_e = self.reg_d,
700 0x5c => self.reg_e = self.reg_h,
701 0x5d => self.reg_e = self.reg_l,
702 0x5e => self.move_from_mem_to_e()?,
703 0x5f => self.reg_e = self.reg_a,
704 0x60 => self.reg_h = self.reg_b,
705 0x61 => self.reg_h = self.reg_c,
706 0x62 => self.reg_h = self.reg_d,
707 0x63 => self.reg_h = self.reg_e,
708 0x65 => self.reg_h = self.reg_l,
709 0x66 => self.move_from_mem_to_h()?,
710 0x67 => self.reg_h = self.reg_a,
711 0x68 => self.reg_l = self.reg_b,
712 0x69 => self.reg_l = self.reg_c,
713 0x6a => self.reg_l = self.reg_d,
714 0x6b => self.reg_l = self.reg_e,
715 0x6c => self.reg_l = self.reg_h,
716 0x6e => self.move_from_mem_to_l()?,
717 0x6f => self.reg_l = self.reg_a,
718 0x70 => self.store_reg_b_to_ram()?,
719 0x71 => self.store_reg_c_to_ram()?,
720 0x72 => self.store_reg_d_to_ram()?,
721 0x73 => self.store_reg_e_to_ram()?,
722 0x74 => self.store_reg_h_to_ram()?,
723 0x75 => self.store_reg_l_to_ram()?,
724 0x76 => std::process::exit(1), 0x77 => self.store_reg_a_to_ram()?,
726 0x78 => self.reg_a = self.reg_b,
727 0x79 => self.reg_a = self.reg_c,
728 0x7a => self.reg_a = self.reg_d,
729 0x7b => self.reg_a = self.reg_e,
730 0x7c => self.reg_a = self.reg_h,
731 0x7d => self.reg_a = self.reg_l,
732 0x7e => self.move_from_mem_to_a()?,
733 0x80 => self.add(self.reg_b),
734 0x81 => self.add(self.reg_c),
735 0x82 => self.add(self.reg_d),
736 0x83 => self.add(self.reg_e),
737 0x84 => self.add(self.reg_h),
738 0x85 => self.add(self.reg_l),
739 0x86 => self.add_m()?,
740 0x87 => self.add(self.reg_a),
741 0x88 => self.adc(self.reg_b),
742 0x89 => self.adc(self.reg_c),
743 0x8a => self.adc(self.reg_d),
744 0x8b => self.adc(self.reg_e),
745 0x8c => self.adc(self.reg_h),
746 0x8d => self.adc(self.reg_l),
747 0x8e => self.adc_m()?,
748 0x8f => self.adc(self.reg_a),
749 0x90 => self.sub(self.reg_b),
750 0x91 => self.sub(self.reg_c),
751 0x92 => self.sub(self.reg_d),
752 0x93 => self.sub(self.reg_e),
753 0x94 => self.sub(self.reg_h),
754 0x95 => self.sub(self.reg_l),
755 0x96 => self.sub_m()?,
756 0x97 => self.sub(self.reg_a),
757 0x98 => self.sbb(self.reg_b),
758 0x99 => self.sbb(self.reg_c),
759 0x9a => self.sbb(self.reg_d),
760 0x9b => self.sbb(self.reg_e),
761 0x9c => self.sbb(self.reg_h),
762 0x9d => self.sbb(self.reg_l),
763 0x9e => self.sbb_m()?,
764 0x9f => self.sbb(self.reg_a),
765 0xa0 => self.and(self.reg_b),
766 0xa1 => self.and(self.reg_c),
767 0xa2 => self.and(self.reg_d),
768 0xa3 => self.and(self.reg_e),
769 0xa4 => self.and(self.reg_h),
770 0xa5 => self.and(self.reg_l),
771 0xa6 => self.ana_m()?,
772 0xa7 => self.and(self.reg_a),
773 0xa8 => self.xor(self.reg_b),
774 0xa9 => self.xor(self.reg_c),
775 0xaa => self.xor(self.reg_d),
776 0xab => self.xor(self.reg_e),
777 0xac => self.xor(self.reg_h),
778 0xad => self.xor(self.reg_l),
779 0xae => self.xra_m()?,
780 0xaf => self.xor(self.reg_a),
781 0xb0 => self.or(self.reg_b),
782 0xb1 => self.or(self.reg_c),
783 0xb2 => self.or(self.reg_d),
784 0xb3 => self.or(self.reg_e),
785 0xb4 => self.or(self.reg_h),
786 0xb5 => self.or(self.reg_l),
787 0xb6 => self.ora_m()?,
788 0xb7 => self.or(self.reg_a),
789 0xb8 => self.cmp(self.reg_b),
790 0xb9 => self.cmp(self.reg_c),
791 0xba => self.cmp(self.reg_d),
792 0xbb => self.cmp(self.reg_e),
793 0xbc => self.cmp(self.reg_h),
794 0xbd => self.cmp(self.reg_l),
795 0xbe => self.cmp_m()?,
796 0xbf => self.cmp(self.reg_a),
797 0xc0 => self.ret_on_zero(!self.conditon_codes.is_zero_set())?,
798 0xc1 => self.pop_b()?,
799 0xc2 => self.jump_on_zero(!self.conditon_codes.is_zero_set())?,
800 0xc3 => self.jmp()?,
801 0xc4 => self.call_on_zero(!self.conditon_codes.is_zero_set())?,
802 0xc5 => self.push_b()?,
803 0xc6 => self.adi()?,
804 0xc7 => self.rst(0)?,
805 0xc8 => self.ret_on_zero(self.conditon_codes.is_zero_set())?,
806 0xc9 => self.ret()?,
807 0xca => self.jump_on_zero(self.conditon_codes.is_zero_set())?,
808 0xcc => self.call_on_zero(self.conditon_codes.is_zero_set())?,
809 0xcd => self.call()?,
810 0xce => self.aci()?,
811 0xcf => self.rst(1)?,
812 0xd0 => self.ret_on_carry(!self.conditon_codes.is_carry_set())?,
813 0xd1 => self.pop_d()?,
814 0xd2 => self.jump_on_carry(!self.conditon_codes.is_carry_set())?,
815 0xd3 => self.output()?,
816 0xd4 => self.call_on_carry(!self.conditon_codes.is_carry_set())?,
817 0xd5 => self.push_d()?,
818 0xd6 => self.sui()?,
819 0xd7 => self.rst(2)?,
820 0xd8 => self.ret_on_carry(self.conditon_codes.is_carry_set())?,
821 0xda => self.jump_on_carry(self.conditon_codes.is_carry_set())?,
822 0xdb => self.input()?,
823 0xdc => self.call_on_carry(self.conditon_codes.is_carry_set())?,
824 0xde => self.sbi()?,
825 0xdf => self.rst(3)?,
826 0xe0 => self.ret_on_parity(!self.conditon_codes.is_parity_set())?,
827 0xe1 => self.pop_h()?,
828 0xe2 => self.jump_on_parity(!self.conditon_codes.is_parity_set())?,
829 0xe3 => self.xthl(),
830 0xe4 => self.call_on_parity(!self.conditon_codes.is_parity_set())?,
831 0xe5 => self.push_h()?,
832 0xe6 => self.ani()?,
833 0xe7 => self.rst(4)?,
834 0xe8 => self.ret_on_parity(self.conditon_codes.is_parity_set())?,
835 0xe9 => self.pc = u16::from_le_bytes([self.reg_l, self.reg_h]),
836 0xea => self.jump_on_parity(self.conditon_codes.is_parity_set())?,
837 0xeb => self.xchg(),
838 0xec => self.call_on_parity(self.conditon_codes.is_parity_set())?,
839 0xee => self.xri()?,
840 0xef => self.rst(5)?,
841 0xf0 => self.ret_on_sign(!self.conditon_codes.is_sign_set())?,
842 0xf1 => self.pop_psw()?,
843 0xf2 => self.jump_on_sign(!self.conditon_codes.is_sign_set())?,
844 0xf3 => self.interrupt_enabled = false,
845 0xf4 => self.call_on_sign(!self.conditon_codes.is_sign_set())?,
846 0xf5 => self.push_psw()?,
847 0xf6 => self.ori()?,
848 0xf7 => self.rst(6)?,
849 0xf8 => self.ret_on_sign(self.conditon_codes.is_sign_set())?,
850 0xf9 => self.sp = u16::from_le_bytes([self.reg_l, self.reg_h]),
851 0xfa => self.jump_on_sign(self.conditon_codes.is_sign_set())?,
852 0xfb => self.interrupt_enabled = true,
853 0xfc => self.call_on_sign(self.conditon_codes.is_sign_set())?,
854 0xfe => self.cpi()?,
855 0xff => self.rst(7)?,
856 }
857 Ok(CLOCK_CYCLES[opcode as usize] as u64)
858 }
859
860 fn load_stack_pointer_from_operand(&mut self) -> Result<()> {
861 self.sp = u16::from_le_bytes(self.load_d16_operand()?);
862 self.pc += 2;
863 Ok(())
864 }
865
866 generate_call_on_condition![
867 (call_on_zero, is_zero_set),
868 (call_on_carry, is_carry_set),
869 (call_on_parity, is_parity_set_set),
870 (call_on_sign, is_sign_set_set)
871 ];
872
873 fn shld(&mut self) -> Result<()> {
874 let address = u16::from_le_bytes(self.load_d16_operand()?);
875 self.store_to_ram(address.into(), self.reg_l)?;
876 self.store_to_ram((address + 1).into(), self.reg_h)?;
877 self.pc += 2;
878 Ok(())
879 }
880
881 fn lhld(&mut self) -> Result<()> {
882 let address = u16::from_le_bytes(self.load_d16_operand()?);
883 let lo = self.load_byte_from_memory(address.into())?;
884 let hi = self.load_byte_from_memory((address + 1).into())?;
885 (self.reg_l, self.reg_h) = (lo, hi);
886 self.pc += 2;
887 Ok(())
888 }
889
890 fn xthl(&mut self) {
891 mem::swap(
892 &mut self.ram[self.sp as usize - self.rom.len()],
893 &mut self.reg_l,
894 );
895 mem::swap(
896 &mut self.ram[(self.sp + 1) as usize - self.rom.len()],
897 &mut self.reg_h,
898 );
899 }
900
901 fn xchg(&mut self) {
902 mem::swap(&mut self.reg_h, &mut self.reg_d);
903 mem::swap(&mut self.reg_l, &mut self.reg_e);
904 }
905
906 fn sta(&mut self) -> Result<()> {
907 let address = u16::from_le_bytes(self.load_d16_operand()?);
908 self.store_to_ram(address.into(), self.reg_a)?;
909 self.pc += 2;
910 Ok(())
911 }
912
913 fn lda(&mut self) -> Result<()> {
914 let address = u16::from_le_bytes(self.load_d16_operand()?);
915 self.reg_a = self.load_byte_from_memory(address.into())?;
916 self.pc += 2;
917 Ok(())
918 }
919
920 pop_to_reg_pair![
921 (pop_b, reg_b, reg_c),
922 (pop_d, reg_d, reg_e),
923 (pop_h, reg_h, reg_l)
924 ];
925
926 fn pop_psw(&mut self) -> Result<()> {
927 let lo = self.load_byte_from_memory(self.sp.into())?;
928 let hi = self.load_byte_from_memory((self.sp + 1).into())?;
929 (*self.conditon_codes.deref_mut(), self.reg_a) = (lo, hi);
930 self.sp += 2;
931 Ok(())
932 }
933
934 push_to_reg_pair![
935 (push_b, reg_b, reg_c),
936 (push_d, reg_d, reg_e),
937 (push_h, reg_h, reg_l)
938 ];
939
940 fn push_psw(&mut self) -> Result<()> {
941 self.store_to_ram((self.sp - 1).into(), self.reg_a)?;
942 self.store_to_ram((self.sp - 2).into(), *self.conditon_codes.deref())?;
943 self.sp -= 2;
944 Ok(())
945 }
946
947 fn call(&mut self) -> Result<()> {
948 let pc_in_bytes = (self.pc + 2).to_be_bytes();
949 self.store_to_ram((self.sp - 1).into(), pc_in_bytes[0])?;
950 self.store_to_ram((self.sp - 2).into(), pc_in_bytes[1])?;
951 self.sp -= 2;
952 #[cfg(feature = "bdos_mock")]
953 let old_pc = self.pc - 1;
954 self.pc = u16::from_le_bytes(self.load_d16_operand()?);
955 #[cfg(feature = "bdos_mock")]
956 println!(
957 "call into {:#06x} from {:#06x}, sp = {:#06x}",
958 self.pc, old_pc, self.sp
959 );
960
961 Ok(())
962 }
963
964 #[cfg(feature = "bdos_mock")]
965 fn call_bdos(&mut self) -> Result<()> {
966 let msg_addr = (u16::from_le_bytes([self.reg_e, self.reg_d]) + 3) as usize; assert_eq!(msg_addr, 0x0178);
968 let msg: Vec<u8> = self
969 .rom
970 .iter()
971 .skip(msg_addr)
972 .take_while(|&&c| c as char != '$')
973 .map(|c| c.to_owned())
974 .collect();
975 println!("{}", String::from_utf8_lossy(&msg));
976 self.ret()?;
977 Ok(())
978 }
979
980 fn rst(&mut self, rst_no: u8) -> Result<()> {
981 match rst_no {
982 1..=7 => {
983 let pc_in_bytes = self.pc.to_be_bytes();
984 self.store_to_ram((self.sp - 1).into(), pc_in_bytes[0])?;
985 self.store_to_ram((self.sp - 2).into(), pc_in_bytes[1])?;
986 self.sp -= 2;
987 #[cfg(feature = "bdos_mock")]
988 let old_pc = self.pc;
989 self.pc = rst_no as u16 * 8;
990 #[cfg(feature = "bdos_mock")]
991 println!("Interrupted to {:#06x} from {:#06x}", self.pc, old_pc);
992 }
993 _ => panic!("unsupported IRQ {rst_no}"),
994 }
995 Ok(())
996 }
997
998 fn output(&mut self) -> Result<()> {
999 let dev_no = self.load_d8_operand()?;
1000 (self.io_callbacks.output)(dev_no, self.reg_a);
1001 Ok(())
1002 }
1003
1004 fn input(&mut self) -> Result<()> {
1005 let dev_no = self.load_d8_operand()?;
1006 self.reg_a = (self.io_callbacks.input)(dev_no);
1007 Ok(())
1008 }
1009
1010 fn daa(&mut self) {
1011 if (self.reg_a & 0xf) > 0x9 || self.conditon_codes.is_aux_carry_set() {
1012 let aux_carry = self.reg_a as u16 + 6;
1013 if (aux_carry & 0xf) < 0x6 {
1014 self.conditon_codes.set_aux_carry()
1015 } else {
1016 self.conditon_codes.reset_aux_carry()
1017 }
1018 self.reg_a = aux_carry as u8;
1019 }
1020 if (self.reg_a & 0xf0) > 0x90 || self.conditon_codes.is_carry_set() {
1021 let result = self.reg_a as u16 + (6u8 << 4) as u16;
1022 if result > u8::MAX.into() {
1023 self.conditon_codes.set_carry()
1024 }
1025 self.reg_a = result as u8;
1026 }
1027 self.set_zero(self.reg_a == 0);
1028 self.set_sign(self.reg_a >= 0x80);
1029 self.set_parity(self.reg_a.count_ones() % 2 == 0);
1030 }
1031
1032 generate_return_on_condition![
1033 (ret_on_zero, is_zero_set),
1034 (ret_on_carry, is_carry_set),
1035 (ret_on_parity, is_parity_set_set),
1036 (ret_on_sign, is_sign_set_set)
1037 ];
1038
1039 fn ret(&mut self) -> Result<()> {
1040 let addr_lo = self.load_byte_from_memory(self.sp.into())?;
1041 let addr_hi = self.load_byte_from_memory((self.sp + 1).into())?;
1042 self.pc = u16::from_le_bytes([addr_lo, addr_hi]);
1043 self.sp += 2;
1044 #[cfg(feature = "bdos_mock")]
1045 println!("Return back to {:#06x}, sp = {:#06x}", self.pc, self.sp);
1046 Ok(())
1047 }
1048
1049 fn load_d16_operand(&self) -> Result<[u8; 2]> {
1051 Ok([
1052 self.load_byte_from_memory((self.pc).into())?,
1053 self.load_byte_from_memory((self.pc + 1).into())?,
1054 ])
1055 }
1056
1057 fn load_d8_operand(&mut self) -> Result<u8> {
1058 let value = self.load_byte_from_memory((self.pc).into())?;
1059 self.pc += 1;
1060 Ok(value)
1061 }
1062
1063 generate_jump_on_condition![
1064 (jump_on_zero, is_zero_set),
1065 (jump_on_carry, is_carry_set),
1066 (jump_on_parity, is_parity_set_set),
1067 (jump_on_sign, is_sign_set_set)
1068 ];
1069
1070 fn jmp(&mut self) -> Result<()> {
1071 #[cfg(feature = "bdos_mock")]
1072 let old_pc = self.pc - 1;
1073 self.pc = u16::from_le_bytes(self.load_d16_operand()?);
1074 #[cfg(feature = "bdos_mock")]
1075 println!("Jump from {:#06x} to {:#06x}", old_pc, self.pc);
1076 Ok(())
1077 }
1078}
1079
1080#[cfg(test)]
1081mod tests {
1082 use super::*;
1083
1084 #[test]
1085 fn cpu_opcode_tests() {
1086 let dummy_rom = &vec![0; 0];
1087 let dummy_ram = &mut vec![0; 0];
1088 pub extern "C" fn input(port: u8) -> u8 {
1089 port
1090 }
1091 pub extern "C" fn output(port: u8, value: u8) {
1092 println!("{port}, {value}")
1093 }
1094 let mut cpu = Cpu8080::new(dummy_rom, dummy_ram, IoCallbacks { input, output });
1095
1096 cpu.reg_a = 0xb5;
1098 cpu.conditon_codes.reset_carry();
1099 cpu.ral();
1100 assert!(cpu.conditon_codes.is_carry_set());
1101 assert_eq!(cpu.reg_a, 0x6a);
1102 cpu.rar();
1103 assert!(!cpu.conditon_codes.is_carry_set());
1104 assert_eq!(cpu.reg_a, 0xb5);
1105
1106 cpu.reg_b = 0x33;
1108 cpu.reg_c = 0x9f;
1109 cpu.reg_h = 0xa1;
1110 cpu.reg_l = 0x7b;
1111 cpu.conditon_codes.reset_carry();
1112 cpu.dad(u16::from_le_bytes([cpu.reg_c, cpu.reg_b]));
1113 assert_eq!(cpu.reg_h, 0xd5);
1114 assert_eq!(cpu.reg_l, 0x1a);
1115 assert!(!cpu.conditon_codes.is_carry_set());
1116
1117 cpu.reg_a = 0x9b;
1119 cpu.conditon_codes.reset_carry();
1120 cpu.conditon_codes.reset_aux_carry();
1121 cpu.daa();
1122 assert_eq!(cpu.reg_a, 0x1);
1123 assert!(cpu.conditon_codes.is_carry_set());
1124 assert!(cpu.conditon_codes.is_aux_carry_set());
1125
1126 cpu.reg_a = 0x88;
1127 cpu.conditon_codes.reset_carry();
1128 cpu.conditon_codes.reset_aux_carry();
1129 cpu.add(cpu.reg_a);
1130 assert!(cpu.conditon_codes.is_carry_set());
1131 assert!(cpu.conditon_codes.is_aux_carry_set());
1132 assert_eq!(0x10, cpu.reg_a);
1133 cpu.daa();
1134 assert_eq!(0x76, cpu.reg_a);
1135 assert!(cpu.conditon_codes.is_carry_set());
1136 assert!(!cpu.conditon_codes.is_aux_carry_set());
1137 }
1138}