feat: implement LCDSTAT interrupt

This commit is contained in:
Rekai Nyangadzayi Musuka 2021-03-21 00:01:21 -05:00
parent c64417fdce
commit 5a42d76f1e
3 changed files with 37 additions and 24 deletions

View File

@ -223,7 +223,16 @@ impl Bus {
0xFF42 => self.ppu.pos.scroll_y = byte, 0xFF42 => self.ppu.pos.scroll_y = byte,
0xFF43 => self.ppu.pos.scroll_x = byte, 0xFF43 => self.ppu.pos.scroll_x = byte,
0xFF44 => self.ppu.pos.line_y = byte, 0xFF44 => self.ppu.pos.line_y = byte,
0xFF45 => self.ppu.pos.ly_compare = byte == 0x01, // FIXME: We don't consider the possibility of a byte being different form 0x00 or 0x01 0xFF45 => {
// Update LYC
self.ppu.pos.ly_compare = byte;
// Update Coincidence Flag
if self.ppu.stat.coincidence_intr() {
let are_equal = self.ppu.pos.line_y == byte;
self.ppu.stat.set_coincidence(are_equal);
}
}
0xFF47 => self.ppu.monochrome.bg_palette = byte.into(), 0xFF47 => self.ppu.monochrome.bg_palette = byte.into(),
0xFF48 => self.ppu.monochrome.obj_palette_0 = byte.into(), 0xFF48 => self.ppu.monochrome.obj_palette_0 = byte.into(),
0xFF49 => self.ppu.monochrome.obj_palette_1 = byte.into(), 0xFF49 => self.ppu.monochrome.obj_palette_1 = byte.into(),

View File

@ -76,24 +76,9 @@ impl Cpu {
pub fn step(&mut self) -> Cycles { pub fn step(&mut self) -> Cycles {
let opcode = self.fetch(); let opcode = self.fetch();
let instr = self.decode(opcode); let instr = self.decode(opcode);
// println!(
// "Addr: {:#06X} | Opcode: {:#04X} | Instr: {:X?}",
// self.reg.pc, opcode, instr
// );
let cycles = self.execute(instr); let cycles = self.execute(instr);
// if self.bus.read_byte(0xFF02) == 0x81 {
// let c = self.bus.read_byte(0xFF01) as char;
// self.bus.write_byte(0xFF02, 0x00);
// print!("{}", c);
// std::io::stdout().flush().unwrap();
// }
self.bus.step(cycles); self.bus.step(cycles);
self.handle_interrupts(); self.handle_interrupts();
cycles cycles
@ -188,7 +173,6 @@ impl Cpu {
// Disable all future interrupts // Disable all future interrupts
self.set_ime(false); self.set_ime(false);
self.execute(Instruction::CALL(Always, register)) self.execute(Instruction::CALL(Always, register))
} }
None => Cycles::new(0), // NO Interrupts were enabled and / or requested None => Cycles::new(0), // NO Interrupts were enabled and / or requested

View File

@ -39,9 +39,6 @@ impl Ppu {
pub fn step(&mut self, cycles: Cycles) { pub fn step(&mut self, cycles: Cycles) {
self.cycles += cycles; self.cycles += cycles;
// let tmp: u32 = self.cycles.into();
// println!("Mode: {:?} | Cycles: {}", self.mode, tmp);
match self.stat.mode() { match self.stat.mode() {
Mode::OamScan => { Mode::OamScan => {
if self.cycles >= 80.into() { if self.cycles >= 80.into() {
@ -59,6 +56,10 @@ impl Ppu {
if self.cycles >= 172.into() { if self.cycles >= 172.into() {
self.cycles %= 172; self.cycles %= 172;
if self.stat.hblank_intr() {
self.interrupt.set_lcd_stat(true);
}
self.stat.set_mode(Mode::HBlank); self.stat.set_mode(Mode::HBlank);
self.draw_scanline(); self.draw_scanline();
} }
@ -71,12 +72,26 @@ impl Ppu {
let next_mode = if self.pos.line_y >= 144 { let next_mode = if self.pos.line_y >= 144 {
self.interrupt.set_vblank(true); self.interrupt.set_vblank(true);
if self.stat.vblank_intr() {
self.interrupt.set_lcd_stat(true);
}
Mode::VBlank Mode::VBlank
} else { } else {
if self.stat.oam_intr() {
self.interrupt.set_lcd_stat(true);
}
Mode::OamScan Mode::OamScan
}; };
self.stat.set_mode(next_mode); self.stat.set_mode(next_mode);
if self.stat.coincidence_intr() {
let are_equal = self.pos.line_y == self.pos.ly_compare;
self.stat.set_coincidence(are_equal);
}
} }
} }
Mode::VBlank => { Mode::VBlank => {
@ -90,6 +105,11 @@ impl Ppu {
self.stat.set_mode(Mode::OamScan); self.stat.set_mode(Mode::OamScan);
self.pos.line_y = 0; self.pos.line_y = 0;
} }
if self.stat.coincidence_intr() {
let are_equal = self.pos.line_y == self.pos.ly_compare;
self.stat.set_coincidence(are_equal);
}
} }
} }
} }
@ -192,11 +212,11 @@ impl Interrupt {
bitfield! { bitfield! {
pub struct LCDStatus(u8); pub struct LCDStatus(u8);
impl Debug; impl Debug;
pub lyc_ly_intr, set_lyc_ly_intr: 6; pub coincidence_intr, set_coincidence_intr: 6;
pub oam_intr, set_oam_intr: 5; pub oam_intr, set_oam_intr: 5;
pub vblank_intr, set_vblank_intr: 4; pub vblank_intr, set_vblank_intr: 4;
pub hblank_intr, set_hblank_intr: 3; pub hblank_intr, set_hblank_intr: 3;
pub coincidence, _: 2; // LYC == LY Flag pub coincidence, set_coincidence: 2; // LYC == LY Flag
from into Mode, _mode, set_mode: 1, 0; from into Mode, _mode, set_mode: 1, 0;
} }
@ -215,7 +235,7 @@ impl Clone for LCDStatus {
impl Default for LCDStatus { impl Default for LCDStatus {
fn default() -> Self { fn default() -> Self {
Self(0) Self(0x80) // bit 7 is always 1
} }
} }
@ -268,7 +288,7 @@ pub struct ScreenPosition {
pub scroll_y: u8, pub scroll_y: u8,
pub scroll_x: u8, pub scroll_x: u8,
pub line_y: u8, pub line_y: u8,
pub ly_compare: bool, pub ly_compare: u8,
pub window_y: u8, pub window_y: u8,
pub window_x: u8, pub window_x: u8,
} }