1use crate::core::{
2    AddressRegister, AddressingMode, ConditionCodes, DataRegister, Exception, ExecuteResult,
3    InstructionExecutor, OpSize, ResolvedAddress,
4};
5use crate::traits::BusInterface;
6use jgenesis_common::num::{GetBit, SignBit};
7
8macro_rules! impl_extend_op_method {
9    ($name:ident, $read_method:ident, $write_method:ident, $op_fn:ident, $size:expr) => {
10        fn $name(&mut self, source: AddressingMode, dest: AddressingMode) -> ExecuteResult<u32> {
11            let (_, operand_r) = self.$read_method(source)?;
12            let (dest_resolved, operand_l) = self.$read_method(dest)?;
13
14            let (value, carry, overflow) =
15                $op_fn(operand_l, operand_r, self.cpu.registers.ccr.extend);
16
17            self.cpu.registers.ccr = ConditionCodes {
18                carry,
19                overflow,
20                zero: self.cpu.registers.ccr.zero && value == 0,
21                negative: value.sign_bit(),
22                extend: carry,
23            };
24
25            self.$write_method(dest_resolved, value)?;
26
27            // ADDX and SUBX only support Dx,Dy and -(Ax),-(Ay)
28            Ok(match ($size, source) {
29                (OpSize::Byte | OpSize::Word, AddressingMode::DataDirect(..)) => 4,
30                (OpSize::LongWord, AddressingMode::DataDirect(..)) => 8,
31                (OpSize::Byte | OpSize::Word, _) => 18,
32                (OpSize::LongWord, _) => 30,
33            })
34        }
35    };
36}
37
38macro_rules! impl_op_method {
39    ($name:ident, $aname:ident, $xname:ident, $read_method:ident, $read_resolved_method:ident, $write_method:ident, $op_fn:ident, $size:expr) => {
40        pub(super) fn $name(
41            &mut self,
42            source: AddressingMode,
43            dest: AddressingMode,
44            with_extend: bool,
45        ) -> ExecuteResult<u32> {
46            if with_extend {
47                return self.$xname(source, dest);
48            }
49
50            if let AddressingMode::AddressDirect(register) = dest {
51                return self.$aname($size, source, register);
52            }
53
54            let operand_r = self.$read_method(source)?;
55
56            let dest_resolved = self.resolve_address_with_post(dest, $size)?;
57            let operand_l = self.$read_resolved_method(dest_resolved)?;
58
59            let (value, carry, overflow) = $op_fn(operand_l, operand_r, false);
60
61            if !dest.is_address_direct() {
62                self.cpu.registers.ccr = ConditionCodes {
63                    carry,
64                    overflow,
65                    zero: value == 0,
66                    negative: value.sign_bit(),
67                    extend: carry,
68                };
69            }
70
71            self.$write_method(dest_resolved, value)?;
72
73            Ok(super::binary_op_cycles($size, source, dest))
74        }
75    };
76}
77
78macro_rules! impl_neg {
79    ($name:ident, $read_method:ident, $write_method:ident, $sub_fn:ident, $size:expr) => {
80        pub(super) fn $name(
81            &mut self,
82            dest: AddressingMode,
83            with_extend: bool,
84        ) -> ExecuteResult<u32> {
85            let dest_resolved = self.resolve_address_with_post(dest, $size)?;
86            let operand_r = self.$read_method(dest_resolved)?;
87            let extend = with_extend && self.cpu.registers.ccr.extend;
88            let (difference, carry, overflow) = $sub_fn(0, operand_r, extend);
89
90            self.cpu.registers.ccr = ConditionCodes {
91                carry,
92                overflow,
93                zero: (!with_extend || self.cpu.registers.ccr.zero) && difference == 0,
94                negative: difference.sign_bit(),
95                extend: carry,
96            };
97
98            self.$write_method(dest_resolved, difference)?;
99
100            Ok(super::unary_op_cycles($size, dest))
101        }
102    };
103}
104
105macro_rules! impl_cmp {
106    ($name:ident, $read_method:ident, $cmp_fn:ident, $cycles_fn:ident, $size:expr) => {
107        pub(super) fn $name(
108            &mut self,
109            source: AddressingMode,
110            dest: AddressingMode,
111        ) -> ExecuteResult<u32> {
112            if let AddressingMode::AddressDirect(dest) = dest {
113                return self.cmpa($size, source, dest);
114            }
115
116            let source_operand = self.$read_method(source)?;
117            let dest_operand = self.$read_method(dest)?;
118
119            $cmp_fn(source_operand, dest_operand, &mut self.cpu.registers.ccr);
120
121            let cycles = $cycles_fn(source, dest);
122            Ok(cycles)
123        }
124    };
125}
126
127macro_rules! impl_cmp_cycles_byte_word {
128    ($name:ident, $size:expr) => {
129        #[inline]
130        pub(super) fn $name(source: AddressingMode, dest: AddressingMode) -> u32 {
131            match (source, dest) {
132                // CMPM.b / CMPM.w
133                (
134                    AddressingMode::AddressIndirectPostincrement(..),
135                    AddressingMode::AddressIndirectPostincrement(..),
136                ) => 12,
137                // CMPI.b / CMPI.w
138                (AddressingMode::Immediate, AddressingMode::DataDirect(..)) => 8,
139                (AddressingMode::Immediate, _) => super::binary_op_cycles($size, source, dest) - 4,
140                // CMP
141                _ => super::binary_op_cycles($size, source, dest),
142            }
143        }
144    };
145}
146
147impl_cmp_cycles_byte_word!(cmp_cycles_byte, OpSize::Byte);
148impl_cmp_cycles_byte_word!(cmp_cycles_word, OpSize::Word);
149
150#[inline]
151pub(super) fn cmp_cycles_long_word(source: AddressingMode, dest: AddressingMode) -> u32 {
152    match (source, dest) {
153        // CMPM.l
154        (
155            AddressingMode::AddressIndirectPostincrement(..),
156            AddressingMode::AddressIndirectPostincrement(..),
157        ) => 20,
158        // CMPI.l
159        (AddressingMode::Immediate, AddressingMode::DataDirect(..)) => 14,
160        (AddressingMode::Immediate, _) => {
161            super::binary_op_cycles(OpSize::LongWord, source, dest) - 8
162        }
163        // CMP
164        (
165            AddressingMode::DataDirect(..) | AddressingMode::AddressDirect(..),
166            AddressingMode::DataDirect(..),
167        ) => 6,
168        _ => super::binary_op_cycles(OpSize::LongWord, source, dest),
169    }
170}
171
172impl<B: BusInterface> InstructionExecutor<'_, '_, B> {
173    fn read_byte_for_extend(
174        &mut self,
175        source: AddressingMode,
176    ) -> ExecuteResult<(ResolvedAddress, u8)> {
177        let address = self.resolve_address_with_post(source, OpSize::Byte)?;
178        let byte = self.read_byte_resolved(address);
179        Ok((address, byte))
180    }
181
182    fn read_word_for_extend(
183        &mut self,
184        source: AddressingMode,
185    ) -> ExecuteResult<(ResolvedAddress, u16)> {
186        let address = self.resolve_address_with_post(source, OpSize::Word)?;
187        let word = self.read_word_resolved(address)?;
188        Ok((address, word))
189    }
190
191    fn read_long_word_for_extend(
192        &mut self,
193        source: AddressingMode,
194    ) -> ExecuteResult<(ResolvedAddress, u32)> {
195        match source {
196            AddressingMode::AddressIndirectPredecrement(register) => {
197                let address = register.read_from(&self.cpu.registers).wrapping_sub(2);
198                register.write_long_word_to(&mut self.cpu.registers, address);
199                let low_word = self.read_bus_word(address)?;
200
201                let address = address.wrapping_sub(2);
202                register.write_long_word_to(&mut self.cpu.registers, address);
203                let high_word = self.read_bus_word(address)?;
204
205                let value = (u32::from(high_word) << 16) | u32::from(low_word);
206                Ok((ResolvedAddress::Memory(address), value))
207            }
208            _ => {
209                let address = self.resolve_address_with_post(source, OpSize::LongWord)?;
210                let value = self.read_long_word_resolved(address)?;
211                Ok((address, value))
212            }
213        }
214    }
215
216    fn read_address_operand(&mut self, size: OpSize, source: AddressingMode) -> ExecuteResult<u32> {
217        let value = match size {
218            OpSize::Word => self.read_word(source)? as i16 as u32,
219            OpSize::LongWord => self.read_long_word(source)?,
220            OpSize::Byte => panic!("ADDA does not support bytes"),
221        };
222        Ok(value)
223    }
224
225    fn adda(
226        &mut self,
227        size: OpSize,
228        source: AddressingMode,
229        dest: AddressRegister,
230    ) -> ExecuteResult<u32> {
231        let operand_r = self.read_address_operand(size, source)?;
232        let operand_l = dest.read_from(&self.cpu.registers);
233
234        let sum = operand_l.wrapping_add(operand_r);
235        dest.write_long_word_to(&mut self.cpu.registers, sum);
236
237        Ok(super::binary_op_cycles(size, source, AddressingMode::AddressDirect(dest)))
238    }
239
240    impl_extend_op_method!(
241        addx_byte,
242        read_byte_for_extend,
243        write_byte_resolved_as_result,
244        add_bytes,
245        OpSize::Byte
246    );
247    impl_extend_op_method!(
248        addx_word,
249        read_word_for_extend,
250        write_word_resolved,
251        add_words,
252        OpSize::Word
253    );
254    impl_extend_op_method!(
255        addx_long_word,
256        read_long_word_for_extend,
257        write_long_word_resolved,
258        add_long_words,
259        OpSize::LongWord
260    );
261
262    impl_op_method!(
263        add_byte,
264        adda,
265        addx_byte,
266        read_byte,
267        read_byte_resolved_as_result,
268        write_byte_resolved_as_result,
269        add_bytes,
270        OpSize::Byte
271    );
272    impl_op_method!(
273        add_word,
274        adda,
275        addx_word,
276        read_word,
277        read_word_resolved,
278        write_word_resolved,
279        add_words,
280        OpSize::Word
281    );
282    impl_op_method!(
283        add_long_word,
284        adda,
285        addx_long_word,
286        read_long_word,
287        read_long_word_resolved,
288        write_long_word_resolved,
289        add_long_words,
290        OpSize::LongWord
291    );
292
293    fn suba(
294        &mut self,
295        size: OpSize,
296        source: AddressingMode,
297        dest: AddressRegister,
298    ) -> ExecuteResult<u32> {
299        let operand_r = self.read_address_operand(size, source)?;
300        let operand_l = dest.read_from(&self.cpu.registers);
301
302        let difference = operand_l.wrapping_sub(operand_r);
303        dest.write_long_word_to(&mut self.cpu.registers, difference);
304
305        Ok(super::binary_op_cycles(size, source, AddressingMode::AddressDirect(dest)))
306    }
307
308    impl_extend_op_method!(
309        subx_byte,
310        read_byte_for_extend,
311        write_byte_resolved_as_result,
312        sub_bytes,
313        OpSize::Byte
314    );
315    impl_extend_op_method!(
316        subx_word,
317        read_word_for_extend,
318        write_word_resolved,
319        sub_words,
320        OpSize::Word
321    );
322    impl_extend_op_method!(
323        subx_long_word,
324        read_long_word_for_extend,
325        write_long_word_resolved,
326        sub_long_words,
327        OpSize::LongWord
328    );
329
330    impl_op_method!(
331        sub_byte,
332        suba,
333        subx_byte,
334        read_byte,
335        read_byte_resolved_as_result,
336        write_byte_resolved_as_result,
337        sub_bytes,
338        OpSize::Byte
339    );
340    impl_op_method!(
341        sub_word,
342        suba,
343        subx_word,
344        read_word,
345        read_word_resolved,
346        write_word_resolved,
347        sub_words,
348        OpSize::Word
349    );
350    impl_op_method!(
351        sub_long_word,
352        suba,
353        subx_long_word,
354        read_long_word,
355        read_long_word_resolved,
356        write_long_word_resolved,
357        sub_long_words,
358        OpSize::LongWord
359    );
360
361    impl_neg!(
362        neg_byte,
363        read_byte_resolved_as_result,
364        write_byte_resolved_as_result,
365        sub_bytes,
366        OpSize::Byte
367    );
368    impl_neg!(neg_word, read_word_resolved, write_word_resolved, sub_words, OpSize::Word);
369    impl_neg!(
370        neg_long_word,
371        read_long_word_resolved,
372        write_long_word_resolved,
373        sub_long_words,
374        OpSize::LongWord
375    );
376
377    impl_cmp!(cmp_byte, read_byte, compare_bytes, cmp_cycles_byte, OpSize::Byte);
378    impl_cmp!(cmp_word, read_word, compare_words, cmp_cycles_word, OpSize::Word);
379    impl_cmp!(
380        cmp_long_word,
381        read_long_word,
382        compare_long_words,
383        cmp_cycles_long_word,
384        OpSize::LongWord
385    );
386
387    fn cmpa(
388        &mut self,
389        size: OpSize,
390        source: AddressingMode,
391        dest: AddressRegister,
392    ) -> ExecuteResult<u32> {
393        let source_operand = self.read_address_operand(size, source)?;
394        let dest_operand = dest.read_from(&self.cpu.registers);
395
396        compare_long_words(source_operand, dest_operand, &mut self.cpu.registers.ccr);
397
398        Ok(6 + source.address_calculation_cycles(size))
399    }
400
401    pub(super) fn muls(
402        &mut self,
403        register: DataRegister,
404        source: AddressingMode,
405    ) -> ExecuteResult<u32> {
406        let operand_l = self.read_word(source)? as i16;
407        let operand_r = register.read_from(&self.cpu.registers) as i16;
408
409        let value = (i32::from(operand_l) * i32::from(operand_r)) as u32;
410        register.write_long_word_to(&mut self.cpu.registers, value);
411
412        self.cpu.registers.ccr = ConditionCodes {
413            carry: false,
414            overflow: false,
415            zero: value == 0,
416            negative: value.sign_bit(),
417            ..self.cpu.registers.ccr
418        };
419
420        let mut last_bit = false;
421        let mut alternating_bits = 0;
422        for i in 0..16 {
423            let bit = operand_l.bit(i);
424            if bit != last_bit {
425                alternating_bits += 1;
426            }
427            last_bit = bit;
428        }
429
430        Ok(38 + 2 * alternating_bits + source.address_calculation_cycles(OpSize::Word))
431    }
432
433    pub(super) fn mulu(
434        &mut self,
435        register: DataRegister,
436        source: AddressingMode,
437    ) -> ExecuteResult<u32> {
438        let operand_l = self.read_word(source)?;
439        let operand_r = register.read_from(&self.cpu.registers) as u16;
440
441        let value = u32::from(operand_l) * u32::from(operand_r);
442        register.write_long_word_to(&mut self.cpu.registers, value);
443
444        self.cpu.registers.ccr = ConditionCodes {
445            carry: false,
446            overflow: false,
447            zero: value == 0,
448            negative: value.sign_bit(),
449            ..self.cpu.registers.ccr
450        };
451
452        Ok(38 + 2 * operand_l.count_ones() + source.address_calculation_cycles(OpSize::Word))
453    }
454
455    fn divide_by_zero_error(&mut self, source: AddressingMode) -> Exception {
456        self.cpu.registers.ccr = ConditionCodes {
457            carry: false,
458            overflow: false,
459            zero: false,
460            negative: false,
461            ..self.cpu.registers.ccr
462        };
463
464        Exception::DivisionByZero { cycles: source.address_calculation_cycles(OpSize::Word) }
465    }
466
467    pub(super) fn divs(
468        &mut self,
469        register: DataRegister,
470        source: AddressingMode,
471    ) -> ExecuteResult<u32> {
472        let operand_l = register.read_from(&self.cpu.registers) as i32;
473        let operand_r: i32 = (self.read_word(source)? as i16).into();
474
475        if operand_r == 0 {
476            return Err(self.divide_by_zero_error(source));
477        }
478
479        let quotient = operand_l / operand_r;
480        let remainder = operand_l % operand_r;
481
482        if quotient > i16::MAX.into() || quotient < i16::MIN.into() {
483            self.cpu.registers.ccr = ConditionCodes {
484                carry: false,
485                overflow: true,
486                zero: false,
487                negative: true,
488                ..self.cpu.registers.ccr
489            };
490
491            return if operand_l.wrapping_abs() >> 16 >= operand_r.abs() {
492                // Absolute overflows take 16 cycles for non-negative dividend and 18 for negative dividend
493                let base_cycles = 16 + 2 * u32::from(operand_l < 0);
494                Ok(base_cycles + source.address_calculation_cycles(OpSize::Word))
495            } else {
496                // Signed overflows are not detected early and take the normal number of cycles
497                Ok(divs_cycle_count(operand_l, operand_r, quotient, source))
498            };
499        }
500
501        let value = ((quotient as u32) & 0x0000_FFFF) | ((remainder as u32) << 16);
502        register.write_long_word_to(&mut self.cpu.registers, value);
503
504        self.cpu.registers.ccr = ConditionCodes {
505            carry: false,
506            overflow: false,
507            zero: quotient == 0,
508            negative: quotient < 0,
509            ..self.cpu.registers.ccr
510        };
511
512        Ok(divs_cycle_count(operand_l, operand_r, quotient, source))
513    }
514
515    pub(super) fn divu(
516        &mut self,
517        register: DataRegister,
518        source: AddressingMode,
519    ) -> ExecuteResult<u32> {
520        let operand_l = register.read_from(&self.cpu.registers);
521        let operand_r: u32 = self.read_word(source)?.into();
522
523        if operand_r == 0 {
524            return Err(self.divide_by_zero_error(source));
525        }
526
527        let quotient = operand_l / operand_r;
528        let remainder = operand_l % operand_r;
529
530        if quotient > u16::MAX.into() {
531            self.cpu.registers.ccr = ConditionCodes {
532                carry: false,
533                overflow: true,
534                zero: false,
535                negative: true,
536                ..self.cpu.registers.ccr
537            };
538
539            // Overflow is always 10 cycles plus the time to read the divisor
540            return Ok(10 + source.address_calculation_cycles(OpSize::Word));
541        }
542
543        let value = (quotient & 0x0000_FFFF) | (remainder << 16);
544        register.write_long_word_to(&mut self.cpu.registers, value);
545
546        self.cpu.registers.ccr = ConditionCodes {
547            carry: false,
548            overflow: false,
549            zero: quotient == 0,
550            negative: quotient.bit(15),
551            ..self.cpu.registers.ccr
552        };
553
554        Ok(divu_cycle_count(operand_l, operand_r, source))
555    }
556
557    pub(super) fn abcd(
558        &mut self,
559        source: AddressingMode,
560        dest: AddressingMode,
561    ) -> ExecuteResult<u32> {
562        let operand_l = self.read_byte(source)?;
563
564        let dest_resolved = self.resolve_address(dest, OpSize::Byte)?;
565        let operand_r = self.read_byte_resolved(dest_resolved);
566
567        let extend: u8 = self.cpu.registers.ccr.extend.into();
568
569        let (sum, carry) = match operand_l.overflowing_add(operand_r) {
570            (sum, true) => (sum + extend, true),
571            (sum, false) => sum.overflowing_add(extend),
572        };
573
574        let mut diff = 0;
575        if ((operand_l & 0x0F) + (operand_r & 0x0F) + extend >= 0x10) || (sum & 0x0F > 0x09) {
576            diff += 0x06;
577        }
578        if sum > 0x99 || carry {
579            diff += 0x60;
580        }
581
582        let (corrected_sum, corrected_carry) = sum.overflowing_add(diff);
583
584        let bit_6_carry = (sum & 0x7F) + (diff & 0x7F) >= 0x80;
585        let overflow = bit_6_carry != corrected_carry;
586
587        log::trace!("sum={sum:02X}");
588
589        let carry = carry || corrected_carry;
590        self.cpu.registers.ccr = ConditionCodes {
591            carry,
592            overflow,
593            zero: self.cpu.registers.ccr.zero && corrected_sum == 0,
594            negative: corrected_sum.sign_bit(),
595            extend: carry,
596        };
597
598        self.write_byte_resolved(dest_resolved, corrected_sum);
599
600        // ABCD only supports Dx,Dy and -(Ax),-(Ay)
601        Ok(match source {
602            AddressingMode::DataDirect(..) => 6,
603            _ => 18,
604        })
605    }
606
607    pub(super) fn sbcd(
608        &mut self,
609        source: AddressingMode,
610        dest: AddressingMode,
611    ) -> ExecuteResult<u32> {
612        let operand_r = self.read_byte(source)?;
613
614        let dest_resolved = self.resolve_address(dest, OpSize::Byte)?;
615        let operand_l = self.read_byte_resolved(dest_resolved);
616
617        let difference = self.decimal_subtract(operand_l, operand_r);
618
619        self.write_byte_resolved(dest_resolved, difference);
620
621        // SBCD only supports Dx,Dy and -(Ax),-(Ay)
622        Ok(match source {
623            AddressingMode::DataDirect(..) => 6,
624            _ => 18,
625        })
626    }
627
628    pub(super) fn nbcd(&mut self, dest: AddressingMode) -> ExecuteResult<u32> {
629        let dest_resolved = self.resolve_address_with_post(dest, OpSize::Byte)?;
630        let operand_r = self.read_byte_resolved(dest_resolved);
631
632        let difference = self.decimal_subtract(0, operand_r);
633
634        self.write_byte_resolved(dest_resolved, difference);
635
636        Ok(if dest.is_data_direct() { 6 } else { super::unary_op_cycles(OpSize::Byte, dest) })
637    }
638
639    fn decimal_subtract(&mut self, operand_l: u8, operand_r: u8) -> u8 {
640        let extend: u8 = self.cpu.registers.ccr.extend.into();
641
642        let (difference, borrow) = match operand_l.overflowing_sub(operand_r) {
643            (difference, true) => (difference - extend, true),
644            (difference, false) => difference.overflowing_sub(extend),
645        };
646
647        let mut diff = 0;
648        if operand_l & 0x0F < (operand_r & 0x0F) + extend {
649            diff += 0x06;
650        }
651        if borrow {
652            diff += 0x60;
653        }
654
655        let (corrected_difference, corrected_borrow) = difference.overflowing_sub(diff);
656
657        let bit_6_borrow = difference & 0x7F < diff & 0x7F;
658        let overflow = bit_6_borrow != corrected_borrow;
659
660        let borrow = borrow || corrected_borrow;
661        self.cpu.registers.ccr = ConditionCodes {
662            carry: borrow,
663            overflow,
664            zero: self.cpu.registers.ccr.zero && corrected_difference == 0,
665            negative: corrected_difference.sign_bit(),
666            extend: borrow,
667        };
668
669        corrected_difference
670    }
671}
672
673fn divu_cycle_count(dividend: u32, divisor: u32, source: AddressingMode) -> u32 {
674    let shifted_divisor = divisor << 16;
675    let mut dividend = dividend;
676
677    let mut added_cycles = 0;
678    for _ in 0..15 {
679        let prev_msb = dividend.bit(31);
680        dividend <<= 1;
681
682        let negative = dividend < shifted_divisor;
683        if prev_msb || !negative {
684            // Subtract if there was a shift out (borrow) or the subtraction result was non-negative
685            dividend = dividend.wrapping_sub(shifted_divisor);
686        }
687
688        // Add 2 cycles if the bit shifted out was a 0
689        added_cycles += 2 * u32::from(!prev_msb);
690
691        // Add 2 cycles if the bit shifted out was a 0 and the subtraction result was negative
692        added_cycles += 2 * u32::from(!prev_msb && negative);
693    }
694
695    76 + added_cycles + source.address_calculation_cycles(OpSize::Word)
696}
697
698fn divs_cycle_count(dividend: i32, divisor: i32, quotient: i32, source: AddressingMode) -> u32 {
699    // All DIVS instructions take at least 120 cycles for a non-negative dividend and 122 for negative
700    let base_cycles = if dividend < 0 { 122 } else { 120 };
701
702    let mut added_cycles = 0;
703
704    // Add 2 cycles for each 0 in the quotient's absolute value's most significant 15 bits
705    let mut absolute_quotient = quotient.wrapping_abs() as i16;
706    for _ in 0..15 {
707        added_cycles += 2 * u32::from(absolute_quotient >= 0);
708        absolute_quotient <<= 1;
709    }
710
711    if divisor < 0 {
712        // Add 2 cycles for a negative divisor
713        added_cycles += 2;
714    } else if dividend < 0 {
715        // Add 4 cycles for negative dividend + positive divisor
716        added_cycles += 4;
717    }
718
719    base_cycles + added_cycles + source.address_calculation_cycles(OpSize::Word)
720}
721
722macro_rules! impl_add_fn {
723    ($name:ident, $t:ty, $overflow_mask:expr) => {
724        fn $name(operand_l: $t, operand_r: $t, extend: bool) -> ($t, bool, bool) {
725            let extend_operand = <$t>::from(extend);
726            let (sum, carry) = match operand_l.overflowing_add(operand_r) {
727                (sum, true) => (sum + extend_operand, true),
728                (sum, false) => sum.overflowing_add(extend_operand),
729            };
730
731            let bit_m1_carry =
732                (operand_l & $overflow_mask) + (operand_r & $overflow_mask) + extend_operand
733                    > $overflow_mask;
734            let overflow = bit_m1_carry != carry;
735
736            (sum, carry, overflow)
737        }
738    };
739}
740
741impl_add_fn!(add_bytes, u8, 0x7F);
742impl_add_fn!(add_words, u16, 0x7FFF);
743impl_add_fn!(add_long_words, u32, 0x7FFF_FFFF);
744
745macro_rules! impl_sub_fn {
746    ($name:ident, $t:ty, $overflow_mask:expr) => {
747        fn $name(operand_l: $t, operand_r: $t, extend: bool) -> ($t, bool, bool) {
748            let extend_operand = <$t>::from(extend);
749            let (difference, borrow) = match operand_l.overflowing_sub(operand_r) {
750                (difference, true) => (difference - extend_operand, true),
751                (difference, false) => difference.overflowing_sub(extend_operand),
752            };
753
754            let bit_m1_borrow =
755                operand_l & $overflow_mask < (operand_r & $overflow_mask) + extend_operand;
756            let overflow = bit_m1_borrow != borrow;
757
758            (difference, borrow, overflow)
759        }
760    };
761}
762
763impl_sub_fn!(sub_bytes, u8, 0x7F);
764impl_sub_fn!(sub_words, u16, 0x7FFF);
765impl_sub_fn!(sub_long_words, u32, 0x7FFF_FFFF);
766
767macro_rules! impl_compare_fn {
768    ($name:ident, $t:ty, $overflow_mask:expr) => {
769        fn $name(source: $t, dest: $t, ccr: &mut ConditionCodes) {
770            let (difference, borrow) = dest.overflowing_sub(source);
771            let bit_m1_borrow = dest & $overflow_mask < source & $overflow_mask;
772            let overflow = bit_m1_borrow != borrow;
773
774            *ccr = ConditionCodes {
775                carry: borrow,
776                overflow,
777                zero: difference == 0,
778                negative: difference.sign_bit(),
779                ..*ccr
780            };
781        }
782    };
783}
784
785impl_compare_fn!(compare_bytes, u8, 0x7F);
786impl_compare_fn!(compare_words, u16, 0x7FFF);
787impl_compare_fn!(compare_long_words, u32, 0x7FFF_FFFF);