# Chip Eight
## Background
This project is an attempt at a generic chip 8 emulator implementation that can be plugged in to any front end (kind of). Ultimately it is a personal learning project for me to eventually run the emulator on a Rasberry Pi on a 64x32 LED array. On the way there though, I would like to be able to keep testing, as I don't have all of the hardware set up yet.
The idea here is that there are two traits that need to be implemented to get the emulator working on a system, `Draw` and `ReadInputState`. These simply give the emulator handles to the functions to draw to the screen, and read the current keyboard state.
```rust
pub trait Draw {
fn draw_buffer(&mut self, screen_buf: &[u8]);
fn clear_screen(&mut self);
}
pub trait ReadInputState {
fn read_keys_state(&self) -> Result<[u8; 16], String>;
fn reset_keys_state(&mut self);
}
```
If interested, see `examples/winit_example.rs` to find a dummy implementation that might work on other platforms than my own.
## Examples
You can also run `cargo run --example winit_example /path/to/chip8/binary.c8` to try it out.
Additionally run `cargo run --example debug_example /path/to/chip8/binary.c8` to step through a program. Hold enter to speed through, type q to quit.
Potentially if you want to see the most cursed implementation check out `cargo run --example debug_example /path/to/chip8/binary.c8`.
## Usage
Once you have implemented your traits you just need to call `init` and `run` on the emulator. Init loads the program, and will throw an error if the program or font would load out of range. Currently the font is static, so it won't cause a panic, but same can't be said if you try load Bee Movie in as a ch8 program.
```rust
let drawer = Drawer::init();
let input_reader = InputReader::init();
let mut emulator = chip_eight::Emulator::init(program, drawer, input_reader)
.expect("The chip 8 program is probably too large")
.set_max_draw_delay(Duration::from_millis(6))
.set_quirks_mode(QuirksMode::Chip8);
// Most simply you can then run the emulator:
emulator.run_blocking();
// You could also iterate through the interpreter if you want.
for emulator_state in emulator {
// Here emulator_state gives you access to the previous instruction as well as
}
```
## Notes
The emulator will block the current thread, so do make sure you do the input handling and display off thread. Maybe this is a place for improving the UX for this library, not really sure.
## References
- [Chip 8 test suite](https://github.com/Timendus/chip8-test-suite/tree/main)
- [Tuturial on how to build a Chip 8 interpreter](https://tobiasvl.github.io/blog/write-a-chip-8-emulator/)
- [How I finally found out how to do the drawing properly](https://www.laurencescotford.net/2020/07/19/chip-8-on-the-cosmac-vip-drawing-sprites/)
- [Where I stole winit example state enum idea](https://github.com/rust-windowing/softbuffer/)
- [Where to find some games to test](https://johnearnest.github.io/chip8Archive/) (Only the top ones I think so far)