jevsnes.git / third-party / rust / jgenesis / backend / gb-core / src / sm83 / arithmetic.rs
1use crate::sm83::bus::BusInterface;
2use crate::sm83::{Flags, Sm83};
3
4impl Sm83 {
5    // ADD: Add without carry
6    pub(super) fn add_a_r<B: BusInterface>(&mut self, bus: &mut B, opcode: u8) {
7        let operand = self.read_register(bus, opcode);
8        self.registers.a = add(self.registers.a, operand, false, &mut self.registers.f);
9    }
10
11    // ADD: Add without carry
12    pub(super) fn add_a_imm<B: BusInterface>(&mut self, bus: &mut B) {
13        let operand = self.fetch_operand(bus);
14        self.registers.a = add(self.registers.a, operand, false, &mut self.registers.f);
15    }
16
17    // ADC: Add with carry
18    pub(super) fn adc_a_r<B: BusInterface>(&mut self, bus: &mut B, opcode: u8) {
19        let operand = self.read_register(bus, opcode);
20        self.registers.a =
21            add(self.registers.a, operand, self.registers.f.carry, &mut self.registers.f);
22    }
23
24    // ADC: Add with carry
25    pub(super) fn adc_a_imm<B: BusInterface>(&mut self, bus: &mut B) {
26        let operand = self.fetch_operand(bus);
27        self.registers.a =
28            add(self.registers.a, operand, self.registers.f.carry, &mut self.registers.f);
29    }
30
31    // SUB: Subtract without carry
32    pub(super) fn sub_a_r<B: BusInterface>(&mut self, bus: &mut B, opcode: u8) {
33        let operand = self.read_register(bus, opcode);
34        self.registers.a = subtract(self.registers.a, operand, false, &mut self.registers.f);
35    }
36
37    // SUB: Subtract without carry
38    pub(super) fn sub_a_imm<B: BusInterface>(&mut self, bus: &mut B) {
39        let operand = self.fetch_operand(bus);
40        self.registers.a = subtract(self.registers.a, operand, false, &mut self.registers.f);
41    }
42
43    // SBC: Subtract with carry
44    pub(super) fn sbc_a_r<B: BusInterface>(&mut self, bus: &mut B, opcode: u8) {
45        let operand = self.read_register(bus, opcode);
46        self.registers.a =
47            subtract(self.registers.a, operand, self.registers.f.carry, &mut self.registers.f);
48    }
49
50    // SBC: Subtract with carry
51    pub(super) fn sbc_a_imm<B: BusInterface>(&mut self, bus: &mut B) {
52        let operand = self.fetch_operand(bus);
53        self.registers.a =
54            subtract(self.registers.a, operand, self.registers.f.carry, &mut self.registers.f);
55    }
56
57    // CP: Compare
58    pub(super) fn cp_a_r<B: BusInterface>(&mut self, bus: &mut B, opcode: u8) {
59        let operand = self.read_register(bus, opcode);
60        subtract(self.registers.a, operand, false, &mut self.registers.f);
61    }
62
63    // CP: Compare
64    pub(super) fn cp_a_imm<B: BusInterface>(&mut self, bus: &mut B) {
65        let operand = self.fetch_operand(bus);
66        subtract(self.registers.a, operand, false, &mut self.registers.f);
67    }
68
69    // INC r: Increment register
70    pub(super) fn inc_r<B: BusInterface>(&mut self, bus: &mut B, opcode: u8) {
71        let value = self.read_register(bus, opcode >> 3).wrapping_add(1);
72        self.write_register(bus, opcode >> 3, value);
73
74        self.registers.f.zero = value == 0;
75        self.registers.f.subtract = false;
76        self.registers.f.half_carry = value & 0x0F == 0;
77    }
78
79    // DEC r: Decrement register
80    pub(super) fn dec_r<B: BusInterface>(&mut self, bus: &mut B, opcode: u8) {
81        let value = self.read_register(bus, opcode >> 3).wrapping_sub(1);
82        self.write_register(bus, opcode >> 3, value);
83
84        self.registers.f.zero = value == 0;
85        self.registers.f.subtract = true;
86        self.registers.f.half_carry = value & 0x0F == 0x0F;
87    }
88
89    // INC rr: Increment register pair or SP
90    pub(super) fn inc_rr<B: BusInterface>(&mut self, bus: &mut B, opcode: u8) {
91        match (opcode >> 4) & 0x3 {
92            0x0 => self.registers.increment_bc(),
93            0x1 => self.registers.increment_de(),
94            0x2 => self.registers.increment_hl(),
95            0x3 => self.registers.increment_sp(),
96            _ => unreachable!("value & 0x3 is always <= 0x3"),
97        }
98
99        // INC rr takes 2 M-cycles
100        bus.idle();
101    }
102
103    // DEC rr: Decrement register pair or SP
104    pub(super) fn dec_rr<B: BusInterface>(&mut self, bus: &mut B, opcode: u8) {
105        match (opcode >> 4) & 0x3 {
106            0x0 => self.registers.decrement_bc(),
107            0x1 => self.registers.decrement_de(),
108            0x2 => self.registers.decrement_hl(),
109            0x3 => self.registers.decrement_sp(),
110            _ => unreachable!("value & 0x3 is always <= 0x3"),
111        }
112
113        // DEC rr takes 2 M-cycles
114        bus.idle();
115    }
116
117    // ADD HL, rr: 16-bit add
118    pub(super) fn add_hl_rr<B: BusInterface>(&mut self, bus: &mut B, opcode: u8) {
119        let operand = match (opcode >> 4) & 0x3 {
120            0x0 => self.registers.bc(),
121            0x1 => self.registers.de(),
122            0x2 => self.registers.hl(),
123            0x3 => self.registers.sp,
124            _ => unreachable!("value & 0x3 is always <= 0x3"),
125        };
126
127        let (sum, flags) = add_u16(self.registers.hl(), operand);
128        self.registers.set_hl(sum);
129
130        // 16-bit addition does not modify the Z flag
131        self.registers.f = Flags { zero: self.registers.f.zero, ..flags };
132
133        // 16-bit addition takes 2 M-cycles
134        bus.idle();
135    }
136
137    // ADD SP, i8: Add signed immediate value to stack pointer
138    pub(super) fn add_sp_e<B: BusInterface>(&mut self, bus: &mut B) {
139        let operand = self.fetch_operand(bus) as i8;
140
141        let (sum, flags) = add_sp(self.registers.sp, operand as u16);
142        self.registers.sp = sum;
143
144        // Adding to stack pointer always sets Z flag to false
145        self.registers.f = Flags { zero: false, ..flags };
146
147        // This instruction takes 4 M-cycles: opcode read + operand read + 2 idle cycles
148        bus.idle();
149        bus.idle();
150    }
151
152    // DAA: Decimal adjust accumulator
153    pub(super) fn daa(&mut self) {
154        if self.registers.f.subtract {
155            // Last op was subtraction
156            let mut value = self.registers.a;
157
158            if self.registers.f.half_carry {
159                value = value.wrapping_sub(0x06);
160            }
161
162            if self.registers.f.carry {
163                value = value.wrapping_sub(0x60);
164            }
165
166            self.registers.a = value;
167            self.registers.f.zero = value == 0;
168            self.registers.f.half_carry = false;
169        } else {
170            // Last op was addition
171            let mut value = self.registers.a;
172            let mut carry = false;
173
174            if value > 0x99 || self.registers.f.carry {
175                value = value.wrapping_add(0x60);
176                carry = true;
177            }
178
179            if value & 0x0F > 0x09 || self.registers.f.half_carry {
180                value = value.wrapping_add(0x06);
181            }
182
183            self.registers.a = value;
184            self.registers.f.zero = value == 0;
185            self.registers.f.half_carry = false;
186            self.registers.f.carry = carry;
187        }
188    }
189
190    pub(super) fn ld_hl_sp_e<B: BusInterface>(&mut self, bus: &mut B) {
191        let operand = self.fetch_operand(bus) as i8;
192        let (sum, flags) = add_sp(self.registers.sp, operand as u16);
193
194        self.registers.set_hl(sum);
195
196        // Adding to stack pointer always sets Z flag to false
197        self.registers.f = Flags { zero: false, ..flags };
198
199        bus.idle();
200    }
201}
202
203fn add(accumulator: u8, operand: u8, carry_in: bool, flags: &mut Flags) -> u8 {
204    let carry_in: u8 = carry_in.into();
205
206    let (partial_sum, carry1) = accumulator.overflowing_add(operand);
207    let (sum, carry2) = partial_sum.overflowing_add(carry_in);
208    let carry = carry1 || carry2;
209
210    let half_carry = (accumulator & 0x0F) + (operand & 0x0F) + carry_in > 0x0F;
211
212    *flags = Flags { zero: sum == 0, subtract: false, half_carry, carry };
213
214    sum
215}
216
217fn add_u16(l_value: u16, r_value: u16) -> (u16, Flags) {
218    let [l_lsb, l_msb] = l_value.to_le_bytes();
219    let [r_lsb, r_msb] = r_value.to_le_bytes();
220    let mut flags = Flags { zero: false, subtract: false, half_carry: false, carry: false };
221
222    let (sum_lsb, lsb_carry) = l_lsb.overflowing_add(r_lsb);
223    let sum_msb = add(l_msb, r_msb, lsb_carry, &mut flags);
224    let sum = u16::from_le_bytes([sum_lsb, sum_msb]);
225
226    (sum, flags)
227}
228
229// This differs from add_u16 in that it sets the flags based on the LSB addition instead of MSB
230fn add_sp(l_value: u16, r_value: u16) -> (u16, Flags) {
231    let [l_lsb, l_msb] = l_value.to_le_bytes();
232    let [r_lsb, r_msb] = r_value.to_le_bytes();
233    let mut flags = Flags { zero: false, subtract: false, half_carry: false, carry: false };
234
235    let sum_lsb = add(l_lsb, r_lsb, false, &mut flags);
236    let sum_msb = l_msb.wrapping_add(r_msb).wrapping_add(flags.carry.into());
237    let sum = u16::from_le_bytes([sum_lsb, sum_msb]);
238
239    (sum, flags)
240}
241
242fn subtract(accumulator: u8, operand: u8, carry_in: bool, flags: &mut Flags) -> u8 {
243    let carry_in: u8 = carry_in.into();
244
245    let (partial_diff, borrow1) = accumulator.overflowing_sub(operand);
246    let (difference, borrow2) = partial_diff.overflowing_sub(carry_in);
247    let borrow = borrow1 || borrow2;
248
249    let half_borrow = accumulator & 0x0F < (operand & 0x0F) + carry_in;
250
251    *flags =
252        Flags { zero: difference == 0, subtract: true, half_carry: half_borrow, carry: borrow };
253
254    difference
255}