From 7c652dac75891cda55bb34b5c2efd0fcd398d18b Mon Sep 17 00:00:00 2001 From: xkevio Date: Fri, 2 Feb 2024 00:56:28 +0100 Subject: [PATCH] chore: find out why timer tests dont work --- src/mmu/timer.rs | 14 ++++++++++++-- src/ppu/lcd.rs | 28 +++++++++++++++++++--------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/mmu/timer.rs b/src/mmu/timer.rs index b929ab0..dde63f1 100644 --- a/src/mmu/timer.rs +++ b/src/mmu/timer.rs @@ -34,7 +34,7 @@ impl Timers { tm_overflow[id] = self[id].tick(); } - if tm_overflow[id] { + if tm_overflow[id] && self[id].irq { iff.set_timer(id); } } @@ -59,7 +59,7 @@ impl Mcu for Timers { fn read8(&mut self, address: u32) -> u8 { match address & 1 == 0 { true => self.read16(address) as u8, - false => (self.read16(address & 1) >> 8) as u8, + false => (self.read16(address & !1) >> 8) as u8, } } @@ -115,16 +115,26 @@ pub struct Timer { freq: Freq, count_up: bool, irq: bool, + start: bool, + prev_start: bool, } impl Timer { /// Update all the bits from the TMxCNT_H register. fn apply_tmr_cnt(&mut self, value: u16) { self.start = value & (1 << 7) != 0; + self.irq = value & (1 << 6) != 0; self.count_up = value & (1 << 2) != 0; self.freq = Freq::try_from(value & 0x3).unwrap(); + + // Reload counter value upon change of start bit from 0 -> 1. + if !self.prev_start && self.start { + self.counter = self.reload; + } + + self.prev_start = self.start; } /// Tick timer by one; if overflow -> load `reload`, else just increase. diff --git a/src/ppu/lcd.rs b/src/ppu/lcd.rs index 35e0de1..ca7f0c8 100644 --- a/src/ppu/lcd.rs +++ b/src/ppu/lcd.rs @@ -503,7 +503,11 @@ impl Ppu { }; if px_idx != 0 { - self.current_sprite_line[screen_x] = Obj { px: Some(px), prio: sprite.prio, alpha: sprite.obj_mode == ObjMode::SemiTransparent }; + self.current_sprite_line[screen_x] = Obj { + px: Some(px), + prio: sprite.prio, + alpha: sprite.obj_mode == ObjMode::SemiTransparent + }; } } } @@ -588,16 +592,22 @@ impl Ppu { // Top two layers (pixel, prio, bg, obj_alpha). let mut layers = ([0u16; 2], [4u8; 2], [0usize; 2], false); - // TODO: same for bg, DONT BLEND LAYERS DISABLED IN WININ/WINOUT let window = self.in_window(x, self.vcount.ly() as usize); - let sp_layer_in_win = match window { - Window::Win0 => self.winin.0 & (1 << 4) != 0, - Window::Win1 => self.winin.0 & (1 << 12) != 0, - Window::WinOut => self.winout.0 & (1 << 4) != 0, - Window::ObjWin => todo!(), + // Check if layer is actually activated inside of a window before using it for blending. + let layer_in_win = |layer: usize| { + if self.dispcnt.win0() || self.dispcnt.win1() || self.dispcnt.obj_win() { + match window { + Window::Win0 => self.winin.0 & (1 << layer) != 0, + Window::Win1 => self.winin.0 & (1 << (layer + 8)) != 0, + Window::WinOut => self.winout.0 & (1 << layer) != 0, + Window::ObjWin => todo!(), + } + } else { + true + } }; - if self.dispcnt.obj() && sp_layer_in_win { + if self.dispcnt.obj() && layer_in_win(4) { if let Some(px) = self.current_sprite_line[x].px { let obj_layer = 4; let prio = self.current_sprite_line[x].prio; @@ -621,7 +631,7 @@ impl Ppu { } } - for bg in (0..4).filter(|b| enabled_bgs & (1 << b) != 0) { + for bg in (0..4).filter(|b| enabled_bgs & (1 << b) != 0 && layer_in_win(*b)) { if let Some(px) = self.current_bg_line[bg][x] { if self.bgxcnt[bg].prio() < layers.1[0] { // Swap top and bottom layer.