bits.rsannotatedbits.rssource336 lines · 10.6 KB · raw
1use crate::core::instructions::{InstructionExecutor, parity_flag, sign_flag, zero_flag};
2use crate::core::{Flags, IndexRegister, Register16, Registers};
3use crate::debug::BusDebugExt;
4use crate::traits::BusInterface;
5use jgenesis_common::num::GetBit;
6
7fn compute_index_address(registers: &Registers, index: IndexRegister, offset: i8) -> u16 {
8    let index_value = index.read_from(registers);
9    (i32::from(index_value) + i32::from(offset)) as u16
10}
11
12macro_rules! impl_r_shift_op {
13    ($name:ident, $op_fn:ident $(, thru_carry: $thru_carry:expr)?) => {
14        pub(super) fn $name(&mut self, opcode: u8, index: Option<(IndexRegister, i8)>) -> u32 {
15            let register = super::parse_register_from_opcode(opcode, None).expect("invalid opcode");
16
17            match index {
18                Some((index_register, offset)) => {
19                    let address = compute_index_address(&self.cpu.registers, index_register, offset);
20                    let original = self.bus.read_memory_debug(address, self.cpu);
21                    let modified = $op_fn(original, $($thru_carry,)? &mut self.cpu.registers.f);
22
23                    self.bus.write_memory_debug(address, modified, self.cpu);
24                    register.write_to(modified, &mut self.cpu.registers);
25
26                    19
27                }
28                None => {
29                    let original = register.read_from(&self.cpu.registers);
30                    let modified = $op_fn(original, $($thru_carry,)? &mut self.cpu.registers.f);
31
32                    register.write_to(modified, &mut self.cpu.registers);
33
34                    8
35                }
36            }
37        }
38    }
39}
40
41macro_rules! impl_hl_shift_op {
42    ($name:ident, $op_fn:ident $(, thru_carry: $thru_carry:expr)?) => {
43        pub(super) fn $name(&mut self, index: Option<(IndexRegister, i8)>) -> u32 {
44            let address = match index {
45                Some((index_register, offset)) => {
46                    let index_value = index_register.read_from(&self.cpu.registers);
47                    (i32::from(index_value) + i32::from(offset)) as u16
48                }
49                None => Register16::HL.read_from(&self.cpu.registers),
50            };
51
52            let original = self.bus.read_memory_debug(address, self.cpu);
53            let modified = $op_fn(original, $($thru_carry,)? &mut self.cpu.registers.f);
54
55            self.bus.write_memory_debug(address, modified, self.cpu);
56
57            match index {
58                Some(_) => 19,
59                None => 15,
60            }
61        }
62    }
63}
64
65macro_rules! impl_rotate_decimal_op {
66    ($name:ident, $op_fn:ident) => {
67        pub(super) fn $name(&mut self) -> u32 {
68            let a = self.cpu.registers.a;
69            let address = Register16::HL.read_from(&self.cpu.registers);
70            let memory_value = self.bus.read_memory_debug(address, self.cpu);
71
72            let (new_a, new_memory_value) = $op_fn(a, memory_value, &mut self.cpu.registers.f);
73
74            self.cpu.registers.a = new_a;
75            self.bus.write_memory_debug(address, new_memory_value, self.cpu);
76
77            18
78        }
79    };
80}
81
82macro_rules! impl_r_bit_op {
83    ($name:ident, $op_fn:ident) => {
84        pub(super) fn $name(&mut self, opcode: u8, index: Option<(IndexRegister, i8)>) -> u32 {
85            let register = super::parse_register_from_opcode(opcode, None).expect("invalid opcode");
86            let bit = (opcode >> 3) & 0x07;
87
88            match index {
89                Some((index, offset)) => {
90                    let address = compute_index_address(&self.cpu.registers, index, offset);
91                    let original = self.bus.read_memory_debug(address, self.cpu);
92                    let modified = $op_fn(original, bit);
93
94                    self.bus.write_memory_debug(address, modified, self.cpu);
95                    register.write_to(modified, &mut self.cpu.registers);
96
97                    19
98                }
99                None => {
100                    let original = register.read_from(&self.cpu.registers);
101                    let modified = $op_fn(original, bit);
102
103                    register.write_to(modified, &mut self.cpu.registers);
104
105                    8
106                }
107            }
108        }
109    };
110}
111
112macro_rules! impl_hl_bit_op {
113    ($name:ident, $op_fn:ident) => {
114        pub(super) fn $name(&mut self, opcode: u8, index: Option<(IndexRegister, i8)>) -> u32 {
115            let address = match index {
116                Some((index, offset)) => compute_index_address(&self.cpu.registers, index, offset),
117                None => Register16::HL.read_from(&self.cpu.registers),
118            };
119            let bit = (opcode >> 3) & 0x07;
120
121            let original = self.bus.read_memory_debug(address, self.cpu);
122            let modified = $op_fn(original, bit);
123
124            self.bus.write_memory_debug(address, modified, self.cpu);
125
126            match index {
127                Some(_) => 19,
128                None => 15,
129            }
130        }
131    };
132}
133
134impl<B: BusInterface> InstructionExecutor<'_, '_, B> {
135    impl_r_shift_op!(rlc_r, rotate_left, thru_carry: false);
136    impl_hl_shift_op!(rlc_hl, rotate_left, thru_carry: false);
137
138    impl_r_shift_op!(rl_r, rotate_left, thru_carry: true);
139    impl_hl_shift_op!(rl_hl, rotate_left, thru_carry: true);
140
141    impl_r_shift_op!(rrc_r, rotate_right, thru_carry: false);
142    impl_hl_shift_op!(rrc_hl, rotate_right, thru_carry: false);
143
144    impl_r_shift_op!(rr_r, rotate_right, thru_carry: true);
145    impl_hl_shift_op!(rr_hl, rotate_right, thru_carry: true);
146
147    impl_r_shift_op!(sla_r, shift_left_arithmetic);
148    impl_hl_shift_op!(sla_hl, shift_left_arithmetic);
149
150    impl_r_shift_op!(sll_r, shift_left_logical);
151    impl_hl_shift_op!(sll_hl, shift_left_logical);
152
153    impl_r_shift_op!(sra_r, shift_right_arithmetic);
154    impl_hl_shift_op!(sra_hl, shift_right_arithmetic);
155
156    impl_r_shift_op!(srl_r, shift_right_logical);
157    impl_hl_shift_op!(srl_hl, shift_right_logical);
158
159    impl_rotate_decimal_op!(rld, rotate_left_decimal);
160    impl_rotate_decimal_op!(rrd, rotate_right_decimal);
161
162    impl_r_bit_op!(set_b_r, set_bit);
163    impl_hl_bit_op!(set_b_hl, set_bit);
164
165    impl_r_bit_op!(res_b_r, reset_bit);
166    impl_hl_bit_op!(res_b_hl, reset_bit);
167
168    // RLCA sets flags differently from RLC
169    pub(super) fn rlca(&mut self) -> u32 {
170        let a = self.cpu.registers.a;
171
172        self.cpu.registers.a = a.rotate_left(1);
173        self.cpu.registers.f =
174            Flags { half_carry: false, subtract: false, carry: a.bit(7), ..self.cpu.registers.f };
175
176        4
177    }
178
179    // RLA sets flags differently from RL
180    pub(super) fn rla(&mut self) -> u32 {
181        let a = self.cpu.registers.a;
182
183        self.cpu.registers.a = (a << 1) | u8::from(self.cpu.registers.f.carry);
184        self.cpu.registers.f =
185            Flags { half_carry: false, subtract: false, carry: a.bit(7), ..self.cpu.registers.f };
186
187        4
188    }
189
190    // RRCA sets flags differently from RRC
191    pub(super) fn rrca(&mut self) -> u32 {
192        let a = self.cpu.registers.a;
193
194        self.cpu.registers.a = a.rotate_right(1);
195        self.cpu.registers.f =
196            Flags { half_carry: false, subtract: false, carry: a.bit(0), ..self.cpu.registers.f };
197
198        4
199    }
200
201    // RRA sets flags differently from RR
202    pub(super) fn rra(&mut self) -> u32 {
203        let a = self.cpu.registers.a;
204
205        self.cpu.registers.a = (a >> 1) | (u8::from(self.cpu.registers.f.carry) << 7);
206        self.cpu.registers.f =
207            Flags { half_carry: false, subtract: false, carry: a.bit(0), ..self.cpu.registers.f };
208
209        4
210    }
211
212    pub(super) fn bit_b_r(&mut self, opcode: u8) -> u32 {
213        let register = super::parse_register_from_opcode(opcode, None).expect("invalid opcode");
214        let bit = (opcode >> 3) & 0x07;
215
216        bit_test(register.read_from(&self.cpu.registers), bit, &mut self.cpu.registers.f);
217
218        8
219    }
220
221    pub(super) fn bit_b_hl(&mut self, opcode: u8, index: Option<(IndexRegister, i8)>) -> u32 {
222        let address = match index {
223            Some((index, offset)) => compute_index_address(&self.cpu.registers, index, offset),
224            None => Register16::HL.read_from(&self.cpu.registers),
225        };
226        let value = self.bus.read_memory_debug(address, self.cpu);
227        let bit = (opcode >> 3) & 0x07;
228
229        bit_test(value, bit, &mut self.cpu.registers.f);
230
231        match index {
232            Some(_) => 16,
233            None => 12,
234        }
235    }
236}
237
238fn set_shift_flags(flags: &mut Flags, value: u8, carry: bool) {
239    *flags = Flags {
240        sign: sign_flag(value),
241        zero: zero_flag(value),
242        half_carry: false,
243        overflow: parity_flag(value),
244        subtract: false,
245        carry,
246        ..*flags
247    };
248}
249
250fn rotate_left(value: u8, thru_carry: bool, flags: &mut Flags) -> u8 {
251    let bit_0 = if thru_carry { flags.carry } else { value.bit(7) };
252    let rotated = (value << 1) | u8::from(bit_0);
253
254    set_shift_flags(flags, rotated, value.bit(7));
255
256    rotated
257}
258
259fn rotate_right(value: u8, thru_carry: bool, flags: &mut Flags) -> u8 {
260    let bit_7 = if thru_carry { flags.carry } else { value.bit(0) };
261    let rotated = (value >> 1) | (u8::from(bit_7) << 7);
262
263    set_shift_flags(flags, rotated, value.bit(0));
264
265    rotated
266}
267
268fn shift_left_arithmetic(value: u8, flags: &mut Flags) -> u8 {
269    let shifted = value << 1;
270
271    set_shift_flags(flags, shifted, value.bit(7));
272
273    shifted
274}
275
276fn shift_left_logical(value: u8, flags: &mut Flags) -> u8 {
277    let shifted = (value << 1) | 0x01;
278
279    set_shift_flags(flags, shifted, value.bit(7));
280
281    shifted
282}
283
284fn shift_right_arithmetic(value: u8, flags: &mut Flags) -> u8 {
285    let shifted = (value >> 1) | (value & 0x80);
286
287    set_shift_flags(flags, shifted, value.bit(0));
288
289    shifted
290}
291
292fn shift_right_logical(value: u8, flags: &mut Flags) -> u8 {
293    let shifted = value >> 1;
294
295    set_shift_flags(flags, shifted, value.bit(0));
296
297    shifted
298}
299
300fn rotate_left_decimal(a: u8, memory_value: u8, flags: &mut Flags) -> (u8, u8) {
301    let new_a = (a & 0xF0) | (memory_value >> 4);
302    let new_memory_value = (memory_value << 4) | (a & 0x0F);
303
304    set_shift_flags(flags, new_a, flags.carry);
305
306    (new_a, new_memory_value)
307}
308
309fn rotate_right_decimal(a: u8, memory_value: u8, flags: &mut Flags) -> (u8, u8) {
310    let new_a = (a & 0xF0) | (memory_value & 0x0F);
311    let new_memory_value = (memory_value >> 4) | (a << 4);
312
313    set_shift_flags(flags, new_a, flags.carry);
314
315    (new_a, new_memory_value)
316}
317
318fn bit_test(value: u8, bit: u8, flags: &mut Flags) {
319    let zero = value & (1 << bit) == 0;
320    *flags = Flags {
321        zero,
322        half_carry: true,
323        subtract: false,
324        overflow: zero,
325        sign: bit == 7 && !zero,
326        ..*flags
327    };
328}
329
330fn set_bit(value: u8, bit: u8) -> u8 {
331    value | (1 << bit)
332}
333
334fn reset_bit(value: u8, bit: u8) -> u8 {
335    value & !(1 << bit)
336}