Crate rgy

Source
Expand description

rgy is no-std cross-platform Rust GameBoy emulator library.

The users of this library only needs to implement Hardware trait, which abstracts OS-specific function. Once it’s implemented, the emulator works.

The following code is the example which just implements Hardware. The implementation does nothing. You can replace the body of each function with the actual meaningful logic.

use rgy::{Config, Key, Stream, VRAM_HEIGHT, VRAM_WIDTH};

struct Hardware {
    dummy_display: Vec<Vec<u32>>,
}

impl Hardware {
    fn new() -> Self {
        // Create a frame buffer with the size VRAM_WIDTH * VRAM_HEIGHT.
        let dummy_display = vec![vec![0u32; VRAM_HEIGHT]; VRAM_WIDTH];

        Self { dummy_display }
    }
}

impl rgy::Hardware for Hardware {
    // Called when a horizontal line in the display is updated by the emulator.
    fn vram_update(&mut self, line: usize, buffer: &[u32]) {
        // `line` corresponds to the y coordinate.
        let y = line;

        for (x, col) in buffer.iter().enumerate() {
            // TODO: Update the pixels in the actual display here.
            self.dummy_display[x][y] = *col;
        }
    }

    // Called when the emulator checks if a key is pressed or not.
    fn joypad_pressed(&mut self, key: Key) -> bool {
        println!("Is {:?} pressed?", key);

        // TODO: Read a keyboard device and check if the `key` is pressed or not.

        false
    }

    // Called when the emulator plays a sound.
    fn sound_play(&mut self, _stream: Box<dyn Stream>) {
        // TODO: Play the wave pattern provided `Stream`.
    }

    // Provides clock for the emulator.
    fn clock(&mut self) -> u64 {
        // TODO: Return the epoch in microseconds.
        let epoch = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .expect("Couldn't get epoch");
        epoch.as_micros() as u64
    }

    // Called when the emulator sends a byte to the serial port.
    fn send_byte(&mut self, _b: u8) {
        // TODO: Send a byte to a serial port.
    }

    // Called when the emulator peeks a byte from the serial port.
    fn recv_byte(&mut self) -> Option<u8> {
        // TODO: Check the status of the serial port and read a byte if any.
        None
    }

    // Called every time the emulator executes an instruction.
    fn sched(&mut self) -> bool {
        // TODO: Do some periodic jobs if any. Return `true` to continue, `false` to stop the emulator.
        println!("It's running!");
        true
    }

    // Called when the emulator stores the save data to the battery-backed RAM.
    fn load_ram(&mut self, size: usize) -> Vec<u8> {
        // TODO: Return save data.
        vec![0; size]
    }

    // Called when the emulator loads the save data from the battery-backed RAM.
    fn save_ram(&mut self, _ram: &[u8]) {
        // TODO: Store save data.
    }
}

fn main() {
    // Create the default config.
    let cfg = Config::new();

    // Create the hardware instance.
    let hw = Hardware::new();

    // TODO: The content of a ROM file, which can be downloaded from the Internet.
    let rom = vec![0u8; 1024];

    // Run the emulator.
    rgy::run(cfg, &rom, hw);
}

Modules§

cpu
CPU state.
debug
Debugger interface.
device
Adaptor to register devices to MMU.
inst
Decoder which evaluates each CPU instructions.
mmu
Handles memory and I/O port access from the CPU.

Structs§

Config
Configuration of the emulator.
System
Represents the entire emulator context.

Enums§

Key
Represents a key of the joypad.

Constants§

VRAM_HEIGHT
The height of the VRAM.
VRAM_WIDTH
The width of the VRAM.

Traits§

Hardware
The interface to abstracts the OS-specific functions.
Stream
Sound wave stream which generates the wave to be played by the sound device.

Functions§

run
Run the emulator with the given configuration.
run_debug
Run the emulator with the given configuration and debugger.