Initial commit: NES emulator with GTK4 desktop frontend
Some checks failed
CI / rust (push) Has been cancelled
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.
This commit is contained in:
108
src/native_core/ppu/api/persistence.rs
Normal file
108
src/native_core/ppu/api/persistence.rs
Normal file
@@ -0,0 +1,108 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user