From be4f9da380fe465d898491b269cd98f614befb26 Mon Sep 17 00:00:00 2001 From: Kevin Hamacher Date: Thu, 2 Jun 2016 13:21:45 +0200 Subject: [PATCH] Add savegame files --- src/cartridge.rs | 43 ++++++++++++++++++++++++++++++++++++------- src/interconnect.rs | 7 +++++-- src/main.rs | 44 +++++++++++++++++++++++++++++++------------- src/mbc/mbc.rs | 7 ++++++- src/mbc/mbc1.rs | 4 ++++ src/mbc/mbc2.rs | 4 ++++ src/mbc/mbc3.rs | 4 ++++ 7 files changed, 90 insertions(+), 23 deletions(-) diff --git a/src/cartridge.rs b/src/cartridge.rs index f373ffd..acbf4d6 100644 --- a/src/cartridge.rs +++ b/src/cartridge.rs @@ -19,10 +19,11 @@ enum RamSize { pub struct Cartridge { mbc: Box, + savefile: Option, } impl Cartridge { - pub fn new(rom: Box<[u8]>) -> Cartridge { + pub fn new(rom: Box<[u8]>, save_file: Option) -> Cartridge { let mbc_type: MemoryBankControllerType = match rom[0x0147] { 0x00 | 0x08 ... 0x09 => MemoryBankControllerType::None, 0x01 ... 0x03 => MemoryBankControllerType::MBC1, @@ -54,12 +55,7 @@ impl Cartridge { println!("Rom size: {} banks", rom_banks); println!("Ram size: {:?}", ram_size); - let ram = match ram_size { - RamSize::None => vec![0u8; 0].into_boxed_slice(), - RamSize::Ram2KB => vec![0u8; 2048].into_boxed_slice(), - RamSize::Ram8KB => vec![0u8; 4 * 2048].into_boxed_slice(), - RamSize::Ram32KB => vec![0u8; 16 * 2048].into_boxed_slice(), - }; + let ram = Cartridge::load_savefile(&save_file, ram_size); let mbc: Box = match mbc_type { MemoryBankControllerType::None => Box::new(super::mbc::mbc::NoMBC::new(rom, ram)), @@ -71,6 +67,39 @@ impl Cartridge { Cartridge { mbc: mbc, + savefile: save_file, + } + } + + fn load_savefile(save_file: &Option, ram_size: RamSize) -> Box<[u8]> { + let old_data; + let size = match ram_size { + RamSize::None => 0, + RamSize::Ram2KB => 2048, + RamSize::Ram8KB => 4 * 2048, + RamSize::Ram32KB => 16 * 2048, + }; + + if let &Some(ref filename) = save_file { + let data = super::read_file(&filename); + if let Ok(success) = data { + old_data = success + } else { + old_data = vec![0u8; size].into_boxed_slice(); + } + } else { + old_data = vec![0u8; size].into_boxed_slice(); + } + + old_data + } + + pub fn save(&self) { + if let &Some(ref fil) = &self.savefile { + self.mbc.dump_ram(fil); + println!("Ram dump updated.") + } else { + println!("Did not update ram dump"); } } diff --git a/src/interconnect.rs b/src/interconnect.rs index 075cfa3..c176fd4 100644 --- a/src/interconnect.rs +++ b/src/interconnect.rs @@ -59,13 +59,16 @@ pub struct Interconnect { joy_regular_keys: u8, joy_special_keys: u8, joy_switch: u8, + + // Used for polling SDL events + cycles: u16, } impl Interconnect { - pub fn new(bios: Box<[u8]>, rom: Box<[u8]>) -> Interconnect { + pub fn new(bios: Box<[u8]>, rom: Box<[u8]>, save_file: Option) -> Interconnect { Interconnect { bios: bios, - cartridge: cartridge::Cartridge::new(rom), + cartridge: cartridge::Cartridge::new(rom, save_file), ram: vec![0; WRAM_SIZE].into_boxed_slice(), hiram: vec![0; HIRAM_SIZE].into_boxed_slice(), wram_bank: 1, diff --git a/src/main.rs b/src/main.rs index fff59b7..fc90f43 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,9 @@ // gameboy (color?) use std::path::Path; +use std::io; use std::io::Read; +use std::io::Write; use std::fs; use std::env; @@ -17,23 +19,39 @@ mod mbc; fn main() { - let bios_path = env::args().nth(1).unwrap(); - let rom_path = env::args().nth(2).unwrap(); - let bios = read_rom(&bios_path); - let rom = read_rom(&rom_path); + let args: Vec = env::args().collect(); + if args.len() < 3 || args.len() > 4 { + println!("Usage: {} bios game [savefile]", args[0]); + } else { + let bios_path = &args[1]; + let rom_path = &args[2]; + let mut save_file: Option = None; + if args.len() == 4 { + save_file = Some(args[3].clone()); + } - // Now we need to execute commands - let interconnect = interconnect::Interconnect::new(bios, rom); - let mut cpu = cpu::CPU::new(interconnect); + let bios = read_file(&bios_path).unwrap(); + let rom = read_file(&rom_path).unwrap(); - loop { - cpu.run_instruction(); + // Now we need to execute commands + let interconnect = interconnect::Interconnect::new(bios, rom, save_file); + let mut cpu = cpu::CPU::new(interconnect); + + loop { + cpu.run(); + } } } -fn read_rom>(rom_path: P) -> Box<[u8]> { - let mut file = fs::File::open(rom_path).unwrap(); +pub fn read_file>(rom_path: P) -> Result, io::Error> { + let mut file = try!(fs::File::open(rom_path)); let mut buf = Vec::new(); - file.read_to_end(&mut buf).expect("Reading file failed"); - buf.into_boxed_slice() + try!(file.read_to_end(&mut buf)); + Ok(buf.into_boxed_slice()) +} + +pub fn write_file>(path: P, data: &Box<[u8]>) -> Result<(), io::Error> { + let mut file = try!(fs::File::create(path)); + try!(file.write(&data)); + Ok(()) } diff --git a/src/mbc/mbc.rs b/src/mbc/mbc.rs index 27e3e2d..50506e2 100644 --- a/src/mbc/mbc.rs +++ b/src/mbc/mbc.rs @@ -1,6 +1,8 @@ pub trait MBC { fn read_byte(&self, addr: u16) -> u8; fn write_byte(&mut self, addr: u16, val: u8); + + fn dump_ram(&self, file: &String); } pub struct NoMBC { @@ -10,7 +12,6 @@ pub struct NoMBC { impl NoMBC { pub fn new(rom: Box<[u8]>, ram: Box<[u8]>) -> NoMBC { - NoMBC { rom: rom, ram: ram, @@ -19,6 +20,10 @@ impl NoMBC { } impl MBC for NoMBC { + fn dump_ram(&self, file: &String){ + super::super::write_file(&file, &self.ram).expect("Saving failed"); + } + fn write_byte(&mut self, addr: u16, val: u8) { println!("Writing not supported for cartridges without MBC. (Tried to set {:04X} to {:02X})", addr, val); } diff --git a/src/mbc/mbc1.rs b/src/mbc/mbc1.rs index c49932c..2fc029e 100644 --- a/src/mbc/mbc1.rs +++ b/src/mbc/mbc1.rs @@ -43,6 +43,10 @@ impl MBC1 { } impl MBC for MBC1 { + fn dump_ram(&self, file: &String){ + super::super::write_file(&file, &self.ram).expect("Saving failed"); + } + fn read_byte(&self, addr: u16) -> u8 { match addr { 0x0000 ... 0x3FFF => self.rom[addr as usize], diff --git a/src/mbc/mbc2.rs b/src/mbc/mbc2.rs index 7728e3b..8a53c0b 100644 --- a/src/mbc/mbc2.rs +++ b/src/mbc/mbc2.rs @@ -23,6 +23,10 @@ impl MBC2 { } impl MBC for MBC2 { + fn dump_ram(&self, file: &String){ + super::super::write_file(&file, &self.ram).expect("Saving failed"); + } + fn read_byte(&self, addr: u16) -> u8 { match addr { 0x0000 ... 0x3FFF => self.rom[addr as usize], diff --git a/src/mbc/mbc3.rs b/src/mbc/mbc3.rs index 4c1c229..07aacf2 100644 --- a/src/mbc/mbc3.rs +++ b/src/mbc/mbc3.rs @@ -29,6 +29,10 @@ impl MBC3 { } impl MBC for MBC3 { + fn dump_ram(&self, file: &String){ + super::super::write_file(&file, &self.ram).expect("Saving failed"); + } + fn read_byte(&self, addr: u16) -> u8 { match addr { 0x0000 ... 0x3FFF => self.rom[addr as usize],