Pass all CPU tests in GBC fast mode (timer)

This commit is contained in:
Kevin Hamacher 2016-06-02 15:26:11 +02:00
parent a58e599c7a
commit 34ae61e649
4 changed files with 64 additions and 31 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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 => {

View File

@ -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;
}
}