diff --git a/rustboyadvance-core/src/gpu/mod.rs b/rustboyadvance-core/src/gpu/mod.rs index 65fa079..fbd4b1c 100644 --- a/rustboyadvance-core/src/gpu/mod.rs +++ b/rustboyadvance-core/src/gpu/mod.rs @@ -5,9 +5,10 @@ use std::rc::Rc; use serde::{Deserialize, Serialize}; use super::interrupt::IrqBitmask; +pub use super::sysbus::consts::*; use super::sysbus::{BoxedMemory, SysBus}; -use super::Bus; use super::VideoInterface; +use super::{Addr, Bus}; use crate::bitfield::Bit; use crate::num::FromPrimitive; @@ -30,11 +31,11 @@ pub use regs::*; #[allow(unused)] pub mod consts { + pub use super::VRAM_ADDR; pub const VIDEO_RAM_SIZE: usize = 128 * 1024; pub const PALETTE_RAM_SIZE: usize = 1 * 1024; pub const OAM_SIZE: usize = 1 * 1024; - pub const VRAM_ADDR: u32 = 0x0600_0000; pub const DISPLAY_WIDTH: usize = 240; pub const DISPLAY_HEIGHT: usize = 160; pub const VBLANK_LINES: usize = 68; @@ -203,6 +204,68 @@ pub struct Gpu { pub(super) frame_buffer: Vec, } +impl Bus for Gpu { + fn read_8(&self, addr: Addr) -> u8 { + let page = (addr >> 24) as usize; + match page { + PAGE_PALRAM => self.palette_ram.read_8(addr & 0x3ff), + PAGE_VRAM => { + // complicated + let mut ofs = addr & ((VIDEO_RAM_SIZE as u32) - 1); + if ofs > 0x18000 { + ofs -= 0x8000; + } + self.vram.read_8(ofs) + } + PAGE_OAM => self.oam.read_8(addr & 0x3ff), + _ => unreachable!(), + } + } + + fn write_16(&mut self, addr: Addr, value: u16) { + let page = (addr >> 24) as usize; + match page { + PAGE_PALRAM => self.palette_ram.write_16(addr & 0x3fe, value), + PAGE_VRAM => { + let mut ofs = addr & ((VIDEO_RAM_SIZE as u32) - 1); + if ofs > 0x18000 { + ofs -= 0x8000; + } + self.vram.write_16(ofs, value) + } + PAGE_OAM => self.oam.write_16(addr & 0x3fe, value), + _ => unreachable!(), + } + } + + fn write_8(&mut self, addr: Addr, value: u8) { + fn expand_value(value: u8) -> u16 { + (value as u16) * 0x101 + } + + let page = (addr >> 24) as usize; + match page { + PAGE_PALRAM => self.oam.write_16(addr & 0x3fe, expand_value(value)), + PAGE_VRAM => { + let mut ofs = addr & ((VIDEO_RAM_SIZE as u32) - 1); + if ofs > 0x18000 { + ofs -= 0x8000; + } + let obj_offset = if self.dispcnt.mode() >= 3 { + 0x14000 + } else { + 0x10000 + }; + if ofs < obj_offset { + self.vram.write_16(ofs & !1, expand_value(value)); + } + } + PAGE_OAM => { /* OAM can't be written with 8bit store */ } + _ => unreachable!(), + }; + } +} + impl Gpu { pub fn new() -> Gpu { Gpu { diff --git a/rustboyadvance-core/src/sysbus.rs b/rustboyadvance-core/src/sysbus.rs index bbeb49a..c22056e 100644 --- a/rustboyadvance-core/src/sysbus.rs +++ b/rustboyadvance-core/src/sysbus.rs @@ -255,15 +255,7 @@ macro_rules! memory_map { }; $sb.io.$read_fn(addr) } - PALRAM_ADDR => $sb.io.gpu.palette_ram.$read_fn($addr & 0x3ff), - VRAM_ADDR => { - let mut ofs = $addr & ((VIDEO_RAM_SIZE as u32) - 1); - if ofs > 0x18000 { - ofs -= 0x8000; - } - $sb.io.gpu.vram.$read_fn(ofs) - } - OAM_ADDR => $sb.io.gpu.oam.$read_fn($addr & 0x3ff), + PALRAM_ADDR | VRAM_ADDR | OAM_ADDR => $sb.io.gpu.$read_fn($addr), GAMEPAK_WS0_LO | GAMEPAK_WS0_HI | GAMEPAK_WS1_LO | GAMEPAK_WS1_HI | GAMEPAK_WS2_LO => { $sb.cartridge.$read_fn($addr) } @@ -289,15 +281,7 @@ macro_rules! memory_map { }; $sb.io.$write_fn(addr, $value) } - PALRAM_ADDR => $sb.io.gpu.palette_ram.$write_fn($addr & 0x3ff, $value), - VRAM_ADDR => { - let mut ofs = $addr & ((VIDEO_RAM_SIZE as u32) - 1); - if ofs > 0x18000 { - ofs -= 0x8000; - } - $sb.io.gpu.vram.$write_fn(ofs, $value) - } - OAM_ADDR => $sb.io.gpu.oam.$write_fn($addr & 0x3ff, $value), + PALRAM_ADDR | VRAM_ADDR | OAM_ADDR => $sb.io.gpu.$write_fn($addr, $value), GAMEPAK_WS0_LO | GAMEPAK_WS0_HI => {} GAMEPAK_WS2_HI => $sb.cartridge.$write_fn($addr, $value), SRAM_LO | SRAM_HI => $sb.cartridge.$write_fn($addr, $value),