[HN Gopher] Pokegb: A gameboy emulator that only plays Pokemon B...
       ___________________________________________________________________
        
       Pokegb: A gameboy emulator that only plays Pokemon Blue, in 68
       lines of C++
        
       Author : brundolf
       Score  : 531 points
       Date   : 2021-06-04 18:31 UTC (1 days ago)
        
 (HTM) web link (binji.github.io)
 (TXT) w3m dump (binji.github.io)
        
       | anthk wrote:
       | Some Forth wacko would reduce that to 40 lines...
        
       | sarak12070 wrote:
       | Secret plan for weight loss Step by step guide
       | http://healthwithbeauty.xyz/2021/06/02/six-week-makeover-die...
       | 
       | Orchid mantis Fun Facts These flowers can walk like animals
       | https://www.interestingnews.club/2021/06/orchid-mantis-fun-f...
       | 
       | Wheel whackers' keep snakes out of planes in California desert
       | https://www.interestingnews.club/2021/06/wheel-whackers-keep...
        
       | mettamage wrote:
       | You might want to add (obfuscated) to the title. The actual
       | source code, while small, is much larger [1]. (edit: at 589 lines
       | it's still impressive!)
       | 
       | 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.
       | 
       | [2] https://www.nand2tetris.org/
        
         | nighthawk454 wrote:
         | Still, the unbofuscated one is only 589 lines including
         | formatting, a copyright header, and what looks to be an 80-char
         | line limit.
         | 
         | Seems sufficiently interesting either way
        
           | Aachen wrote:
           | See, the truth is just as impressive to me, but knowing it's
           | not a lie and a more than fair line length makes me
           | appreciate it.
        
         | smithza wrote:
         | 68 lines of code is pretty much arbitrary. It could have been
         | far less, he just put it all to fit his poke ball pattern.
        
           | anonymousiam wrote:
           | The author's tweet claimed 62 lines.
        
             | binji wrote:
             | Yep, I made a mistake it's actually 68.
        
           | dheera wrote:
           | That, and obfuscation is also relative. You could call the
           | 589 lines obfuscated as well.
        
         | ngokevin wrote:
         | The obfuscated one is awesome though, the code is in the shape
         | of pokeballs!
        
         | userbinator wrote:
         | I think instead of line count, either final binary size or
         | source code size in bytes should be more common in claims of
         | minimalism; the demoscene, for example, always uses binary
         | size.
        
           | Ekaros wrote:
           | Final binary size including all external dependencies is
           | probably fairest metric. With heavy use of libraries things
           | get messy.
        
           | binji wrote:
           | I got kinda dragged about this on reddit/twitter. Afterwards
           | I posted on r/tinycode with the size in bytes:
           | 
           | https://www.reddit.com/r/tinycode/comments/nn5djb/pokegb_a_g.
           | ..
        
             | kzrdude wrote:
             | would it be possible to push it down to IOCCC size? Would
             | be fun to see it there, of course.
        
               | binji wrote:
               | I think so, when I was doing the write-up I noticed a few
               | things I could have improved (and a few bugs!)
        
             | iampims wrote:
             | Don't let any of these comments take away from how great
             | this is, _especially_ with the in-depth blog post.
        
           | IgorPartola wrote:
           | Number of nodes in the AST or number of machine instructions
           | might be more meaningful.
        
             | deathanatos wrote:
             | That metric is game-able, too: you just implement a VM, and
             | only count the instructions to to VM. The rest is one big
             | binary blob of "data", occupying a single node in the AST
             | of the host language.
             | 
             | 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.)
        
           | Blikkentrekker wrote:
           | source code size can still be manipulated by using very small
           | identifiers or reusing them.
           | 
           | 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.
        
       | [deleted]
        
       | vmception wrote:
       | "This is super impressive Binji we would love to have you on our
       | team, now that you've got our attention pass this leetcode
       | challenge with a random assortment of unrelated skills instead,
       | and faster than the people that only study this specific kind of
       | test"
        
         | tkiolp4 wrote:
         | Ha. This made my day.
        
         | binji wrote:
         | Ha, I guess we'll see when I go for my next gig :-)
        
         | mosselman wrote:
         | "It's nothing personal, everybody has to do these, it wouldn't
         | be fair to the rest otherwise."
        
         | userbinator wrote:
         | I can't speak for Binji but in my experience those who know the
         | low-level enough to be able to write emulators like this will
         | also do very well on leetcode-like challenges.
        
       | andrewmcwatters wrote:
       | > When I started pokegb, I spent most of the first few days
       | implementing the CPU. Every time I hit an instruction that wasn't
       | implemented, I'd implement it and see if it would run any
       | further.
       | 
       | 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/...
        
         | binji wrote:
         | It really is one of the best things about emulation
         | development. It's surprising how quickly you go from "nothing
         | works" to "I'm playing Super Mario Bros!"
        
         | missblit wrote:
         | I never did get very far with my NES emulator after getting an
         | actual job (it was plan B for if no one liked my resume), but I
         | do remember that being oddly satisfying [1]
         | 
         | [1]
         | https://github.com/missblit/nesnes/blob/master/instructions_...
        
           | city41 wrote:
           | It's one of my favorite things about programming. For example
           | I made a Neo Geo tile viewer and decoding the format and
           | figuring out just what needs to be done to get it working
           | then suddenly BAM! tiles tiles everywhere! It's so
           | satisfying.
        
             | makapuf wrote:
             | I made a game console on an embedded system. The magic when
             | you actually bitbang pixels to a screen and you see that
             | first image is breathtaking.
        
         | tiddles wrote:
         | This x1000. I started implementing a JVM for shits and giggles
         | a while ago, and once I had laid out ~220 panics for each
         | opcode, it was incredibly satisfying to implement them one at a
         | time to work towards bootstrapping the standard library.
         | 
         | 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 :^)
        
           | binji wrote:
           | JVM is a great choice! You might also want to check out
           | WebAssembly too (full disclosure: I used to work on wasm).
           | There aren't too many opcodes, and a lot of them are
           | relatively simple math operations.
           | 
           | Once you get it working, you could run things like JSLinux! h
           | ttps://bellard.org/jslinux/vm.html?url=win2k.cfg&mem=192&gr..
           | .
        
             | javajosh wrote:
             | Given your experience at this level of abstraction, do you
             | have any thoughts on what an ideal set of opcodes look
             | like? E.g. something like Knuth's MMIX. Do you prefer RISC
             | or CISC? What about RISC-V? How much do the designers of
             | real-world micro-architectures talk to folks like you?
             | 
             | A bit of a tangent, I know, but it feels important.
        
               | binji wrote:
               | I'm probably the wrong person to ask, to be honest. I was
               | around for a lot of the design of Wasm, but wasn't really
               | involved at that level.
               | 
               | 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.
        
               | ywei3410 wrote:
               | Are there any meeting notes/chat logs for those
               | discussions? It would be fascinating to get some insight
               | into the design process for a modern VM.
        
               | binji wrote:
               | Yes, you can find all the meeting notes here:
               | https://github.com/webassembly/meetings
               | 
               | 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.
        
             | tiddles wrote:
             | That's a great idea, I'm not that familiar with wasm and
             | the best way to learn is of course to implement a VM :)
             | 
             | Cheers for the link to the meeting notes in the other
             | comment chain, sounds like a great rabbit hole
        
           | skitter wrote:
           | I've just started the same, it's definitely fun. One thing
           | that surprised me about field resolution is that a class can
           | have multiple fields with the same name (if they have
           | different types).
        
             | tiddles wrote:
             | The gigantic spec has so many surprises hidden in it - the
             | use of a bespoke "modified utf8" for native strings was a
             | fun discovery.
             | 
             | 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
        
         | hota_mazi wrote:
         | Exactly this. I wrote an Apple ][ emulator, so I started by
         | writing a 6502 emulator, and this is the only approach. Start
         | with a giant switch, implement a few opcodes, run a program,
         | wait until it reaches the not implemented case, implement it,
         | repeat.
         | 
         | It is a surprisingly satisfying activity.
        
           | toast0 wrote:
           | On topic, I had tremendous fun writing the CPU emulation for
           | my maybe 1/3rd done NES emulator (that I likely won't finish,
           | but who knows).
           | 
           | 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
        
         | seligman99 wrote:
         | I've done things along these lines for things like the Advent
         | of Code "int-code" assembly language implementations. It's
         | satisfying to go from crashing because an opcode isn't
         | implemented to something that produces output.
        
       | greatNespresso wrote:
       | That's really incredible ! Still, for a total beginner like I am,
       | 589 lines of C++ don't seem enough to cover it all, so what's the
       | fuss? Where are the assets? What should I look for? Agreed, feel
       | free to post on show HN to level up the debate
        
         | hoten wrote:
         | It's an emulator, not the game data/ROM.
        
       | ggambetta wrote:
       | I did something similar with an X86, with enough opcodes
       | implemented so it could run Goody (an ancient CGA game):
       | https://gabrielgambetta.com/remakes.html Super fun exercise!
        
       | binji wrote:
       | Hi all, I'm the author of this post! Happy to answer any
       | questions. :-)
        
         | shawntan wrote:
         | Does the MissingNo glitch work?
        
           | binji wrote:
           | Not sure, I think it should! Would be really cool if someone
           | tried it out. I'm a little worried I didn't implement some
           | necessary instructions/hardware features so the game isn't
           | actually winnable :-}
        
             | shawntan wrote:
             | Love the project. nostalgia++
        
         | Andrex wrote:
         | I hope it's OK I blogged about your project!
         | 
         | https://gameboy.blog/2021/06/04/good-read-pokegb-a-gameboy-e...
        
         | crowf wrote:
         | I may have missed it in the post, but how is blue different
         | than red? I realise that they have slightly different Pokemon,
         | but is that enough to make the emulator run only blue?
        
           | binji wrote:
           | Oops you're right, I should have mentioned that. Red works
           | too, I just didn't want to write Blue/Red everwhere :)
        
             | northern-lights wrote:
             | What about Yellow? If yes, you could shorted it as RBY
             | which is more familiar to most old genners.
        
             | glhaynes wrote:
             | In the spirit of the project I'm surprised you didn't pick
             | "Red" because it's one fewer characters. :)
        
           | Y_Y wrote:
           | It probably needs less memory, since you only 8 bits to store
           | blue but red needs 3.
        
       | anonytrary wrote:
       | #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.
        
       | belthesar wrote:
       | This reminds me of the GB emulator that ran inside of Pokemon
       | Stadium. Folks found some tricks to make it work with other
       | cartridges, but it turned out the emulator was not complete.
       | https://n64today.com/2019/06/02/play-game-boy-games-on-n64/
        
       | deepfriedrice wrote:
       | Love the explanation of the DAA instruction. I wrote a gbc
       | emulator in college, but couldn't figure out what that
       | instruction was supposed to do.
       | 
       | 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.
        
         | binji wrote:
         | I kind of dreaded writing that one, to be honest! I didn't
         | quite cover all the details but I hope it made a little more
         | sense. :)
        
       | ReflectedImage wrote:
       | I wrote a GB emulator, the main issue was debugging it. Subtlely
       | wrong tends to lead to game crash very quickly.
       | 
       | 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.
        
         | progbits wrote:
         | Comparing to an existing, known-good emulator is probably the
         | most convenient way. This can be printf debugging like you
         | describe, or even trying to compare framebuffer contents etc.
         | 
         | 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.
         | 
         | [1]: https://gbdev.gg8.se/wiki/articles/Test_ROMs
        
           | ReflectedImage wrote:
           | Ahh but it already passed the test ROMs at the point I turned
           | to printf debugging.
        
       ___________________________________________________________________
       (page generated 2021-06-05 23:02 UTC)