core/gpu/bugfix: Support firing HBlank IRQs during VBlank

This commit fixes #43


Former-commit-id: 6a4367282c673a35316643e16413f9a602094d9d
This commit is contained in:
Michel Heily 2020-03-13 16:26:21 +02:00
parent 7f34e8bd08
commit 699b2decd2
2 changed files with 38 additions and 15 deletions

View file

@ -40,8 +40,8 @@ pub mod consts {
pub const VBLANK_LINES: usize = 68; pub const VBLANK_LINES: usize = 68;
pub(super) const CYCLES_PIXEL: usize = 4; pub(super) const CYCLES_PIXEL: usize = 4;
pub(super) const CYCLES_HDRAW: usize = 960; pub(super) const CYCLES_HDRAW: usize = 960 + 46;
pub(super) const CYCLES_HBLANK: usize = 272; pub(super) const CYCLES_HBLANK: usize = 272 - 46;
pub(super) const CYCLES_SCANLINE: usize = 1232; pub(super) const CYCLES_SCANLINE: usize = 1232;
pub(super) const CYCLES_VDRAW: usize = 197120; pub(super) const CYCLES_VDRAW: usize = 197120;
pub(super) const CYCLES_VBLANK: usize = 83776; pub(super) const CYCLES_VBLANK: usize = 83776;
@ -57,16 +57,29 @@ pub enum PixelFormat {
} }
#[derive(Serialize, Deserialize, Debug, PartialEq, Copy, Clone)] #[derive(Serialize, Deserialize, Debug, PartialEq, Copy, Clone)]
#[serde(deny_unknown_fields)]
pub enum GpuState { pub enum GpuState {
HDraw = 0, HDraw = 0,
HBlank, HBlank,
VBlank, VBlankHDraw,
VBlankHBlank,
} }
impl Default for GpuState { impl Default for GpuState {
fn default() -> GpuState { fn default() -> GpuState {
GpuState::HDraw GpuState::HDraw
} }
} }
impl GpuState {
pub fn is_vblank(&self) -> bool {
match self {
VBlankHBlank | VBlankHDraw => true,
_ => false,
}
}
}
use GpuState::*; use GpuState::*;
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
@ -380,8 +393,6 @@ impl Gpu {
} }
self.cycles_left_for_current_state = CYCLES_HDRAW; self.cycles_left_for_current_state = CYCLES_HDRAW;
} else { } else {
self.state = VBlank;
// latch BG2/3 reference points on vblank // latch BG2/3 reference points on vblank
for i in 0..2 { for i in 0..2 {
self.bg_aff[i].internal_x = self.bg_aff[i].x; self.bg_aff[i].internal_x = self.bg_aff[i].x;
@ -397,20 +408,32 @@ impl Gpu {
sb.io.dmac.notify_vblank(); sb.io.dmac.notify_vblank();
video_device.borrow_mut().render(&self.frame_buffer); video_device.borrow_mut().render(&self.frame_buffer);
self.obj_buffer_reset(); self.obj_buffer_reset();
self.cycles_left_for_current_state = CYCLES_SCANLINE; self.cycles_left_for_current_state = CYCLES_HDRAW;
self.state = VBlankHDraw;
} }
} }
VBlank => { VBlankHDraw => {
if self.vcount < DISPLAY_HEIGHT + VBLANK_LINES - 1 { self.cycles_left_for_current_state = CYCLES_HBLANK;
self.state = VBlankHBlank;
self.dispstat.set_hblank_flag(true);
if self.dispstat.hblank_irq_enable() {
irqs.set_LCD_HBlank(true);
};
}
VBlankHBlank => {
self.update_vcount(self.vcount + 1, irqs); self.update_vcount(self.vcount + 1, irqs);
self.cycles_left_for_current_state = CYCLES_SCANLINE;
if self.vcount < DISPLAY_HEIGHT + VBLANK_LINES - 1 {
self.dispstat.set_hblank_flag(false);
self.cycles_left_for_current_state = CYCLES_HDRAW;
self.state = VBlankHDraw;
} else { } else {
self.update_vcount(0, irqs); self.update_vcount(0, irqs);
self.dispstat.set_vblank_flag(false); self.dispstat.set_vblank_flag(false);
self.render_scanline(); self.render_scanline();
self.state = HDraw;
self.cycles_left_for_current_state = CYCLES_HDRAW; self.cycles_left_for_current_state = CYCLES_HDRAW;
self.state = HDraw;
} }
} }
}; };

