diff --git a/Cargo.toml b/Cargo.toml index 89d2759..3c94247 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/ngraf3255/RbGB" keywords = ["gamedev", "graphics", "emulator"] [lib] -name = "rbgb_emulator" +name = "rbgb" path = "src/lib.rs" [[bin]] diff --git a/src/emulator.rs b/src/emulator.rs index 594e7b9..470e2db 100644 --- a/src/emulator.rs +++ b/src/emulator.rs @@ -12,6 +12,14 @@ mod joypad; mod mem; mod sound; +/// High-level Game Boy emulator coordinator. +/// +/// Owns the CPU, memory, graphics, and input subsystems and drives the +/// per-frame execution loop. The emulator starts paused and must be unpaused +/// (or a ROM loaded) before it will execute instructions. +/// +/// This type exposes the core API used by the frontend to load ROMs, advance +/// frames, provide input, and read the display buffer. pub struct Emulator { screen: graphics::Screen, cpu: cpu::CPU, @@ -27,10 +35,23 @@ impl Default for Emulator { } impl Emulator { - /// Calls the needed functions once a frame + /// Maximum CPU cycles executed per frame. + /// + /// This matches the approximate number of cycles a Game Boy runs in one + /// video frame. The update loop runs until this budget is reached. const MAXCYCLES: u32 = 69905; + /// Target duration for a single frame (approx. 59.7 Hz). + /// + /// The update loop sleeps to align with this duration after processing + /// enough CPU cycles. const FRAME_DURATION: Duration = Duration::from_nanos(16_741_000); + /// Create a new emulator instance with initialized subsystems. + /// + /// Memory is initialized to its startup state and the emulator begins + /// paused until a ROM is loaded or `toggle_pause` is called. + /// + /// Returns a ready-to-use `Emulator` in the paused state. pub fn new() -> Self { let mem = Arc::new(Mutex::new(mem::Memory::new())); mem.lock().unwrap().ram_startup(); @@ -43,6 +64,13 @@ impl Emulator { } } + /// Execute one frame of emulation if not paused. + /// + /// Runs CPU instructions, updates timers and graphics, and handles + /// interrupts until the frame's cycle budget is consumed. The function then + /// sleeps to maintain the target frame rate. + /// + /// Returns `()` and has no effect if the emulator is paused. pub fn update(&mut self) { if self.paused { return; @@ -63,14 +91,33 @@ impl Emulator { } } + /// Toggle the paused state. + /// + /// When paused, `update` returns immediately without advancing emulation. + /// + /// Takes `&mut self` and returns `()`. pub fn toggle_pause(&mut self) { self.paused = !self.paused; } + /// Check whether emulation is currently paused. + /// + /// Returns `true` if the emulator will skip work in `update`. + /// + /// Takes `&self` and returns a `bool` indicating pause state. pub fn is_paused(&self) -> bool { self.paused } + /// Load a ROM from disk and reset the CPU and memory state. + /// + /// The ROM contents are copied into memory, memory is reinitialized, and + /// the CPU is reset. On success, the emulator is unpaused. + /// + /// Parameters: + /// - `path`: filesystem path to the ROM file. + /// + /// Returns `Ok(())` on success or a string I/O error on failure. pub fn load_rom(&mut self, path: &str) -> Result<(), String> { let data = std::fs::read(path).map_err(|e| e.to_string())?; let mut mem = self.memory.lock().unwrap(); @@ -82,10 +129,22 @@ impl Emulator { Ok(()) } + /// Borrow the current display buffer for rendering. + /// + /// The buffer contains raw pixel data produced by the graphics subsystem. + /// Its length and format are determined by `graphics::Screen`. + /// + /// Returns a borrowed `&[u8]` slice tied to the emulator's lifetime. pub fn get_display_buffer(&self) -> &[u8] { &self.screen.buffer } + /// Dump key LCD and input registers for debugging. + /// + /// This is only compiled in debug builds and logs directly to stdout via + /// `debug_println`. If not compiled for debug this function does nothing. + /// + /// Takes `&self` and returns `()`. All details are dumped to the console pub fn dump_lcd_mem(&self) { #[cfg(debug_assertions)] let mem = self.memory.lock().unwrap(); @@ -113,7 +172,16 @@ impl Emulator { ); } - /// Handle input to the emulator + /// Handle input for the emulator's joypad. + /// + /// Updates the joypad state and forwards the input to memory-mapped input + /// registers. + /// + /// Parameters: + /// - `input`: which Game Boy control was pressed or released. + /// - `val`: the key state for that control. + /// + /// Returns `()`. pub fn game_input(&mut self, input: GameInput, val: KeyState) { self.joypad.log_input(input, val) }