Skip to content

Commit

Permalink
Support saves
Browse files Browse the repository at this point in the history
  • Loading branch information
nathsou committed Jul 1, 2023
1 parent 68f6771 commit 440bb8d
Show file tree
Hide file tree
Showing 16 changed files with 424 additions and 36 deletions.
16 changes: 16 additions & 0 deletions crate/src/bus/controller.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use bitflags::bitflags;

use crate::savestate::{Save, SaveState};

bitflags! {
#[derive(Copy, Clone)]
pub struct JoypadStatus: u8 {
Expand Down Expand Up @@ -63,3 +65,17 @@ impl Joypad {
*self.status.0.bits_mut() = val;
}
}

impl Save for Joypad {
fn save(&self, s: &mut SaveState) {
s.write_bool(self.strobe);
s.write_u8(self.index);
s.write_u8(self.status.bits());
}

fn load(&mut self, s: &mut SaveState) {
self.strobe = s.read_bool();
self.index = s.read_u8();
self.update(s.read_u8());
}
}
23 changes: 21 additions & 2 deletions crate/src/bus/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use self::controller::Joypad;
use super::ppu::PPU;
use crate::cpu::{memory::Memory, rom::ROM};
use crate::{
cpu::{memory::Memory, rom::ROM},
savestate::{Save, SaveState},
};
pub mod controller;

#[allow(clippy::upper_case_acronyms)]
Expand Down Expand Up @@ -56,7 +59,7 @@ impl Bus {
}
}

