core/gpu/bugfix: Support firing HBlank IRQs during VBlank
This commit fixes #43 Former-commit-id: 6a4367282c673a35316643e16413f9a602094d9d
This commit is contained in:
parent
7f34e8bd08
commit
699b2decd2
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue