From 9386638f60b9381d1a21bb4b3332bade3db88909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com> Date: Sat, 29 Apr 2023 16:41:24 +0100 Subject: [PATCH] chore: initial support for multiple vram banks --- src/mmu.rs | 5 ++++- src/ppu.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/src/mmu.rs b/src/mmu.rs index 983dcbdd..54894f76 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -69,6 +69,9 @@ pub struct Mmu { /// the 0xD000-0xDFFF memory range (CGB only). ram_bank: u8, + /// The offset to be used in the read and write operation of + /// the RAM, this value should be consistent with the RAM bank + /// that is currently selected (CGB only). ram_offset: u16, mode: GameBoyMode, @@ -323,7 +326,7 @@ impl Mmu { // 0xFF70 - SVBK: WRAM bank (CGB only) 0x70 => { - let mut ram_bank = value & 0x7; + let mut ram_bank = value & 0x07; if ram_bank == 0x0 { ram_bank = 0x1; } diff --git a/src/ppu.rs b/src/ppu.rs index fbd91fe1..35c3d2cd 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -9,7 +9,9 @@ use wasm_bindgen::prelude::*; use crate::warnln; -pub const VRAM_SIZE: usize = 8192; +pub const VRAM_SIZE_DMG: usize = 8192; +pub const VRAM_SIZE_CGB: usize = 16384; +pub const VRAM_SIZE: usize = VRAM_SIZE_CGB; pub const HRAM_SIZE: usize = 128; pub const OAM_SIZE: usize = 260; pub const PALETTE_SIZE: usize = 4; @@ -19,9 +21,12 @@ pub const TILE_WIDTH: usize = 8; pub const TILE_HEIGHT: usize = 8; pub const TILE_DOUBLE_HEIGHT: usize = 16; +pub const TILE_COUNT_DMG: usize = 384; +pub const TILE_COUNT_CGB: usize = 768; + /// The number of tiles that can be store in Game Boy's /// VRAM memory according to specifications. -pub const TILE_COUNT: usize = 384; +pub const TILE_COUNT: usize = TILE_COUNT_CGB; /// The number of objects/sprites that can be handled at /// the same time by the Game Boy. @@ -161,6 +166,26 @@ impl Display for ObjectData { } } +#[cfg_attr(feature = "wasm", wasm_bindgen)] +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct TileData { + palette: u8, + vram_bank: u8, + xflip: bool, + yflip: bool, + priority: bool, +} + +impl Display for TileData { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "Palette => {}\nVRAM Bank => {}\nX Flip => {}\nY Flip => {}", + self.palette, self.vram_bank, self.xflip, self.yflip + ) + } +} + pub struct PpuRegisters { pub scy: u8, pub scx: u8, @@ -203,6 +228,15 @@ pub struct Ppu { /// sprite attributes for each of the 40 sprites of the Game Boy. oam: [u8; OAM_SIZE], + /// The VRAM bank to be used in the read and write operation of + /// the 0x8000-0x9FFF memory range (CGB only). + vram_bank: u8, + + /// The offset to be used in the read and write operation of + /// the VRAM, this value should be consistent with the VRAM bank + /// that is currently selected (CGB only). + vram_offset: u16, + /// The current set of processed tiles that are store in the /// PPU related structures. tiles: [Tile; TILE_COUNT], @@ -366,6 +400,8 @@ impl Ppu { vram: [0u8; VRAM_SIZE], hram: [0u8; HRAM_SIZE], oam: [0u8; OAM_SIZE], + vram_bank: 0x0, + vram_offset: 0x0000, tiles: [Tile { buffer: [0u8; 64] }; TILE_COUNT], obj_data: [ObjectData { x: 0, @@ -420,8 +456,10 @@ impl Ppu { pub fn reset(&mut self) { self.color_buffer = Box::new([0u8; COLOR_BUFFER_SIZE]); self.frame_buffer = Box::new([0u8; FRAME_BUFFER_SIZE]); - self.vram = [0u8; VRAM_SIZE]; + self.vram = [0u8; VRAM_SIZE_CGB]; self.hram = [0u8; HRAM_SIZE]; + self.vram_bank = 0x0; + self.vram_offset = 0x0000; self.tiles = [Tile { buffer: [0u8; 64] }; TILE_COUNT]; self.palette = [[0u8; RGB_SIZE]; PALETTE_SIZE]; self.palette_obj_0 = [[0u8; RGB_SIZE]; PALETTE_SIZE]; @@ -544,7 +582,7 @@ impl Ppu { pub fn read(&mut self, addr: u16) -> u8 { match addr { - 0x8000..=0x9fff => self.vram[(addr & 0x1fff) as usize], + 0x8000..=0x9fff => self.vram[(self.vram_offset + (addr & 0x1fff)) as usize], 0xfe00..=0xfe9f => self.oam[(addr & 0x009f) as usize], 0xff80..=0xfffe => self.hram[(addr & 0x007f) as usize], 0xff40 => @@ -577,7 +615,7 @@ impl Ppu { 0xff4a => self.wy, 0xff4b => self.wx, // 0xFF4F — VBK (CGB only) - 0xff4f => 0xff, + 0xff4f => self.vram_bank | 0xfe, // 0xFF68 — BCPS/BGPI (CGB only) 0xff68 => self.palette_address_bg | if self.auto_increment_bg { 0x80 } else { 0x00 }, // 0xFF69 — BCPD/BGPD (CGB only) @@ -596,7 +634,7 @@ impl Ppu { pub fn write(&mut self, addr: u16, value: u8) { match addr { 0x8000..=0x9fff => { - self.vram[(addr & 0x1fff) as usize] = value; + self.vram[(self.vram_offset + (addr & 0x1fff)) as usize] = value; if addr < 0x9800 { self.update_tile(addr, value); } @@ -653,7 +691,10 @@ impl Ppu { 0xff4a => self.wy = value, 0xff4b => self.wx = value, // 0xFF4F — VBK (CGB only) - 0xff4f => (), + 0xff4f => { + self.vram_bank = value & 0x01; + self.vram_offset = self.vram_bank as u16 * 0x2000; + } // 0xFF68 — BCPS/BGPI (CGB only) 0xff68 => { self.palette_address_bg = value & 0x3f; @@ -786,7 +827,7 @@ impl Ppu { /// just been written to a location on the VRAM associated /// with tiles. fn update_tile(&mut self, addr: u16, _value: u8) { - let addr = (addr & 0x1ffe) as usize; + let addr = (self.vram_offset + (addr & 0x1ffe)) as usize; let tile_index = (addr >> 4) & 0x01ff; let tile = self.tiles[tile_index].borrow_mut(); let y = (addr >> 1) & 0x0007; -- GitLab