From abdff1251eec5d365635ecca7ac2fd301ed8605f Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Wed, 5 May 2021 08:29:39 -0500 Subject: [PATCH] fix: properly implement LY==LYC behaviour --- src/bus.rs | 13 ++++++++----- src/ppu.rs | 28 +++++++++++++++++----------- src/ppu/registers.rs | 16 ++++++++++------ 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/bus.rs b/src/bus.rs index b4d163d..4ef1851 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -245,7 +245,7 @@ impl Bus { 0xFF00 => self.joypad.status.update(byte), 0xFF01 => self.serial.next = byte, 0xFF02 => self.serial.control = byte.into(), - 0xFF04 => self.timer.divider = 0x00, + 0xFF04 => self.timer.divider = 0x0000, 0xFF05 => self.timer.counter = byte, 0xFF06 => self.timer.modulo = byte, 0xFF07 => self.timer.control = byte.into(), @@ -258,7 +258,7 @@ impl Bus { 0xFF25 => self.sound.control.output = byte.into(), 0xFF26 => self.sound.control.status = byte.into(), // FIXME: Should we control which bytes are written to here? 0xFF40 => self.ppu.control = byte.into(), - 0xFF41 => self.ppu.stat = byte.into(), + 0xFF41 => self.ppu.stat.update(byte), 0xFF42 => self.ppu.pos.scroll_y = byte, 0xFF43 => self.ppu.pos.scroll_x = byte, 0xFF44 => self.ppu.pos.line_y = byte, @@ -267,9 +267,12 @@ impl Bus { self.ppu.pos.ly_compare = byte; // Update Coincidence Flag - if self.ppu.stat.coincidence_int() { - let are_equal = self.ppu.pos.line_y == byte; - self.ppu.stat.set_coincidence(are_equal); + let are_equal = self.ppu.pos.line_y == byte; + self.ppu.stat.set_coincidence(are_equal); + + // If enabled, request a LCD STAT interrupt + if self.ppu.stat.coincidence_int() && are_equal { + self.ppu.int.set_lcd_stat(true); } } 0xFF47 => self.ppu.monochrome.bg_palette = byte.into(), diff --git a/src/ppu.rs b/src/ppu.rs index 3c0932e..f5c3e9a 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -103,10 +103,13 @@ impl Ppu { self.cycles %= 456; self.pos.line_y += 1; - // New Scanline is next, check for LYC=LY - if self.stat.coincidence_int() { - let are_equal = self.pos.line_y == self.pos.ly_compare; - self.stat.set_coincidence(are_equal); + // Update LY==LYC bit + let are_equal = self.pos.line_y == self.pos.ly_compare; + self.stat.set_coincidence(are_equal); + + // Request LCD STAT interrupt if conditions met + if self.stat.coincidence_int() && are_equal { + self.int.set_lcd_stat(true); } let next_mode = if self.pos.line_y >= 144 { @@ -140,10 +143,13 @@ impl Ppu { self.cycles %= 456; self.pos.line_y += 1; - // New Scanline is next, check for LYC=LY - if self.stat.coincidence_int() { - let are_equal = self.pos.line_y == self.pos.ly_compare; - self.stat.set_coincidence(are_equal); + // Update LY==LYC bit + let are_equal = self.pos.line_y == self.pos.ly_compare; + self.stat.set_coincidence(are_equal); + + // Request LCD STAT interrupt if conditions met + if self.stat.coincidence_int() && are_equal { + self.int.set_lcd_stat(true); } if self.pos.line_y == 154 { @@ -687,8 +693,8 @@ impl PixelFetcher { let id = self.bg.tile.id.expect("Tile Number unexpectedly missing"); let tile_data_addr = match control.tile_data_addr() { - TileDataAddress::X8800 => 0x9000u16.wrapping_add((id as i8 * 16) as u16), - TileDataAddress::X8000 => 0x8000 + (id as u16 * 16), + TileDataAddress::X8800 => 0x9000u16.wrapping_add((id as i8).wrapping_mul(16) as u16), + TileDataAddress::X8000 => 0x8000 + (id as u16).wrapping_mul(16), }; let offset = 2 * if window { @@ -737,7 +743,7 @@ impl PixelFetcher { (line_y + scroll_y) % 8 }; - 0x8000 + (attr.tile_index as u16 * 16) + offset as u16 + 0x8000 + (tile_number as u16 * 16) + offset as u16 } } diff --git a/src/ppu/registers.rs b/src/ppu/registers.rs index f169ebd..d07847a 100644 --- a/src/ppu/registers.rs +++ b/src/ppu/registers.rs @@ -13,6 +13,16 @@ bitfield! { pub from into PpuMode, mode, set_mode: 1, 0; } +impl LCDStatus { + pub fn update(&mut self, byte: u8) { + // Bytes 2 -> 0 are read only + let mask = 0b00000111; + + let read_only = self.0 & mask; + self.0 = (byte & !mask) | read_only; + } +} + impl Copy for LCDStatus {} impl Clone for LCDStatus { fn clone(&self) -> Self { @@ -26,12 +36,6 @@ impl Default for LCDStatus { } } -impl From for LCDStatus { - fn from(byte: u8) -> Self { - Self(byte) - } -} - impl From for u8 { fn from(status: LCDStatus) -> Self { status.0