1mod arithmetic; 2mod bits; 3mod control; 4mod io; 5mod jump; 6mod load; 7mod mnemonics; 8 9use crate::Z80; 10use crate::core::{IndexRegister, InterruptMode, Register8, Register16}; 11use crate::debug::BusDebugExt; 12use crate::traits::{BusInterface, InterruptLine}; 13use jgenesis_common::num::GetBit; 14 15#[derive(Debug, Clone, Copy, PartialEq, Eq)] 16pub enum BlockMode { 17 Increment, 18 Decrement, 19} 20 21impl BlockMode { 22 fn apply(self, value: u16) -> u16 { 23 match self { 24 Self::Increment => value.wrapping_add(1), 25 Self::Decrement => value.wrapping_sub(1), 26 } 27 } 28} 29 30#[derive(Debug, Clone, Copy, PartialEq, Eq)] 31enum InterruptType { 32 Nmi, 33 Int, 34} 35 36fn parse_register_from_opcode(opcode: u8, index: Option<IndexRegister>) -> Option<Register8> { 37 match opcode & 0x07 { 38 0x00 => Some(Register8::B), 39 0x01 => Some(Register8::C), 40 0x02 => Some(Register8::D), 41 0x03 => Some(Register8::E), 42 0x04 => Some(index.map_or(Register8::H, IndexRegister::high_byte)), 43 0x05 => Some(index.map_or(Register8::L, IndexRegister::low_byte)), 44 0x06 => None, 45 0x07 => Some(Register8::A), 46 _ => unreachable!("value & 0x07 is always <= 0x07"), 47 } 48} 49 50fn parse_dd_register(opcode: u8, index: Option<IndexRegister>) -> Register16 { 51 match opcode & 0x30 { 52 0x00 => Register16::BC, 53 0x10 => Register16::DE, 54 0x20 => index.map_or(Register16::HL, IndexRegister::into), 55 0x30 => Register16::SP, 56 _ => unreachable!("value & 0x30 is always 0x00/0x10/0x20/0x30"), 57 } 58} 59 60fn parse_qq_register(opcode: u8, index: Option<IndexRegister>) -> Register16 { 61 match opcode & 0x30 { 62 0x00 => Register16::BC, 63 0x10 => Register16::DE, 64 0x20 => index.map_or(Register16::HL, IndexRegister::into), 65 0x30 => Register16::AF, 66 _ => unreachable!("value & 0x30 is always 0x00/0x10/0x20/0x30"), 67 } 68} 69 70fn sign_flag(value: u8) -> bool { 71 value.bit(7) 72} 73 74fn zero_flag(value: u8) -> bool { 75 value == 0 76} 77 78fn parity_flag(value: u8) -> bool { 79 value.count_ones().is_multiple_of(2) 80} 81 82#[derive(Debug, Clone, Copy)] 83struct ParseResult { 84 opcode: u8, 85 index_prefix: Option<IndexRegister>, 86 index_fetch_t_cycles: u32, 87} 88 89struct InstructionExecutor<'cpu, 'bus, B> { 90 cpu: &'cpu mut Z80, 91 bus: &'bus mut B, 92} 93 94impl<'cpu, 'bus, B: BusInterface> InstructionExecutor<'cpu, 'bus, B> { 95 fn new(cpu: &'cpu mut Z80, bus: &'bus mut B) -> Self { 96 Self { cpu, bus } 97 } 98 99 fn fetch_operand(&mut self) -> u8 { 100 let operand = self.bus.read_memory(self.cpu.registers.pc); 101 self.cpu.registers.pc = self.cpu.registers.pc.wrapping_add(1); 102 operand 103 } 104 105 fn fetch_operand_u16(&mut self) -> u16 { 106 let lsb = self.fetch_operand(); 107 let msb = self.fetch_operand(); 108 u16::from_le_bytes([lsb, msb]) 109 } 110 111 fn parse_opcode(&mut self) -> ParseResult { 112 let mut index = None; 113 let mut t_cycles = 0; 114 loop { 115 // Increment R on every opcode fetch, including DD/FD prefixes 116 self.cpu.registers.increment_r(); 117 118 let opcode = self.fetch_operand(); 119 match opcode { 120 0xDD => { 121 index = Some(IndexRegister::IX); 122 t_cycles += 4; 123 } 124 0xFD => { 125 index = Some(IndexRegister::IY); 126 t_cycles += 4; 127 } 128 _ => { 129 return ParseResult { 130 opcode, 131 index_prefix: index, 132 index_fetch_t_cycles: t_cycles, 133 }; 134 } 135 } 136 } 137 } 138 139 // Replaces (HL) with (IX+d) or (IY+d) if index register is Some 140 fn fetch_indirect_hl_address(&mut self, index: Option<IndexRegister>) -> u16 { 141 match index { 142 Some(index) => { 143 let index = index.read_from(&self.cpu.registers); 144 let offset = self.fetch_operand() as i8; 145 (i32::from(index) + i32::from(offset)) as u16 146 } 147 None => Register16::HL.read_from(&self.cpu.registers), 148 } 149 } 150 151 fn read_memory_u16(&mut self, address: u16) -> u16 { 152 let lsb = self.bus.read_memory_debug(address, self.cpu); 153 let msb = self.bus.read_memory_debug(address.wrapping_add(1), self.cpu); 154 u16::from_le_bytes([lsb, msb]) 155 } 156 157 fn write_memory_u16(&mut self, address: u16, value: u16) { 158 let [lsb, msb] = value.to_le_bytes(); 159 self.bus.write_memory_debug(address, lsb, self.cpu); 160 self.bus.write_memory_debug(address.wrapping_add(1), msb, self.cpu); 161 } 162 163 fn push_stack(&mut self, value: u16) { 164 let [lsb, msb] = value.to_le_bytes(); 165 166 self.cpu.registers.sp = self.cpu.registers.sp.wrapping_sub(1); 167 self.bus.write_memory_debug(self.cpu.registers.sp, msb, self.cpu); 168 self.cpu.registers.sp = self.cpu.registers.sp.wrapping_sub(1); 169 self.bus.write_memory_debug(self.cpu.registers.sp, lsb, self.cpu); 170 } 171 172 fn pop_stack(&mut self) -> u16 { 173 let lsb = self.bus.read_memory_debug(self.cpu.registers.sp, self.cpu); 174 self.cpu.registers.sp = self.cpu.registers.sp.wrapping_add(1); 175 let msb = self.bus.read_memory_debug(self.cpu.registers.sp, self.cpu); 176 self.cpu.registers.sp = self.cpu.registers.sp.wrapping_add(1); 177 178 u16::from_le_bytes([lsb, msb]) 179 } 180 181 fn check_pending_interrupt(&self) -> Option<InterruptType> { 182 if self.cpu.registers.interrupt_delay { 183 None 184 } else if self.bus.nmi() == InterruptLine::Low 185 && self.cpu.registers.last_nmi == InterruptLine::High 186 { 187 Some(InterruptType::Nmi) 188 } else if self.cpu.registers.iff1 && self.bus.int() == InterruptLine::Low { 189 Some(InterruptType::Int) 190 } else { 191 None 192 } 193 } 194 195 fn interrupt_service_routine(&mut self, interrupt_type: InterruptType) -> u32 { 196 log::trace!("Executing interrupt service routine for interrupt type {interrupt_type:?}"); 197 198 self.cpu.registers.halted = false; 199 200 match interrupt_type { 201 InterruptType::Nmi => { 202 self.push_stack(self.cpu.registers.pc); 203 self.cpu.registers.pc = 0x0066; 204 self.cpu.registers.iff1 = false; 205 206 11 207 } 208 InterruptType::Int => { 209 self.cpu.registers.iff1 = false; 210 self.cpu.registers.iff2 = false; 211 212 #[allow(unreachable_code)] 213 match self.cpu.registers.interrupt_mode { 214 // Modes 0 and 1 don't actually work the same way in actual hardware, but for 215 // the purposes of emulating these consoles they do. 216 // Mode 1 (used exclusively by the overwhelming majority of games) is defined to 217 // always execute RST $38. 218 // Mode 0 reads an opcode from the data bus, but on these consoles, the Z80 219 // will always read $FF (RST $38) if it handles an interrupt while in mode 0. 220 // Some games depend on this mode 0 behavior, e.g. Blaster Master 2 221 InterruptMode::Mode0 | InterruptMode::Mode1 => { 222 self.push_stack(self.cpu.registers.pc); 223 self.cpu.registers.pc = 0x0038; 224 225 13 226 } 227 InterruptMode::Mode2 => { 228 log::error!("Interrupt mode 2 is not implemented; treating as mode 1"); 229 230 self.push_stack(self.cpu.registers.pc); 231 self.cpu.registers.pc = 0x0038; 232 233 19 234 } 235 } 236 } 237 } 238 } 239 240 fn execute_cb_prefix(&mut self, index: Option<IndexRegister>) -> u32 { 241 // CB-prefixed instructions increment R an extra time, but only if there's no DD/FD prefix 242 if index.is_none() { 243 self.cpu.registers.increment_r(); 244 } 245 246 // For DD+CB and FD+CB instructions, the index offset comes before the last opcode byte 247 let index_with_offset = match index { 248 Some(index) => { 249 let offset = self.fetch_operand() as i8; 250 Some((index, offset)) 251 } 252 None => None, 253 }; 254 255 let opcode2 = self.fetch_operand(); 256 257 log::trace!("CB prefix opcode: {opcode2:02X}"); 258 259 match opcode2 { 260 0x00..=0x05 | 0x07 => self.rlc_r(opcode2, index_with_offset), 261 0x06 => self.rlc_hl(index_with_offset), 262 0x08..=0x0D | 0x0F => self.rrc_r(opcode2, index_with_offset), 263 0x0E => self.rrc_hl(index_with_offset), 264 0x10..=0x15 | 0x17 => self.rl_r(opcode2, index_with_offset), 265 0x16 => self.rl_hl(index_with_offset), 266 0x18..=0x1D | 0x1F => self.rr_r(opcode2, index_with_offset), 267 0x1E => self.rr_hl(index_with_offset), 268 0x20..=0x25 | 0x27 => self.sla_r(opcode2, index_with_offset), 269 0x26 => self.sla_hl(index_with_offset), 270 0x28..=0x2D | 0x2F => self.sra_r(opcode2, index_with_offset), 271 0x2E => self.sra_hl(index_with_offset), 272 0x30..=0x35 | 0x37 => self.sll_r(opcode2, index_with_offset), 273 0x36 => self.sll_hl(index_with_offset), 274 0x38..=0x3D | 0x3F => self.srl_r(opcode2, index_with_offset), 275 0x3E => self.srl_hl(index_with_offset), 276 0x40..=0x7F => { 277 if opcode2 & 0x07 == 0x06 { 278 self.bit_b_hl(opcode2, index_with_offset) 279 } else { 280 self.bit_b_r(opcode2) 281 } 282 } 283 0x80..=0xBF => { 284 if opcode2 & 0x07 == 0x06 { 285 self.res_b_hl(opcode2, index_with_offset) 286 } else { 287 self.res_b_r(opcode2, index_with_offset) 288 } 289 } 290 0xC0..=0xFF => { 291 if opcode2 & 0x07 == 0x06 { 292 self.set_b_hl(opcode2, index_with_offset) 293 } else { 294 self.set_b_r(opcode2, index_with_offset) 295 } 296 } 297 } 298 } 299 300 fn execute_ed_prefix(&mut self) -> u32 { 301 // ED-prefixed instructions increment R an extra time for the second opcode fetch 302 self.cpu.registers.increment_r(); 303 304 let opcode2 = self.fetch_operand(); 305 306 match opcode2 { 307 0x40 | 0x48 | 0x50 | 0x58 | 0x60 | 0x68 | 0x70 | 0x78 => self.in_r_c(opcode2), 308 0x41 | 0x49 | 0x51 | 0x59 | 0x61 | 0x69 | 0x71 | 0x79 => self.out_c_r(opcode2), 309 0x42 | 0x52 | 0x62 | 0x72 => self.sbc_hl_ss(opcode2), 310 0x43 | 0x53 | 0x63 | 0x73 => self.ld_direct_dd(opcode2), 311 0x44 => self.neg(), 312 0x45 | 0x4D => self.reti_retn(), 313 0x46 => self.im(InterruptMode::Mode0), 314 0x47 => self.ld_ir_a(Register8::I), 315 0x4A | 0x5A | 0x6A | 0x7A => self.adc_hl_ss(opcode2), 316 0x4B | 0x5B | 0x6B | 0x7B => self.ld_dd_direct(opcode2), 317 0x4F => self.ld_ir_a(Register8::R), 318 0x56 => self.im(InterruptMode::Mode1), 319 0x57 => self.ld_a_ir(Register8::I), 320 0x5E => self.im(InterruptMode::Mode2), 321 0x5F => self.ld_a_ir(Register8::R), 322 0x67 => self.rrd(), 323 0x6F => self.rld(), 324 0xA0 => self.block_transfer(BlockMode::Increment, false), 325 0xA1 => self.compare_block(BlockMode::Increment, false), 326 0xA2 => self.in_block(BlockMode::Increment, false), 327 0xA3 => self.out_block(BlockMode::Increment, false), 328 0xA8 => self.block_transfer(BlockMode::Decrement, false), 329 0xA9 => self.compare_block(BlockMode::Decrement, false), 330 0xAA => self.in_block(BlockMode::Decrement, false), 331 0xAB => self.out_block(BlockMode::Decrement, false), 332 0xB0 => self.block_transfer(BlockMode::Increment, true), 333 0xB1 => self.compare_block(BlockMode::Increment, true), 334 0xB2 => self.in_block(BlockMode::Increment, true), 335 0xB3 => self.out_block(BlockMode::Increment, true), 336 0xB8 => self.block_transfer(BlockMode::Decrement, true), 337 0xB9 => self.compare_block(BlockMode::Decrement, true), 338 0xBA => self.in_block(BlockMode::Decrement, true), 339 0xBB => self.out_block(BlockMode::Decrement, true), 340 _ => { 341 // Treat unused opcodes as NOPs 342 control::nop() 343 } 344 } 345 } 346 347 fn execute(mut self) -> u32 { 348 let interrupt_type = self.check_pending_interrupt(); 349 350 self.cpu.registers.interrupt_delay = false; 351 self.cpu.registers.last_nmi = self.bus.nmi(); 352 353 if let Some(interrupt_type) = interrupt_type { 354 self.cpu.registers.increment_r(); 355 return self.interrupt_service_routine(interrupt_type); 356 } 357 358 if self.cpu.registers.halted { 359 return control::nop(); 360 } 361 362 self.bus.check_execute(self.cpu.registers.pc, self.cpu); 363 364 let ParseResult { opcode, index_prefix: index, index_fetch_t_cycles } = self.parse_opcode(); 365 366 log::trace!( 367 "PC={:04X}, opcode={opcode:02X} ({}), index={index:?}, a={:02X}, next={:02X} {:02X}, sp={:04X}, a={:02X}, f={:02X}, b={:02X}, c={:02X}, d={:02X}, e={:02X}, h={:02X}, l={:02X}, ix={:04X}, iy={:04X}, iff1={}", 368 self.cpu.registers.pc.wrapping_sub(1), 369 mnemonics::for_opcode(opcode, self.bus.read_memory(self.cpu.registers.pc)), 370 self.cpu.registers.a, 371 self.bus.read_memory(self.cpu.registers.pc), 372 self.bus.read_memory(self.cpu.registers.pc.wrapping_add(1)), 373 self.cpu.registers.sp, 374 self.cpu.registers.a, 375 u8::from(self.cpu.registers.f), 376 self.cpu.registers.b, 377 self.cpu.registers.c, 378 self.cpu.registers.d, 379 self.cpu.registers.e, 380 self.cpu.registers.h, 381 self.cpu.registers.l, 382 self.cpu.registers.ix, 383 self.cpu.registers.iy, 384 self.cpu.registers.iff1 385 ); 386 387 let instruction_t_cycles = match opcode { 388 0x00 => control::nop(), 389 0x01 | 0x11 | 0x21 | 0x31 => self.ld_dd_immediate(opcode, index), 390 0x02 => self.ld_indirect_a(Register16::BC), 391 0x03 | 0x13 | 0x23 | 0x33 => self.inc_ss(opcode, index), 392 0x04 | 0x0C | 0x14 | 0x1C | 0x24 | 0x2C | 0x3C => self.inc_r(opcode, index), 393 0x34 => self.inc_hl(index), 394 0x05 | 0x0D | 0x15 | 0x1D | 0x25 | 0x2D | 0x3D => self.dec_r(opcode, index), 395 0x35 => self.dec_hl(index), 396 0x06 | 0x0E | 0x16 | 0x1E | 0x26 | 0x2E | 0x3E => self.ld_r_immediate(opcode, index), 397 0x36 => self.ld_hl_immediate(index), 398 0x07 => self.rlca(), 399 0x08 => self.exchange_af(), 400 0x09 | 0x19 | 0x29 | 0x39 => self.add_hl_ss(opcode, index), 401 0x0A => self.ld_a_indirect(Register16::BC), 402 0x0B | 0x1B | 0x2B | 0x3B => self.dec_ss(opcode, index), 403 0x0F => self.rrca(), 404 0x10 => self.djnz_e(), 405 0x12 => self.ld_indirect_a(Register16::DE), 406 0x17 => self.rla(), 407 0x18 => self.jr_e(), 408 0x1A => self.ld_a_indirect(Register16::DE), 409 0x1F => self.rra(), 410 0x20 => self.jr_nz_e(), 411 0x22 => self.ld_direct_hl(index), 412 0x27 => self.daa(), 413 0x28 => self.jr_z_e(), 414 0x2A => self.ld_hl_direct(index), 415 0x2F => self.cpl(), 416 0x30 => self.jr_nc_e(), 417 0x32 => self.ld_direct_a(), 418 0x37 => self.scf(), 419 0x38 => self.jr_c_e(), 420 0x3A => self.ld_a_direct(), 421 0x3F => self.ccf(), 422 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x47 | 0x48 | 0x49 | 0x4A | 0x4B | 0x4C 423 | 0x4D | 0x4F | 0x50 | 0x51 | 0x52 | 0x53 | 0x54 | 0x55 | 0x57 | 0x58 | 0x59 | 0x5A 424 | 0x5B | 0x5C | 0x5D | 0x5F | 0x60 | 0x61 | 0x62 | 0x63 | 0x64 | 0x65 | 0x67 | 0x68 425 | 0x69 | 0x6A | 0x6B | 0x6C | 0x6D | 0x6F | 0x78 | 0x79 | 0x7A | 0x7B | 0x7C | 0x7D 426 | 0x7F => self.ld_r_r(opcode, index), 427 0x46 | 0x4E | 0x56 | 0x5E | 0x66 | 0x6E | 0x7E => self.ld_r_hl(opcode, index), 428 0x70 | 0x71 | 0x72 | 0x73 | 0x74 | 0x75 | 0x77 => self.ld_hl_r(opcode, index), 429 0x76 => self.halt(), 430 0x80 | 0x81 | 0x82 | 0x83 | 0x84 | 0x85 | 0x87 => self.add_a_r(opcode, index, false), 431 0x86 => self.add_a_hl(index, false), 432 0x88 | 0x89 | 0x8A | 0x8B | 0x8C | 0x8D | 0x8F => self.add_a_r(opcode, index, true), 433 0x8E => self.add_a_hl(index, true), 434 0x90 | 0x91 | 0x92 | 0x93 | 0x94 | 0x95 | 0x97 => self.sub_a_r(opcode, index, false), 435 0x96 => self.sub_a_hl(index, false), 436 0x98 | 0x99 | 0x9A | 0x9B | 0x9C | 0x9D | 0x9F => self.sub_a_r(opcode, index, true), 437 0x9E => self.sub_a_hl(index, true), 438 0xA0 | 0xA1 | 0xA2 | 0xA3 | 0xA4 | 0xA5 | 0xA7 => self.and_a_r(opcode, index), 439 0xA6 => self.and_a_hl(index), 440 0xA8 | 0xA9 | 0xAA | 0xAB | 0xAC | 0xAD | 0xAF => self.xor_a_r(opcode, index), 441 0xAE => self.xor_a_hl(index), 442 0xB0 | 0xB1 | 0xB2 | 0xB3 | 0xB4 | 0xB5 | 0xB7 => self.or_a_r(opcode, index), 443 0xB6 => self.or_a_hl(index), 444 0xB8 | 0xB9 | 0xBA | 0xBB | 0xBC | 0xBD | 0xBF => self.cp_a_r(opcode, index), 445 0xBE => self.cp_a_hl(index), 446 0xC0 | 0xC8 | 0xD0 | 0xD8 | 0xE0 | 0xE8 | 0xF0 | 0xF8 => self.ret_cc(opcode), 447 0xC1 | 0xD1 | 0xE1 | 0xF1 => self.pop_qq(opcode, index), 448 0xC2 | 0xCA | 0xD2 | 0xDA | 0xE2 | 0xEA | 0xF2 | 0xFA => self.jp_cc_nn(opcode), 449 0xC3 => self.jp_nn(), 450 0xC4 | 0xCC | 0xD4 | 0xDC | 0xE4 | 0xEC | 0xF4 | 0xFC => self.call_cc_nn(opcode), 451 0xC5 | 0xD5 | 0xE5 | 0xF5 => self.push_qq(opcode, index), 452 0xC6 => self.add_a_immediate(false), 453 0xC7 | 0xCF | 0xD7 | 0xDF | 0xE7 | 0xEF | 0xF7 | 0xFF => self.rst_p(opcode), 454 0xC9 => self.ret(), 455 0xCB => self.execute_cb_prefix(index), 456 0xCD => self.call_nn(), 457 0xCE => self.add_a_immediate(true), 458 0xD3 => self.out_n_a(), 459 0xD6 => self.sub_a_immediate(false), 460 0xD9 => self.exchange_bcdehl(), 461 0xDB => self.in_a_n(), 462 0xDE => self.sub_a_immediate(true), 463 0xE3 => self.exchange_stack_hl(index), 464 0xE6 => self.and_a_immediate(), 465 0xE9 => self.jp_hl(index), 466 0xEB => self.exchange_de_hl(), 467 0xED => self.execute_ed_prefix(), 468 0xEE => self.xor_a_immediate(), 469 0xF3 => self.di(), 470 0xF6 => self.or_a_immediate(), 471 0xF9 => self.ld_sp_hl(index), 472 0xFB => self.ei(), 473 0xFE => self.cp_a_immediate(), 474 0xDD | 0xFD => unreachable!("DD/FD prefixes have already been removed"), 475 }; 476 477 index_fetch_t_cycles + instruction_t_cycles 478 } 479} 480 481pub fn execute<B: BusInterface>(cpu: &mut Z80, bus: &mut B) -> u32 { 482 InstructionExecutor::new(cpu, bus).execute() 483}