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}