diff --git a/src/lib.rs b/src/lib.rs index 7c7a1c8..d7906a3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,38 +6,32 @@ bigint_helper_methods )] -use std::{ - fs, - io::{self, stdout, Write}, +use crate::{ + processor::memory::Memory, + util::{pause, print_cycles}, }; - use gilrs::Gilrs; use minifb::Window; use once_cell::sync::OnceCell; use processor::{memory::Rom, Cpu}; - -use crate::processor::memory::Memory; +use std::{ + fs, + io::{stdout, Write}, +}; +use util::pause_then_step; mod constants; mod processor; -mod util; +pub mod util; -#[macro_export] -macro_rules! verbose_println { - ($($tts:tt)*) => { - if $crate::is_verbose() { - println!($($tts)*); - } - }; -} - -#[macro_export] -macro_rules! verbose_print { - ($($tts:tt)*) => { - if $crate::is_verbose() { - print!($($tts)*); - } - }; +pub struct Options { + pub rom_path: String, + pub bootrom_path: Option, + pub connect_serial: bool, + pub verbose: bool, + pub step_by: Option, + pub cycle_count: bool, + pub factor: usize, } static mut PAUSE_ENABLED: bool = false; @@ -50,22 +44,12 @@ pub const HEIGHT: usize = 144; static FACTOR: OnceCell = OnceCell::new(); #[allow(clippy::too_many_arguments)] -pub fn init( - rom_path: String, - bootrom_path: Option, - mut window: Window, - connect_serial: bool, - tile_window: bool, - verbose: bool, - step_by: Option, - cycle_count: bool, - factor: usize, -) { - VERBOSE.set(verbose).unwrap(); - FACTOR.set(factor).unwrap(); +pub fn init(options: Options, mut window: Window, tile_window: bool) { + VERBOSE.set(options.verbose).unwrap(); + FACTOR.set(options.factor).unwrap(); crate::processor::memory::mmio::gpu::init_statics(); - let rom: Rom = match fs::read(rom_path) { + let rom: Rom = match fs::read(options.rom_path) { Ok(data) => Rom::load(data), Err(e) => { println!("Error reading ROM: {e}"); @@ -74,8 +58,8 @@ pub fn init( }; window.set_title(format!("{} on {}", rom.get_title(), rom.mbc_type()).as_str()); - let bootrom_enabled = bootrom_path.is_some(); - let bootrom: Option> = if let Some(path) = bootrom_path { + let bootrom_enabled = options.bootrom_path.is_some(); + let bootrom: Option> = if let Some(path) = options.bootrom_path { match fs::read(path) { Ok(data) => Some(data), Err(e) => { @@ -88,7 +72,7 @@ pub fn init( }; let mut cpu = Cpu::new( - Memory::init(bootrom, rom, window, connect_serial, tile_window), + Memory::init(bootrom, rom, window, options.connect_serial, tile_window), bootrom_enabled, Gilrs::new().unwrap(), ); @@ -96,11 +80,11 @@ pub fn init( let mut cycle_num = 0; verbose_println!("\n\n Begin execution...\n"); - match step_by { + match options.step_by { Some(step_size) => loop { for _ in 0..step_size { cycle_num += 1; - if cycle_count { + if options.cycle_count { print_cycles(&cycle_num); } run_cycle(&mut cpu); @@ -111,7 +95,7 @@ pub fn init( }, None => loop { cycle_num += 1; - if cycle_count { + if options.cycle_count { print_cycles(&cycle_num); } run_cycle(&mut cpu); @@ -130,46 +114,3 @@ fn run_cycle(cpu: &mut Cpu) { pause_then_step(); } } - -fn pause_then_step() { - unsafe { - if PAUSE_ENABLED { - let line = pause(); - PAUSE_QUEUED = !line.contains("continue"); - } - } -} - -#[allow(dead_code)] -fn pause_once() { - println!("paused..."); - pause(); -} - -fn pause() -> String { - let mut line = String::new(); - match io::stdin().read_line(&mut line) { - Ok(_) => line, - Err(_) => String::from(""), - } -} - -fn print_cycles(cycles: &i32) { - if *cycles % 45678 != 0 { - return; - } - let instructions_per_second = 400000; - print!( - "cycle {} - approx {} seconds on real hardware\r", - cycles, - cycles / instructions_per_second - ); - stdout().flush().unwrap(); -} - -fn is_verbose() -> bool { - match VERBOSE.get() { - Some(v) => *v, - None => false, - } -} diff --git a/src/main.rs b/src/main.rs index 68d2fad..ccd413f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,8 +3,6 @@ use gb_emu::{HEIGHT, WIDTH}; use minifb::{Window, WindowOptions}; - - /// Gameboy (DMG-A/B/C) emulator #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] @@ -66,15 +64,15 @@ fn main() { window.topmost(true); - gb_emu::init( - args.rom, - args.bootrom, - window, - args.connect_serial, - args.tile_window, - args.verbose, - args.step_by, - args.cycle_count, + let options = gb_emu::Options { + rom_path: args.rom, + bootrom_path: args.bootrom, + connect_serial: args.connect_serial, + verbose: args.verbose, + step_by: args.step_by, + cycle_count: args.cycle_count, factor, - ); + }; + + gb_emu::init(options, window, args.tile_window); } diff --git a/src/util.rs b/src/util.rs index 356ac30..46f19b9 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,5 +1,69 @@ -use crate::processor::Direction; -use std::mem::transmute; +use crate::{processor::Direction, PAUSE_ENABLED, PAUSE_QUEUED, VERBOSE}; +use std::{ + io::{self, stdout, Write}, + mem::transmute, +}; + +#[macro_export] +macro_rules! verbose_println { + ($($tts:tt)*) => { + if $crate::util::is_verbose() { + println!($($tts)*); + } + }; +} + +#[macro_export] +macro_rules! verbose_print { + ($($tts:tt)*) => { + if $crate::util::is_verbose() { + print!($($tts)*); + } + }; +} + +pub(crate) fn pause_then_step() { + unsafe { + if PAUSE_ENABLED { + let line = pause(); + PAUSE_QUEUED = !line.contains("continue"); + } + } +} + +#[allow(dead_code)] +pub(crate) fn pause_once() { + println!("paused..."); + pause(); +} + +pub(crate) fn pause() -> String { + let mut line = String::new(); + match io::stdin().read_line(&mut line) { + Ok(_) => line, + Err(_) => String::from(""), + } +} + +pub(crate) fn print_cycles(cycles: &i32) { + if *cycles % 45678 != 0 { + return; + } + let instructions_per_second = 400000; + print!( + "cycle {} - approx {} seconds on real hardware\r", + cycles, + cycles / instructions_per_second + ); + stdout().flush().unwrap(); +} + +pub(crate) fn is_verbose() -> bool { + match VERBOSE.get() { + Some(v) => *v, + None => false, + } +} pub(crate) fn as_signed(unsigned: u8) -> i8 { unsafe { transmute(unsigned) }