gb-emu/src/processor/gpu.rs

113 lines
3.1 KiB
Rust
Raw Normal View History

2023-02-05 18:46:55 +11:00
use crate::{HEIGHT, WIDTH};
use super::{set_bit, set_or_clear_bit, CPU};
#[derive(PartialEq)]
enum DrawMode {
HBlank,
VBlank,
Mode2,
Mode3,
}
pub struct GPU {
pub buffer: Vec<u32>,
mode: DrawMode,
mode_clock: usize,
scanline: usize,
}
impl Default for GPU {
fn default() -> Self {
Self {
buffer: vec![0; WIDTH * HEIGHT],
mode: DrawMode::Mode2,
mode_clock: 0,
scanline: 0,
}
}
}
impl CPU {
pub fn advance_gpu_clock(&mut self, steps: u8) {
let real_steps = (steps as usize) * 4;
self.gpu.mode_clock += real_steps;
match self.gpu.mode {
DrawMode::HBlank => {
// mode 0: hblank
if self.gpu.mode_clock >= 204 {
self.gpu.mode_clock = 0;
self.gpu.scanline += 1;
if self.gpu.scanline == 143 {
self.enter_vblank();
} else {
self.gpu.mode = DrawMode::Mode2;
}
}
}
DrawMode::VBlank => {
// mode 1: vblank
if self.gpu.mode_clock >= 456 {
self.gpu.mode_clock = 0;
self.gpu.scanline += 1;
if self.gpu.scanline == 153 {
self.gpu.mode = DrawMode::Mode2;
self.gpu.scanline = 0;
}
}
}
DrawMode::Mode2 => {
// search oam for sprites on this line
// we dont really have to emulate this
if self.gpu.mode_clock >= 80 {
self.gpu.mode_clock = 0;
self.gpu.mode = DrawMode::Mode3;
}
}
DrawMode::Mode3 => {
// generate scanline
if self.gpu.mode_clock >= 172 {
self.gpu.mode_clock = 0;
self.enter_hblank();
}
}
}
self.set_lcd_status();
}
fn enter_hblank(&mut self) {
self.gpu.mode = DrawMode::HBlank;
self.render_scanline(self.gpu.scanline);
}
fn enter_vblank(&mut self) {
self.gpu.mode = DrawMode::VBlank;
self.render_window();
self.memory.set(0xFF0F, set_bit(self.memory.get(0xFF0F), 0));
}
fn set_lcd_status(&mut self) {
let mut stat = self.memory.get(0xFF41);
stat = set_or_clear_bit(stat, 2, self.memory.get(0xFF44) == self.memory.get(0xFF45));
stat = set_or_clear_bit(
stat,
1,
(self.gpu.mode == DrawMode::Mode2) || (self.gpu.mode == DrawMode::Mode3),
);
stat = set_or_clear_bit(
stat,
0,
(self.gpu.mode == DrawMode::VBlank) || (self.gpu.mode == DrawMode::Mode3),
);
self.memory.set(0xFF41, stat);
}
fn render_scanline(&mut self, _scanline: usize) {}
fn render_window(&mut self) {
self.window
.update_with_buffer(&self.gpu.buffer, WIDTH, HEIGHT)
.unwrap();
}
}