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:
parent
2978fde0dc
commit
dcab1e6328
|
@ -16,6 +16,7 @@ pub use regs::*;
|
||||||
pub const VRAM_ADDR: Addr = 0x0600_0000;
|
pub const VRAM_ADDR: Addr = 0x0600_0000;
|
||||||
pub const DISPLAY_WIDTH: usize = 240;
|
pub const DISPLAY_WIDTH: usize = 240;
|
||||||
pub const DISPLAY_HEIGHT: usize = 160;
|
pub const DISPLAY_HEIGHT: usize = 160;
|
||||||
|
pub const VBLANK_LINES: usize = 68;
|
||||||
|
|
||||||
const CYCLES_PIXEL: usize = 4;
|
const CYCLES_PIXEL: usize = 4;
|
||||||
const CYCLES_HDRAW: usize = 960;
|
const CYCLES_HDRAW: usize = 960;
|
||||||
|
@ -445,6 +446,17 @@ impl Gpu {
|
||||||
&self.frame_buffer.0
|
&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
|
// Returns the new gpu state
|
||||||
pub fn step(
|
pub fn step(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -454,57 +466,54 @@ impl Gpu {
|
||||||
) -> Option<GpuState> {
|
) -> Option<GpuState> {
|
||||||
self.cycles += cycles;
|
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 {
|
match self.state {
|
||||||
HDraw => {
|
HDraw => {
|
||||||
if self.cycles > CYCLES_HDRAW {
|
if self.cycles > CYCLES_HDRAW {
|
||||||
self.current_scanline += 1;
|
|
||||||
self.cycles -= CYCLES_HDRAW;
|
self.cycles -= CYCLES_HDRAW;
|
||||||
|
|
||||||
if self.current_scanline < DISPLAY_HEIGHT {
|
|
||||||
self.render_scanline(sb);
|
|
||||||
// HBlank
|
// HBlank
|
||||||
self.dispstat.set_hblank(true);
|
self.dispstat.set_hblank_flag(true);
|
||||||
if self.dispstat.hblank_irq_enable() {
|
if self.dispstat.hblank_irq_enable() {
|
||||||
irqs.set_LCD_HBlank(true);
|
irqs.set_LCD_HBlank(true);
|
||||||
};
|
};
|
||||||
self.state = HBlank;
|
self.state = HBlank;
|
||||||
return Some(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 => {
|
HBlank => {
|
||||||
if self.cycles > CYCLES_HBLANK {
|
if self.cycles > CYCLES_HBLANK {
|
||||||
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.state = HDraw;
|
||||||
self.dispstat.set_hblank(false);
|
|
||||||
self.dispstat.set_vblank(false);
|
|
||||||
return Some(HDraw);
|
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 => {
|
VBlank => {
|
||||||
if self.cycles > CYCLES_VBLANK {
|
if self.cycles > CYCLES_SCANLINE {
|
||||||
self.cycles -= CYCLES_VBLANK;
|
self.cycles -= CYCLES_SCANLINE;
|
||||||
self.state = HDraw;
|
|
||||||
self.dispstat.set_hblank(false);
|
if self.current_scanline < DISPLAY_HEIGHT + VBLANK_LINES {
|
||||||
self.dispstat.set_vblank(false);
|
self.update_vcount(self.current_scanline + 1, irqs);
|
||||||
self.current_scanline = 0;
|
return None;
|
||||||
|
} else {
|
||||||
|
self.update_vcount(0, irqs);
|
||||||
|
self.dispstat.set_vblank_flag(false);
|
||||||
self.render_scanline(sb);
|
self.render_scanline(sb);
|
||||||
return Some(HDraw);
|
self.state = HDraw;
|
||||||
|
return Some(self.state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,9 +87,9 @@ bitfield! {
|
||||||
pub struct DisplayStatus(u16);
|
pub struct DisplayStatus(u16);
|
||||||
impl Debug;
|
impl Debug;
|
||||||
u16;
|
u16;
|
||||||
pub get_vblank, set_vblank: 0;
|
pub get_vblank_flag, set_vblank_flag: 0;
|
||||||
pub get_hblank, set_hblank: 1;
|
pub get_hblank_flag, set_hblank_flag: 1;
|
||||||
pub get_vcount, set_vcount: 2;
|
pub get_vcount_flag, set_vcount_flag: 2;
|
||||||
pub vblank_irq_enable, _ : 3;
|
pub vblank_irq_enable, _ : 3;
|
||||||
pub hblank_irq_enable, _ : 4;
|
pub hblank_irq_enable, _ : 4;
|
||||||
pub vcount_irq_enable, _ : 5;
|
pub vcount_irq_enable, _ : 5;
|
||||||
|
|
Reference in a new issue