1 个不稳定版本

0.0.1 2022年5月16日

#54 in #gameboy

自定义许可

765KB
5K SLoC

Padme 核心库

像素点阵模拟器

padme-core 是一个 Gameboy 模拟器引擎。它本身不依赖于 libstd 或动态内存,这使得它在任何嵌入式平台或 [https://github.com/alexlren/padme-browser web assembly](https://github.com/alexlren/padme-browser) 中更容易使用。

测试

用于快速单元/集成/文档测试

cargo test

对于更昂贵的测试,你可以使用

cargo test -- --ignored

或运行所有测试

cargo test -- --include-ignored

示例

  1. 创建你的硬件组件:一个屏幕、一个扬声器和串行输出

这些组件应针对您的平台特定。

use padme_core::{AudioSpeaker, Button, Pixel, Rom, Screen, SerialOutput, System};

struct MyScreen {
    // ... your framebuffer implementation
}

impl Screen for MyScreen {
    fn set_pixel(&mut self, pixel: &Pixel, x: u8, y: u8) {
        // add pixel to your framebuffer
    }
}

struct MySpeaker {
    // ... your audio buffer implementation
}

impl AudioSpeaker for MySpeaker {
    fn set_samples(&mut self, left: f32, right: f32) {
        // add samples for left and right channels
    }
}

struct MySerialConsole {
}

impl SerialOutput for MySerialConsole {
    fn putchar(&mut self, ch: u8) {
        // add char to 
    }
}

或者,如果您不需要/想要这些组件中的一些,则可以使用空版本

use padme::default::{NoScreen, NoSerial, NoSpeaker};
  1. 加载一个 rom
use padme_core::Rom;

let bin: Vec<u8> = std::fs::read("some_game.gb").expect("could not find game");
let mut rom = Rom::load(bin).unwrap();
  1. 创建您的模拟器并运行它
use std::time::Instant;
use std::thread::sleep;

let mut emulator = System::new(rom, MyScreen, MySerialConsole, MySpeaker);
// Set the number of frame per seconds
// This also sets the number of cycles needed per frame given the fixed CPU clock frequency
emulator.set_frame_rate(60);

while running {
    // We need to know how much time it took to display a frame
    let t0 = Instant::now();
    // This executes all the cycles needed to display one frame
    emulator.update_frame();
    // Deal with button inputs
    emulator.set_button(Button::A, a_pressed);
    emulator.set_button(Button::B, b_pressed);
    emulator.set_button(Button::Start, start_pressed);
    emulator.set_button(Button::Select, select_pressed);
    emulator.set_button(Button::Up, up_pressed);
    emulator.set_button(Button::Down, down_pressed);
    emulator.set_button(Button::Left, left_pressed);
    emulator.set_button(Button::Right, right_pressed);
    // Now we just need to wait the remaining time before the next frame
    // This is because we need to keep ~60 frames / second
    let frame_time = t0.elapsed();
    let min_frame_time = emulator.min_frame_time();
    if frame_time < min_frame_time {
        sleep(min_frame_time - frame_time);
    }
}

或者,您可能希望自行执行这些步骤

use padme_core::{CLOCK_SPEED};

let cycles_per_frame = CLOCK_SPEED / 60;
let mut cycles = 0u32;
while cycles < cycles_per_frame {
    cycles += emulator.step() as u32;
}
emulator.screen().update();

要查看一些实现,请查看 [https://github.com/alexlren/padme-demo padme-demo](https://github.com/alexlren/padme-demo),一个桌面演示或 [https://github.com/alexlren/padme-browser padme-browser](https://github.com/alexlren/padme-browser),一个 web assembly 版本。

功能

  • no_std
  • 定时器
  • DMA
  • CPU 汇编器
  • 带 fifo 的像素处理器单元
  • 外部屏幕
  • 外部串行端口
  • 手柄
  • ROM、MBC1、MBC3
  • 集成测试
  • 音频处理单元

待办事项

  • 添加对 MBC2、MBC4、MBC5、MBC6、MBC7 的支持
  • 为每个模块添加单元测试

依赖项