# Padme core
## Pixel As Dot-Matrix Emulator
padme-core is a Gameboy emulator engine. It itself doesn't rely on libstd or on dynamic memory, which makes it easier to use in any embedded platforms or [web assembly](https://github.com/alexlren/padme-browser).
## Tests
For fast unit / integration / doc tests:
```
cargo test
```
For more expensive tests, you can use:
```
cargo test -- --ignored
```
or run all tests with:
```
cargo test -- --include-ignored
```
## Examples
1. Create your hardware components: a screen, a speaker and a serial output
These components should be specific to your platform.
```rust
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
}
}
```
Alternatively, if you don't need / want some of these components, it's possible to use empty versions:
```rust
use padme::default::{NoScreen, NoSerial, NoSpeaker};
```
2. Load a rom
```rust
use padme_core::Rom;
let bin: Vec = std::fs::read("some_game.gb").expect("could not find game");
let mut rom = Rom::load(bin).unwrap();
```
3. Create your emulator and run it
```rust
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);
}
}
```
Alternatively, you may want to execute the steps yourself:
```rust
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();
```
To see some implementations, check out [padme-demo](https://github.com/alexlren/padme-demo), a desktop demo or [padme-browser](https://github.com/alexlren/padme-browser), a web assembly version.
## Features
- [x] no_std
- [x] Timer
- [x] DMA
- [x] CPU Dissassembler
- [x] Pixel Processor Unit with fifo
- [x] External Screen
- [x] External Serial port
- [x] Joypad
- [x] Rom, MBC1, MBC3
- [x] Integration tests
- [x] Audio processor unit
## Todo
- [ ] Add support for MBC2, MBC4, MBC5, MBC6, MBC7
- [ ] Add unit tests for each module