Support zip files and add --no-framerate-limit
Former-commit-id: 62a7122fb0b3e832eeb3cbf347a0966e4cd32d50
This commit is contained in:
parent
fa211fa77e
commit
7cc1a50d12
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,7 +90,9 @@ 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 {
|
||||||
::std::thread::sleep(frame_time - time_passed);
|
if !no_framerate_limit {
|
||||||
|
::std::thread::sleep(frame_time - time_passed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
Reference in a new issue