Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Malax committed Oct 23, 2018
0 parents commit cb53cbf
Show file tree
Hide file tree
Showing 47 changed files with 15,632 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.cache
.DS_Store
.idea
dist
elm-stuff
node_modules
repl-temp-*
661 changes: 661 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Elmboy
A work in progress Game Boy emulator written in pure Elm.

![The Legend of Zelda: Link's Awakening Gameplay](https://raw.githubusercontent.com/Malax/elmboy/master/readme-assets/zelda.png)
![Kirby's Dreamland Gameplay](https://raw.githubusercontent.com/Malax/elmboy/master/readme-assets/kirby.png)
![Pokemon Red Title Screen](https://raw.githubusercontent.com/Malax/elmboy/master/readme-assets/pokemon.png)

## Goals
This is mainly for my own entertainment, education and challenge. It's a non-trivial problem to solve, I love retro games and have a some sort of emotional
connection to the Game Boy. There are hundreds of Game Boy emulators out there, but none for Elm yet. And as I like Elm very much, this is the perfect
side-project for me. Also, I think it's pretty cool!

However, there are some goals I set for myself when I started. I wanted to be able to run my favourite Game Boy games:

1. [The Legend of Zelda: Link's Awakening](https://en.wikipedia.org/wiki/The_Legend_of_Zelda:_Link%27s_Awakening)
2. [Pokémon Red and Blue](https://en.wikipedia.org/wiki/Pok%C3%A9mon_Red_and_Blue)
3. [Super Mario Land 2: 6 Golden Coins](https://en.wikipedia.org/wiki/Super_Mario_Land_2:_6_Golden_Coins)
4. [Super Mario Land](https://en.wikipedia.org/wiki/Super_Mario_Land)
5. [Tetris](https://en.wikipedia.org/wiki/Tetris)

Except for poor performance and Pokémon, all of them run to a certain degree.

Another goal was staying true to Elm. As little Javascript as possible and nice functional code all around. Sadly, I had to compromise on the **nice**
functional code in some cases due to performance.

## Non-Goals
- Achieving a very high degree of emulation accuracy
- Becoming a "serious" emulator that is used by Homebrew developers and/or speed runners
- Debugging capabilities
- Game Boy Color support

## Performance
In its current state, the emulator runs at about 50% speed compared to an original Game Boy.
This is on my MacBook Pro (Mid 2015, 2.5 GHz Intel Core i7, 16 GB RAM), running Chrome 69.0.3497.100. Performance in Firefox is even worse,
Chrome seems to have a better performing JIT for this project.

The main issue seems to be the very frequent state updates (100k+ times per second) which always require a record copy which tends the be quite slow. To
mitigate the issue, the amount of state changes needs to be minimised as much as possible, probably requiring a serious overhaul of the whole codebase.

I already refactored the codebase several times for performance, removing a lot of abstractions that made the code a lot nicer but performed worse than the
current version. I want to reintroduce some of those abstractions and conciser types down the line, without sacrificing performance too much. It's hard to
strike a perfect balance on that. If you see very un-Elm-y code, it's probably due to some performance impact the more idiomatic solution had.

Eventually, I plan to bring emulation speed up to 100% on a decently sized machine.

### So Elm is slow?
No, that is not what I am saying. Elm is made for web applications — not emulator development. This project does almost never change the DOM and has
requirements that you usual web app does not have. Especially the amount of state updates is by magnitudes larger than I can imagine even the fanciest
web app might have. If you look at emulators written in other statically typed functional languages, like Haskell, you will see that, even though they compile to
native machine code, do use *escape hatches* to implement state in a performant way like
[IORef](https://hackage.haskell.org/package/base-4.12.0.0/docs/Data-IORef.html)s that are not available in Elm.

I'm actually surprised how fast it is, without spending too much time on optimisation. I imagined that performance might be the hardest hurdle to overcome
with this project before I even started.

I'm curious how much performance can be squeezed out of the code after optimisation! I bet there are a lot of things I could do more efficiently.

## Building
Run `npm install` to produce an optimised build in the `dist` folder. For development, run `npm start` to spawn a HMR development server.
Binary file added assets/cartridge.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions elm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"type": "application",
"source-directories": [
"src/elm"
],
"elm-version": "0.19.0",
"dependencies": {
"direct": {
"elm/browser": "1.0.0",
"elm/core": "1.0.0",
"elm/html": "1.0.0",
"elm/json": "1.0.0",
"elm/random": "1.0.0",
"rtfeldman/elm-hex": "1.0.0",
"rundis/elm-bootstrap": "5.0.0"
},
"indirect": {
"avh4/elm-color": "1.0.0",
"elm/time": "1.0.0",
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.0"
}
},
"test-dependencies": {
"direct": {},
"indirect": {}
}
}
Loading

0 comments on commit cb53cbf

Please sign in to comment.