View file

@ -138,7 +138,7 @@ impl Bus for IoDevices {
let index = (io_addr - REG_BG2X_L) / 0x10; let index = (io_addr - REG_BG2X_L) / 0x10;
let t = io.gpu.bg_aff[index as usize].x as u32; let t = io.gpu.bg_aff[index as usize].x as u32;
io.gpu.bg_aff[index as usize].x = ((t & 0xffff0000) + (value as u32)) as i32; io.gpu.bg_aff[index as usize].x = ((t & 0xffff0000) + (value as u32)) as i32;
if io.gpu.state != GpuState::VBlank { if !io.gpu.state.is_vblank() {
io.gpu.bg_aff[index as usize].internal_x = io.gpu.bg_aff[index as usize].x; io.gpu.bg_aff[index as usize].internal_x = io.gpu.bg_aff[index as usize].x;
} }
} }
@ -146,7 +146,7 @@ impl Bus for IoDevices {
let index = (io_addr - REG_BG2X_L) / 0x10; let index = (io_addr - REG_BG2X_L) / 0x10;
let t = io.gpu.bg_aff[index as usize].y as u32; let t = io.gpu.bg_aff[index as usize].y as u32;
io.gpu.bg_aff[index as usize].y = ((t & 0xffff0000) + (value as u32)) as i32; io.gpu.bg_aff[index as usize].y = ((t & 0xffff0000) + (value as u32)) as i32;
if io.gpu.state != GpuState::VBlank { if !io.gpu.state.is_vblank() {
io.gpu.bg_aff[index as usize].internal_y = io.gpu.bg_aff[index as usize].y; io.gpu.bg_aff[index as usize].internal_y = io.gpu.bg_aff[index as usize].y;
} }
} }
@ -155,7 +155,7 @@ impl Bus for IoDevices {
let t = io.gpu.bg_aff[index as usize].x; let t = io.gpu.bg_aff[index as usize].x;
io.gpu.bg_aff[index as usize].x = io.gpu.bg_aff[index as usize].x =
(t & 0xffff) | ((sign_extend_i32((value & 0xfff) as i32, 12)) << 16); (t & 0xffff) | ((sign_extend_i32((value & 0xfff) as i32, 12)) << 16);
if io.gpu.state != GpuState::VBlank { if !io.gpu.state.is_vblank() {
io.gpu.bg_aff[index as usize].internal_x = io.gpu.bg_aff[index as usize].x; io.gpu.bg_aff[index as usize].internal_x = io.gpu.bg_aff[index as usize].x;
} }
} }
@ -164,7 +164,7 @@ impl Bus for IoDevices {
let t = io.gpu.bg_aff[index as usize].y; let t = io.gpu.bg_aff[index as usize].y;
io.gpu.bg_aff[index as usize].y = io.gpu.bg_aff[index as usize].y =
(t & 0xffff) | ((sign_extend_i32((value & 0xfff) as i32, 12)) << 16); (t & 0xffff) | ((sign_extend_i32((value & 0xfff) as i32, 12)) << 16);
if io.gpu.state != GpuState::VBlank { if !io.gpu.state.is_vblank() {
io.gpu.bg_aff[index as usize].internal_y = io.gpu.bg_aff[index as usize].y; io.gpu.bg_aff[index as usize].internal_y = io.gpu.bg_aff[index as usize].y;
} }
} }