Support zip files and add --no-framerate-limit

Former-commit-id: 62a7122fb0b3e832eeb3cbf347a0966e4cd32d50
This commit is contained in:
Michel Heily 2019-09-11 21:26:40 +03:00
parent fa211fa77e
commit 7cc1a50d12
6 changed files with 55 additions and 19 deletions

View file

@ -21,6 +21,7 @@ minifb = "0.11.2"
time = "0.1.42" time = "0.1.42"
bitfield = "0.13.1" bitfield = "0.13.1"
bitflags = "1.1.0" bitflags = "1.1.0"
zip = "0.5.3"
[profile.dev] [profile.dev]
opt-level = 1 opt-level = 1

View file

@ -16,6 +16,9 @@ args:
- skip_bios: - skip_bios:
long: skip-bios long: skip-bios
help: Skip running bios and start from the ROM instead help: Skip running bios and start from the ROM instead
- no_framerate_limit:
long: no-framerate-limit
help: Run without frame limiter
- backend: - backend:
long: backend long: backend
takes_value: true takes_value: true

View file

@ -1,8 +1,14 @@
use std::time; use std::time;
use std::fs::File;
use std::path::Path;
use std::ffi::OsStr;
use std::io::prelude::*;
#[macro_use] #[macro_use]
extern crate clap; extern crate clap;
extern crate zip;
use clap::{App, ArgMatches}; use clap::{App, ArgMatches};
extern crate rustboyadvance_ng; extern crate rustboyadvance_ng;
@ -10,19 +16,35 @@ extern crate rustboyadvance_ng;
use rustboyadvance_ng::backend::*; use rustboyadvance_ng::backend::*;
use rustboyadvance_ng::core::arm7tdmi::Core; use rustboyadvance_ng::core::arm7tdmi::Core;
use rustboyadvance_ng::core::cartridge::Cartridge; use rustboyadvance_ng::core::cartridge::Cartridge;
use rustboyadvance_ng::core::{GBAResult, GameBoyAdvance}; use rustboyadvance_ng::core::{GBAError, GBAResult, GameBoyAdvance};
use rustboyadvance_ng::debugger::Debugger; use rustboyadvance_ng::debugger::Debugger;
use rustboyadvance_ng::util::read_bin_file; use rustboyadvance_ng::util::read_bin_file;
fn load_rom(path: &str) -> GBAResult<Vec<u8>> {
if path.ends_with(".zip") {
let zipfile = File::open(path)?;
let mut archive = zip::ZipArchive::new(zipfile)?;
for i in 0..archive.len()
{
let mut file = archive.by_index(i)?;
if file.name().ends_with(".gba") {
let mut buf = Vec::new();
file.read_to_end(&mut buf)?;
return Ok(buf);
}
}
panic!("no .gba file contained in the zip file");
} else {
let buf = read_bin_file(path)?;
Ok(buf)
}
}
fn run_emulator(matches: &ArgMatches) -> GBAResult<()> { fn run_emulator(matches: &ArgMatches) -> GBAResult<()> {
let skip_bios = match matches.occurrences_of("skip_bios") { let skip_bios = matches.occurrences_of("skip_bios") != 0;
0 => false, let no_framerate_limit = matches.occurrences_of("no_framerate_limit") != 0;
_ => true, let debug = matches.occurrences_of("debug") != 0;
};
let debug = match matches.occurrences_of("debug") {
0 => false,
_ => true,
};
let backend: Box<EmulatorBackend> = match matches.value_of("backend") { let backend: Box<EmulatorBackend> = match matches.value_of("backend") {
Some("sdl2") => Box::new(Sdl2Backend::new()), Some("sdl2") => Box::new(Sdl2Backend::new()),
@ -34,8 +56,9 @@ fn run_emulator(matches: &ArgMatches) -> GBAResult<()> {
let bios_bin = read_bin_file(matches.value_of("bios").unwrap_or_default())?; let bios_bin = read_bin_file(matches.value_of("bios").unwrap_or_default())?;
let gamepak = Cartridge::load(matches.value_of("game_rom").unwrap())?; let rom_bin = load_rom(matches.value_of("game_rom").unwrap())?;
println!("loaded rom: {:#?}", gamepak.header); let cart = Cartridge::new(rom_bin);
println!("loaded rom: {:#?}", cart.header);
let mut core = Core::new(); let mut core = Core::new();
if skip_bios { if skip_bios {
@ -52,7 +75,7 @@ fn run_emulator(matches: &ArgMatches) -> GBAResult<()> {
core.cpsr.set(0x5f); core.cpsr.set(0x5f);
} }
let mut gba = GameBoyAdvance::new(core, bios_bin, gamepak, backend); let mut gba = GameBoyAdvance::new(core, bios_bin, cart, backend);
if debug { if debug {
gba.cpu.set_verbose(true); gba.cpu.set_verbose(true);
@ -67,10 +90,12 @@ fn run_emulator(matches: &ArgMatches) -> GBAResult<()> {
gba.frame(); gba.frame();
let time_passed = start_time.elapsed(); let time_passed = start_time.elapsed();
if time_passed <= frame_time { if time_passed <= frame_time {
if !no_framerate_limit {
::std::thread::sleep(frame_time - time_passed); ::std::thread::sleep(frame_time - time_passed);
} }
} }
} }
}
Ok(()) Ok(())
} }

View file

@ -4,8 +4,6 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use super::arm7tdmi::{bus::Bus, Addr}; use super::arm7tdmi::{bus::Bus, Addr};
use crate::util::read_bin_file;
/// From GBATEK /// From GBATEK
/// ///
/// The first 192 bytes at 8000000h-80000BFh in ROM are used as cartridge header. The same header is also used for Multiboot images at 2000000h-20000BFh (plus some additional multiboot entries at 20000C0h and up). /// The first 192 bytes at 8000000h-80000BFh in ROM are used as cartridge header. The same header is also used for Multiboot images at 2000000h-20000BFh (plus some additional multiboot entries at 20000C0h and up).
@ -74,17 +72,16 @@ pub struct Cartridge {
impl Cartridge { impl Cartridge {
const MIN_SIZE: usize = 4 * 1024 * 1024; const MIN_SIZE: usize = 4 * 1024 * 1024;
pub fn load(path: &str) -> Result<Cartridge, ::std::io::Error> { pub fn new(mut rom_bin: Vec<u8>) -> Cartridge {
let mut rom_bin = read_bin_file(path)?;
if rom_bin.len() < Cartridge::MIN_SIZE { if rom_bin.len() < Cartridge::MIN_SIZE {
rom_bin.resize_with(Cartridge::MIN_SIZE, Default::default); rom_bin.resize_with(Cartridge::MIN_SIZE, Default::default);
} }
let header = CartridgeHeader::parse(&rom_bin); let header = CartridgeHeader::parse(&rom_bin);
Ok(Cartridge { Cartridge {
header: header, header: header,
bytes: rom_bin.into_boxed_slice(), bytes: rom_bin.into_boxed_slice(),
}) }
} }
} }

View file

@ -16,6 +16,8 @@ pub mod timer;
use crate::debugger; use crate::debugger;
use zip;
pub trait SyncedIoDevice { pub trait SyncedIoDevice {
fn step(&mut self, cycles: usize, sb: &mut SysBus, irqs: &mut IrqBitmask); fn step(&mut self, cycles: usize, sb: &mut SysBus, irqs: &mut IrqBitmask);
} }
@ -46,3 +48,9 @@ impl From<debugger::DebuggerError> for GBAError {
GBAError::DebuggerError(err) GBAError::DebuggerError(err)
} }
} }
impl From<zip::result::ZipError> for GBAError {
fn from(err: zip::result::ZipError) -> GBAError {
GBAError::IO(::std::io::Error::from(::std::io::ErrorKind::InvalidInput))
}
}

View file

@ -18,6 +18,8 @@ extern crate nom;
extern crate ansi_term; extern crate ansi_term;
extern crate colored; // not needed in Rust 2018 extern crate colored; // not needed in Rust 2018
extern crate zip;
#[macro_use] #[macro_use]
pub mod util; pub mod util;
pub mod backend; pub mod backend;