From 2a5d8b816caf9553b403fa183d91ad8d5ac23dcc Mon Sep 17 00:00:00 2001 From: Alex Janka Date: Thu, 20 Apr 2023 21:07:15 +1000 Subject: [PATCH] wow! ding! --- lib/src/processor/memory.rs | 32 +++++++++++++------ lib/src/processor/memory/addresses.rs | 4 +++ lib/src/processor/memory/mmio/gpu/cgb.rs | 39 +++++++++++++++++++++++- 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/lib/src/processor/memory.rs b/lib/src/processor/memory.rs index e5ce558..f4459e9 100644 --- a/lib/src/processor/memory.rs +++ b/lib/src/processor/memory.rs @@ -101,6 +101,7 @@ where serial: Serial, timers: Timer, camera: CameraWrapperRef, + is_cgb: bool, } #[serde_with::serde_as] @@ -124,6 +125,7 @@ where apu: ApuSaveState, serial: SerialSaveState, timers: Timer, + is_cgb: bool, } impl MemorySaveState @@ -147,6 +149,7 @@ where apu: ApuSaveState::create(&memory.apu), serial: SerialSaveState::create(&memory.serial), timers: memory.timers, + is_cgb: memory.is_cgb, } } } @@ -217,6 +220,7 @@ where serial: Serial::new(output.serial_target), timers: Timer::init(), camera: output.camera, + is_cgb: cgb, } } @@ -240,11 +244,19 @@ where Address::Rom(address) => { // rom access // todo - switchable rom banks - if let Some(bootrom) = &self.bootrom && (address.inner() as usize) < bootrom.len() { - bootrom[address.inner() as usize] - } else { - self.rom.get(address) + if let Some(bootrom) = &self.bootrom { + if self.is_cgb { + if address.inner() < 0x100 + || (address.inner() >= 0x200 + && ((address.inner()) as usize) < bootrom.len()) + { + return bootrom[address.inner() as usize]; + } + } else if (address.inner() as usize) < bootrom.len() { + return bootrom[address.inner() as usize]; + } } + self.rom.get(address) } Address::Vram(address) => self.gpu.get_vram(address), Address::CartRam(address) => self.rom.get_ram(address), @@ -344,7 +356,7 @@ where CgbIoAddress::VramDma(_) => todo!(), CgbIoAddress::Infrared => todo!(), CgbIoAddress::Palette(address) => self.gpu.get_cgb_palette(address), - CgbIoAddress::ObjPriority => todo!(), + CgbIoAddress::ObjPriority => self.gpu.get_obj_priority(), CgbIoAddress::WramBank => ((*selected) & 0b111) as u8, CgbIoAddress::Pcm12 => todo!(), CgbIoAddress::Pcm34 => todo!(), @@ -362,6 +374,7 @@ where } fn set_io(&mut self, address: IoAddress, data: u8) { + // println!("set 0x{:0>4X} to 0x{:0>2X}", address.inner(), data); match address { IoAddress::Joypad => self.joypad.mmio_write(data), IoAddress::Serial(address) => match address.inner() { @@ -404,7 +417,7 @@ where CgbIoAddress::VramDma(_) => todo!(), CgbIoAddress::Infrared => todo!(), CgbIoAddress::Palette(address) => self.gpu.set_cgb_palette(address, data), - CgbIoAddress::ObjPriority => todo!(), + CgbIoAddress::ObjPriority => self.gpu.set_obj_priority(data), CgbIoAddress::WramBank => *selected = (data & 0b111).max(1) as usize, CgbIoAddress::Pcm12 => todo!(), CgbIoAddress::Pcm34 => todo!(), @@ -485,6 +498,7 @@ where serial: Serial::from_save_state(state.serial, serial_target), timers: state.timers, camera, + is_cgb: state.is_cgb, } } } @@ -522,14 +536,14 @@ where let gpu_interrupts = self.memory.gpu.tick(steps); - self.memory - .interrupts - .set_interrupt(Interrupt::Vblank, gpu_interrupts.vblank); self.memory .interrupts .set_interrupt(Interrupt::LcdStat, gpu_interrupts.lcd_stat); if gpu_interrupts.vblank { + self.memory + .interrupts + .set_interrupt(Interrupt::Vblank, true); let latest_state = self.memory.gpu.window.latest_joypad_state(); let joypad_interrupt = self.memory.update_pressed_keys(latest_state); self.memory diff --git a/lib/src/processor/memory/addresses.rs b/lib/src/processor/memory/addresses.rs index 394076e..f6e0581 100644 --- a/lib/src/processor/memory/addresses.rs +++ b/lib/src/processor/memory/addresses.rs @@ -26,11 +26,13 @@ pub(crate) type VideoAddress = BoundedAddress<0xFF40, 0xFF4C>; pub(crate) type VramDmaAddress = BoundedAddress<0xFF51, 0xFF56>; pub(crate) type CgbPaletteAddress = BoundedAddress<0xFF68, 0xFF6C>; +#[derive(Clone, Copy)] pub(crate) enum RomAddress { Bank0(Bank0Address), MappedBank(MappedBankAddress), } +#[derive(Clone, Copy)] pub(crate) enum IoAddress { Joypad, Serial(SerialAddress), @@ -43,6 +45,7 @@ pub(crate) enum IoAddress { Unused(u16), } +#[derive(Clone, Copy)] pub(crate) enum CgbIoAddress { PrepareSpeed, VramBank, @@ -56,6 +59,7 @@ pub(crate) enum CgbIoAddress { Unused(u16), } +#[derive(Clone, Copy)] pub(crate) enum Address { Rom(RomAddress), Vram(VramAddress), diff --git a/lib/src/processor/memory/mmio/gpu/cgb.rs b/lib/src/processor/memory/mmio/gpu/cgb.rs index 2165b72..e4a819b 100644 --- a/lib/src/processor/memory/mmio/gpu/cgb.rs +++ b/lib/src/processor/memory/mmio/gpu/cgb.rs @@ -8,9 +8,25 @@ use crate::{ use super::{Colour, Gpu}; -#[derive(Serialize, Deserialize, Clone, Copy, Default)] +#[derive(Serialize, Deserialize, Clone, Copy)] pub(super) struct CgbData { palettes: CgbPaletteRegisters, + object_priority_mode: ObjectPriorityMode, +} + +impl Default for CgbData { + fn default() -> Self { + Self { + palettes: Default::default(), + object_priority_mode: ObjectPriorityMode::Coordinate, + } + } +} + +#[derive(Serialize, Deserialize, Clone, Copy)] +enum ObjectPriorityMode { + OamLocation = 0, + Coordinate = 1, } #[derive(Serialize, Deserialize, Clone, Copy, Default)] @@ -50,6 +66,9 @@ impl CgbPalette { fn set_data(&mut self, data: u8) { self.data[self.index as usize] = data; + if self.auto_increment { + self.index = (self.index + 1) & 0b111111 + } } fn get_data(&self) -> u8 { @@ -87,4 +106,22 @@ where } } } + + pub(crate) fn get_obj_priority(&self) -> u8 { + if let Some(cgb_data) = &self.cgb_data { + cgb_data.object_priority_mode as u8 + } else { + 0xFF + } + } + + pub(crate) fn set_obj_priority(&mut self, data: u8) { + if let Some(cgb_data) = &mut self.cgb_data { + cgb_data.object_priority_mode = if data & 0b1 == 0 { + ObjectPriorityMode::OamLocation + } else { + ObjectPriorityMode::Coordinate + } + } + } }