Pokegb: A gameboy emulator that only plays Pokémon Blue, in 68 lines of C++
binji.github.io
binji.github.io
If you've ever written a drop-in replacement for some existing piece of software and filled the implementation with a bunch of `notimplemented()` (example)[1], you know exactly how satisfying this is. I love it.
[1]: https://github.com/Planimeter/lgf/blob/master/lua/framework/...
[1] https://github.com/missblit/nesnes/blob/master/instructions_...
Granted, most opcodes are implemented incorrectly as minor things like method and field resolution aren’t quite there yet.. as soon as I’ve implemented enough opcodes to actually run something and return/exit/throw, the correctness will be a bugger to fix :^)
Once you get it working, you could run things like JSLinux! https://bellard.org/jslinux/vm.html?url=win2k.cfg&mem=192&gr...
A bit of a tangent, I know, but it feels important.
That said, in my opinion the ideal set of opcodes really depends on your goal. There were many goals For Wasm, but I think there was a focus on keeping it small and simple. Originally it was AST-based, but it was changed to a stack machine to reduce size. It was also designed to be AoT or JIT compiled, so the opcode layout is not particularly friendly to hardware decoding or interpreters (although people have made some very high quality Wasm interpreters).
And of course there were a lot of discussions and disagreements about the best way forward: AST vs. register VM vs. stack machine. Structured control flow vs. goto. How to handle unreachable code. How to store integer literals (LEB vs. prefix byte). What the text format should look like (sexprs vs. ...?) etc.
However there were a lot of discussions that were not in those meetings and were in smaller groups or held in GitHub issues or PRs. Most of these were in https://github.com/webassembly/design.
Cheers for the link to the meeting notes in the other comment chain, sounds like a great rabbit hole
Good luck with the mammoth project! I think the fun will really start when it comes to running mini programs to test against a reference implementation and finding out we implemented core parts like method/field/(super)interface resolution totally wrong.
Oh, and optimisation too. It’d be cool to implement a JIT but that’s a long way away
It is a surprisingly satisfying activity.
Off topic, I wouldn't do a 6502 as a giant switch, you'll likely miss out on a lot of the shared logic. If you decode the instructions differently, you can easily reuse logic for addressing modes and what not.
I really like how the opcodes are laid out in the table on this wiki http://wiki.nesdev.com/w/index.php/CPU_unofficial_opcodes
My emulator passes the Klaus2m functional suite and my Apple ][ emulator is able to run quite a few protected games.
https://gameboy.blog/2021/06/04/good-read-pokegb-a-gameboy-e...
The trick I used was to take an existing GB emulator, add a printf debugging statement to print out each current instruction and the registers. Add the same printf statements on mine. Then use diff on the outputs of both emulators.
It does play Pokemon. The emulator is called FireGB.
However I feel like that "spoils" a bit of the fun. A more adventurous approach is to test with test ROMs [1] - they are simpler to follow by hand and discover why they don't work than real games.
Of course if some game ROM is relying on some more obscure hardware quirks this might not be enough. Just wanted to bring it to attention for anyone interested in writing and debugging their emulators.
I ended up just copying a lookup table from an open source emulator at the time, which of course didn't help my understanding: https://github.com/visualboyadvance-m/visualboyadvance-m/blo...
Funny to finally realize what this does, and now see how the lookup table works.
#include <SDL2/SDL.h>
How big is the final binary? It would be interesting to compare the final size to the total size of the GBC game. Although apparently> Many features are not implemented!
So I'm not sure it's ready for that comparison.
For people who like this kind of thing and/or for people who want to be able to understand what is going on at all, you might like the course NAND2Tetris [2]. It's a good prerequisite to understanding this blog post if computer systems isn't a topic that one has explored before.
[1] https://gist.github.com/binji/395669d45e9005950232043ab4378a... -- the author notes this in the article.
Seems sufficiently interesting either way
https://www.reddit.com/r/tinycode/comments/nn5djb/pokegb_a_g...
Now, of course, that's basically cooking the books, but there's a wide gulf between a full VM & smaller, domain specific ones that might not look like VMs. (All or most of data-driven programming, really.)
The OS too?
There should rather be a normalization metric where all identifiers are treated as eight characters long
Resulting binary will be different depending on the compiler and type of optimization and would simply be manipulated by optimizing heavily for size.