sm83.rsannotatedsm83.rssource614 lines · 19.7 KB · raw

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

6mod arithmetic;
7mod bits;
8pub mod bus;
9mod disassemble;
10mod flags;
11mod flow;
12mod load;
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}