From c9d0c501ca55c734675c85903d7210129cf55ae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com> Date: Sun, 30 Apr 2023 20:08:43 +0100 Subject: [PATCH] fix: object tile usage Allows usage of tiles from multiple VRAM banks. --- src/mmu.rs | 17 ++++++++++++++++- src/ppu.rs | 31 +++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/mmu.rs b/src/mmu.rs index b1967f33..7418189c 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -22,6 +22,13 @@ pub struct Mmu { /// to be enabled and should be triggered. pub ie: u8, + /// Register that controls the compatibility mode in use, this + /// value comes directly from 0x0143 (CGB flag). The possible (and + /// valid) values are: 0x80 for games that support CGB enhancements + /// and 0xC0 for games that are compatible only with a CGB device + /// (CGB only). + pub key0: u8, + /// Reference to the PPU (Pixel Processing Unit) that is going /// to be used both for VRAM reading/writing and to forward /// some of the access operations. @@ -102,6 +109,7 @@ impl Mmu { ram_bank: 0x1, ram_offset: 0x1000, ie: 0x0, + key0: 0x0, mode, gbc, } @@ -115,6 +123,7 @@ impl Mmu { self.ram_bank = 0x1; self.ram_offset = 0x1000; self.ie = 0x0; + self.key0 = 0x0; } pub fn allocate_default(&mut self) { @@ -241,7 +250,7 @@ impl Mmu { } // 0xFF4C - KEY0 (CGB only) - 0x4c => todo!("Need to see what to do with KEY0"), + 0x4c => self.key0, // 0xFF4D - KEY1 (CGB only) 0x4d => todo!("CGB speed switch"), @@ -329,6 +338,12 @@ impl Mmu { self.pad.set_int_pad(value & 0x10 == 0x10); } + // 0xFF4C - KEY0 (CGB only) + 0x4c => self.key0 = value, + + // 0xFF4D - KEY1 (CGB only) + 0x4d => todo!("CGB speed switch WRITE"), + // 0xFF50 - Boot active flag 0x50 => self.boot_active = false, diff --git a/src/ppu.rs b/src/ppu.rs index 5787ee71..aca5adbb 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -782,10 +782,10 @@ impl Ppu { } // 0xFF6B — OCPD/OBPD (CGB only) 0xff6b => { - let palette_index = self.palette_address_bg / 8; + let palette_index = self.palette_address_obj / 8; let palette_color = &mut self.palettes_color[1]; - palette_color[self.palette_address_bg as usize] = value; + palette_color[self.palette_address_obj as usize] = value; let palette = &mut self.palettes_color_obj[palette_index as usize]; Self::compute_palette_color(palette, palette_color, palette_index); @@ -910,7 +910,7 @@ impl Ppu { /// with tiles. fn update_tile(&mut self, addr: u16, _value: u8) { let addr = (self.vram_offset + (addr & 0x1ffe)) as usize; - let tile_index = (addr >> 4) & 0x01ff; + let tile_index = ((addr >> 4) & 0x01ff) + (self.vram_bank as usize * TILE_COUNT_DMG); let tile = self.tiles[tile_index].borrow_mut(); let y = (addr >> 1) & 0x0007; @@ -966,8 +966,7 @@ impl Ppu { }; let tile_data: &mut TileData = bg_map_attrs[tile_index as usize].borrow_mut(); tile_data.palette = value & 0x07; - tile_data.vram_bank = (value & 0x08) >> 4; - tile_data.vram_bank = (value & 0x08) >> 4; + tile_data.vram_bank = (value & 0x08 == 0x08) as u8; tile_data.xflip = value & 0x20 == 0x20; tile_data.yflip = value & 0x40 == 0x40; tile_data.priority = value & 0x80 == 0x80; @@ -1052,6 +1051,10 @@ impl Ppu { &self.palette_bg }; + // increments the tile index value by the required offset for the VRAM + // bank in which the tile is stored, this is only required for CGB mode + tile_index += tile_attr.vram_bank as usize * TILE_COUNT_DMG; + // calculates the offset that is going to be used in the update of the color buffer // which stores Game Boy colors from 0 to 3 let mut color_offset = self.ly as usize * DISPLAY_WIDTH; @@ -1116,6 +1119,10 @@ impl Ppu { } else { &self.palette_bg }; + + // increments the tile index value by the required offset for the VRAM + // bank in which the tile is stored, this is only required for CGB mode + tile_index += tile_attr.vram_bank as usize * TILE_COUNT_DMG; } } @@ -1199,22 +1206,30 @@ impl Ppu { // is going to be used in the current operation let tile: &Tile; + // "calculates" the index offset that is going to be applied + // to the tile index to retrieve the proper tile taking into + // consideration the VRAM in which the tile is stored + let tile_bank_offset = obj.tile_bank as usize * TILE_COUNT_DMG; + // in case we're facing a 8x16 object then we must // differentiate between the handling of the top tile // and the bottom tile through bitwise manipulation // of the tile index if self.obj_size { if tile_offset < 8 { - tile = &self.tiles[obj.tile as usize & 0xfe]; + let tile_index = (obj.tile as usize & 0xfe) + tile_bank_offset; + tile = &self.tiles[tile_index]; } else { - tile = &self.tiles[obj.tile as usize | 0x01]; + let tile_index = (obj.tile as usize | 0x01) + tile_bank_offset; + tile = &self.tiles[tile_index]; tile_offset -= 8; } } // otherwise we're facing a 8x8 sprite and we should grab // the tile directly from the object's tile index else { - tile = &self.tiles[obj.tile as usize]; + let tile_index = obj.tile as usize + tile_bank_offset; + tile = &self.tiles[tile_index as usize]; } let tile_row = tile.get_row(tile_offset as usize); -- GitLab