Sharp SM83, the Game Boy CPU
SM83 is kind of like a Z80-lite, but it's different enough that you can't just drop in a Z80 core and expect it to work
14use crate::HardwareMode; 15use crate::sm83::bus::BusInterface; 16use bincode::{Decode, Encode}; 17use jgenesis_common::num::GetBit; 18 19#[derive(Debug, Clone, Copy, Encode, Decode)] 20struct Flags { 21 zero: bool, 22 subtract: bool, 23 half_carry: bool, 24 carry: bool, 25} 26 27impl From<Flags> for u8 { 28 fn from(value: Flags) -> Self { 29 (u8::from(value.zero) << 7) 30 | (u8::from(value.subtract) << 6) 31 | (u8::from(value.half_carry) << 5) 32 | (u8::from(value.carry) << 4) 33 } 34} 35 36impl From<u8> for Flags { 37 fn from(value: u8) -> Self { 38 Self { 39 zero: value.bit(7), 40 subtract: value.bit(6), 41 half_carry: value.bit(5), 42 carry: value.bit(4), 43 } 44 } 45} 46 47#[derive(Debug, Clone, Encode, Decode)] 48struct Registers { 49 a: u8, 50 f: Flags, 51 b: u8, 52 c: u8, 53 d: u8, 54 e: u8, 55 h: u8, 56 l: u8, 57 sp: u16, 58 pc: u16, 59 ime: bool, 60} 61 62macro_rules! impl_increment_register_pair { 63 (@inner $name:ident, $r1:ident, $r2:ident, $overflowing_op:ident, $wrapping_op:ident) => { 64 fn $name(&mut self) { 65 let ($r2, carry) = self.$r2.$overflowing_op(1); 66 self.$r2 = $r2; 67 self.$r1 = self.$r1.$wrapping_op(carry.into()); 68 } 69 }; 70 ($name:ident, $r1:ident, $r2:ident, increment) => { 71 impl_increment_register_pair!(@inner $name, $r1, $r2, overflowing_add, wrapping_add); 72 }; 73 ($name:ident, $r1:ident, $r2:ident, decrement) => { 74 impl_increment_register_pair!(@inner $name, $r1, $r2, overflowing_sub, wrapping_sub); 75 }; 76} 77 78const BOOT_ROM_ENTRY_POINT: u16 = 0x0000; 79const CARTRIDGE_ENTRY_POINT: u16 = 0x0100; 80const HRAM_END: u16 = 0xFFFE; 81 82impl Registers { 83 fn new(hardware_mode: HardwareMode, boot_rom_present: bool) -> Self { 84 let pc = if boot_rom_present { BOOT_ROM_ENTRY_POINT } else { CARTRIDGE_ENTRY_POINT }; 85 86 // Values from https://gbdev.io/pandocs/Power_Up_Sequence.html 87 // Most important is that DMG sets A=$01 and CGB sets A=$11 88 match hardware_mode { 89 HardwareMode::Dmg => Self { 90 a: 0x01, 91 f: Flags { zero: true, subtract: false, half_carry: false, carry: false }, 92 b: 0x00, 93 c: 0x13, 94 d: 0x00, 95 e: 0xD8, 96 h: 0x01, 97 l: 0x4D, 98 sp: HRAM_END, 99 pc, 100 ime: false, 101 }, 102 HardwareMode::Cgb => Self { 103 a: 0x11, 104 f: Flags { zero: true, subtract: false, half_carry: false, carry: false }, 105 b: 0x00, 106 c: 0x00, 107 d: 0xFF, 108 e: 0x56, 109 h: 0x00, 110 l: 0x0D, 111 sp: HRAM_END, 112 pc, 113 ime: false, 114 }, 115 } 116 } 117 118 fn bc(&self) -> u16 { 119 u16::from_be_bytes([self.b, self.c]) 120 } 121 122 fn de(&self) -> u16 { 123 u16::from_be_bytes([self.d, self.e]) 124 } 125 126 fn hl(&self) -> u16 { 127 u16::from_be_bytes([self.h, self.l]) 128 } 129 130 fn af(&self) -> u16 { 131 u16::from_be_bytes([self.a, self.f.into()]) 132 } 133 134 impl_increment_register_pair!(increment_bc, b, c, increment); 135 impl_increment_register_pair!(decrement_bc, b, c, decrement); 136 137 impl_increment_register_pair!(increment_de, d, e, increment); 138 impl_increment_register_pair!(decrement_de, d, e, decrement); 139 140 impl_increment_register_pair!(increment_hl, h, l, increment); 141 impl_increment_register_pair!(decrement_hl, h, l, decrement); 142 143 fn increment_sp(&mut self) { 144 self.sp = self.sp.wrapping_add(1); 145 } 146 147 fn decrement_sp(&mut self) { 148 self.sp = self.sp.wrapping_sub(1); 149 } 150 151 fn set_hl(&mut self, hl: u16) { 152 let [h, l] = hl.to_be_bytes(); 153 self.h = h; 154 self.l = l; 155 } 156} 157 158#[derive(Debug, Clone, Encode, Decode)] 159struct State { 160 pending_ime_set: bool, 161 handling_interrupt: bool, 162 halted: bool, 163 halt_bug_triggered: bool, 164 executed_invalid_opcode: bool, 165 // Used to ensure that "pretend to be GBA" flag works correctly when booting from boot ROM 166 pending_b_override: Option<u8>, 167} 168 169impl State { 170 fn new(hardware_mode: HardwareMode, pretend_to_be_gba: bool) -> Self { 171 Self { 172 pending_ime_set: false, 173 handling_interrupt: false, 174 halted: false, 175 halt_bug_triggered: false, 176 executed_invalid_opcode: false, 177 // Some GBC games detect GBA by checking that B == $01 at game boot 178 pending_b_override: (hardware_mode == HardwareMode::Cgb && pretend_to_be_gba) 179 .then_some(0x01), 180 } 181 } 182} 183 184#[derive(Debug, Clone, Copy, PartialEq, Eq)] 185pub enum InterruptType { 186 VBlank, 187 LcdStatus, 188 Timer, 189 Serial, 190 Joypad, 191} 192 193impl InterruptType { 194 // In descending priority order 195 pub const ALL: [Self; 5] = 196 [Self::VBlank, Self::LcdStatus, Self::Timer, Self::Serial, Self::Joypad]; 197 198 fn interrupt_vector(self) -> u16 { 199 match self { 200 Self::VBlank => 0x0040, 201 Self::LcdStatus => 0x0048, 202 Self::Timer => 0x0050, 203 Self::Serial => 0x0058, 204 Self::Joypad => 0x0060, 205 } 206 } 207 208 pub fn register_mask(self) -> u8 { 209 match self { 210 Self::VBlank => 1 << 0, 211 Self::LcdStatus => 1 << 1, 212 Self::Timer => 1 << 2, 213 Self::Serial => 1 << 3, 214 Self::Joypad => 1 << 4, 215 } 216 } 217 218 pub fn from_bits(bits: u8) -> Option<Self> { 219 Self::ALL.into_iter().find(|interrupt_type| bits & interrupt_type.register_mask() != 0) 220 } 221} 222 223trait BusExt { 224 fn write_u16(&mut self, address: u16, value: u16); 225} 226 227impl<B: BusInterface> BusExt for B { 228 fn write_u16(&mut self, address: u16, value: u16) { 229 let [lsb, msb] = value.to_le_bytes(); 230 self.write(address, lsb); 231 self.write(address.wrapping_add(1), msb); 232 } 233} 234 235#[derive(Debug, Clone, Encode, Decode)] 236pub struct Sm83 { 237 registers: Registers, 238 state: State, 239} 240 241impl Sm83 { 242 pub fn new( 243 hardware_mode: HardwareMode, 244 pretend_to_be_gba: bool, 245 boot_rom_present: bool, 246 ) -> Self { 247 Self { 248 registers: Registers::new(hardware_mode, boot_rom_present), 249 state: State::new(hardware_mode, pretend_to_be_gba), 250 } 251 } 252 253 pub fn execute_instruction<B: BusInterface>(&mut self, bus: &mut B) { 254 if self.state.executed_invalid_opcode || bus.halt() { 255 // CPU is halted or frozen 256 bus.idle(); 257 return; 258 } 259 260 if self.state.halted && !self.state.handling_interrupt { 261 // HALT halts the CPU until an interrupt triggers. IME is not checked for this so the 262 // CPU will not necessarily handle the interrupt 263 if !bus.interrupt_pending() { 264 bus.idle(); 265 return; 266 } 267 268 // TODO should there be a delay here? 269 self.state.halted = false; 270 self.state.handling_interrupt |= self.registers.ime; 271 } 272 273 if self.state.handling_interrupt { 274 self.execute_interrupt_service_routine(bus); 275 276 self.state.halted = false; 277 self.state.handling_interrupt = false; 278 279 return; 280 } 281 282 if self.state.pending_ime_set { 283 self.registers.ime = true; 284 self.state.pending_ime_set = false; 285 } 286 287 if let Some(b_override) = self.state.pending_b_override 288 && self.registers.pc == CARTRIDGE_ENTRY_POINT 289 { 290 self.registers.b = b_override; 291 self.state.pending_b_override = None; 292 } 293 294 let opcode = self.fetch_operand(bus); 295 296 log::trace!( 297 "Executing opcode {opcode:02X} ({}) from PC {:04X}; IME={}, A={:02X}, F={:02X}, B={:02X}, C={:02X}, D={:02X}, E={:02X}, H={:02X}, L={:02X}, SP={:04X}", 298 disassemble::instruction_str(opcode), 299 self.registers.pc.wrapping_sub(1), 300 self.registers.ime, 301 self.registers.a, 302 u8::from(self.registers.f), 303 self.registers.b, 304 self.registers.c, 305 self.registers.d, 306 self.registers.e, 307 self.registers.h, 308 self.registers.l, 309 self.registers.sp 310 ); 311 312 self.execute_opcode(bus, opcode); 313 314 self.poll_for_interrupts(bus); 315 } 316 317 fn execute_opcode<B: BusInterface>(&mut self, bus: &mut B, opcode: u8) { 318 match opcode { 319 // NOP 320 0x00 => {} 321 // LD rr, u16 322 0x01 | 0x11 | 0x21 | 0x31 => self.ld_rr_nn(bus, opcode), 323 // INC rr 324 0x03 | 0x13 | 0x23 | 0x33 => self.inc_rr(bus, opcode), 325 // DEC rr 326 0x0B | 0x1B | 0x2B | 0x3B => self.dec_rr(bus, opcode), 327 // ADD HL, rr 328 0x09 | 0x19 | 0x29 | 0x39 => self.add_hl_rr(bus, opcode), 329 // INC r / INC (HL) 330 0x04 | 0x0C | 0x14 | 0x1C | 0x24 | 0x2C | 0x34 | 0x3C => self.inc_r(bus, opcode), 331 // DEC r / DEC (HL) 332 0x05 | 0x0D | 0x15 | 0x1D | 0x25 | 0x2D | 0x35 | 0x3D => self.dec_r(bus, opcode), 333 // LD r, u8 / LD (HL), u8 334 0x06 | 0x0E | 0x16 | 0x1E | 0x26 | 0x2E | 0x36 | 0x3E => self.ld_r_imm(bus, opcode), 335 // LD (BC), A 336 0x02 => self.ld_bc_a(bus), 337 // RLCA 338 0x07 => self.rlca(), 339 // LD (u16), SP 340 0x08 => self.ld_indirect_sp(bus), 341 // LD A, (BC) 342 0x0A => self.ld_a_bc(bus), 343 // RRCA 344 0x0F => self.rrca(), 345 // STOP 346 0x10 => self.stop(bus), 347 // LD (DE), A 348 0x12 => self.ld_de_a(bus), 349 // RLA 350 0x17 => self.rla(), 351 // JR i8 352 0x18 => self.jr_e(bus), 353 // LD A, (DE) 354 0x1A => self.ld_a_de(bus), 355 // RRA 356 0x1F => self.rra(), 357 // JR cc, i8 358 0x20 | 0x28 | 0x30 | 0x38 => self.jr_cc_e(bus, opcode), 359 // LD (HL+), A 360 0x22 => self.ld_hl_a_postinc(bus), 361 // DAA 362 0x27 => self.daa(), 363 // LD A, (HL+) 364 0x2A => self.ld_a_hl_postinc(bus), 365 // CPL 366 0x2F => self.cpl(), 367 // LD (HL-), A 368 0x32 => self.ld_hl_a_postdec(bus), 369 // SCF 370 0x37 => self.scf(), 371 // LD A, (HL-) 372 0x3A => self.ld_a_hl_postdec(bus), 373 // CCF 374 0x3F => self.ccf(), 375 // LD r, r' / LD (HL), r / LD r, (HL) 376 0x40..=0x75 | 0x77..=0x7F => self.ld_r_r(bus, opcode), 377 // HALT 378 0x76 => self.halt(bus), 379 // ADD A, r / ADD A, (HL) 380 0x80..=0x87 => self.add_a_r(bus, opcode), 381 // ADC A, r / ADC A, (HL) 382 0x88..=0x8F => self.adc_a_r(bus, opcode), 383 // SUB A, r / SUB A, (HL) 384 0x90..=0x97 => self.sub_a_r(bus, opcode), 385 // SBC A, r / SBC A, (HL) 386 0x98..=0x9F => self.sbc_a_r(bus, opcode), 387 // AND A, r / AND A, (HL) 388 0xA0..=0xA7 => self.and_a_r(bus, opcode), 389 // XOR A, r / XOR A, (HL) 390 0xA8..=0xAF => self.xor_a_r(bus, opcode), 391 // OR A, r / OR A, (HL) 392 0xB0..=0xB7 => self.or_a_r(bus, opcode), 393 // CP A, r / CP A, (HL) 394 0xB8..=0xBF => self.cp_a_r(bus, opcode), 395 // POP rr 396 0xC1 | 0xD1 | 0xE1 | 0xF1 => self.pop_rr(bus, opcode), 397 // PUSH rr 398 0xC5 | 0xD5 | 0xE5 | 0xF5 => self.push_rr(bus, opcode), 399 // RET cc 400 0xC0 | 0xC8 | 0xD0 | 0xD8 => self.ret_cc(bus, opcode), 401 // JP cc, u16 402 0xC2 | 0xCA | 0xD2 | 0xDA => self.jp_cc_nn(bus, opcode), 403 // CALL cc, u16 404 0xC4 | 0xCC | 0xD4 | 0xDC => self.call_cc_nn(bus, opcode), 405 // RST $xx 406 0xC7 | 0xCF | 0xD7 | 0xDF | 0xE7 | 0xEF | 0xF7 | 0xFF => self.rst(bus, opcode), 407 // JP u16 408 0xC3 => self.jp_nn(bus), 409 // ADD A, u8 410 0xC6 => self.add_a_imm(bus), 411 // RET 412 0xC9 => self.ret(bus), 413 // $CB prefix requires a second opcode fetch to determine instruction 414 0xCB => self.execute_cb_prefix_opcode(bus), 415 // CALL nn 416 0xCD => self.call_nn(bus), 417 // ADC A, u8 418 0xCE => self.adc_a_imm(bus), 419 // SUB A, u8 420 0xD6 => self.sub_a_imm(bus), 421 // RETI 422 0xD9 => self.reti(bus), 423 // SBC A, u8 424 0xDE => self.sbc_a_imm(bus), 425 // LDH (u8), A 426 0xE0 => self.ldh_imm_a(bus), 427 // LD ($FF00+C), A 428 0xE2 => self.ld_c_a_high_page(bus), 429 // AND A, u8 430 0xE6 => self.and_a_imm(bus), 431 // ADD SP, i8 432 0xE8 => self.add_sp_e(bus), 433 // JP HL 434 0xE9 => self.jp_hl(), 435 // LD (u16), A 436 0xEA => self.ld_indirect_a(bus), 437 // XOR A, u8 438 0xEE => self.xor_a_imm(bus), 439 // LDH A, (u8) 440 0xF0 => self.ldh_a_imm(bus), 441 // LD A, ($FF00+C) 442 0xF2 => self.ld_a_c_high_page(bus), 443 // DI 444 0xF3 => self.di(), 445 // OR A, u8 446 0xF6 => self.or_a_imm(bus), 447 // LD HL, SP+i8 448 0xF8 => self.ld_hl_sp_e(bus), 449 // LD SP, HL 450 0xF9 => self.ld_sp_hl(bus), 451 // LD A, (u16) 452 0xFA => self.ld_a_indirect(bus), 453 // EI 454 0xFB => self.ei(), 455 // CP A, u8 456 0xFE => self.cp_a_imm(bus), 457 // Invalid opcodes; executing one of these causes the CPU to lock up 458 0xD3 | 0xDB | 0xDD | 0xE3 | 0xE4 | 0xEB | 0xEC | 0xED | 0xF4 | 0xFC | 0xFD => { 459 log::error!( 460 "SM83 executed invalid opcode ${opcode:02X} at address ${:04X}; CPU is now frozen", 461 self.registers.pc.wrapping_sub(1) 462 ); 463 self.state.executed_invalid_opcode = true; 464 } 465 } 466 } 467 468 fn execute_cb_prefix_opcode<B: BusInterface>(&mut self, bus: &mut B) { 469 let opcode = self.fetch_operand(bus); 470 471 log::trace!( 472 " CB prefix opcode: {opcode:02X} ({})", 473 disassemble::cb_instruction_str(opcode) 474 ); 475 476 match opcode { 477 // RLC r / RLC (HL) 478 0x00..=0x07 => self.rlc_r(bus, opcode), 479 // RRC r / RRC (HL) 480 0x08..=0x0F => self.rrc_r(bus, opcode), 481 // RL r / RL (HL) 482 0x10..=0x17 => self.rl_r(bus, opcode), 483 // RR r / RR (HL) 484 0x18..=0x1F => self.rr_r(bus, opcode), 485 // SLA r / SLA (HL) 486 0x20..=0x27 => self.sla(bus, opcode), 487 // SRA r / SRA (HL) 488 0x28..=0x2F => self.sra(bus, opcode), 489 // SWAP r / SWAP (HL) 490 0x30..=0x37 => self.swap(bus, opcode), 491 // SRL r / SRL (HL) 492 0x38..=0x3F => self.srl(bus, opcode), 493 // BIT n, r / BIT n, (HL) 494 0x40..=0x7F => self.bit(bus, opcode), 495 // RES n, r / RES n, (HL) 496 0x80..=0xBF => self.res(bus, opcode), 497 // SET n, r / SET n, (HL) 498 0xC0..=0xFF => self.set(bus, opcode), 499 } 500 } 501 502 fn execute_interrupt_service_routine<B: BusInterface>(&mut self, bus: &mut B) { 503 // The CPU idles for 2 M-cycles at the start of the interrupt service routine 504 bus.idle(); 505 bus.idle(); 506 507 let [pc_lsb, pc_msb] = self.registers.pc.to_le_bytes(); 508 509 self.push_stack(bus, pc_msb); 510 511 // The IE register gets read in between the MSB push and LSB push, as verified on hardware by the ie_push test 512 // ROM in mooneye-test-suite. 513 // This matters for the (contrived) case where one of the two stack pushes will write to the IE register 514 let ie_register = bus.read_ie_register(); 515 self.push_stack(bus, pc_lsb); 516 517 // Take the last idle cycle before reading IF; this *seems* to fix Pinball Deluxe 518 bus.idle(); 519 520 let if_register = bus.read_if_register(); 521 self.registers.ime = false; 522 self.state.pending_ime_set = false; 523 524 let Some(interrupt_type) = InterruptType::from_bits(ie_register & if_register) else { 525 // IE & IF can equal 0 if one of the stack pushes wrote to IE and cleared bits that were previously set. 526 // In this case PC is set to $0000, as verified on hardware by the ie_push test ROM in mooneye-test-suite 527 self.registers.pc = 0x0000; 528 return; 529 }; 530 bus.acknowledge_interrupt(interrupt_type); 531 532 self.registers.pc = interrupt_type.interrupt_vector(); 533 534 log::trace!("Handling interrupt of type {interrupt_type:?}"); 535 } 536 537 fn fetch_operand<B: BusInterface>(&mut self, bus: &mut B) -> u8 { 538 let operand = bus.read(self.registers.pc); 539 if self.state.halt_bug_triggered { 540 // If the HALT bug just triggered, don't increment PC for this opcode fetch 541 // The Smurfs (SGB) depends on this to boot 542 self.state.halt_bug_triggered = false; 543 } else { 544 self.registers.pc = self.registers.pc.wrapping_add(1); 545 } 546 547 log::trace!(" Fetched operand {operand:02X}"); 548 549 operand 550 } 551 552 fn fetch_operand_u16<B: BusInterface>(&mut self, bus: &mut B) -> u16 { 553 let operand_lsb = self.fetch_operand(bus); 554 let operand_msb = self.fetch_operand(bus); 555 u16::from_le_bytes([operand_lsb, operand_msb]) 556 } 557 558 fn push_stack<B: BusInterface>(&mut self, bus: &mut B, value: u8) { 559 self.registers.sp = self.registers.sp.wrapping_sub(1); 560 bus.write(self.registers.sp, value); 561 } 562 563 fn push_stack_u16<B: BusInterface>(&mut self, bus: &mut B, value: u16) { 564 let [value_lsb, value_msb] = value.to_le_bytes(); 565 self.push_stack(bus, value_msb); 566 self.push_stack(bus, value_lsb); 567 } 568 569 fn pop_stack<B: BusInterface>(&mut self, bus: &mut B) -> u8 { 570 let value = bus.read(self.registers.sp); 571 self.registers.sp = self.registers.sp.wrapping_add(1); 572 value 573 } 574 575 fn pop_stack_u16<B: BusInterface>(&mut self, bus: &mut B) -> u16 { 576 let lsb = self.pop_stack(bus); 577 let msb = self.pop_stack(bus); 578 u16::from_le_bytes([lsb, msb]) 579 } 580 581 fn poll_for_interrupts<B: BusInterface>(&mut self, bus: &mut B) { 582 self.state.handling_interrupt = self.registers.ime && bus.interrupt_pending(); 583 } 584 585 fn read_register<B: BusInterface>(&self, bus: &mut B, register_bits: u8) -> u8 { 586 match register_bits & 0x7 { 587 0x0 => self.registers.b, 588 0x1 => self.registers.c, 589 0x2 => self.registers.d, 590 0x3 => self.registers.e, 591 0x4 => self.registers.h, 592 0x5 => self.registers.l, 593 // Indirect HL 594 0x6 => bus.read(self.registers.hl()), 595 0x7 => self.registers.a, 596 _ => unreachable!("value & 0x7 is always <= 0x7"), 597 } 598 } 599 600 fn write_register<B: BusInterface>(&mut self, bus: &mut B, register_bits: u8, value: u8) { 601 match register_bits & 0x7 { 602 0x0 => self.registers.b = value, 603 0x1 => self.registers.c = value, 604 0x2 => self.registers.d = value, 605 0x3 => self.registers.e = value, 606 0x4 => self.registers.h = value, 607 0x5 => self.registers.l = value, 608 // Indirect HL 609 0x6 => bus.write(self.registers.hl(), value), 610 0x7 => self.registers.a = value, 611 _ => unreachable!("value & 0x7 is always <= 0x7"), 612 } 613 } 614}