Files
nesemu/src/native_core/ppu/api/persistence.rs
se.cherkasov bdf23de8db
Some checks failed
CI / rust (push) Has been cancelled
Initial commit: NES emulator with GTK4 desktop frontend
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.
2026-03-13 11:48:45 +03:00

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)
}
}