From eb1016cd25db5ed2fe9f4200876ddd89f5c5f9b4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com>
Date: Sat, 2 Jul 2022 14:05:54 +0100
Subject: [PATCH] feat: more PPU support added

---
 src/cpu.rs  | 10 +++++++
 src/inst.rs | 13 +++++++--
 src/mmu.rs  |  4 +--
 src/ppu.rs  | 83 ++++++++++++++++++++++++++++++++++++++++++-----------
 4 files changed, 89 insertions(+), 21 deletions(-)

diff --git a/src/cpu.rs b/src/cpu.rs
index ff2f4c52..04cd30ec 100644
--- a/src/cpu.rs
+++ b/src/cpu.rs
@@ -244,4 +244,14 @@ impl Cpu {
     pub fn set_carry(&mut self, value: bool) {
         self.carry = value;
     }
+
+    #[inline(always)]
+    pub fn enable_int(&mut self) {
+        // @todo implement this one
+    }
+
+    #[inline(always)]
+    pub fn disable_int(&mut self) {
+        // @todo implement this one
+    }
 }
diff --git a/src/inst.rs b/src/inst.rs
index 8ff0b303..314afe79 100644
--- a/src/inst.rs
+++ b/src/inst.rs
@@ -59,7 +59,7 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
-    (noimpl, 4, "! UNIMP !"),
+    (ld_mhl_u8, 12, "LD [HL], u8 "),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
@@ -260,7 +260,7 @@ pub const INSTRUCTIONS: [(fn(&mut Cpu), u8, &'static str); 256] = [
     (ld_a_mff00u8, 12, "LD A, [FF00+u8]"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
-    (noimpl, 4, "! UNIMP !"),
+    (di, 4, "DI"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
     (noimpl, 4, "! UNIMP !"),
@@ -681,6 +681,11 @@ fn ld_mhld_a(cpu: &mut Cpu) {
     cpu.set_hl(cpu.hl().wrapping_sub(1));
 }
 
+fn ld_mhl_u8(cpu: &mut Cpu) {
+    let byte = cpu.read_u8();
+    cpu.mmu.write(cpu.hl(), byte);
+}
+
 fn dec_a(cpu: &mut Cpu) {
     let a = cpu.a;
     let value = a.wrapping_sub(1);
@@ -808,6 +813,10 @@ fn ld_a_mff00u8(cpu: &mut Cpu) {
     cpu.a = cpu.mmu.read(0xff00 + byte as u16);
 }
 
+fn di(cpu: &mut Cpu) {
+    cpu.disable_int();
+}
+
 fn cp_a_u8(cpu: &mut Cpu) {
     let byte = cpu.read_u8();
     sub_set_flags(cpu, cpu.a, byte);
diff --git a/src/mmu.rs b/src/mmu.rs
index 06a10491..a840ad23 100644
--- a/src/mmu.rs
+++ b/src/mmu.rs
@@ -64,7 +64,7 @@ impl Mmu {
                 0x000 | 0x100 | 0x200 | 0x300 | 0x400 | 0x500 | 0x600 | 0x700 | 0x800 | 0x900
                 | 0xa00 | 0xb00 | 0xc00 | 0xd00 => self.ram[(addr & 0x1fff) as usize],
                 0xe00 => {
-                    println!("READING FROM GPU OAM - NOT IMPLEMENTED");
+                    println!("READING FROM PPU OAM - NOT IMPLEMENTED");
                     0x00
                 }
                 0xf00 => {
@@ -126,7 +126,7 @@ impl Mmu {
                     self.ram[(addr & 0x1fff) as usize] = value;
                 }
                 0xe00 => {
-                    println!("WRITING TO GPU OAM");
+                    println!("WRITING TO PPU OAM");
                 }
                 0xf00 => {
                     if addr >= 0xff80 {
diff --git a/src/ppu.rs b/src/ppu.rs
index 0b321b17..f83abba0 100644
--- a/src/ppu.rs
+++ b/src/ppu.rs
@@ -32,7 +32,7 @@ pub struct Ppu {
     /// processed set of pixels ready to be displayed on screen.
     pub frame_buffer: Box<[u8; FRAME_BUFFER_SIZE]>,
     /// Video dedicated memory (VRAM) where both the tiles and
-    /// the sprites are going to be stored.
+    /// the sprites/objects are going to be stored.
     pub vram: [u8; VRAM_SIZE],
     /// High RAM memory that should provide extra speed for regular
     /// operations.
@@ -40,8 +40,13 @@ pub struct Ppu {
     /// The current set of processed tiles that are store in the
     /// PPU related structures.
     tiles: [[[u8; 8]; 8]; TILE_COUNT],
-    /// The palette of colors that is currently loaded in Game Boy.
+    /// The palette of colors that is currently loaded in Game Boy
+    /// and used for background (tiles).
     palette: [[u8; RGB_SIZE]; PALETTE_SIZE],
+    // The palette that is going to be used for sprites/objects #0.
+    palette_obj_0: [[u8; RGB_SIZE]; PALETTE_SIZE],
+    // The palette that is going to be used for sprites/objects #1.
+    palette_obj_1: [[u8; RGB_SIZE]; PALETTE_SIZE],
     /// The scroll Y register that controls the Y offset
     /// of the background.
     scy: u8,
@@ -52,10 +57,16 @@ pub struct Ppu {
     /// range between 0 (0x00) and 153 (0x99), representing
     /// the 154 lines plus 10 extra v-blank lines.
     line: u8,
+    /// The current execution mode of the PPU, should change
+    /// between states over the drawing of a frame.
+    mode: PpuMode,
+    /// Internal clock counter used to control the time in ticks
+    /// spent in each of the PPU modes.
+    mode_clock: u16,
     /// Controls if the background is going to be drawn to screen.
     switch_bg: bool,
-    /// Controls if the sprites are going to be drawn to screen.
-    switch_sprites: bool,
+    /// Controls if the sprites/objects are going to be drawn to screen.
+    switch_obj: bool,
     /// Controls the map that is going to be drawn to screen, the
     /// offset in VRAM will be adjusted according to this.
     bg_map: bool,
@@ -65,12 +76,10 @@ pub struct Ppu {
     /// Flag that controls if the LCD screen is ON and displaying
     /// content.
     switch_lcd: bool,
-    /// The current execution mode of the PPU, should change
-    /// between states over the drawing of a frame.
-    mode: PpuMode,
-    /// Internal clock counter used to control the time in ticks
-    /// spent in each of the PPU modes.
-    mode_clock: u16,
+    stat_hblank: bool,
+    stat_vblank: bool,
+    stat_oam: bool,
+    stat_lyc: bool,
 }
 
 pub enum PpuMode {
@@ -88,16 +97,22 @@ impl Ppu {
             hram: [0u8; HRAM_SIZE],
             tiles: [[[0u8; 8]; 8]; TILE_COUNT],
             palette: [[0u8; RGB_SIZE]; PALETTE_SIZE],
+            palette_obj_0: [[0u8; RGB_SIZE]; PALETTE_SIZE],
+            palette_obj_1: [[0u8; RGB_SIZE]; PALETTE_SIZE],
             scy: 0x0,
             scx: 0x0,
             line: 0x0,
+            mode: PpuMode::OamRead,
+            mode_clock: 0,
             switch_bg: false,
-            switch_sprites: false,
+            switch_obj: false,
             bg_map: false,
             bg_tile: false,
             switch_lcd: false,
-            mode: PpuMode::OamRead,
-            mode_clock: 0,
+            stat_hblank: false,
+            stat_vblank: false,
+            stat_oam: false,
+            stat_lyc: false,
         }
     }
 
@@ -105,7 +120,7 @@ impl Ppu {
         self.mode_clock += cycles as u16;
         match self.mode {
             PpuMode::OamRead => {
-                if self.mode_clock >= 204 {
+                if self.mode_clock >= 80 {
                     self.mode_clock = 0;
                     self.mode = PpuMode::VramRead;
                 }
@@ -157,12 +172,19 @@ impl Ppu {
         match addr & 0x00ff {
             0x0040 => {
                 let value = if self.switch_bg { 0x01 } else { 0x00 }
-                    | if self.switch_sprites { 0x02 } else { 0x00 }
+                    | if self.switch_obj { 0x02 } else { 0x00 }
                     | if self.bg_map { 0x08 } else { 0x00 }
                     | if self.bg_tile { 0x10 } else { 0x00 }
                     | if self.switch_lcd { 0x80 } else { 0x00 };
                 value
             }
+            0x0041 => {
+                let value = if self.stat_hblank { 0x04 } else { 0x00 }
+                    | if self.stat_vblank { 0x08 } else { 0x00 }
+                    | if self.stat_oam { 0x10 } else { 0x00 }
+                    | if self.stat_lyc { 0x20 } else { 0x00 };
+                value
+            }
             0x0042 => self.scy,
             0x0043 => self.scx,
             0x0044 => self.line,
@@ -174,11 +196,17 @@ impl Ppu {
         match addr & 0x00ff {
             0x0040 => {
                 self.switch_bg = value & 0x01 == 0x01;
-                self.switch_sprites = value & 0x02 == 0x02;
+                self.switch_obj = value & 0x02 == 0x02;
                 self.bg_map = value & 0x08 == 0x08;
                 self.bg_tile = value & 0x10 == 0x10;
                 self.switch_lcd = value & 0x80 == 0x80;
             }
+            0x0041 => {
+                self.stat_hblank = value & 0x04 == 0x04;
+                self.stat_vblank = value & 0x08 == 0x08;
+                self.stat_oam = value & 0x10 == 0x10;
+                self.stat_lyc = value & 0x20 == 0x20;
+            }
             0x0042 => self.scy = value,
             0x0043 => self.scx = value,
             0x0047 => {
@@ -192,6 +220,28 @@ impl Ppu {
                     }
                 }
             }
+            0x0048 => {
+                for index in 0..PALETTE_SIZE {
+                    match (value >> (index * 2)) & 3 {
+                        0 => self.palette_obj_0[index] = [255, 255, 255],
+                        1 => self.palette_obj_0[index] = [192, 192, 192],
+                        2 => self.palette_obj_0[index] = [96, 96, 96],
+                        3 => self.palette_obj_0[index] = [0, 0, 0],
+                        color_index => panic!("Invalid palette color index {:04x}", color_index),
+                    }
+                }
+            }
+            0x0049 => {
+                for index in 0..PALETTE_SIZE {
+                    match (value >> (index * 2)) & 3 {
+                        0 => self.palette_obj_1[index] = [255, 255, 255],
+                        1 => self.palette_obj_1[index] = [192, 192, 192],
+                        2 => self.palette_obj_1[index] = [96, 96, 96],
+                        3 => self.palette_obj_1[index] = [0, 0, 0],
+                        color_index => panic!("Invalid palette color index {:04x}", color_index),
+                    }
+                }
+            }
             addr => panic!("Writing in unknown PPU location 0x{:04x}", addr),
         }
     }
@@ -246,7 +296,6 @@ impl Ppu {
         // Game Boy screen width and RGB pixel (3 bytes) size
         let mut frame_offset = self.line as usize * DISPLAY_WIDTH * RGB_SIZE;
 
-
         for _index in 0..DISPLAY_WIDTH {
             // obtains the current pixel data from the tile and
             // re-maps it according to the current palette
-- 
GitLab