Some checks failed
CI / rust (push) Has been cancelled
Full NES emulation: CPU, PPU, APU, 47 mappers, iNES/NES 2.0 parsing. GTK4 desktop client with HeaderBar, pixel-perfect Cairo rendering, drag-and-drop ROM loading, and keyboard shortcuts. 187 tests covering core emulation, mappers, and runtime.
109 lines
4.6 KiB
Rust
109 lines
4.6 KiB
Rust
use super::*;
|
|
|
|
impl Ppu {
|
|
pub fn save_state(&self, out: &mut Vec<u8>) {
|
|
out.extend_from_slice(&self.vram);
|
|
out.extend_from_slice(&self.palette_ram);
|
|
out.extend_from_slice(&self.oam);
|
|
out.push(self.ctrl);
|
|
out.push(self.mask);
|
|
out.push(self.status);
|
|
out.push(self.oam_addr);
|
|
out.push(u8::from(self.write_latch));
|
|
out.extend_from_slice(&self.vram_addr.to_le_bytes());
|
|
out.extend_from_slice(&self.temp_addr.to_le_bytes());
|
|
out.push(self.fine_x);
|
|
out.push(self.scroll_x);
|
|
out.push(self.scroll_y);
|
|
out.push(self.read_buffer);
|
|
out.push(self.io_latch);
|
|
out.extend_from_slice(&self.bg_shift_pattern_lo.to_le_bytes());
|
|
out.extend_from_slice(&self.bg_shift_pattern_hi.to_le_bytes());
|
|
out.extend_from_slice(&self.bg_shift_attr_lo.to_le_bytes());
|
|
out.extend_from_slice(&self.bg_shift_attr_hi.to_le_bytes());
|
|
out.push(self.next_tile_id);
|
|
out.push(self.next_tile_attr);
|
|
out.push(self.next_tile_lsb);
|
|
out.push(self.next_tile_msb);
|
|
out.push(self.sprite_count);
|
|
out.extend_from_slice(&self.sprite_indices);
|
|
out.push(self.next_sprite_count);
|
|
out.extend_from_slice(&self.next_sprite_indices);
|
|
}
|
|
|
|
pub fn load_state(&mut self, data: &[u8]) -> Result<usize, String> {
|
|
let mut cursor = 0usize;
|
|
self.vram.copy_from_slice(sio::take_exact(
|
|
data,
|
|
&mut cursor,
|
|
VRAM_SIZE,
|
|
PPU_STATE_CTX,
|
|
)?);
|
|
self.palette_ram.copy_from_slice(sio::take_exact(
|
|
data,
|
|
&mut cursor,
|
|
PALETTE_SIZE,
|
|
PPU_STATE_CTX,
|
|
)?);
|
|
self.oam
|
|
.copy_from_slice(sio::take_exact(data, &mut cursor, OAM_SIZE, PPU_STATE_CTX)?);
|
|
self.ctrl = sio::take_u8(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.mask = sio::take_u8(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.status = sio::take_u8(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.oam_addr = sio::take_u8(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.write_latch = sio::take_u8(data, &mut cursor, PPU_STATE_CTX)? != 0;
|
|
self.vram_addr = sio::take_u16(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.vram_addr &= 0x3FFF;
|
|
self.temp_addr = sio::take_u16(data, &mut cursor, PPU_STATE_CTX)? & 0x3FFF;
|
|
self.fine_x = sio::take_u8(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.scroll_x = sio::take_u8(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.scroll_y = sio::take_u8(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.read_buffer = sio::take_u8(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.io_latch = if cursor < data.len() {
|
|
sio::take_u8(data, &mut cursor, PPU_STATE_CTX)?
|
|
} else {
|
|
0
|
|
};
|
|
if cursor + 30 <= data.len() {
|
|
self.bg_shift_pattern_lo = sio::take_u16(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.bg_shift_pattern_hi = sio::take_u16(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.bg_shift_attr_lo = sio::take_u16(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.bg_shift_attr_hi = sio::take_u16(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.next_tile_id = sio::take_u8(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.next_tile_attr = sio::take_u8(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.next_tile_lsb = sio::take_u8(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.next_tile_msb = sio::take_u8(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.sprite_count = sio::take_u8(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.sprite_indices.copy_from_slice(sio::take_exact(
|
|
data,
|
|
&mut cursor,
|
|
8,
|
|
PPU_STATE_CTX,
|
|
)?);
|
|
self.next_sprite_count = sio::take_u8(data, &mut cursor, PPU_STATE_CTX)?;
|
|
self.next_sprite_indices.copy_from_slice(sio::take_exact(
|
|
data,
|
|
&mut cursor,
|
|
8,
|
|
PPU_STATE_CTX,
|
|
)?);
|
|
} else {
|
|
self.bg_shift_pattern_lo = 0;
|
|
self.bg_shift_pattern_hi = 0;
|
|
self.bg_shift_attr_lo = 0;
|
|
self.bg_shift_attr_hi = 0;
|
|
self.next_tile_id = 0;
|
|
self.next_tile_attr = 0;
|
|
self.next_tile_lsb = 0;
|
|
self.next_tile_msb = 0;
|
|
self.sprite_count = 0;
|
|
self.sprite_indices = [0; 8];
|
|
self.next_sprite_count = 0;
|
|
self.next_sprite_indices = [0; 8];
|
|
}
|
|
self.scroll_events.clear();
|
|
self.scroll_events.push(self.current_scroll_event(0, 0));
|
|
Ok(cursor)
|
|
}
|
|
}
|