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