diff --git a/src/cpu.rs b/src/cpu.rs index 5b5ceb8..11db72d 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -883,32 +883,52 @@ impl CPU { } } - fn check_interrupts(&mut self) { + fn check_interrupts(&mut self, execute: bool) -> bool { // read pending interrupts let pending = self.interconnect.read_byte(0xFF0F); let enabled = self.interconnect.read_byte(0xFFFF); let e_pending = pending & enabled; if e_pending & interconnect::INTERRUPT_DISPLAY_VBLANK > 0 { - self.handle_interrupt(0x40, interconnect::INTERRUPT_DISPLAY_VBLANK); + if execute { + self.handle_interrupt(0x40, interconnect::INTERRUPT_DISPLAY_VBLANK); + } + return true; } else if e_pending & interconnect::INTERRUPT_DISPLAY_STAT > 0 { - self.handle_interrupt(0x48, interconnect::INTERRUPT_DISPLAY_STAT); + if execute { + self.handle_interrupt(0x48, interconnect::INTERRUPT_DISPLAY_STAT); + } + return true; } else if e_pending & interconnect::INTERRUPT_TIMER_OVERFLOW > 0 { - self.handle_interrupt(0x50, interconnect::INTERRUPT_TIMER_OVERFLOW); + if execute { + self.handle_interrupt(0x50, interconnect::INTERRUPT_TIMER_OVERFLOW); + } + return true; } else if e_pending & interconnect::INTERRUPT_SERIAL > 0 { - self.handle_interrupt(0x58, interconnect::INTERRUPT_SERIAL); + if execute { + self.handle_interrupt(0x58, interconnect::INTERRUPT_SERIAL); + } + return true; } else if e_pending & interconnect::INTERRUPT_INPUT > 0 { - self.handle_interrupt(0x60, interconnect::INTERRUPT_INPUT); + if execute { + self.handle_interrupt(0x60, interconnect::INTERRUPT_INPUT); + } + return true; } else if e_pending > 0 { panic!("Unknown pending interrupt: {:02X}", e_pending); } + false } pub fn run_instruction(&mut self) -> u8 { // self.debug = !self.interconnect.is_boot_rom(); // Check for interrupts. if self.ime { - self.check_interrupts(); + self.check_interrupts(true); + } else if self.halted { + if self.check_interrupts(false) { + self.halted = false; + } } let mut cycles: u8 = 1; diff --git a/src/display.rs b/src/display.rs index 3950806..d3e568c 100644 --- a/src/display.rs +++ b/src/display.rs @@ -452,7 +452,7 @@ impl Display { // We need to draw this. let wide_mode = self.control & CTRL_BG_SPRITE_SIZE > 0; if wide_mode { - panic!("TODO"); + // panic!("TODO"); } let limit = match wide_mode { true => 16, @@ -472,15 +472,19 @@ impl Display { _ => {} } } - let x_o2: u8 = match sprite.is_x_flipped() { - true => x_o ^ 7, - false => x_o, - }; if wide_mode && x_o > 7 { - b1 = (tile_line_3 & 1 << (14 - x_o2)) > 0; - b2 = (tile_line_4 & 1 << (14 - x_o2)) > 0; + let x_o2: u8 = match sprite.is_x_flipped() { + true => (x_o - 8) ^ 7, + false => (x_o - 8), + }; + b1 = (tile_line_3 & 1 << (7 - x_o2)) > 0; + b2 = (tile_line_4 & 1 << (7 - x_o2)) > 0; } else { + let x_o2: u8 = match sprite.is_x_flipped() { + true => x_o ^ 7, + false => x_o, + }; b1 = (tile_line_1 & 1 << (7 - x_o2)) > 0; b2 = (tile_line_2 & 1 << (7 - x_o2)) > 0; } diff --git a/src/interconnect.rs b/src/interconnect.rs index 0f64c4c..a614d9b 100644 --- a/src/interconnect.rs +++ b/src/interconnect.rs @@ -231,6 +231,7 @@ impl Interconnect { 0xFF01 ... 0xFF02 => self.serial.read_byte(addr), 0xFF04 ... 0xFF07 => self.timer.read_byte(addr), 0xFF0F => { + // println!("Reading IF: {:02X}", self.interrupt_request_flags); self.interrupt_request_flags }, 0xFF10 ... 0xFF26 => { diff --git a/src/timer.rs b/src/timer.rs index 3f1e2d7..105d54d 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -7,26 +7,31 @@ pub struct Timer { timer_interrupt: bool, tick_counter: u16, div_tick_counter: u16, + + gb_ticks: u16, } +const TIMER_SPEED: [u16; 4] = [64, 1, 4, 16]; +const TIMER_ENABLE: u8 = (1 << 2); + impl Timer { pub fn new() -> Timer { Timer::default() } - pub fn tick(&mut self, ticks: u16) { - // One tick 1/4.194304MHz on regular speed? - if self.tac & 1 << 2 == 1 { // Is timer enabled? - self.tick_counter += ticks; - let req_ticks = match self.tac & 3 { - 0 => 10240, - 1 => 160, - 2 => 640, - 3 => 2560, - _ => unreachable!() - }; + fn timer_clock_tick(&mut self) { + // The div reg will always tick + self.div_tick_counter += 1; + if self.div_tick_counter >= TIMER_SPEED[3] { + self.div = self.div.wrapping_add(1); + self.div_tick_counter -= TIMER_SPEED[3]; + } - if self.tick_counter > req_ticks { + if (self.tac & TIMER_ENABLE) == TIMER_ENABLE { // Is timer enabled? + self.tick_counter += 1; + let req_ticks = TIMER_SPEED[(self.tac & 3) as usize]; + + if self.tick_counter >= req_ticks { if self.tima == 0xFF { self.timer_interrupt = true; self.tima = 0; @@ -36,12 +41,15 @@ impl Timer { self.tick_counter -= req_ticks; } } + } - // The div reg will always tick - self.div_tick_counter += ticks; - if self.div_tick_counter > 2560 { - self.div = self.div.wrapping_add(1); - self.div_tick_counter -= 2560; + pub fn tick(&mut self, ticks: u16) { + // One tick 1/4.194304MHz on regular speed => 16 gb ticks + self.gb_ticks += ticks; + // If we're in GBC fast mode, we'd require 32 ticks instead of 16 + while self.gb_ticks >= 16 { + self.timer_clock_tick(); + self.gb_ticks -= 16; } }