i8080emulator/
cpu.rs

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
15/// shared with consumer for delivering interrupts to our CPU
16pub static INTERRUPT_SENDER: OnceLock<Mutex<Sender<(u8, bool)>>> = OnceLock::new();
17
18/// shared with consumer for pause/start the execution
19pub 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        // Z, S, P, AC
236        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    /// It is allowed to load content from either ROM or RAM
316    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    /// It is only allowed to write to RAM, we shall never write to ROM
328    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); // always reset carry
425        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        // 2Mhz => 2 circles per microsecond
542        // if we run as 120Hz, 1 / 120 => 8333 microseconds
543        // we supposed to be able to run 16666 circles
544        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), // HLT
725            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; // skipping 0CH,0DH,0AH
967        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    /// get operand parts in (lo, hi)
1050    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        // test RAL & RAR
1097        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        // test DAD
1107        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        // // test DAA
1118        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}