From 7cc1a50d120cc1fb9be91a496bfcea59306a4979 Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Wed, 11 Sep 2019 21:26:40 +0300 Subject: [PATCH] Support zip files and add --no-framerate-limit Former-commit-id: 62a7122fb0b3e832eeb3cbf347a0966e4cd32d50 --- Cargo.toml | 1 + src/bin/cli.yml | 3 +++ src/bin/main.rs | 51 ++++++++++++++++++++++++++++++++----------- src/core/cartridge.rs | 9 +++----- src/core/mod.rs | 8 +++++++ src/lib.rs | 2 ++ 6 files changed, 55 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 11aed8a..ae40fcc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ minifb = "0.11.2" time = "0.1.42" bitfield = "0.13.1" bitflags = "1.1.0" +zip = "0.5.3" [profile.dev] opt-level = 1 diff --git a/src/bin/cli.yml b/src/bin/cli.yml index 9d47533..30d4ae8 100644 --- a/src/bin/cli.yml +++ b/src/bin/cli.yml @@ -16,6 +16,9 @@ args: - skip_bios: long: skip-bios help: Skip running bios and start from the ROM instead + - no_framerate_limit: + long: no-framerate-limit + help: Run without frame limiter - backend: long: backend takes_value: true diff --git a/src/bin/main.rs b/src/bin/main.rs index c1a341c..08a3c14 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,8 +1,14 @@ use std::time; +use std::fs::File; +use std::path::Path; +use std::ffi::OsStr; +use std::io::prelude::*; #[macro_use] extern crate clap; +extern crate zip; + use clap::{App, ArgMatches}; extern crate rustboyadvance_ng; @@ -10,19 +16,35 @@ extern crate rustboyadvance_ng; use rustboyadvance_ng::backend::*; use rustboyadvance_ng::core::arm7tdmi::Core; 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::util::read_bin_file; + +fn load_rom(path: &str) -> GBAResult> { + 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<()> { - let skip_bios = match matches.occurrences_of("skip_bios") { - 0 => false, - _ => true, - }; - let debug = match matches.occurrences_of("debug") { - 0 => false, - _ => true, - }; + let skip_bios = matches.occurrences_of("skip_bios") != 0; + let no_framerate_limit = matches.occurrences_of("no_framerate_limit") != 0; + let debug = matches.occurrences_of("debug") != 0; let backend: Box = match matches.value_of("backend") { 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 gamepak = Cartridge::load(matches.value_of("game_rom").unwrap())?; - println!("loaded rom: {:#?}", gamepak.header); + let rom_bin = load_rom(matches.value_of("game_rom").unwrap())?; + let cart = Cartridge::new(rom_bin); + println!("loaded rom: {:#?}", cart.header); let mut core = Core::new(); if skip_bios { @@ -52,7 +75,7 @@ fn run_emulator(matches: &ArgMatches) -> GBAResult<()> { 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 { gba.cpu.set_verbose(true); @@ -67,7 +90,9 @@ fn run_emulator(matches: &ArgMatches) -> GBAResult<()> { gba.frame(); let time_passed = start_time.elapsed(); if time_passed <= frame_time { - ::std::thread::sleep(frame_time - time_passed); + if !no_framerate_limit { + ::std::thread::sleep(frame_time - time_passed); + } } } } diff --git a/src/core/cartridge.rs b/src/core/cartridge.rs index 68e091d..f6a6f1c 100644 --- a/src/core/cartridge.rs +++ b/src/core/cartridge.rs @@ -4,8 +4,6 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use super::arm7tdmi::{bus::Bus, Addr}; -use crate::util::read_bin_file; - /// 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). @@ -74,17 +72,16 @@ pub struct Cartridge { impl Cartridge { const MIN_SIZE: usize = 4 * 1024 * 1024; - pub fn load(path: &str) -> Result { - let mut rom_bin = read_bin_file(path)?; + pub fn new(mut rom_bin: Vec) -> Cartridge { if rom_bin.len() < Cartridge::MIN_SIZE { rom_bin.resize_with(Cartridge::MIN_SIZE, Default::default); } let header = CartridgeHeader::parse(&rom_bin); - Ok(Cartridge { + Cartridge { header: header, bytes: rom_bin.into_boxed_slice(), - }) + } } } diff --git a/src/core/mod.rs b/src/core/mod.rs index ab29ecc..26852ee 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -16,6 +16,8 @@ pub mod timer; use crate::debugger; +use zip; + pub trait SyncedIoDevice { fn step(&mut self, cycles: usize, sb: &mut SysBus, irqs: &mut IrqBitmask); } @@ -46,3 +48,9 @@ impl From for GBAError { GBAError::DebuggerError(err) } } + +impl From for GBAError { + fn from(err: zip::result::ZipError) -> GBAError { + GBAError::IO(::std::io::Error::from(::std::io::ErrorKind::InvalidInput)) + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 8572f4a..3ff1421 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,8 @@ extern crate nom; extern crate ansi_term; extern crate colored; // not needed in Rust 2018 +extern crate zip; + #[macro_use] pub mod util; pub mod backend;