fix(ppu): ensure better timings for sprite fetcher

This commit is contained in:
Rekai Nyangadzayi Musuka 2021-04-20 03:14:00 -05:00
parent db1b40fe2d
commit 4f4c867a63
1 changed files with 73 additions and 68 deletions

View File

@ -168,9 +168,6 @@ impl Ppu {
fn draw(&mut self, cycle: u32) { fn draw(&mut self, cycle: u32) {
use FetcherState::*; use FetcherState::*;
// By only running on odd cycles, we can ensure that we draw every two T cycles
if cycle % 2 != 0 {
let control = &self.control; let control = &self.control;
let pos = &self.pos; let pos = &self.pos;
@ -180,6 +177,7 @@ impl Ppu {
// Determine whether we need to enable sprite fetching // Determine whether we need to enable sprite fetching
let mut obj_attr = None; let mut obj_attr = None;
for i in 0..self.obj_buffer.len() { for i in 0..self.obj_buffer.len() {
if let Some(attr) = self.obj_buffer.get(i) { if let Some(attr) = self.obj_buffer.get(i) {
if attr.x <= (self.x_pos + 8) { if attr.x <= (self.x_pos + 8) {
@ -194,19 +192,21 @@ impl Ppu {
} }
if let Some(attr) = obj_attr { if let Some(attr) = obj_attr {
// Run the Object Fetcher match self.fetcher.obj.state {
TileNumber => {
if cycle % 2 != 0 {
self.fetcher.obj.tile.with_id(attr.tile_index);
self.fetcher.obj.next(TileDataLow);
}
}
TileDataLow => {
if cycle % 2 != 0 {
let obj_size = match self.control.obj_size() { let obj_size = match self.control.obj_size() {
ObjectSize::EightByEight => 8, ObjectSize::EightByEight => 8,
ObjectSize::EightBySixteen => 16, ObjectSize::EightBySixteen => 16,
}; };
match self.fetcher.obj.state {
TileNumber => {
self.fetcher.obj.tile.with_id(attr.tile_index);
self.fetcher.obj.next(TileDataLow);
}
TileDataLow => {
let addr = PixelFetcher::get_obj_low_addr(attr, &self.pos, obj_size); let addr = PixelFetcher::get_obj_low_addr(attr, &self.pos, obj_size);
let byte = self.read_byte(addr); let byte = self.read_byte(addr);
@ -214,7 +214,14 @@ impl Ppu {
self.fetcher.obj.next(TileDataHigh); self.fetcher.obj.next(TileDataHigh);
} }
}
TileDataHigh => { TileDataHigh => {
if cycle % 2 != 0 {
let obj_size = match self.control.obj_size() {
ObjectSize::EightByEight => 8,
ObjectSize::EightBySixteen => 16,
};
let addr = PixelFetcher::get_obj_low_addr(attr, &self.pos, obj_size); let addr = PixelFetcher::get_obj_low_addr(attr, &self.pos, obj_size);
let byte = self.read_byte(addr + 1); let byte = self.read_byte(addr + 1);
@ -222,13 +229,13 @@ impl Ppu {
self.fetcher.obj.next(SendToFifo); self.fetcher.obj.next(SendToFifo);
} }
}
SendToFifo => { SendToFifo => {
self.fetcher.obj.fifo_count += 1; self.fetcher.obj.fifo_count += 1;
if self.fetcher.obj.fifo_count == 1 { if self.fetcher.obj.fifo_count == 1 {
// Load into fifo // Load into Fifo
let tile_bytes = let tile_bytes = self.fetcher.obj.tile.low.zip(self.fetcher.obj.tile.high);
self.fetcher.obj.tile.low.zip(self.fetcher.obj.tile.high);
if let Some(bytes) = tile_bytes { if let Some(bytes) = tile_bytes {
let low = bytes.0; let low = bytes.0;
@ -258,19 +265,21 @@ impl Ppu {
self.fifo.object.push_back(fifo_pixel); self.fifo.object.push_back(fifo_pixel);
} }
}
} else if self.fetcher.obj.fifo_count == 2 {
self.fetcher.bg.resume(); self.fetcher.bg.resume();
self.fifo.resume(); self.fifo.resume();
}
} else if self.fetcher.obj.fifo_count == 2 {
self.fetcher.obj.reset(); self.fetcher.obj.reset();
} else { } else {
panic!("Rekai Musuka <rekai@musuka.dev> is a bad programmer"); panic!("Object FIFO Logic Error has occurred :angry:");
} }
} }
} }
} }
// By only running on odd cycles, we can ensure that we draw every two T cycles
if cycle % 2 != 0 {
if self.fetcher.bg.is_enabled() { if self.fetcher.bg.is_enabled() {
match self.fetcher.bg.state { match self.fetcher.bg.state {
TileNumber => { TileNumber => {
@ -316,8 +325,6 @@ impl Ppu {
self.fetcher.bg.next(TileNumber); self.fetcher.bg.next(TileNumber);
} }
} }
} else {
self.fetcher.bg.resume();
} }
} }
@ -339,8 +346,6 @@ impl Ppu {
self.x_pos += 1; self.x_pos += 1;
} }
} else {
self.fifo.resume();
} }
} }