Improve GPU state machine.

This fixes the glitch in dma_demo.gba where the rendering of the circle
was off by a scanline.


Former-commit-id: 907fefd548b6557ce46e06a99d0bc6ab83a8f332
This commit is contained in:
Michel Heily 2019-11-12 18:11:45 +02:00
parent 2978fde0dc
commit dcab1e6328
2 changed files with 50 additions and 41 deletions

View file

@ -16,6 +16,7 @@ pub use regs::*;
pub const VRAM_ADDR: Addr = 0x0600_0000;
pub const DISPLAY_WIDTH: usize = 240;
pub const DISPLAY_HEIGHT: usize = 160;
pub const VBLANK_LINES: usize = 68;
const CYCLES_PIXEL: usize = 4;
const CYCLES_HDRAW: usize = 960;
@ -445,6 +446,17 @@ impl Gpu {
&self.frame_buffer.0
}
fn update_vcount(&mut self, value: usize, irqs: &mut IrqBitmask) {
self.current_scanline = value;
let vcount_setting = self.dispstat.vcount_setting();
self.dispstat
.set_vcount_flag(vcount_setting == self.current_scanline as u16);
if self.dispstat.vcount_irq_enable() && self.dispstat.get_vcount_flag() {
irqs.set_LCD_VCounterMatch(true);
}
}
// Returns the new gpu state
pub fn step(
&mut self,
@ -454,57 +466,54 @@ impl Gpu {
) -> Option<GpuState> {
self.cycles += cycles;
if self.dispstat.vcount_setting() != 0 {
self.dispstat
.set_vcount(self.dispstat.vcount_setting() == self.current_scanline as u16);
}
if self.dispstat.vcount_irq_enable() && self.dispstat.get_vcount() {
irqs.set_LCD_VCounterMatch(true);
}
match self.state {
HDraw => {
if self.cycles > CYCLES_HDRAW {
self.current_scanline += 1;
self.cycles -= CYCLES_HDRAW;
if self.current_scanline < DISPLAY_HEIGHT {
self.render_scanline(sb);
// HBlank
self.dispstat.set_hblank(true);
self.dispstat.set_hblank_flag(true);
if self.dispstat.hblank_irq_enable() {
irqs.set_LCD_HBlank(true);
};
self.state = HBlank;
return Some(HBlank);
} else {
self.dispstat.set_vblank(true);
if self.dispstat.vblank_irq_enable() {
irqs.set_LCD_VBlank(true);
};
self.state = VBlank;
return Some(VBlank);
};
}
}
HBlank => {
if self.cycles > CYCLES_HBLANK {
self.cycles -= CYCLES_HBLANK;
self.dispstat.set_hblank_flag(false);
self.update_vcount(self.current_scanline + 1, irqs);
if self.current_scanline < DISPLAY_HEIGHT {
self.render_scanline(sb);
self.state = HDraw;
self.dispstat.set_hblank(false);
self.dispstat.set_vblank(false);
return Some(HDraw);
} else {
self.state = VBlank;
self.dispstat.set_vblank_flag(true);
if self.dispstat.vblank_irq_enable() {
irqs.set_LCD_VBlank(true);
};
return Some(VBlank);
}
}
}
VBlank => {
if self.cycles > CYCLES_VBLANK {
self.cycles -= CYCLES_VBLANK;
self.state = HDraw;
self.dispstat.set_hblank(false);
self.dispstat.set_vblank(false);
self.current_scanline = 0;
if self.cycles > CYCLES_SCANLINE {
self.cycles -= CYCLES_SCANLINE;
if self.current_scanline < DISPLAY_HEIGHT + VBLANK_LINES {
self.update_vcount(self.current_scanline + 1, irqs);
return None;
} else {
self.update_vcount(0, irqs);
self.dispstat.set_vblank_flag(false);
self.render_scanline(sb);
return Some(HDraw);
self.state = HDraw;
return Some(self.state);
}
}
}
}

View file

@ -87,9 +87,9 @@ bitfield! {
pub struct DisplayStatus(u16);
impl Debug;
u16;
pub get_vblank, set_vblank: 0;
pub get_hblank, set_hblank: 1;
pub get_vcount, set_vcount: 2;
pub get_vblank_flag, set_vblank_flag: 0;
pub get_hblank_flag, set_hblank_flag: 1;
pub get_vcount_flag, set_vcount_flag: 2;
pub vblank_irq_enable, _ : 3;
pub hblank_irq_enable, _ : 4;
pub vcount_irq_enable, _ : 5;