pub fn advance_ppu(&mut self, frame: &mut [u8], cpu_cycles: usize) {
pub fn advance_ppu(&mut self, frame: &mut [u8], cpu_cycles: u32) {
let ppu_cycles = cpu_cycles * 3;

for _ in 0..ppu_cycles {
Expand Down Expand Up @@ -111,3 +114,19 @@ impl Memory for Bus {
}
}
}

impl Save for Bus {
fn save(&self, s: &mut SaveState) {
s.write_slice(&self.ram.ram);
self.ppu.save(s);
self.joypad1.save(s);
s.write_bool(self.dma_transfer);
}

fn load(&mut self, s: &mut SaveState) {
s.read_slice(&mut self.ram.ram);
self.ppu.load(s);
self.joypad1.load(s);
self.dma_transfer = s.read_bool();
}
}
4 changes: 2 additions & 2 deletions crate/src/cpu/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const NMI_VECTOR: u16 = 0xfffa;
const IRQ_VECTOR: u16 = 0xfffe;

impl CPU {
pub fn step(&mut self) -> usize {
pub fn step(&mut self) -> u32 {
self.instr_cycles = 0;

if self.bus.dma_transfer {
Expand Down Expand Up @@ -223,7 +223,7 @@ impl CPU {
}

#[allow(dead_code)]
pub fn trace_step(&mut self) -> (usize, String) {
pub fn trace_step(&mut self) -> (u32, String) {
let op_code = self.bus.read_byte(self.pc) as usize;
let inst_name = INST_NAMES[op_code].unwrap_or("???");
let addr_mode = AddressingMode::from(INST_ADDR_MODES[op_code]);
Expand Down
31 changes: 30 additions & 1 deletion crate/src/cpu/mappers/mmc1.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::cpu::rom::{Cart, Mirroring};
use crate::{
cpu::rom::{Cart, Mirroring},
savestate::{Save, SaveState},
};

use super::Mapper;

Expand Down Expand Up @@ -157,3 +160,29 @@ impl MMC1 {
};
}
}

impl Save for MMC1 {
fn save(&self, s: &mut SaveState) {
s.write_slice(&self.prg_ram);
s.write_slice(&self.chr_ram);
s.write_u8(self.shift_reg);
s.write_u8(self.control);
s.write_u8(self.prg_mode);
s.write_u8(self.chr_mode);
s.write_u8(self.chr_bank0);
s.write_u8(self.chr_bank1);
s.write_u8(self.prg_bank);
}

fn load(&mut self, s: &mut SaveState) {
s.read_slice(&mut self.prg_ram);
s.read_slice(&mut self.chr_ram);
self.shift_reg = s.read_u8();
self.control = s.read_u8();
self.prg_mode = s.read_u8();
self.chr_mode = s.read_u8();
self.chr_bank0 = s.read_u8();
self.chr_bank1 = s.read_u8();
self.prg_bank = s.read_u8();
}
}
4 changes: 3 additions & 1 deletion crate/src/cpu/mappers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use crate::savestate::Save;

use super::rom::Cart;

pub mod mmc1;
pub mod nrom;
pub mod unrom;

pub trait Mapper {
pub trait Mapper: Save {
fn read(&mut self, cart: &mut Cart, addr: u16) -> u8;
fn write(&mut self, cart: &mut Cart, addr: u16, val: u8);

Expand Down
15 changes: 14 additions & 1 deletion crate/src/cpu/mappers/nrom.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::cpu::rom::Cart;
use crate::{
cpu::rom::Cart,
savestate::{Save, SaveState},
};

use super::Mapper;

Expand Down Expand Up @@ -52,3 +55,13 @@ impl Mapper for NROM {
}
}
}

impl Save for NROM {
fn save(&self, s: &mut SaveState) {
s.write_slice(&self.ram);
}

fn load(&mut self, s: &mut SaveState) {
s.read_slice(&mut self.ram);
}
}
19 changes: 18 additions & 1 deletion crate/src/cpu/mappers/unrom.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::cpu::rom::Cart;
use crate::{
cpu::rom::Cart,
savestate::{Save, SaveState},
};

use super::Mapper;

Expand Down Expand Up @@ -68,3 +71,17 @@ impl Mapper for UNROM {
}
}
}

impl Save for UNROM {
fn save(&self, s: &mut SaveState) {
s.write_slice(&self.prg_ram);
s.write_slice(&self.chr_ram);
s.write_u8(self.bank);
}

fn load(&mut self, s: &mut SaveState) {
s.read_slice(&mut self.prg_ram);
s.read_slice(&mut self.chr_ram);
self.bank = s.read_u8();
}
}
38 changes: 34 additions & 4 deletions crate/src/cpu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ pub mod rom;

use bitflags::bitflags;

use crate::savestate::{Save, SaveState};

use self::memory::Memory;
use super::bus::Bus;
use std::fmt;
Expand Down Expand Up @@ -61,11 +63,11 @@ pub struct CPU {
y: u8,
pub pc: u16,
sp: u8,
instr_cycles: usize,
total_cycles: usize,
instr_cycles: u32,
total_cycles: u32,
status: Status,
pub bus: Bus,
stall: usize,
stall: u32,
}

impl CPU {
Expand All @@ -86,7 +88,7 @@ impl CPU {
}
}

fn reset(&mut self) {
pub fn reset(&mut self) {
self.a = 0;
self.x = 0;
self.y = 0;
Expand Down Expand Up @@ -320,3 +322,31 @@ impl fmt::Debug for CPU {
)
}
}

impl Save for CPU {
fn save(&self, s: &mut SaveState) {
s.write_u8(self.a);
s.write_u8(self.x);
s.write_u8(self.y);
s.write_u16(self.pc);
s.write_u8(self.sp);
s.write_u32(self.instr_cycles);
s.write_u32(self.total_cycles);
s.write_u8(self.status.bits());
s.write_u32(self.stall);
self.bus.save(s);
}

fn load(&mut self, s: &mut SaveState) {
self.a = s.read_u8();
self.x = s.read_u8();
self.y = s.read_u8();
self.pc = s.read_u16();
self.sp = s.read_u8();
self.instr_cycles = s.read_u32();
self.total_cycles = s.read_u32();
*self.status.0.bits_mut() = s.read_u8();
self.stall = s.read_u32();
self.bus.load(s);
}
}
2 changes: 1 addition & 1 deletion crate/src/cpu/opcodes.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub const INST_CYCLES: [usize; 256] = [
pub const INST_CYCLES: [u32; 256] = [
7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6, 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7,
Expand Down
2 changes: 2 additions & 0 deletions crate/src/cpu/rom.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::savestate::Save;

use super::mappers::mmc1::MMC1;
use super::mappers::nrom::NROM;
use super::mappers::unrom::UNROM;
Expand Down
27 changes: 20 additions & 7 deletions crate/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ mod cpu;
mod js;
mod nes;
mod ppu;
use bus::controller::JoypadStatus;
use cfg_if::cfg_if;
use cpu::rom::ROM;
use nes::Nes;
mod savestate;
extern crate console_error_panic_hook;
use savestate::{Save, SaveState};
use wasm_bindgen::prelude::wasm_bindgen;

cfg_if! {
Expand All @@ -24,22 +25,34 @@ pub fn create_console(rom: Vec<u8>) -> Nes {
Nes::new(rom)
}

#[wasm_bindgen(js_name = resetConsole)]
pub fn reset_console(console: &mut Nes) {
console.reset();
}

#[wasm_bindgen(js_name = nextFrame)]
pub fn next_frame(console: &mut Nes, buffer: &mut [u8]) {
console.next_frame(buffer);
}

#[wasm_bindgen(js_name = updateJoypad1)]
pub fn update_joypad1(console: &mut Nes, button: u8, pressed: bool) {
let btn = JoypadStatus::from_bits(button).unwrap();
console.joypad1().update_button_state(btn, pressed);
}

#[wasm_bindgen(js_name = setJoypad1)]
pub fn set_joypad1(console: &mut Nes, buttons: u8) {
console.joypad1().update(buttons);
}

#[wasm_bindgen(js_name = saveState)]
pub fn save_state(console: &mut Nes) -> Vec<u8> {
let mut state = SaveState::new();
console.save(&mut state);
state.get_data()
}

#[wasm_bindgen(js_name = loadState)]
pub fn load_state(console: &mut Nes, data: Vec<u8>) {
let mut state = SaveState::from(data);
console.load(&mut state);
}

#[cfg(test)]
mod tests {
use std::fs::File;
Expand Down
15 changes: 15 additions & 0 deletions crate/src/nes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use wasm_bindgen::prelude::wasm_bindgen;
use crate::{
bus::{controller::Joypad, Bus},
cpu::{rom::ROM, CPU},
savestate::{Save, SaveState},
};

#[wasm_bindgen]
Expand Down Expand Up @@ -30,6 +31,10 @@ impl Nes {
self.cpu.bus.ppu.frame_complete = false;
}

pub fn reset(&mut self) {
self.cpu.reset();
}

#[inline]
pub fn joypad1(&mut self) -> &mut Joypad {
&mut self.cpu.bus.joypad1
Expand All @@ -46,3 +51,13 @@ impl Nes {
format!("{cpu_trace}|{ppu_trace}")
}
}

impl Save for Nes {
fn save(&self, s: &mut SaveState) {
self.cpu.save(s);
}

fn load(&mut self, s: &mut SaveState) {
self.cpu.load(s);
}
}
Loading

0 comments on commit 440bb8d

Please sign in to comment.