diff --git a/src/cartridge/cnrom.rs b/src/cartridge/cnrom.rs index ce399e3..bc6a790 100644 --- a/src/cartridge/cnrom.rs +++ b/src/cartridge/cnrom.rs @@ -1,4 +1,4 @@ -use super::{Cartridge, Mapper, Mirror}; +use super::{Cartridge, Mapper, Mirror, serialize::*}; pub struct Cnrom { cart: Cartridge, @@ -41,4 +41,20 @@ impl Mapper for Cnrom { fn save_battery_backed_ram(&self) {} fn clock(&mut self) {} fn check_irq(&mut self) -> bool {false} + + fn save_state(&self) -> MapperData { + MapperData::Cnrom( + CnromData { + cart: self.cart.clone(), + chr_bank_select: self.chr_bank_select, + } + ) + } + + fn load_state(&mut self, mapper_data: MapperData) { + if let MapperData::Cnrom(cnrom_data) = mapper_data { + self.cart = cnrom_data.cart; + self.chr_bank_select = cnrom_data.chr_bank_select; + } + } } diff --git a/src/cartridge/mmc1.rs b/src/cartridge/mmc1.rs index 24a26a1..08e25ba 100644 --- a/src/cartridge/mmc1.rs +++ b/src/cartridge/mmc1.rs @@ -1,4 +1,4 @@ -use super::{Cartridge, Mapper, Mirror}; +use super::{Cartridge, Mapper, Mirror, serialize::*}; use std::fs::File; use std::io::{Read, Write}; @@ -210,4 +210,42 @@ impl Mapper for Mmc1 { fn clock(&mut self) {} fn check_irq(&mut self) -> bool {false} + + fn save_state(&self) -> MapperData { + MapperData::Mmc1( + Mmc1Data { + cart: self.cart.clone(), + step: self.step, + shift_register: self.shift_register, + mirroring: self.mirroring, + control: self.control, + prg_ram_bank: self.prg_ram_bank.clone(), + prg_ram_enabled: self.prg_ram_enabled, + prg_bank_mode: self.prg_bank_mode, + prg_bank_select: self.prg_bank_select, + chr_ram_bank: self.chr_ram_bank.clone(), + chr_low_bank: self.chr_low_bank, + chr_high_bank: self.chr_high_bank, + chr_bank_mode: self.chr_bank_mode, + } + ) + } + + fn load_state(&mut self, mapper_data: MapperData) { + if let MapperData::Mmc1(mmc1_data) = mapper_data { + self.cart = mmc1_data.cart; + self.step = mmc1_data.step; + self.shift_register = mmc1_data.shift_register; + self.mirroring = mmc1_data.mirroring; + self.control = mmc1_data.control; + self.prg_ram_bank = mmc1_data.prg_ram_bank; + self.prg_ram_enabled = mmc1_data.prg_ram_enabled; + self.prg_bank_mode = mmc1_data.prg_bank_mode; + self.prg_bank_select = mmc1_data.prg_bank_select; + self.chr_ram_bank = mmc1_data.chr_ram_bank; + self.chr_low_bank = mmc1_data.chr_low_bank; + self.chr_high_bank = mmc1_data.chr_high_bank; + self.chr_bank_mode = mmc1_data.chr_bank_mode; + } + } } diff --git a/src/cartridge/mmc3.rs b/src/cartridge/mmc3.rs index a0995ee..218651e 100644 --- a/src/cartridge/mmc3.rs +++ b/src/cartridge/mmc3.rs @@ -1,4 +1,4 @@ -use super::{Cartridge, Mapper, Mirror}; +use super::{Cartridge, Mapper, Mirror, serialize::*}; pub struct Mmc3 { cart: Cartridge, @@ -222,4 +222,44 @@ impl Mapper for Mmc3 { } false } + + fn save_state(&self) -> MapperData { + MapperData::Mmc3( + Mmc3Data { + cart: self.cart.clone(), + mirroring: self.mirroring, + bank_registers: self.bank_registers.clone(), + next_bank: self.next_bank, + irq_latch: self.irq_latch, + irq_counter: self.irq_counter, + irq_enable: self.irq_enable, + trigger_irq: self.trigger_irq, + reload_counter: self.reload_counter, + irq_delay: self.irq_delay, + prg_ram_bank: self.prg_ram_bank.clone(), + prg_rom_bank_mode: self.prg_rom_bank_mode, + chr_rom_bank_mode: self.chr_rom_bank_mode, + chr_ram_bank: self.chr_ram_bank.clone(), + } + ) + } + + fn load_state(&mut self, mapper_data: MapperData) { + if let MapperData::Mmc3(mmc3_data) = mapper_data { + self.cart = mmc3_data.cart; + self.mirroring = mmc3_data.mirroring; + self.bank_registers = mmc3_data.bank_registers; + self.next_bank = mmc3_data.next_bank; + self.irq_latch = mmc3_data.irq_latch; + self.irq_counter = mmc3_data.irq_counter; + self.irq_enable = mmc3_data.irq_enable; + self.trigger_irq = mmc3_data.trigger_irq; + self.reload_counter = mmc3_data.reload_counter; + self.irq_delay = mmc3_data.irq_delay; + self.prg_ram_bank = mmc3_data.prg_ram_bank; + self.prg_rom_bank_mode = mmc3_data.prg_rom_bank_mode; + self.chr_rom_bank_mode = mmc3_data.chr_rom_bank_mode; + self.chr_ram_bank = mmc3_data.chr_ram_bank; + } + } } diff --git a/src/cartridge/mod.rs b/src/cartridge/mod.rs index 1059c0c..c933ef9 100644 --- a/src/cartridge/mod.rs +++ b/src/cartridge/mod.rs @@ -3,6 +3,7 @@ mod mmc1; mod uxrom; mod cnrom; mod mmc3; +pub mod serialize; use nrom::Nrom; use mmc1::Mmc1; @@ -12,8 +13,6 @@ use mmc3::Mmc3; use std::cell::RefCell; use std::fs::File; -use std::io; -use std::io::prelude::*; use std::io::Read; use std::rc::Rc; @@ -25,9 +24,11 @@ pub trait Mapper { fn save_battery_backed_ram(&self); fn clock(&mut self); fn check_irq(&mut self) -> bool; + fn save_state(&self) -> serialize::MapperData; + fn load_state(&mut self, mapper_data: serialize::MapperData); } -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)] pub enum Mirror { LowBank, HighBank, @@ -49,6 +50,7 @@ pub fn get_mapper(filename: String) -> Rc> { } } +#[derive(Clone, serde::Serialize, serde::Deserialize)] pub struct Cartridge { filename: String, prg_rom_size: usize, diff --git a/src/cartridge/nrom.rs b/src/cartridge/nrom.rs index 881cc18..4246e95 100644 --- a/src/cartridge/nrom.rs +++ b/src/cartridge/nrom.rs @@ -1,4 +1,4 @@ -use super::{Cartridge, Mapper, Mirror}; +use super::{Cartridge, Mapper, Mirror, serialize::*}; pub struct Nrom { cart: Cartridge, @@ -57,4 +57,20 @@ impl Mapper for Nrom { fn save_battery_backed_ram(&self) {} fn clock(&mut self) {} fn check_irq(&mut self) -> bool {false} + + fn save_state(&self) -> MapperData { + MapperData::Nrom( + NromData { + cart: self.cart.clone(), + chr_ram: self.chr_ram.clone(), + } + ) + } + + fn load_state(&mut self, mapper_data: MapperData) { + if let MapperData::Nrom(nrom_data) = mapper_data { + self.cart = nrom_data.cart; + self.chr_ram = nrom_data.chr_ram; + } + } } diff --git a/src/cartridge/serialize.rs b/src/cartridge/serialize.rs new file mode 100644 index 0000000..c00e1c8 --- /dev/null +++ b/src/cartridge/serialize.rs @@ -0,0 +1,65 @@ +use super::{Cartridge, Mirror}; + +#[derive(serde::Serialize, serde::Deserialize)] +pub enum MapperData { + Nrom(NromData), + Mmc1(Mmc1Data), + Uxrom(UxromData), + Cnrom(CnromData), + Mmc3(Mmc3Data), +} + + +#[derive(serde::Serialize, serde::Deserialize)] +pub struct NromData { + pub cart: Cartridge, + pub chr_ram: Vec, +} + +#[derive(serde::Serialize, serde::Deserialize)] +pub struct Mmc1Data { + pub cart: Cartridge, + pub step: u8, + pub shift_register: u8, + pub mirroring: Mirror, + pub control: u8, + pub prg_ram_bank: Vec, + pub prg_ram_enabled: bool, + pub prg_bank_mode: u8, + pub prg_bank_select: usize, + pub chr_ram_bank: Vec, + pub chr_low_bank: usize, + pub chr_high_bank: usize, + pub chr_bank_mode: bool, +} + +#[derive(serde::Serialize, serde::Deserialize)] +pub struct UxromData { + pub cart: Cartridge, + pub chr_ram: Vec, + pub bank_select: usize, +} + +#[derive(serde::Serialize, serde::Deserialize)] +pub struct CnromData { + pub cart: Cartridge, + pub chr_bank_select: usize, +} + +#[derive(serde::Serialize, serde::Deserialize)] +pub struct Mmc3Data { + pub cart: Cartridge, + pub mirroring: Mirror, + pub bank_registers: Vec, + pub next_bank: u8, + pub irq_latch: u8, + pub irq_counter: u8, + pub irq_enable: bool, + pub trigger_irq: bool, + pub reload_counter: bool, + pub irq_delay: u8, + pub prg_ram_bank: Vec, + pub prg_rom_bank_mode: bool, + pub chr_rom_bank_mode: bool, + pub chr_ram_bank: Vec, +} diff --git a/src/cartridge/uxrom.rs b/src/cartridge/uxrom.rs index c660bda..1e38dd7 100644 --- a/src/cartridge/uxrom.rs +++ b/src/cartridge/uxrom.rs @@ -1,4 +1,4 @@ -use super::{Cartridge, Mapper, Mirror}; +use super::{Cartridge, Mapper, Mirror, serialize::*}; pub struct Uxrom { cart: Cartridge, @@ -52,4 +52,22 @@ impl Mapper for Uxrom { fn save_battery_backed_ram(&self) {} fn clock(&mut self) {} fn check_irq(&mut self) -> bool {false} + + fn save_state(&self) -> MapperData { + MapperData::Uxrom( + UxromData { + cart: self.cart.clone(), + chr_ram: self.chr_ram.clone(), + bank_select: self.bank_select, + } + ) + } + + fn load_state(&mut self, mapper_data: MapperData) { + if let MapperData::Uxrom(uxrom_data) = mapper_data { + self.cart = uxrom_data.cart; + self.chr_ram = uxrom_data.chr_ram; + self.bank_select = uxrom_data.bank_select; + } + } } diff --git a/src/cpu/mod.rs b/src/cpu/mod.rs index 9a3252b..0862895 100644 --- a/src/cpu/mod.rs +++ b/src/cpu/mod.rs @@ -65,7 +65,7 @@ pub struct Cpu { clock: u64, // number of ticks in current cycle delay: usize, // for skipping cycles during OAM DMA - mapper: Rc>, // cartridge data + pub mapper: Rc>, // cartridge data pub ppu: super::Ppu, pub apu: super::Apu, @@ -301,36 +301,36 @@ $4020-$FFFF $BFE0 Cartridge space: PRG ROM, PRG RAM, and mapper registers (See // For debug output const _OPCODE_DISPLAY_NAMES: [&str; 256] = [ - "BRK", "ORA", "BAD", "SLO", "NOP", "ORA", "ASL", "SLO", - "PHP", "ORA", "ASL", "ANC", "NOP", "ORA", "ASL", "SLO", - "BPL", "ORA", "BAD", "SLO", "NOP", "ORA", "ASL", "SLO", - "CLC", "ORA", "NOP", "SLO", "NOP", "ORA", "ASL", "SLO", - "JSR", "AND", "BAD", "RLA", "BIT", "AND", "ROL", "RLA", - "PLP", "AND", "ROL", "ANC", "BIT", "AND", "ROL", "RLA", - "BMI", "AND", "BAD", "RLA", "NOP", "AND", "ROL", "RLA", - "SEC", "AND", "NOP", "RLA", "NOP", "AND", "ROL", "RLA", - "RTI", "EOR", "BAD", "SRE", "NOP", "EOR", "LSR", "SRE", - "PHA", "EOR", "LSR", "ALR", "JMP", "EOR", "LSR", "SRE", - "BVC", "EOR", "BAD", "SRE", "NOP", "EOR", "LSR", "SRE", - "CLI", "EOR", "NOP", "SRE", "NOP", "EOR", "LSR", "SRE", - "RTS", "ADC", "BAD", "RRA", "NOP", "ADC", "ROR", "RRA", - "PLA", "ADC", "ROR", "ARR", "JMP", "ADC", "ROR", "RRA", - "BVS", "ADC", "BAD", "RRA", "NOP", "ADC", "ROR", "RRA", - "SEI", "ADC", "NOP", "RRA", "NOP", "ADC", "ROR", "RRA", - "NOP", "STA", "NOP", "SAX", "STY", "STA", "STX", "SAX", - "DEY", "NOP", "TXA", "XAA", "STY", "STA", "STX", "SAX", - "BCC", "STA", "BAD", "AHX", "STY", "STA", "STX", "SAX", - "TYA", "STA", "TXS", "TAS", "SHY", "STA", "SHX", "AHX", - "LDY", "LDA", "LDX", "LAX", "LDY", "LDA", "LDX", "LAX", - "TAY", "LDA", "TAX", "LAX", "LDY", "LDA", "LDX", "LAX", - "BCS", "LDA", "BAD", "LAX", "LDY", "LDA", "LDX", "LAX", - "CLV", "LDA", "TSX", "LAS", "LDY", "LDA", "LDX", "LAX", - "CPY", "CMP", "NOP", "DCP", "CPY", "CMP", "DEC", "DCP", - "INY", "CMP", "DEX", "AXS", "CPY", "CMP", "DEC", "DCP", - "BNE", "CMP", "BAD", "DCP", "NOP", "CMP", "DEC", "DCP", - "CLD", "CMP", "NOP", "DCP", "NOP", "CMP", "DEC", "DCP", - "CPX", "SBC", "NOP", "ISC", "CPX", "SBC", "INC", "ISC", - "INX", "SBC", "NOP", "SBC", "CPX", "SBC", "INC", "ISC", - "BEQ", "SBC", "BAD", "ISC", "NOP", "SBC", "INC", "ISC", + "BRK", "ORA", "BAD", "SLO", "NOP", "ORA", "ASL", "SLO", + "PHP", "ORA", "ASL", "ANC", "NOP", "ORA", "ASL", "SLO", + "BPL", "ORA", "BAD", "SLO", "NOP", "ORA", "ASL", "SLO", + "CLC", "ORA", "NOP", "SLO", "NOP", "ORA", "ASL", "SLO", + "JSR", "AND", "BAD", "RLA", "BIT", "AND", "ROL", "RLA", + "PLP", "AND", "ROL", "ANC", "BIT", "AND", "ROL", "RLA", + "BMI", "AND", "BAD", "RLA", "NOP", "AND", "ROL", "RLA", + "SEC", "AND", "NOP", "RLA", "NOP", "AND", "ROL", "RLA", + "RTI", "EOR", "BAD", "SRE", "NOP", "EOR", "LSR", "SRE", + "PHA", "EOR", "LSR", "ALR", "JMP", "EOR", "LSR", "SRE", + "BVC", "EOR", "BAD", "SRE", "NOP", "EOR", "LSR", "SRE", + "CLI", "EOR", "NOP", "SRE", "NOP", "EOR", "LSR", "SRE", + "RTS", "ADC", "BAD", "RRA", "NOP", "ADC", "ROR", "RRA", + "PLA", "ADC", "ROR", "ARR", "JMP", "ADC", "ROR", "RRA", + "BVS", "ADC", "BAD", "RRA", "NOP", "ADC", "ROR", "RRA", + "SEI", "ADC", "NOP", "RRA", "NOP", "ADC", "ROR", "RRA", + "NOP", "STA", "NOP", "SAX", "STY", "STA", "STX", "SAX", + "DEY", "NOP", "TXA", "XAA", "STY", "STA", "STX", "SAX", + "BCC", "STA", "BAD", "AHX", "STY", "STA", "STX", "SAX", + "TYA", "STA", "TXS", "TAS", "SHY", "STA", "SHX", "AHX", + "LDY", "LDA", "LDX", "LAX", "LDY", "LDA", "LDX", "LAX", + "TAY", "LDA", "TAX", "LAX", "LDY", "LDA", "LDX", "LAX", + "BCS", "LDA", "BAD", "LAX", "LDY", "LDA", "LDX", "LAX", + "CLV", "LDA", "TSX", "LAS", "LDY", "LDA", "LDX", "LAX", + "CPY", "CMP", "NOP", "DCP", "CPY", "CMP", "DEC", "DCP", + "INY", "CMP", "DEX", "AXS", "CPY", "CMP", "DEC", "DCP", + "BNE", "CMP", "BAD", "DCP", "NOP", "CMP", "DEC", "DCP", + "CLD", "CMP", "NOP", "DCP", "NOP", "CMP", "DEC", "DCP", + "CPX", "SBC", "NOP", "ISC", "CPX", "SBC", "INC", "ISC", + "INX", "SBC", "NOP", "SBC", "CPX", "SBC", "INC", "ISC", + "BEQ", "SBC", "BAD", "ISC", "NOP", "SBC", "INC", "ISC", "SED", "SBC", "NOP", "ISC", "NOP", "SBC", "INC", "ISC", ]; diff --git a/src/main.rs b/src/main.rs index 9dfd272..aef22ca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,8 +63,13 @@ fn main() -> Result<(), String> { Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => return Ok(()), Event::DropFile{ filename: f, .. } => { - name = f; - break 'waiting; + match check_signature(&f) { + Ok(()) => { + name = f; + break 'waiting; + }, + Err(e) => println!("{}", e), + } }, _ => (), // println!("event: {:?}", event), } @@ -210,7 +215,7 @@ fn process_events(event_pump: &mut EventPump, filepath: &PathBuf, cpu: &mut Cpu) res.unwrap(); // } else if f.len() > 4 && &f[f.len()-4..] == ".nes" { } else { - match cartridge::check_signature(&f) { + match check_signature(&f) { Ok(()) => return GameExitMode::NewGame(f), Err(e) => println!("{}", e), } diff --git a/src/state.rs b/src/state.rs index be794ce..5106f13 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,17 +1,18 @@ use super::cpu; use super::ppu; use super::apu; +use super::cartridge; use std::fs::File; use std::io::{Read, Write}; use std::path::{Path, PathBuf}; -use serde::{Serialize, Deserialize}; -#[derive(Serialize, Deserialize)] +#[derive(serde::Serialize, serde::Deserialize)] struct SaveState { cpu: cpu::serialize::CpuData, ppu: ppu::serialize::PpuData, apu: apu::serialize::ApuData, + mapper: cartridge::serialize::MapperData, } pub fn save_state(cpu: &cpu::Cpu, save_file: &PathBuf) -> Result<(), String> { @@ -19,6 +20,7 @@ pub fn save_state(cpu: &cpu::Cpu, save_file: &PathBuf) -> Result<(), String> { cpu: cpu.save_state(), ppu: cpu.ppu.save_state(), apu: cpu.apu.save_state(), + mapper: cpu.mapper.borrow().save_state(), }; let serialized = serde_json::to_string(&data) .map_err(|e| e.to_string())?; @@ -44,6 +46,7 @@ pub fn load_state(cpu: &mut cpu::Cpu, save_file: &PathBuf) -> Result<(), String> cpu.load_state(state.cpu); cpu.ppu.load_state(state.ppu); cpu.apu.load_state(state.apu); + cpu.mapper.borrow_mut().load_state(state.mapper); println!("loading save state from file: {:?}", save_file); Ok(()) } else {