diff --git a/src/args.rs b/src/args.rs index 767e14c..645a3be 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,8 +1,10 @@ use clap::Parser; -#[derive(Debug,Parser)] -#[command(version, about, long_about = "Byte Pusher Emulator")] -pub struct BytePusherArgs{ - #[arg(short,long)] - pub file_name:Option +#[derive(Debug, Parser)] +#[command(version, about, author)] +pub struct BytePusherArgs { + #[arg(short, long, help = "ROM file to load")] + pub file_name: Option, + #[arg(short, long, help = "Scale at which to draw", default_value_t = 2.0)] + pub draw_scale: f32, } \ No newline at end of file diff --git a/src/emu/audio.rs b/src/emu/audio.rs index e7309c4..173bbb4 100644 --- a/src/emu/audio.rs +++ b/src/emu/audio.rs @@ -8,7 +8,10 @@ use crate::misc::error::EmulatorError; use crate::misc::result::EmulatorResult; pub const AUDIO_BUFFER_SIZE: usize = 256; - +const I8_SIGN_BYTE: u8 = 0x80; +const AUDIO_REG_START: usize = 6; +const AUDIO_REG_LEN: usize = 2; +const AUDIO_REG_END: usize = AUDIO_REG_START + AUDIO_REG_LEN -1; pub struct AudioProcessor<'a> { ram: &'a RamMemory, @@ -31,6 +34,7 @@ impl<'a> AudioProcessor<'a> { } } + impl<'a> AudioProcessor<'a> { pub fn queue(&mut self) -> EmulatorResult<()> { let audio_base_reg = (self.get_audio_base_reg() as u32) << 8; @@ -39,22 +43,22 @@ impl<'a> AudioProcessor<'a> { // The CPU frame timing is just a little less than 60 fps to prevent audio stutter. // We will then wait for audio to drain to adjust frame timing if self.audio_queue.size() == 0 { - log::trace!("Detected Queue empty!"); + log::info!("Detected Queue empty! Audio stutter may occur"); } - while self.audio_queue.size() > 32 { + while self.audio_queue.size() > (AUDIO_BUFFER_SIZE / 2) as u32 { ::std::thread::sleep(Duration::from_micros(1)) } self.ram.try_copy_block(audio_base_reg, fb)?; //convert to u8 audio format (Bytepusher stores it as "i8") fb.iter_mut().for_each(|item|{ - *item^= 0x80; + *item ^= I8_SIGN_BYTE; }); self.audio_queue.queue_audio(fb).map_err(|s| { EmulatorError::OtherError(Some(AUDIO), s) }) } fn get_audio_base_reg(&self) -> u16 { let data = self.ram.get_data_ref(); - let audio_base_reg = data.get(6..8).unwrap(); + let audio_base_reg = data.get(AUDIO_REG_START..=AUDIO_REG_END).unwrap(); read_big_endian_u16(audio_base_reg.try_into().unwrap()) } } \ No newline at end of file diff --git a/src/emu/graphics.rs b/src/emu/graphics.rs index 29998f0..e87df34 100644 --- a/src/emu/graphics.rs +++ b/src/emu/graphics.rs @@ -5,7 +5,8 @@ use crate::misc::error::DeviceType::GRAPHICS; use crate::misc::error::EmulatorError; use crate::misc::result::EmulatorResult; -pub const DEVICE_FRAMEBUFFER_SIZE: usize = 256 * 256; +pub const DEVICE_RESOLUTION: usize = 256; +pub const DEVICE_FRAMEBUFFER_SIZE: usize = DEVICE_RESOLUTION * DEVICE_RESOLUTION; #[derive(Debug)] pub struct GraphicsProcessor<'a> { diff --git a/src/main.rs b/src/main.rs index b5d84e3..8336aeb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ use simple_logger::SimpleLogger; use crate::args::BytePusherArgs; use crate::emu::audio::AudioProcessor; use crate::emu::cpu::Cpu; -use crate::emu::graphics::GraphicsProcessor; +use crate::emu::graphics::{DEVICE_RESOLUTION, GraphicsProcessor}; use crate::emu::keyboard::Keyboard; use crate::emu::memory::{MEM_LENGTH, RamMemory}; use crate::graphics::graphics_adapter::SDLGraphicsAdapter; @@ -26,14 +26,13 @@ mod misc; mod graphics; fn main() -> EmulatorResult<()> { - let BytePusherArgs { file_name } = BytePusherArgs::parse(); - SimpleLogger::new().with_level(LevelFilter::Info).env().init().unwrap(); + let BytePusherArgs { file_name ,draw_scale} = BytePusherArgs::parse(); + SimpleLogger::new().with_level(LevelFilter::Info).env().init()?; - let (file_bytes, x) = try_load_rom(&file_name)?; - assert!(x < MEM_LENGTH); + let (file_bytes, ..) = try_load_rom(&file_name)?; - let (mut canvas, mut event_pump, audio_queue) = initiate_sdl(); + let (mut canvas, mut event_pump, audio_queue) = initiate_sdl(draw_scale); let ram = RamMemory::try_from(file_bytes.as_slice())?; @@ -44,9 +43,9 @@ fn main() -> EmulatorResult<()> { let mut sdl2_graphics_adapter = SDLGraphicsAdapter::new(&graphics_processor); + canvas.set_draw_color(Color::BLACK); + canvas.clear(); 'running: loop { - canvas.set_draw_color(Color::BLACK); - canvas.clear(); for event in event_pump.poll_iter() { match event { Event::Quit { .. } | @@ -71,13 +70,12 @@ fn main() -> EmulatorResult<()> { // The rest of the game loop goes here... cpu.cycle()?; - // draw graphics - sdl2_graphics_adapter.draw(&mut canvas)?; - // TODO render audio - audio_processor.queue()?; + sdl2_graphics_adapter.draw(&mut canvas)?; + audio_processor.queue()?; canvas.present(); + // 60fps - small offset to consider for cpu cycle time ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60 - 2000_000)); } @@ -121,10 +119,8 @@ fn try_load_rom(file_name_option: &Option) -> EmulatorResult<(Vec, u Ok((file_bytes, bytes_read)) } -fn initiate_sdl() -> (WindowCanvas, EventPump, AudioQueue) { - const BASE_RESOLUTION: u32 = 256; - const DRAW_FACTOR: u32 = 4; - const WINDOW_RESOLUTION: u32 = BASE_RESOLUTION * DRAW_FACTOR; +fn initiate_sdl(draw_scale:f32) -> (WindowCanvas, EventPump, AudioQueue) { + let window_resolution: u32 = (DEVICE_RESOLUTION as f32 * draw_scale) as u32; let sdl_context = sdl2::init().unwrap(); let video_subsystem = sdl_context.video().unwrap(); let audio_subsystem = sdl_context.audio().unwrap(); @@ -137,18 +133,16 @@ fn initiate_sdl() -> (WindowCanvas, EventPump, AudioQueue) { audio_queue.resume(); - let window = video_subsystem.window("byte-pusher-emu", WINDOW_RESOLUTION, WINDOW_RESOLUTION) + let window = video_subsystem.window("byte-pusher-emu", window_resolution, window_resolution) .position_centered() .build() .unwrap(); let mut canvas = window.into_canvas().build().unwrap(); - canvas.set_draw_color(Color::RGB(0x10, 0x10, 0x10)); - canvas.set_integer_scale(true).expect("Setting int scale"); + canvas.set_scale(draw_scale, draw_scale).expect("Setting scale"); - canvas.set_scale(DRAW_FACTOR as f32, DRAW_FACTOR as f32).expect("Setting scale"); - canvas.clear(); canvas.set_blend_mode(BlendMode::None); + canvas.clear(); canvas.present(); let event_pump = sdl_context.event_pump().unwrap(); (canvas, event_pump, audio_queue) diff --git a/src/misc/error.rs b/src/misc/error.rs index 9ec9eeb..7658f86 100644 --- a/src/misc/error.rs +++ b/src/misc/error.rs @@ -1,6 +1,7 @@ use std::array::TryFromSliceError; use std::fmt::Debug; use std::io::Error; +use log::SetLoggerError; use crate::misc::error::EmulatorError::EmulatorIOError; #[derive(Debug, Copy, Clone)] @@ -24,12 +25,18 @@ impl From for EmulatorError { } } -impl From for EmulatorError { +impl From for EmulatorError { fn from(value: Error) -> Self { EmulatorIOError(value) } } +impl From for EmulatorError{ + fn from(value: SetLoggerError) -> Self { + EmulatorError::OtherError(None,format!("Logger allocation failed! Error: {}",value)) + } +} +