[][src]Crate rgy

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.