1use crate::core::instructions::{
2    BlockMode, InstructionExecutor, parity_flag, sign_flag, zero_flag,
3};
4use crate::core::{Flags, IndexRegister, Register16};
5use crate::debug::BusDebugExt;
6use crate::traits::BusInterface;
7use jgenesis_common::num::GetBit;
8
9macro_rules! impl_a_r_add_op {
10    ($name:ident, $op_fn:ident) => {
11        pub(super) fn $name(
12            &mut self,
13            opcode: u8,
14            index: Option<IndexRegister>,
15            with_carry: bool,
16        ) -> u32 {
17            let read_target =
18                super::parse_register_from_opcode(opcode, index).expect("invalid opcode");
19            let operand = read_target.read_from(&self.cpu.registers);
20
21            self.cpu.registers.a =
22                $op_fn(self.cpu.registers.a, operand, with_carry, &mut self.cpu.registers.f);
23
24            4
25        }
26    };
27}
28
29macro_rules! impl_a_immediate_add_op {
30    ($name:ident, $op_fn:ident) => {
31        pub(super) fn $name(&mut self, with_carry: bool) -> u32 {
32            let operand = self.fetch_operand();
33
34            self.cpu.registers.a =
35                $op_fn(self.cpu.registers.a, operand, with_carry, &mut self.cpu.registers.f);
36
37            7
38        }
39    };
40}
41
42macro_rules! impl_a_hl_add_op {
43    ($name:ident, $op_fn:ident) => {
44        pub(super) fn $name(&mut self, index: Option<IndexRegister>, with_carry: bool) -> u32 {
45            let address = self.fetch_indirect_hl_address(index);
46            let operand = self.bus.read_memory_debug(address, self.cpu);
47
48            self.cpu.registers.a =
49                $op_fn(self.cpu.registers.a, operand, with_carry, &mut self.cpu.registers.f);
50
51            match index {
52                Some(_) => 15,
53                None => 7,
54            }
55        }
56    };
57}
58
59macro_rules! impl_a_r_bit_op {
60    ($name:ident, $op_fn:ident) => {
61        pub(super) fn $name(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 {
62            let read_target =
63                super::parse_register_from_opcode(opcode, index).expect("invalid opcode");
64            let operand = read_target.read_from(&self.cpu.registers);
65
66            self.cpu.registers.a = $op_fn(self.cpu.registers.a, operand, &mut self.cpu.registers.f);
67
68            4
69        }
70    };
71}
72
73macro_rules! impl_a_immediate_bit_op {
74    ($name:ident, $op_fn:ident) => {
75        pub(super) fn $name(&mut self) -> u32 {
76            let operand = self.fetch_operand();
77
78            self.cpu.registers.a = $op_fn(self.cpu.registers.a, operand, &mut self.cpu.registers.f);
79
80            7
81        }
82    };
83}
84
85macro_rules! impl_a_hl_bit_op {
86    ($name:ident, $op_fn:ident) => {
87        pub(super) fn $name(&mut self, index: Option<IndexRegister>) -> u32 {
88            let address = self.fetch_indirect_hl_address(index);
89            let operand = self.bus.read_memory_debug(address, self.cpu);
90
91            self.cpu.registers.a = $op_fn(self.cpu.registers.a, operand, &mut self.cpu.registers.f);
92
93            match index {
94                Some(_) => 15,
95                None => 7,
96            }
97        }
98    };
99}
100
101macro_rules! impl_r_increment_op {
102    ($name:ident, $op_fn:ident) => {
103        pub(super) fn $name(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 {
104            let register =
105                super::parse_register_from_opcode(opcode >> 3, index).expect("invalid opcode");
106            let original = register.read_from(&self.cpu.registers);
107            let modified = $op_fn(original, &mut self.cpu.registers.f);
108
109            register.write_to(modified, &mut self.cpu.registers);
110
111            4
112        }
113    };
114}
115
116macro_rules! impl_hl_increment_op {
117    ($name:ident, $op_fn:ident) => {
118        pub(super) fn $name(&mut self, index: Option<IndexRegister>) -> u32 {
119            let address = self.fetch_indirect_hl_address(index);
120            let original = self.bus.read_memory_debug(address, self.cpu);
121            let modified = $op_fn(original, &mut self.cpu.registers.f);
122
123            self.bus.write_memory_debug(address, modified, self.cpu);
124
125            match index {
126                Some(_) => 19,
127                None => 11,
128            }
129        }
130    };
131}
132
133macro_rules! impl_16_bit_increment_op {
134    ($name:ident, $op_fn:ident) => {
135        pub(super) fn $name(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 {
136            let register = super::parse_dd_register(opcode, index);
137            let original = register.read_from(&self.cpu.registers);
138            let modified = $op_fn(original);
139
140            register.write_to(modified, &mut self.cpu.registers);
141
142            6
143        }
144    };
145}
146
147impl<B: BusInterface> InstructionExecutor<'_, '_, B> {
148    impl_a_r_add_op!(add_a_r, add);
149    impl_a_immediate_add_op!(add_a_immediate, add);
150    impl_a_hl_add_op!(add_a_hl, add);
151
152    impl_a_r_add_op!(sub_a_r, subtract);
153    impl_a_immediate_add_op!(sub_a_immediate, subtract);
154    impl_a_hl_add_op!(sub_a_hl, subtract);
155
156    impl_a_r_bit_op!(and_a_r, and);
157    impl_a_immediate_bit_op!(and_a_immediate, and);
158    impl_a_hl_bit_op!(and_a_hl, and);
159
160    impl_a_r_bit_op!(or_a_r, or);
161    impl_a_immediate_bit_op!(or_a_immediate, or);
162    impl_a_hl_bit_op!(or_a_hl, or);
163
164    impl_a_r_bit_op!(xor_a_r, xor);
165    impl_a_immediate_bit_op!(xor_a_immediate, xor);
166    impl_a_hl_bit_op!(xor_a_hl, xor);
167
168    impl_a_r_bit_op!(cp_a_r, compare);
169    impl_a_immediate_bit_op!(cp_a_immediate, compare);
170    impl_a_hl_bit_op!(cp_a_hl, compare);
171
172    impl_r_increment_op!(inc_r, increment);
173    impl_hl_increment_op!(inc_hl, increment);
174
175    impl_r_increment_op!(dec_r, decrement);
176    impl_hl_increment_op!(dec_hl, decrement);
177
178    impl_16_bit_increment_op!(inc_ss, increment_u16);
179    impl_16_bit_increment_op!(dec_ss, decrement_u16);
180
181    pub(super) fn add_hl_ss(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 {
182        let l_register = index.map_or(Register16::HL, IndexRegister::into);
183        let r_register = super::parse_dd_register(opcode, index);
184
185        let l_value = l_register.read_from(&self.cpu.registers);
186        let r_value = r_register.read_from(&self.cpu.registers);
187
188        let sum = add_u16(l_value, r_value, false, &mut self.cpu.registers.f);
189        l_register.write_to(sum, &mut self.cpu.registers);
190
191        11
192    }
193
194    pub(super) fn adc_hl_ss(&mut self, opcode: u8) -> u32 {
195        let register = super::parse_dd_register(opcode, None);
196
197        let l_value = Register16::HL.read_from(&self.cpu.registers);
198        let r_value = register.read_from(&self.cpu.registers);
199
200        let sum = add_u16(l_value, r_value, true, &mut self.cpu.registers.f);
201        Register16::HL.write_to(sum, &mut self.cpu.registers);
202
203        15
204    }
205
206    pub(super) fn sbc_hl_ss(&mut self, opcode: u8) -> u32 {
207        let register = super::parse_dd_register(opcode, None);
208
209        let l_value = Register16::HL.read_from(&self.cpu.registers);
210        let r_value = register.read_from(&self.cpu.registers);
211
212        let difference = sbc_u16(l_value, r_value, &mut self.cpu.registers.f);
213        Register16::HL.write_to(difference, &mut self.cpu.registers);
214
215        15
216    }
217
218    pub(super) fn daa(&mut self) -> u32 {
219        let a = self.cpu.registers.a;
220        let flags = self.cpu.registers.f;
221
222        let mut diff = 0;
223        if flags.half_carry || (a & 0x0F > 0x09) {
224            diff |= 0x06;
225        }
226        let carry = flags.carry || a > 0x99;
227        if carry {
228            diff |= 0x60;
229        }
230
231        let value = if flags.subtract { a.wrapping_sub(diff) } else { a.wrapping_add(diff) };
232
233        let half_carry = a.bit(4) != value.bit(4);
234
235        self.cpu.registers.a = value;
236        self.cpu.registers.f = Flags {
237            sign: sign_flag(value),
238            zero: zero_flag(value),
239            half_carry,
240            overflow: parity_flag(value),
241            carry,
242            ..flags
243        };
244
245        4
246    }
247
248    pub(super) fn cpl(&mut self) -> u32 {
249        self.cpu.registers.a = !self.cpu.registers.a;
250        self.cpu.registers.f = Flags { half_carry: true, subtract: true, ..self.cpu.registers.f };
251
252        4
253    }
254
255    pub(super) fn neg(&mut self) -> u32 {
256        self.cpu.registers.a = subtract(0, self.cpu.registers.a, false, &mut self.cpu.registers.f);
257
258        8
259    }
260
261    pub(super) fn ccf(&mut self) -> u32 {
262        let prev_carry = self.cpu.registers.f.carry;
263        self.cpu.registers.f = Flags {
264            half_carry: prev_carry,
265            subtract: false,
266            carry: !prev_carry,
267            ..self.cpu.registers.f
268        };
269
270        4
271    }
272
273    pub(super) fn scf(&mut self) -> u32 {
274        self.cpu.registers.f =
275            Flags { half_carry: false, subtract: false, carry: true, ..self.cpu.registers.f };
276
277        4
278    }
279
280    pub(super) fn compare_block(&mut self, mode: BlockMode, repeat: bool) -> u32 {
281        let a = self.cpu.registers.a;
282        let bc = Register16::BC.read_from(&self.cpu.registers);
283        let hl = Register16::HL.read_from(&self.cpu.registers);
284        let operand = self.bus.read_memory_debug(hl, self.cpu);
285
286        let difference = a.wrapping_sub(operand);
287        let half_carry = a & 0x0F < operand & 0x0F;
288
289        Register16::HL.write_to(mode.apply(hl), &mut self.cpu.registers);
290        Register16::BC.write_to(bc.wrapping_sub(1), &mut self.cpu.registers);
291
292        self.cpu.registers.f = Flags {
293            sign: sign_flag(difference),
294            zero: zero_flag(difference),
295            half_carry,
296            overflow: bc != 1,
297            subtract: true,
298            ..self.cpu.registers.f
299        };
300
301        let should_repeat = repeat && difference != 0 && bc != 1;
302        if should_repeat {
303            self.cpu.registers.pc -= 2;
304            21
305        } else {
306            16
307        }
308    }
309}
310
311fn add(l: u8, r: u8, with_carry: bool, flags: &mut Flags) -> u8 {
312    let carry_operand = if with_carry { u8::from(flags.carry) } else { 0 };
313
314    let (sum, carry) = match l.overflowing_add(r) {
315        (sum, true) => (sum + carry_operand, true),
316        (sum, false) => sum.overflowing_add(carry_operand),
317    };
318
319    let half_carry = (l & 0x0F) + (r & 0x0F) + carry_operand >= 0x10;
320    let bit_6_carry = (l & 0x7F) + (r & 0x7F) + carry_operand >= 0x80;
321    let overflow = bit_6_carry != carry;
322
323    *flags = Flags {
324        sign: sign_flag(sum),
325        zero: zero_flag(sum),
326        half_carry,
327        overflow,
328        subtract: false,
329        carry,
330        ..*flags
331    };
332
333    sum
334}
335
336fn add_u16(l: u16, r: u16, with_carry: bool, flags: &mut Flags) -> u16 {
337    let carry_operand = if with_carry { u16::from(flags.carry) } else { 0 };
338
339    let (sum, carry) = match l.overflowing_add(r) {
340        (sum, true) => (sum + carry_operand, true),
341        (sum, false) => sum.overflowing_add(carry_operand),
342    };
343
344    let half_carry = (l & 0x0FFF) + (r & 0x0FFF) + carry_operand >= 0x1000;
345
346    *flags = Flags { half_carry, subtract: false, carry, ..*flags };
347
348    if with_carry {
349        // S, Z, and P/V are only set in 16-bit ADC, not 16-bit ADD
350        let bit_14_carry = (l & 0x7FFF) + (r & 0x7FFF) + carry_operand >= 0x8000;
351        let overflow = bit_14_carry != carry;
352
353        *flags = Flags { sign: sum.bit(15), zero: sum == 0, overflow, ..*flags };
354    }
355
356    sum
357}
358
359fn subtract(l: u8, r: u8, with_carry: bool, flags: &mut Flags) -> u8 {
360    let carry_operand = if with_carry { u8::from(flags.carry) } else { 0 };
361
362    let (difference, carry) = match l.overflowing_sub(r) {
363        (difference, true) => (difference - carry_operand, true),
364        (difference, false) => difference.overflowing_sub(carry_operand),
365    };
366
367    let half_carry = l & 0x0F < (r & 0x0F) + carry_operand;
368    let bit_6_borrow = l & 0x7F < (r & 0x7F) + carry_operand;
369    let overflow = bit_6_borrow != carry;
370
371    *flags = Flags {
372        sign: sign_flag(difference),
373        zero: zero_flag(difference),
374        half_carry,
375        overflow,
376        subtract: true,
377        carry,
378        ..*flags
379    };
380
381    difference
382}
383
384fn sbc_u16(l: u16, r: u16, flags: &mut Flags) -> u16 {
385    let carry_operand = u16::from(flags.carry);
386
387    let (difference, carry) = match l.overflowing_sub(r) {
388        (difference, true) => (difference - carry_operand, true),
389        (difference, false) => difference.overflowing_sub(carry_operand),
390    };
391
392    let half_carry = l & 0x0FFF < (r & 0x0FFF) + carry_operand;
393    let bit_14_borrow = l & 0x7FFF < (r & 0x7FFF) + carry_operand;
394    let overflow = bit_14_borrow != carry;
395
396    *flags = Flags {
397        sign: difference.bit(15),
398        zero: difference == 0,
399        half_carry,
400        overflow,
401        subtract: true,
402        carry,
403        ..*flags
404    };
405
406    difference
407}
408
409fn and(l: u8, r: u8, flags: &mut Flags) -> u8 {
410    let value = l & r;
411
412    *flags = Flags {
413        sign: sign_flag(value),
414        zero: zero_flag(value),
415        half_carry: true,
416        overflow: parity_flag(value),
417        subtract: false,
418        carry: false,
419        ..*flags
420    };
421
422    value
423}
424
425fn or(l: u8, r: u8, flags: &mut Flags) -> u8 {
426    let value = l | r;
427
428    *flags = Flags {
429        sign: sign_flag(value),
430        zero: zero_flag(value),
431        half_carry: false,
432        overflow: parity_flag(value),
433        subtract: false,
434        carry: false,
435        ..*flags
436    };
437
438    value
439}
440
441fn xor(l: u8, r: u8, flags: &mut Flags) -> u8 {
442    let value = l ^ r;
443
444    *flags = Flags {
445        sign: sign_flag(value),
446        zero: zero_flag(value),
447        half_carry: false,
448        overflow: parity_flag(value),
449        subtract: false,
450        carry: false,
451        ..*flags
452    };
453
454    value
455}
456
457fn compare(l: u8, r: u8, flags: &mut Flags) -> u8 {
458    let (difference, carry) = l.overflowing_sub(r);
459
460    let half_carry = l & 0x0F < r & 0x0F;
461    let bit_6_borrow = l & 0x7F < r & 0x7F;
462    let overflow = bit_6_borrow != carry;
463
464    *flags = Flags {
465        sign: sign_flag(difference),
466        zero: zero_flag(difference),
467        half_carry,
468        overflow,
469        subtract: true,
470        carry,
471        ..*flags
472    };
473
474    l
475}
476
477fn increment(value: u8, flags: &mut Flags) -> u8 {
478    let half_carry = value & 0x0F == 0x0F;
479    let overflow = value == 0x7F;
480
481    let incremented = value.wrapping_add(1);
482    *flags = Flags {
483        sign: sign_flag(incremented),
484        zero: zero_flag(incremented),
485        half_carry,
486        overflow,
487        subtract: false,
488        ..*flags
489    };
490
491    incremented
492}
493
494fn decrement(value: u8, flags: &mut Flags) -> u8 {
495    let half_carry = value & 0x0F == 0x00;
496    let overflow = value == 0x80;
497
498    let decremented = value.wrapping_sub(1);
499    *flags = Flags {
500        sign: sign_flag(decremented),
501        zero: zero_flag(decremented),
502        half_carry,
503        overflow,
504        subtract: true,
505        ..*flags
506    };
507
508    decremented
509}
510
511fn increment_u16(value: u16) -> u16 {
512    value.wrapping_add(1)
513}
514
515fn decrement_u16(value: u16) -> u16 {
516    value.wrapping_sub(1)
517}
518
519#[cfg(test)]
520mod tests {
521    use super::*;
522    use crate::Z80;
523    use crate::traits::InMemoryBus;
524
525    #[test]
526    fn cpl() {
527        let mut cpu = Z80::new();
528        let mut bus = InMemoryBus::new();
529
530        cpu.registers.a = 0x37;
531        cpu.registers.f = 0_u8.into();
532
533        InstructionExecutor::new(&mut cpu, &mut bus).cpl();
534
535        assert_eq!(cpu.registers.a, 0xC8);
536        assert_eq!(u8::from(cpu.registers.f) & 0xD7, 0x12);
537
538        let value = rand::random();
539        cpu.registers.a = value;
540        cpu.registers.f = 0xFF_u8.into();
541
542        InstructionExecutor::new(&mut cpu, &mut bus).cpl();
543
544        assert_eq!(cpu.registers.a, !value);
545        assert_eq!(u8::from(cpu.registers.f) & 0xD7, 0xD7);
546    }
547
548    #[test]
549    fn ccf() {
550        let mut cpu = Z80::new();
551        let mut bus = InMemoryBus::new();
552
553        cpu.registers.f = 0_u8.into();
554
555        InstructionExecutor::new(&mut cpu, &mut bus).ccf();
556        assert_eq!(u8::from(cpu.registers.f) & 0xD7, 0x01);
557
558        InstructionExecutor::new(&mut cpu, &mut bus).ccf();
559        assert_eq!(u8::from(cpu.registers.f) & 0xD7, 0x10);
560
561        InstructionExecutor::new(&mut cpu, &mut bus).ccf();
562        assert_eq!(u8::from(cpu.registers.f) & 0xD7, 0x01);
563
564        cpu.registers.f = 0xFF_u8.into();
565
566        InstructionExecutor::new(&mut cpu, &mut bus).ccf();
567        assert_eq!(u8::from(cpu.registers.f) & 0xD7, 0xD4);
568
569        InstructionExecutor::new(&mut cpu, &mut bus).ccf();
570        assert_eq!(u8::from(cpu.registers.f) & 0xD7, 0xC5);
571    }
572
573    #[test]
574    fn scf() {
575        let mut cpu = Z80::new();
576        let mut bus = InMemoryBus::new();
577
578        cpu.registers.f = 0_u8.into();
579
580        for _ in 0..2 {
581            InstructionExecutor::new(&mut cpu, &mut bus).scf();
582            assert_eq!(u8::from(cpu.registers.f) & 0xD7, 0x01);
583        }
584
585        cpu.registers.f = 0xFF_u8.into();
586
587        for _ in 0..2 {
588            InstructionExecutor::new(&mut cpu, &mut bus).scf();
589            assert_eq!(u8::from(cpu.registers.f) & 0xD7, 0xC5);
590        }
591    }
592}