From 798d8601c742bb2b6def467b514c7952423cc3da Mon Sep 17 00:00:00 2001 From: Jonathan Balls Date: Thu, 12 Sep 2024 21:31:36 +0100 Subject: [PATCH] various instruction implementations and starting to implement stat interrupt --- src/cartridge/mbc1.rs | 1 + src/cpu/execution/alu.rs | 50 +++++++++++++++++++++++---------------- src/cpu/execution/bit.rs | 27 ++++++++++++++++++--- src/cpu/execution/load.rs | 18 ++++++++++++++ src/cpu/mod.rs | 15 ++++++++++++ src/mmu/mod.rs | 1 + src/mmu/ppu.rs | 41 ++++++++++++++++++++++++++++---- 7 files changed, 125 insertions(+), 28 deletions(-) diff --git a/src/cartridge/mbc1.rs b/src/cartridge/mbc1.rs index ad47ea1..3152c9f 100644 --- a/src/cartridge/mbc1.rs +++ b/src/cartridge/mbc1.rs @@ -43,6 +43,7 @@ impl MBC for MBC1 { match addr { 0x0..=0x1FFF => (), // enable ram in theory 0x2000..=0x3FFF => self.rom_bank = value & 0x1F, + 0x6000..=0x7FFF => (), // banking mode 0xA000..=0xBFFF => self.ram[addr as usize - 0xA000] = value, _ => { dbg!(addr); diff --git a/src/cpu/execution/alu.rs b/src/cpu/execution/alu.rs index 7eecd31..ff2a3cf 100644 --- a/src/cpu/execution/alu.rs +++ b/src/cpu/execution/alu.rs @@ -57,10 +57,10 @@ impl CPU { self.registers.set_r16(a, result); } - pub(in crate::cpu) fn inc(&mut self, memory: &mut MMU, a: R8) { - let value = self.get_r8_byte(memory, a); + pub(in crate::cpu) fn inc(&mut self, mmu: &mut MMU, a: R8) { + let value = self.get_r8_byte(mmu, a); let result = value.wrapping_add(1); - self.set_r8_byte(memory, a, result); + self.set_r8_byte(mmu, a, result); self.registers.f.zero = result == 0; self.registers.f.subtract = false; @@ -68,13 +68,13 @@ impl CPU { self.registers.f.half_carry = (value & 0xF) == 0xF; } - pub(in crate::cpu) fn dec(&mut self, mmu: &mut MMU, a: R8) { - let value = self.get_r8_byte(mmu, a); + pub(in crate::cpu) fn dec(&mut self, mmu: &mut MMU, r: R8) { + let value = self.get_r8_byte(mmu, r); let result = value.wrapping_sub(1); - self.set_r8_byte(mmu, a, result); + self.set_r8_byte(mmu, r, result); self.registers.f.zero = result == 0; - self.registers.f.subtract = false; + self.registers.f.subtract = true; // Half carry will occur when the lower nibble was 0b0000 self.registers.f.half_carry = (value & 0xF) == 0x0; } @@ -85,12 +85,12 @@ impl CPU { * */ pub(in crate::cpu) fn add(&mut self, b: u8) { - let result = self.registers.a.wrapping_add(b); + let (result, carry) = self.registers.a.overflowing_add(b); self.registers.f.zero = result == 0; self.registers.f.subtract = false; // Carry if a and b go over 0xFF - self.registers.f.carry = (self.registers.a as u16) + (b as u16) > 0xFF; + self.registers.f.carry = carry; // Half carry if the lower nibbles of a and b go over 0xF self.registers.f.half_carry = (self.registers.a & 0xF) + (b & 0xF) > 0xF; @@ -99,26 +99,25 @@ impl CPU { pub(in crate::cpu) fn add_r16(&mut self, a_reg: R16, b: u16) { let a = self.registers.get_r16(a_reg); - let result = a.wrapping_add(b); + let (result, carry) = a.overflowing_add(b); self.registers.f.half_carry = (a & 0x0FFF) + (b & 0x0FFF) > 0x0FFF; self.registers.f.subtract = false; - self.registers.f.carry = result < a; + self.registers.f.carry = carry; self.registers.set_r16(a_reg, result); } pub(in crate::cpu) fn adc(&mut self, value: u8) { - let result = self - .registers - .a - .wrapping_add(value) - .wrapping_add(self.registers.f.carry as u8); - self.registers.a = result; + let a = self.registers.a; + let c = self.registers.f.carry as u8; + let result = a.wrapping_add(value).wrapping_add(c); self.registers.f.zero = result == 0; - self.registers.f.carry = value > self.registers.a; - self.registers.f.half_carry = (value & 0x0F) == 0x0F; // Hmmmm... self.registers.f.subtract = false; + self.registers.f.half_carry = (a as u16 & 0xF) + (value as u16 & 0xF) + c as u16 > 0xF; + self.registers.f.carry = (a as u16) + (value as u16) + (c as u16) > 0xFF; + + self.registers.a = result; } pub(in crate::cpu) fn sub(&mut self, b: u8) { @@ -136,7 +135,16 @@ impl CPU { self.registers.f.carry = self.registers.a < b; } - pub(in crate::cpu) fn sbc(&mut self, b: u8) { - self.sub(b.wrapping_add(self.registers.f.carry as u8)); + pub(in crate::cpu) fn sbc(&mut self, value: u8) { + let a = self.registers.a; + let c = self.registers.f.carry as u8; + let result = a.wrapping_sub(value).wrapping_sub(c); + + self.registers.f.zero = result == 0; + self.registers.f.subtract = true; + self.registers.f.half_carry = (a & 0xF).wrapping_sub(value & 0xF).wrapping_sub(c) > 0xF; + self.registers.f.carry = (a as u16) < (value as u16) + (c as u16); + + self.registers.a = result; } } diff --git a/src/cpu/execution/bit.rs b/src/cpu/execution/bit.rs index bcc8b54..3b32e7e 100644 --- a/src/cpu/execution/bit.rs +++ b/src/cpu/execution/bit.rs @@ -65,7 +65,7 @@ impl CPU { } pub(in crate::cpu) fn sla(&mut self, mmu: &mut MMU, reg: R8) { - let value = self.get_r8_byte(mmu, R8::A); + let value = self.get_r8_byte(mmu, reg); let new_value = value << 1; self.set_r8_byte(mmu, reg, new_value); @@ -77,11 +77,11 @@ impl CPU { pub(in crate::cpu) fn rlca(&mut self) { let value = self.registers.a; - self.registers.f.carry = value >> 7 > 0; + self.registers.f.carry = value & 0x80 == 0x80; self.registers.f.zero = false; self.registers.f.half_carry = false; self.registers.f.subtract = false; - self.registers.a = (self.registers.a << 1) | (self.registers.a >> 7); + self.registers.a = (value << 1) | (value >> 7); } pub(in crate::cpu) fn cpl(&mut self) { @@ -113,6 +113,27 @@ impl CPU { self.set_r8_byte(mmu, r, result); } + pub(in crate::cpu) fn rra(&mut self, mmu: &mut MMU) { + self.rr(mmu, R8::A); + self.registers.f.zero = false; + } + + pub(in crate::cpu) fn rrc(&mut self, mmu: &mut MMU, r: R8) { + let value = self.get_r8_byte(mmu, r); + let result = value >> 1 | (value << 7); + self.registers.f.carry = value & 1 > 0; + self.registers.f.half_carry = false; + self.registers.f.subtract = false; + self.registers.f.zero = result == 0; + + self.set_r8_byte(mmu, r, result); + } + + pub(in crate::cpu) fn rrca(&mut self, mmu: &mut MMU) { + self.rrc(mmu, R8::A); + self.registers.f.zero = false; + } + pub(in crate::cpu) fn daa(&mut self) { let mut correction = 0; let mut set_carry = false; diff --git a/src/cpu/execution/load.rs b/src/cpu/execution/load.rs index 040c548..0ba7ce7 100644 --- a/src/cpu/execution/load.rs +++ b/src/cpu/execution/load.rs @@ -28,4 +28,22 @@ impl CPU { pub(in crate::cpu) fn ldh_addr(&mut self, mmu: &mut MMU, offset: u8, value: u8) { mmu.write_byte(0xFF00 + offset as u16, value) } + + pub(in crate::cpu) fn ld_hl_sp(&mut self, e8: u8) { + let sp = self.registers.sp; + let offset = e8 as i8 as i16 as u16; // Convert i8 to u16 via i16 to preserve sign + let result = sp.wrapping_add(offset); + + // Set flags based on the addition of the lower bytes + let half_carry = (sp & 0xF) + (offset & 0xF) > 0xF; + let carry = (sp & 0xFF) + (offset & 0xFF) > 0xFF; + + self.registers.set_r16(R16::HL, result); + + // Set flags + self.registers.f.zero = false; + self.registers.f.subtract = false; + self.registers.f.half_carry = half_carry; + self.registers.f.carry = carry; + } } diff --git a/src/cpu/mod.rs b/src/cpu/mod.rs index 37c231d..6a24eb7 100644 --- a/src/cpu/mod.rs +++ b/src/cpu/mod.rs @@ -44,6 +44,8 @@ impl CPU { Instruction::LdhImm8memA(offset) => self.ldh_addr(mmu, offset, self.registers.a), Instruction::LdhAImm8mem(addr) => self.lda(mmu.read_byte(0xFF00 + addr as u16)), Instruction::LdhACmem => self.lda(mmu.read_byte(0xFF00 + self.registers.c as u16)), + Instruction::LdHlSpImm8(n) => self.ld_hl_sp(n), + Instruction::LdSpHl => self.ld_r16(R16::SP, self.registers.get_r16(R16::HL)), // Arithmetic Instruction::IncR8(reg) => self.inc(mmu, reg), @@ -85,6 +87,9 @@ impl CPU { Instruction::SwapR8(reg) => self.swap(mmu, reg), Instruction::Scf => self.scf(), Instruction::RrR8(r) => self.rr(mmu, r), + Instruction::Rra => self.rra(mmu), + Instruction::Rrca => self.rrca(mmu), + Instruction::RrcR8(r) => self.rrc(mmu, r), // Jump instructions Instruction::JpImm16(addr) => self.jp(addr.wrapping_sub(length)), @@ -130,6 +135,7 @@ impl CPU { .yellow() ); enable_debug(); + dbg!(&instruction); dbg!(self.registers.pc); } }; @@ -157,6 +163,15 @@ impl CPU { self.registers.pc = 0x40; } + // stat + if mmu.ie & 2 > 0 && mmu.ppu.stat_irq { + //mmu.ppu.stat_irq = false; + //self.ime = false; + // + //self.push(mmu, return_pc); + //self.registers.pc = 0x48; + } + // timer if mmu.ie & 4 > 0 && mmu.timer.timer_irq { mmu.timer.timer_irq = false; diff --git a/src/mmu/mod.rs b/src/mmu/mod.rs index e5106af..02ba7a0 100644 --- a/src/mmu/mod.rs +++ b/src/mmu/mod.rs @@ -76,6 +76,7 @@ impl MMU { // VBlank interrupt 0xFF0F => { (self.ppu.vblank_irq as u8) + | ((self.ppu.stat_irq as u8) << 1) | ((self.timer.timer_irq as u8) << 2) | ((self.joypad.joypad_irq as u8) << 4) } diff --git a/src/mmu/ppu.rs b/src/mmu/ppu.rs index 90d5108..f7f3886 100644 --- a/src/mmu/ppu.rs +++ b/src/mmu/ppu.rs @@ -1,19 +1,22 @@ use std::{ - thread, + fmt, thread, time::{Duration, Instant}, }; +use crate::debugger::is_gameboy_doctor; + const VRAM_SIZE: usize = 0x2000; const VOAM_SIZE: usize = 0xA0; pub type Tile = [[u8; 8]; 8]; -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct PPU { frame_available: bool, frame_number: u32, last_frame_time: Instant, pub vblank_irq: bool, + pub stat_irq: bool, vram: [u8; VRAM_SIZE], voam: [u8; VOAM_SIZE], @@ -42,6 +45,7 @@ impl PPU { frame_number: 1, last_frame_time: Instant::now(), vblank_irq: false, + stat_irq: false, scy: 0, scx: 0, @@ -81,11 +85,15 @@ impl PPU { self.vblank_irq = true } + if self.ly == self.lyc && self.stat & 0x40 == 0x40 { + self.stat_irq = true; + } + // Frame finished - flush to screen if self.ly == 0 { // Calculate how long to sleep let elapsed = self.last_frame_time.elapsed(); - let frame_duration = Duration::from_secs_f64(1.0 / 240.0); + let frame_duration = Duration::from_secs_f64(1.0 / 60.0); if elapsed < frame_duration { thread::sleep(frame_duration - elapsed); @@ -110,7 +118,16 @@ impl PPU { 0xFF10..=0xFF3F => return 0, 0xFF40 => self.lcdc, - 0xFF41 => self.stat, + 0xFF41 => { + let mut ret = self.stat & 0xF8; + if self.ly == self.lyc { + ret |= 0x4; + } + + // just put it into mode 3... + + return ret; + } 0xFF42 => self.scy, 0xFF43 => self.scx, 0xFF44 => { @@ -219,3 +236,19 @@ impl PPU { ret } } + +impl fmt::Debug for PPU { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("PPU") + .field("scy", &self.scy) + .field("scx", &self.scx) + .field("ly", &self.ly) + .field("lyc", &self.lyc) + .field("wy", &self.wy) + .field("wx", &self.wx) + .field("lcdc", &self.lcdc) + .field("bgp", &self.bgp) + .field("modeclock", &self.modeclock) + .finish() + } +}