zacharyestep / rosettaboy

A gameboy emulator in several different languages

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

RosettaBoy

Trying to implement a gameboy emulator in a bunch of languages for my own amusement and education; also giving people an opportunity to compare the same code written in different languages, similar to Rosetta Code but with a non-trivial codebase :)

The main goals are:

  • Readability of the code
  • Consistency across langauges
  • Idiomatic use of language features
  • Basic playability

Notably, 100% accuracy is not a goal - if Tetris works perfectly then I'm happy, if other games require more obscure hardware features, then I'll weigh up whether or not the feature is worth the complexity.

Also yes, "consistent across languages" and "idiomatic" can be at odds - there are subjective compromises to be made, but for the most part that doesn't seem to be a huge problem. Rust uses Result, Python uses Exception, Go uses error - but so far it's always been pretty obvious that eg NewCart() in go and Cart.new() in rust are doing fundamentally the same thing in the same way.

So far all the implementations follow a fairly standard layout, with each module teaching me how to do a new thing. In fact they're all so similar, I wrote one copy of the documentation for all the implementations:

  • main: argument parsing
  • cpu: CPU emulation
  • gpu: graphical processing
  • apu: audio processing
  • buttons: user input
  • cart: binary file I/O and parsing
  • clock: timing / sleeping
  • consts: lists of constant values
  • errors: standard errors / exceptions / etc
  • ram: array access where some array values are special

Pull requests to translate into new languages, or fleshing out existing languages, are very welcome :)

Benchmarks

Warning: These implementations aren't fully in-sync, so take numbers with a large grain of salt. For example: the Python implementation uses native code to blit whole 8x8 sprites in one go, while the other languages do one pixel at a time (which is more correct, and necessary for things like parallax effects), which means that the python version is unfairly fast.

If somebody knows how to measure CPU instructions instead of clock time, that seems fairer; especially if we can get the measurement included automatically via github actions. Pull requests welcome :)

Running on an M1 Macbook Pro:

$ ./bench.sh
 zig: Emulated 600 frames in  0.23s (2880fps)
  rs: Emulated 600 frames in  0.35s (1691fps)
 cpp: Emulated 600 frames in  0.40s (1519fps)
 nim: Emulated 600 frames in  0.44s (1367fps)
  go: Emulated 600 frames in  1.78s (338fps)
 php: Emulated 600 frames in 23.80s (25fps)
  py: Emulated 600 frames in 33.10s (18fps)

Also if you spot some bit of code that is weirdly slow and making your favourite language look bad, pull requests to fix that might be welcome too, but "simplicity and consistency" are going to take priority (eg an "add an inline flag to this function" would be great but "replace python's CPU interpreter with a JIT compiler written as a C extension module" would probably be rejected[0])

[0] That said if somebody wanted to come up with a separate "python but all the slow parts are replaced with C modules like they would be in a real app" implementation, that could be interesting...

About

A gameboy emulator in several different languages

License:MIT License


Languages

Language:C++ 31.0%Language:Rust 15.2%Language:Zig 11.6%Language:PHP 11.4%Language:Python 11.2%Language:Nim 10.0%Language:Go 9.2%Language:Shell 0.2%Language:CMake 0.1%Language:Dockerfile 0.0%