1use crate::core::instructions::{BlockMode, InstructionExecutor, sign_flag, zero_flag}; 2use crate::core::{Flags, IndexRegister, Register8, Register16}; 3use crate::debug::BusDebugExt; 4use crate::traits::BusInterface; 5use std::mem; 6 7impl<B: BusInterface> InstructionExecutor<'_, '_, B> { 8 pub(super) fn ld_r_r(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 { 9 let write_target = 10 super::parse_register_from_opcode(opcode >> 3, index).expect("invalid opcode"); 11 let read_target = super::parse_register_from_opcode(opcode, index).expect("invalid opcode"); 12 13 let value = read_target.read_from(&self.cpu.registers); 14 write_target.write_to(value, &mut self.cpu.registers); 15 16 4 17 } 18 19 pub(super) fn ld_r_immediate(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 { 20 let write_target = 21 super::parse_register_from_opcode(opcode >> 3, index).expect("invalid opcode)"); 22 let value = self.fetch_operand(); 23 24 write_target.write_to(value, &mut self.cpu.registers); 25 26 7 27 } 28 29 pub(super) fn ld_r_hl(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 { 30 let write_target = 31 super::parse_register_from_opcode(opcode >> 3, None).expect("invalid opcode"); 32 let address = self.fetch_indirect_hl_address(index); 33 let value = self.bus.read_memory_debug(address, self.cpu); 34 35 write_target.write_to(value, &mut self.cpu.registers); 36 37 match index { 38 Some(_) => 15, 39 None => 7, 40 } 41 } 42 43 pub(super) fn ld_hl_r(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 { 44 let read_target = super::parse_register_from_opcode(opcode, None).expect("invalid opcode"); 45 let value = read_target.read_from(&self.cpu.registers); 46 let address = self.fetch_indirect_hl_address(index); 47 48 self.bus.write_memory_debug(address, value, self.cpu); 49 50 match index { 51 Some(_) => 15, 52 None => 7, 53 } 54 } 55 56 pub(super) fn ld_hl_immediate(&mut self, index: Option<IndexRegister>) -> u32 { 57 let address = self.fetch_indirect_hl_address(index); 58 let value = self.fetch_operand(); 59 60 self.bus.write_memory_debug(address, value, self.cpu); 61 62 match index { 63 Some(_) => 15, 64 None => 10, 65 } 66 } 67 68 pub(super) fn ld_a_indirect(&mut self, register: Register16) -> u32 { 69 let address = register.read_from(&self.cpu.registers); 70 let value = self.bus.read_memory_debug(address, self.cpu); 71 72 self.cpu.registers.a = value; 73 74 7 75 } 76 77 pub(super) fn ld_a_direct(&mut self) -> u32 { 78 let address = self.fetch_operand_u16(); 79 let value = self.bus.read_memory_debug(address, self.cpu); 80 81 self.cpu.registers.a = value; 82 83 13 84 } 85 86 pub(super) fn ld_indirect_a(&mut self, register: Register16) -> u32 { 87 let address = register.read_from(&self.cpu.registers); 88 89 self.bus.write_memory_debug(address, self.cpu.registers.a, self.cpu); 90 91 7 92 } 93 94 pub(super) fn ld_direct_a(&mut self) -> u32 { 95 let address = self.fetch_operand_u16(); 96 self.bus.write_memory_debug(address, self.cpu.registers.a, self.cpu); 97 98 13 99 } 100 101 // LD A, I and LD A, R 102 pub(super) fn ld_a_ir(&mut self, register: Register8) -> u32 { 103 debug_assert!(register == Register8::I || register == Register8::R); 104 105 let value = register.read_from(&self.cpu.registers); 106 self.cpu.registers.a = value; 107 108 self.cpu.registers.f = Flags { 109 sign: sign_flag(value), 110 zero: zero_flag(value), 111 half_carry: false, 112 overflow: self.cpu.registers.iff2, 113 subtract: false, 114 ..self.cpu.registers.f 115 }; 116 117 9 118 } 119 120 // LD I, A and LD R, A 121 pub(super) fn ld_ir_a(&mut self, register: Register8) -> u32 { 122 debug_assert!(register == Register8::I || register == Register8::R); 123 124 register.write_to(self.cpu.registers.a, &mut self.cpu.registers); 125 126 9 127 } 128 129 pub(super) fn ld_dd_immediate(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 { 130 let register = super::parse_dd_register(opcode, index); 131 let value = self.fetch_operand_u16(); 132 133 register.write_to(value, &mut self.cpu.registers); 134 135 10 136 } 137 138 pub(super) fn ld_hl_direct(&mut self, index: Option<IndexRegister>) -> u32 { 139 let address = self.fetch_operand_u16(); 140 let value = self.read_memory_u16(address); 141 142 let register = index.map_or(Register16::HL, IndexRegister::into); 143 register.write_to(value, &mut self.cpu.registers); 144 145 16 146 } 147 148 pub(super) fn ld_dd_direct(&mut self, opcode: u8) -> u32 { 149 let register = super::parse_dd_register(opcode, None); 150 let address = self.fetch_operand_u16(); 151 let value = self.read_memory_u16(address); 152 153 register.write_to(value, &mut self.cpu.registers); 154 155 20 156 } 157 158 pub(super) fn ld_direct_hl(&mut self, index: Option<IndexRegister>) -> u32 { 159 let register = index.map_or(Register16::HL, IndexRegister::into); 160 let value = register.read_from(&self.cpu.registers); 161 let address = self.fetch_operand_u16(); 162 163 self.write_memory_u16(address, value); 164 165 16 166 } 167 168 pub(super) fn ld_direct_dd(&mut self, opcode: u8) -> u32 { 169 let register = super::parse_dd_register(opcode, None); 170 let value = register.read_from(&self.cpu.registers); 171 let address = self.fetch_operand_u16(); 172 173 self.write_memory_u16(address, value); 174 175 20 176 } 177 178 pub(super) fn ld_sp_hl(&mut self, index: Option<IndexRegister>) -> u32 { 179 let register = index.map_or(Register16::HL, IndexRegister::into); 180 let value = register.read_from(&self.cpu.registers); 181 182 self.cpu.registers.sp = value; 183 184 6 185 } 186 187 pub(super) fn push_qq(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 { 188 let register = super::parse_qq_register(opcode, index); 189 let value = register.read_from(&self.cpu.registers); 190 191 self.push_stack(value); 192 193 11 194 } 195 196 pub(super) fn pop_qq(&mut self, opcode: u8, index: Option<IndexRegister>) -> u32 { 197 let register = super::parse_qq_register(opcode, index); 198 let value = self.pop_stack(); 199 200 register.write_to(value, &mut self.cpu.registers); 201 202 10 203 } 204 205 pub(super) fn exchange_de_hl(&mut self) -> u32 { 206 mem::swap(&mut self.cpu.registers.d, &mut self.cpu.registers.h); 207 mem::swap(&mut self.cpu.registers.e, &mut self.cpu.registers.l); 208 209 4 210 } 211 212 pub(super) fn exchange_af(&mut self) -> u32 { 213 mem::swap(&mut self.cpu.registers.a, &mut self.cpu.registers.ap); 214 mem::swap(&mut self.cpu.registers.f, &mut self.cpu.registers.fp); 215 216 4 217 } 218 219 pub(super) fn exchange_bcdehl(&mut self) -> u32 { 220 mem::swap(&mut self.cpu.registers.b, &mut self.cpu.registers.bp); 221 mem::swap(&mut self.cpu.registers.c, &mut self.cpu.registers.cp); 222 mem::swap(&mut self.cpu.registers.d, &mut self.cpu.registers.dp); 223 mem::swap(&mut self.cpu.registers.e, &mut self.cpu.registers.ep); 224 mem::swap(&mut self.cpu.registers.h, &mut self.cpu.registers.hp); 225 mem::swap(&mut self.cpu.registers.l, &mut self.cpu.registers.lp); 226 227 4 228 } 229 230 pub(super) fn exchange_stack_hl(&mut self, index: Option<IndexRegister>) -> u32 { 231 let register = index.map_or(Register16::HL, IndexRegister::into); 232 let register_value = register.read_from(&self.cpu.registers); 233 let stack_value = self.pop_stack(); 234 235 register.write_to(stack_value, &mut self.cpu.registers); 236 self.push_stack(register_value); 237 238 19 239 } 240 241 pub(super) fn block_transfer(&mut self, mode: BlockMode, repeat: bool) -> u32 { 242 let hl = Register16::HL.read_from(&self.cpu.registers); 243 let de = Register16::DE.read_from(&self.cpu.registers); 244 245 let value = self.bus.read_memory_debug(hl, self.cpu); 246 self.bus.write_memory_debug(de, value, self.cpu); 247 248 let bc = Register16::BC.read_from(&self.cpu.registers); 249 Register16::BC.write_to(bc.wrapping_sub(1), &mut self.cpu.registers); 250 251 Register16::HL.write_to(mode.apply(hl), &mut self.cpu.registers); 252 Register16::DE.write_to(mode.apply(de), &mut self.cpu.registers); 253 254 let should_repeat = repeat && bc != 1; 255 if should_repeat { 256 self.cpu.registers.pc = self.cpu.registers.pc.wrapping_sub(2); 257 } 258 259 self.cpu.registers.f = 260 Flags { half_carry: false, overflow: bc != 1, subtract: false, ..self.cpu.registers.f }; 261 262 if should_repeat { 21 } else { 16 } 263 } 264} 265 266#[cfg(test)] 267mod tests { 268 use super::*; 269 use crate::Z80; 270 use crate::traits::InMemoryBus; 271 272 const REAL_REGISTERS: &[Register8] = &[ 273 Register8::B, 274 Register8::C, 275 Register8::D, 276 Register8::E, 277 Register8::H, 278 Register8::L, 279 Register8::A, 280 ]; 281 282 fn register_opcode_bits(register: Register8) -> u8 { 283 use Register8::*; 284 285 match register { 286 B => 0x00, 287 C => 0x01, 288 D => 0x02, 289 E => 0x03, 290 H => 0x04, 291 L => 0x05, 292 A => 0x07, 293 _ => panic!("unexpected register: {register:?}"), 294 } 295 } 296 297 #[test] 298 fn load_r_r() { 299 let mut cpu = Z80::new(); 300 let mut bus = InMemoryBus::new(); 301 302 for &r in REAL_REGISTERS { 303 for &rp in REAL_REGISTERS { 304 let opcode = 0x40 | (register_opcode_bits(r) << 3) | register_opcode_bits(rp); 305 306 r.write_to(rand::random(), &mut cpu.registers); 307 let value = rand::random(); 308 rp.write_to(value, &mut cpu.registers); 309 310 InstructionExecutor::new(&mut cpu, &mut bus).ld_r_r(opcode, None); 311 312 assert_eq!(r.read_from(&cpu.registers), value, "LD {r:?}, {rp:?}"); 313 assert_eq!(rp.read_from(&cpu.registers), value, "LD {r:?}, {rp:?}"); 314 } 315 } 316 } 317 318 #[test] 319 fn load_r_hl() { 320 let mut cpu = Z80::new(); 321 let mut bus = InMemoryBus::new(); 322 323 for &r in REAL_REGISTERS { 324 let opcode = 0x46 | (register_opcode_bits(r) << 3); 325 326 let address = rand::random(); 327 let value = rand::random(); 328 329 bus.write_memory(address, value); 330 r.write_to(rand::random(), &mut cpu.registers); 331 Register16::HL.write_to(address, &mut cpu.registers); 332 333 InstructionExecutor::new(&mut cpu, &mut bus).ld_r_hl(opcode, None); 334 335 assert_eq!(r.read_from(&cpu.registers), value, "LD {r:?}, (HL)"); 336 assert_eq!(bus.read_memory(address), value, "LD {r:?}, (HL)"); 337 } 338 } 339 340 #[test] 341 fn load_r_immediate() { 342 let mut cpu = Z80::new(); 343 let mut bus = InMemoryBus::new(); 344 345 for &r in REAL_REGISTERS { 346 let opcode = 0x06 | (register_opcode_bits(r) << 3); 347 348 let value = rand::random(); 349 r.write_to(rand::random(), &mut cpu.registers); 350 351 let pc = rand::random(); 352 cpu.registers.pc = pc; 353 bus.write_memory(cpu.registers.pc, value); 354 355 InstructionExecutor::new(&mut cpu, &mut bus).ld_r_immediate(opcode, None); 356 357 assert_eq!(cpu.registers.pc, pc.wrapping_add(1), "LD {r:?}, n"); 358 assert_eq!(r.read_from(&cpu.registers), value, "LD {r:?}, n"); 359 } 360 } 361 362 #[test] 363 fn load_hl_r() { 364 let mut cpu = Z80::new(); 365 let mut bus = InMemoryBus::new(); 366 367 for &r in REAL_REGISTERS { 368 let opcode = 0x70 | register_opcode_bits(r); 369 370 let address = rand::random(); 371 let value = rand::random(); 372 373 Register16::HL.write_to(address, &mut cpu.registers); 374 r.write_to(value, &mut cpu.registers); 375 let address = Register16::HL.read_from(&cpu.registers); 376 377 bus.write_memory(address, rand::random()); 378 379 InstructionExecutor::new(&mut cpu, &mut bus).ld_hl_r(opcode, None); 380 381 assert_eq!(r.read_from(&cpu.registers), value, "LD (HL), {r:?}"); 382 assert_eq!(bus.read_memory(address), value, "LD (HL), {r:?}"); 383 } 384 } 385 386 #[test] 387 fn load_hl_immediate() { 388 let mut cpu = Z80::new(); 389 let mut bus = InMemoryBus::new(); 390 391 let address = rand::random(); 392 let value = rand::random(); 393 394 Register16::HL.write_to(address, &mut cpu.registers); 395 396 bus.write_memory(address, rand::random()); 397 398 let pc = rand::random(); 399 cpu.registers.pc = pc; 400 bus.write_memory(pc, value); 401 402 InstructionExecutor::new(&mut cpu, &mut bus).ld_hl_immediate(None); 403 404 assert_eq!(cpu.registers.pc, pc.wrapping_add(1), "LD (HL), n"); 405 assert_eq!(bus.read_memory(address), value, "LD (HL), n"); 406 } 407 408 #[test] 409 fn load_a_indirect() { 410 let mut cpu = Z80::new(); 411 let mut bus = InMemoryBus::new(); 412 413 for r16 in [Register16::BC, Register16::DE] { 414 let address = rand::random(); 415 let value = rand::random(); 416 417 r16.write_to(address, &mut cpu.registers); 418 bus.write_memory(address, value); 419 420 cpu.registers.a = rand::random(); 421 422 InstructionExecutor::new(&mut cpu, &mut bus).ld_a_indirect(r16); 423 424 assert_eq!(cpu.registers.a, value, "LD A, ({r16:?})"); 425 assert_eq!(bus.read_memory(address), value, "LD A, ({r16:?})"); 426 } 427 } 428 429 #[test] 430 fn load_a_direct() { 431 let mut cpu = Z80::new(); 432 let mut bus = InMemoryBus::new(); 433 434 let address: u16 = rand::random(); 435 let value = rand::random(); 436 let pc = rand::random(); 437 438 let [address_lsb, address_msb] = address.to_le_bytes(); 439 440 cpu.registers.pc = pc; 441 bus.write_memory(pc, address_lsb); 442 bus.write_memory(pc.wrapping_add(1), address_msb); 443 bus.write_memory(address, value); 444 445 cpu.registers.a = rand::random(); 446 447 InstructionExecutor::new(&mut cpu, &mut bus).ld_a_direct(); 448 449 assert_eq!(cpu.registers.pc, pc.wrapping_add(2), "LD A, (nn)"); 450 assert_eq!(cpu.registers.a, value, "LD A, (nn)"); 451 } 452 453 #[test] 454 fn load_indirect_a() { 455 let mut cpu = Z80::new(); 456 let mut bus = InMemoryBus::new(); 457 458 for r16 in [Register16::BC, Register16::DE] { 459 let address = rand::random(); 460 let value = rand::random(); 461 462 r16.write_to(address, &mut cpu.registers); 463 cpu.registers.a = value; 464 465 bus.write_memory(address, rand::random()); 466 467 InstructionExecutor::new(&mut cpu, &mut bus).ld_indirect_a(r16); 468 469 assert_eq!(bus.read_memory(address), value, "LD ({r16:?}), A"); 470 assert_eq!(cpu.registers.a, value, "LD ({r16:?}), A"); 471 } 472 } 473 474 #[test] 475 fn load_direct_a() { 476 let mut cpu = Z80::new(); 477 let mut bus = InMemoryBus::new(); 478 479 let address: u16 = rand::random(); 480 let [address_lsb, address_msb] = address.to_le_bytes(); 481 let value = rand::random(); 482 let pc = rand::random(); 483 484 cpu.registers.pc = pc; 485 cpu.registers.a = value; 486 bus.write_memory(pc, address_lsb); 487 bus.write_memory(pc.wrapping_add(1), address_msb); 488 489 bus.write_memory(address, rand::random()); 490 491 InstructionExecutor::new(&mut cpu, &mut bus).ld_direct_a(); 492 493 assert_eq!(cpu.registers.pc, pc.wrapping_add(2), "LD (nn), A"); 494 assert_eq!(bus.read_memory(address), value, "LD (nn), A"); 495 assert_eq!(cpu.registers.a, value, "LD (nn), A"); 496 } 497}