Improve Display

This commit is contained in:
Kevin Hamacher 2016-05-29 14:11:34 +02:00
parent b71397d16a
commit 2499eedfd2
2 changed files with 56 additions and 26 deletions

View File

@ -109,7 +109,8 @@ impl Cartridge {
fn write_byte_none(&mut self, addr: u16, val: u8) { fn write_byte_none(&mut self, addr: u16, val: u8) {
match addr { match addr {
0xA000 ... 0xBFFF => { 0xA000 ... 0xBFFF => {
self.ram[addr as usize - 0xA000] = val; // self.ram[addr as usize - 0xA000] = val;
println!("No MBC, ignoring RAM write {:02X} to {:04X}", val, addr);
} }
_ => println!("No MBC, unable to write {:02X} to {:04X}", val, addr), _ => println!("No MBC, unable to write {:02X} to {:04X}", val, addr),
} }

View File

@ -28,17 +28,23 @@ const CTRL_BG_SPRITE_SIZE: u8 = 1 << 2;
const CTRL_BG_SPRITE_ENABLE: u8 = 1 << 1; const CTRL_BG_SPRITE_ENABLE: u8 = 1 << 1;
const CTRL_BG_DISPLAY: u8 = 1 << 0; const CTRL_BG_DISPLAY: u8 = 1 << 0;
// Status flags
const STAT_LYC_LC_COINCIDENCE_INT: u8 = 1 << 6;
const STAT_MODE_OAM_INT: u8 = 1 << 5;
const STAT_MODE_VBLANK_INT: u8 = 1 << 4;
const STAT_MODE_HBLANK_INT: u8 = 1 << 3;
#[derive(Debug)] #[derive(Debug)]
enum DisplayMode { enum DisplayMode {
Scanline, ReadOAMMemory,
Readmode, ReadFullMemory,
HBlank, HBlank,
VBlank, VBlank,
} }
impl Default for DisplayMode { impl Default for DisplayMode {
fn default() -> DisplayMode { fn default() -> DisplayMode {
DisplayMode::Scanline DisplayMode::HBlank
} }
} }
@ -67,7 +73,6 @@ pub struct Display {
pub event_pump: sdl2::EventPump, pub event_pump: sdl2::EventPump,
vblank_fired: bool, vblank_fired: bool,
stat_fired: bool,
vblank_interrupt: bool, vblank_interrupt: bool,
stat_interrupt: bool, stat_interrupt: bool,
} }
@ -102,7 +107,6 @@ impl Display {
event_pump: event_pump, event_pump: event_pump,
vblank_fired: false, vblank_fired: false,
stat_fired: false,
vblank_interrupt: false, vblank_interrupt: false,
stat_interrupt: false, stat_interrupt: false,
} }
@ -179,52 +183,76 @@ impl Display {
// Do we want to have a time delta here? // Do we want to have a time delta here?
pub fn tick(&mut self, ticks: u16) { pub fn tick(&mut self, ticks: u16) {
self.current_ticks += ticks;
self.status &= 0xFC; self.status &= 0xFC;
if self.control & CTRL_LCD_DISPLAY_ENABLE == 0 {
// Display is disabled
self.current_ticks = 0;
self.current_mode = DisplayMode::VBlank;
self.curline = 0;
return;
}
self.current_ticks += ticks;
match self.current_mode { match self.current_mode {
DisplayMode::Scanline => { DisplayMode::ReadOAMMemory => { // Mode 2, Reading OAM memory, RAM may be accessed.
if self.current_ticks > TICKS_END_SCANLINE { if self.current_ticks > TICKS_END_SCANLINE {
self.vblank_fired = false;
self.stat_fired = false;
self.current_ticks = 0; self.current_ticks = 0;
self.current_mode = DisplayMode::Readmode; self.current_mode = DisplayMode::ReadFullMemory;
} }
self.status |= 3; self.status |= 2;
}, },
DisplayMode::Readmode => { DisplayMode::ReadFullMemory => { // Mode 3, reading OAM, VMEM and palette data.
// Nothing may be accessed.
if self.current_ticks > TICKS_END_READMODE { if self.current_ticks > TICKS_END_READMODE {
self.current_ticks = 0; self.current_ticks = 0;
self.current_mode = DisplayMode::HBlank; self.current_mode = DisplayMode::HBlank;
self.renderscan(); self.renderscan();
if self.status & STAT_MODE_HBLANK_INT > 0 {
self.stat_interrupt = true;
}
} }
self.status |= 2; self.status |= 3;
}, },
DisplayMode::HBlank => { DisplayMode::HBlank => { // Mode 0, H-Blank, Memory (RAM, OAM) may be accessed.
if self.current_ticks > TICKS_END_HBLANK { if self.current_ticks > TICKS_END_HBLANK {
self.current_ticks = 0; self.current_ticks = 0;
self.curline += 1; self.curline += 1;
// render scan?
if self.curline == 143 { if self.curline == 143 {
self.current_mode = DisplayMode::VBlank; self.current_mode = DisplayMode::VBlank; // To Mode 1
self.vblank_interrupt = true; if self.status & STAT_MODE_VBLANK_INT > 0 {
self.vblank_fired = true; // We don't need this, do we? self.stat_interrupt = true;
}
// render frame.
self.renderer.present();
self.renderer.set_draw_color(sdl2::pixels::Color::RGB(0, 0, 0));
self.renderer.clear();
} else { } else {
self.current_mode = DisplayMode::Scanline; self.current_mode = DisplayMode::ReadOAMMemory; // Mode 2 again
if self.status & STAT_MODE_OAM_INT > 0 {
self.stat_interrupt = true;
}
} }
} }
self.status &= 0xFC; self.status &= 0xFC;
self.status |= 0; self.status |= 0;
}, },
DisplayMode::VBlank => { DisplayMode::VBlank => { // Mode 1, V-Blank (or display disabled), Memory (RAM, OAM)
// may be accessed
if self.current_ticks > TICKS_END_VBLANK { if self.current_ticks > TICKS_END_VBLANK {
self.current_ticks = 0; self.current_ticks = 0;
self.curline += 1; self.curline += 1;
if self.curline == 144 {
self.vblank_interrupt = true;
}
if self.curline > 153 { if self.curline > 153 {
self.renderer.present(); self.current_mode = DisplayMode::ReadOAMMemory; // Mode 2, scanline.
self.renderer.set_draw_color(sdl2::pixels::Color::RGB(0, 0, 0));
self.renderer.clear();
self.current_mode = DisplayMode::Scanline;
self.curline = 0; self.curline = 0;
if self.status & STAT_MODE_OAM_INT > 0 {
self.stat_interrupt = true;
}
} }
} }
self.status |= 1; self.status |= 1;
@ -234,8 +262,9 @@ impl Display {
// Update the status register // Update the status register
if self.curline == self.lyc { if self.curline == self.lyc {
self.status |= 1 << 2; self.status |= 1 << 2;
self.stat_fired = true; if self.status & STAT_LYC_LC_COINCIDENCE_INT > 0 {
self.stat_interrupt = true; self.stat_interrupt = true;
}
} else { } else {
self.status &= !(1 << 2); self.status &= !(1 << 2);
} }