[HN Gopher] Writing a Game Boy Emulator in OCaml
       ___________________________________________________________________
        
       Writing a Game Boy Emulator in OCaml
        
       Author : yakshaving_jgt
       Score  : 354 points
       Date   : 2022-01-12 10:08 UTC (12 hours ago)
        
 (HTM) web link (linoscope.github.io)
 (TXT) w3m dump (linoscope.github.io)
        
       | fareesh wrote:
       | OCaml
       | 
       | I am but a fool
        
       | sandebert wrote:
       | Looks nice, well done.
       | 
       | I'd also like to add that it seems like a missed opportunity
       | here. It could have been named OBoy.
        
         | ackfoobar wrote:
         | It doesn't seem OCaml's object system is used there. That name
         | would not be fitting. Sorry to ruin your joke. :P
        
       | d3nj4l wrote:
       | Great job! Really well written, easily one of the better
       | technical posts I've seen on HN in a while. I loved messing
       | around with the (homebrew?) ROMs on the online emulator, too!
        
       | padator wrote:
       | Not sure you really need GADTs for the instruction set. A
       | separate arg8 and arg16 ADT types would be enough, so you would
       | have | Add8 of arg8 * arg8
        
         | linoscope wrote:
         | Hi, author here. Yeah, I thought the same and tried that too,
         | but it failed due to the same reason mentioned in the "Problem
         | with the definition using variants" section. Namely, the return
         | value type of `read_arg` would not be uniquely determinable. We
         | CAN define separate `read_arg8` for `read_arg16` for the `arg8`
         | and `arg16` respectively, but I thought the GADT solution was
         | more clean.
        
       | Zababa wrote:
       | Great article, thanks for writing that. A small question for the
       | author: in the Addressable_intf.S signature, read_byte has
       | regular arguments and write_byte named arguments. Is there a
       | reason for that?
        
         | linoscope wrote:
         | Thanks!
         | 
         | I added labels based on the number of arguments. `write_byte`
         | has two arguments (other than `t`), the `addr` and `data`, so I
         | used labeled arguments to distinguish the two easily. On the
         | other hand, `read_byte` only has one argument, so I didn't
         | label the argument. I saw this approach used in some Jane
         | Street libraries: for example, `Hashtbl.set` takes two
         | arguments and is labeled, while `Hashtbl.find` only has one
         | argument and is not labeled.
         | 
         | But I was sometimes confused and wrongly provided labels to
         | `read_byte`, so looking back at it now, maybe I should have
         | just labeled both functions for consistency.
        
       | rixed wrote:
       | Looks very polished, but major disappointment that it's not
       | showcasing OCaml as part of RosettaBoy
       | (https://github.com/shish/rosettaboy)
        
         | Zababa wrote:
         | It seems like the RosettaBoy project/repo is not well known at
         | all. I've search information about gameboy emulators before and
         | never saw it mentioned, the project has only one contributor
         | that's active, a few language, not much stars or watchers. I'm
         | surprised that you expected the author to know that project.
        
           | rixed wrote:
           | True, yet it has been submitted in HN not so long ago
           | (https://news.ycombinator.com/item?id=28800673) but didn't
           | reach anywhere near the front page.
        
       | aliswe wrote:
       | A developer at our place did our log search tool in OCaml, the
       | reason being "because I've never worked with it before". It had
       | to be scrapped shortly after he left.
        
         | fsloth wrote:
         | Naur's classic essay (and maybe my favorite essay in all of
         | software engineering) "Programming as theory building" [0 ]
         | comes to mind. If the theory of the program is lost then it's
         | quite hard to continue work no matter what the language used.
         | 
         | Based on your description it might as well have been scrapped
         | regardless of the programming language used?
         | 
         | [0] https://pages.cs.wisc.edu/~remzi/Naur.pdf
        
           | aliswe wrote:
           | No, the problem is that hardly noone had even heard of OCaml,
           | much less had any experience with any functional language,
           | much less knew how to maintain this tool.
           | 
           | My point is that it was very tone deaf to introduce a new
           | technology onto the stack for this reason (so called resume-
           | based development I think?).
        
             | Kototama wrote:
             | I doubt it, ocaml has very little job offers. Didn't you
             | have a process or better communication to avoid this
             | situation?
        
               | aliswe wrote:
               | You doubt what exactly? Nah we hardly had any processes
               | at all back then.
        
               | Kototama wrote:
               | I doubt it's for the resume because there are very few
               | ocaml jobs.
        
               | hiptobecubic wrote:
               | You don't need to find a job that wants ocaml, just a job
               | that recognizes what it means that you've written it.
        
         | Zababa wrote:
         | This says a lot more about your place than about OCaml, so I'm
         | not sure why you mention this here.
        
         | TurboHaskal wrote:
         | So it had to be scrapped due to the same reason why it got
         | written in the first place. Poetic.
        
           | aliswe wrote:
           | indeed!
        
         | squeaky-clean wrote:
         | I heard about similar story from some old coworkers. I left the
         | company because it always had a problem with good
         | communication, devs being siloed, etc...
         | 
         | A "python dev" left the company. A different python dev was
         | assigned to maintain his projects. They were surprised to find
         | out all of ex-employee's "python" projects over the past 2
         | years were actually written in Rust. There was absolutely no
         | code review in his department so no one was aware of this! No
         | one else at the company knew Rust and they were debating
         | rewriting it all, or hiring a Rust dev.
         | 
         | My old coworkers were basically putting all the blame on that
         | one guy. And sure, that's shitty and unprofessional of him. But
         | how could someone write Rust for 2 years and no one else
         | notices?? I didn't understand how they could blame the guy and
         | also not feel supremely embarrassed for even getting into that
         | situation.
        
           | maupin wrote:
           | I'm guessing he was hired for Python then decided to learn
           | Rust by doing a few work-related tasks in Rust and it
           | snowballed.
        
         | Kototama wrote:
         | It sounds like you had a smart developer that needed more
         | challenges at work :) ?
        
         | rixed wrote:
         | You forgot to say why it had to be scrapped ?
        
           | aliswe wrote:
           | consistent stack that we can find competence for!
        
         | willcipriano wrote:
         | People who make statements like this always seem to be
         | programming language operators rather than computer scientists.
         | If you are good you can make almost anything work.
        
           | stonemetal12 wrote:
           | Or they could be engineers. Cost benefit of learning a new
           | language to support something designed and built in random
           | language by some one who didn't actually know how to do high
           | quality design work in that language is rather low.
           | 
           | It is like reading the first Turkish works of an English
           | poet, who decided to learn Turkish by writing poems.
        
             | willcipriano wrote:
             | None of what you mentioned is the fault of the language.
             | Turkish isn't a bad language, you are bad at Turkish.
        
         | LAC-Tech wrote:
         | Ocaml is not a particularly hard language IMHO. If anyone had
         | wanted to learn, they would have learned.
         | 
         | Sounds like the real issue is you wanted to write your own log
         | tool.
        
         | keewee7 wrote:
         | >because I've never worked with it before
         | 
         | Yeah, that is the wrong reason to pick a new language to build
         | an internal tool.
        
         | postalrat wrote:
         | So another developer thought they could do it better and used
         | ocaml as the excuse?
        
       | laputan_machine wrote:
       | Really nice write up! It would have been nice to see more on how
       | you handled the display, on my emulator journey the two big "i
       | have no idea how to solve this" problems I had were 1)
       | synchronising cpu/gpu/sound (and I settled on the exact method
       | you use, 'catching up'), and 2) writing the framebuffer to the
       | screen. The resources I've used always seem to skip over it, so I
       | assume it's obvious, but it isn't to me.
        
         | linoscope wrote:
         | Thanks! I ended up omitting the GPU since it didn't use much
         | interesting OCaml features. But yes, the GPU was the most time
         | consuming part for me too (both to understand and to
         | implement), so I can relate to the "i have no idea how to solve
         | this" feeling.
        
       | anthk wrote:
       | From Ocaml I still use MLDonkey daily. I hope the multicore Ocaml
       | brings a speed up for it. I am not saying MLDonkey is slow or
       | unstable, but it could gain a performance boost on current
       | machines.
        
         | Kototama wrote:
         | I started it last year again and was surprised that the network
         | is still working.
        
           | anthk wrote:
           | It's the best network for old stuff, you can't legally get
           | lots of old series, comic books or music.
           | 
           | Inb4 piracy, thanks to CBR's I've got more physical mangas
           | and comic books than ever.
        
       | tombert wrote:
       | An emulator is still on my "bucket list as an engineer." I feel
       | like it's a hurdle I still haven't crossed and I'm reasonably
       | certain I _could_ make one.
       | 
       | I have some free time this weekend...I might take this repo and
       | port it over to clojure to get the hang of things.
        
         | easterncalculus wrote:
         | The UXN project might also be fun, the virtual machine is
         | fairly simple to implement and there are a lot of interesting
         | programs written for it.
         | https://wiki.xxiivv.com/site/uxn.html
         | 
         | There is also the LC3 virtual virtual machine, with a fairly
         | great guide on creating it.
         | https://justinmeiners.github.io/lc3-vm/
        
         | djxfade wrote:
         | My first "emulator" was a Brainfuck interpreter. Really simple
         | to implement and understand
        
           | tombert wrote:
           | That's a great idea! I think you win for my weekend
           | project...if nothing else it will be fun to bring up that I
           | made a Brainfuck compiler.
        
         | toast0 wrote:
         | I've written somewhere around 1/3rd of a NES emulator. It does
         | the CPU, and the backround half of the PPU, but not foreground
         | sprites, sound, controllers, or running at decent speed ;)
         | 
         | Anyhow, I found the CPU part a lot of fun, and there's public
         | domain test roms with expected registers after each instruction
         | that you can use to test and confirm. Interaction with other
         | hardware and emulation of that hardware gets a lot more
         | challenging. The gameboy is certainly different than the NES,
         | but I suspect there's a lot of similarity at the high level.
         | It's certainly reasonable to stop (or pause, perhaps), when it
         | stops being so fun, too.
         | 
         | I'm also not sure porting an emulator is going to give you the
         | same understanding as writing one, but maybe.
        
         | mzs wrote:
         | Emulating old terminals is fun.
        
         | CyberRabbi wrote:
         | A nice perk of writing an emulator is the exposure you'll get
         | when it hits the front page of HN and other tech news sites.
        
         | Cyph0n wrote:
         | It is definitely a fun learning exercise, but also quite
         | addictive and grueling (yes, a contradiction)!
         | 
         | I wrote a Gameboy Color emulator[1] earlier this year, but
         | stopped as soon as I realized that I wasn't learning anything
         | new. As a result, my emulator has a few issues and does not
         | support sound, but it is able to run quite a few games. I also
         | got it running in a browser via WASM, which was fun.
         | 
         | [1]: https://github.com/aksiksi/gbc
        
         | jjnoakes wrote:
         | For a fun and fairly basic task, consider giving the 2019
         | advent of code a try. You will end up with a basic emulator for
         | an imaginary machine, but you will get to solve interesting
         | puzzles with it.
        
         | hota_mazi wrote:
         | Start with a CHIP-8 emulator, it's a great first emulator to
         | write that will expose you to a lot of core concepts without
         | all the complexity that comes with more advanced systems.
        
         | eatonphil wrote:
         | My unpopular opinion is to emulate an extremely reduced subset
         | of x86. For example, jump to main and emulate the result of
         | `int main() {return 2;}` compiled with gcc. You already have
         | the compiler (no need to cross compile), you already have the
         | decompiler and you can run the binary on the reference machine
         | without an emulator. You save so much time having this entire
         | toolchain already and you can start emulating simple C programs
         | for x86 with <10 instructions and 1 or 2 addressing modes. I've
         | written about this process before in Node and Go [0].
         | 
         | Yeah everyone will comment after me that x86 gets way more
         | complex over time but if you just want to get a quick intro and
         | you aren't a perfectionist x86 is kind of compelling.
         | 
         | And recently I wanted to try emulating MSP341 at someone's
         | recommendation because it has a very simple architecture. But
         | just getting a C compiler for it isn't easy! When I've tried to
         | cross-compile C to other archs like RISC-V it also wasn't
         | straightforward and I just got stuck in this toolchain spot.
         | 
         | If it were easier to cross-compile simple languages like C then
         | writing emulators for other environments would be easier.
         | 
         | If you're on a new Mac, my whole argument applies for aarch64
         | instead of x86.
         | 
         | [0] https://notes.eatonphil.com/tags/emulators.html
        
           | gavinray wrote:
           | I thoroughly enjoyed what little I read of this, bookmarked
           | it for later -- thanks!
           | 
           | https://notes.eatonphil.com/emulating-amd64-starting-with-
           | el...
        
           | dogprez wrote:
           | But emulating the CPU is probably the least interesting part
           | about writing an emulator for a video game system. Writing
           | the other hardware components and getting them to work
           | together is the interesting part imo. I'd say skip writing
           | your own CPU emulator and just start with someone else's.
        
             | eatonphil wrote:
             | As a typical backend dev, being able to emulate my own
             | program compiled with GCC was pretty rewarding personally.
             | 
             | But I'm not arguing everyone must do it. Just trying to
             | share why one unintuitive approach (the "complex" x86
             | architecture) might actually be easier and cooler than you
             | think.
        
           | ant6n wrote:
           | I wish there was an easy way to compile to a subset of x86
           | (e.g. mem access only with simple mov, only using one flag,
           | no extensions, no floats, pure 32bit instructions).
        
             | eatonphil wrote:
             | Yeah that would be even more convenient!
        
           | pizza234 wrote:
           | > My unpopular opinion is to emulate an extremely reduced
           | subset of x86
           | 
           | I don't think 808x is such an unpopular machine for
           | approaching emulation.
           | 
           | Some people use Space invaders (or contemporary titles),
           | which is based on an 8080, as stepping stone between CHIP-8
           | and more modern (complex) platforms.
        
         | [deleted]
        
         | AnIdiotOnTheNet wrote:
         | If you think you can do it, you probably can. It's not really
         | all that conceptually difficult until you want to do dynamic
         | recompilation.
         | 
         | I wrote my first emulator a while ago, for the Gigatron. People
         | recommend CHIP-8 a lot but I just thought it looked too trivial
         | and uninteresting. The Gigatron is still incredibly simple, but
         | it's also a really elegant little beast worth studying for its
         | own sake.
        
         | agentultra wrote:
         | Try your hand at a CHIP-8 emulator. The instruction set is
         | really small, well documented, and easy to implement for your
         | first project.
         | 
         | https://multigesture.net/articles/how-to-write-an-emulator-c...
        
         | Gunax wrote:
         | I wrote (or tried writing) a gameboy emulator once.
         | 
         | My only qarning is that there are a lot of edge cases in the
         | specification--and the proper specs are wrong.
         | 
         | I ended up spending most of the time searching through
         | undocumented/missing CPU specifications. It became rather
         | tedious.
         | 
         | For a learning project, this made it poorly suited. There are
         | so many good emulators out there, the only reason to write one
         | is for the learning experience. I just felt that I stopped
         | oearning after a while and was just debugging obscure
         | combinations of cpu states.
        
           | tombert wrote:
           | That seems to be the consensus that I've read online.
           | 
           | Still, the reason I want to do it online is specifically
           | because I want an excuse to really understand low-level
           | hardware. I (and probably a majority of people on HN who do
           | software) really only have "real" experience with "Java or
           | Higher" with _maybe_ hitting C if I have the rare occasion of
           | having to worry about saving a few milliseconds. An emulator
           | would force me _understand_ low level hardware, or at least I
           | think it would.
        
             | coldpie wrote:
             | Another fun option for learning low-level stuff is
             | analyzing existing games. I did this to create a level map
             | dumper for one of my favorite NES games[1]. You can see
             | other ideas on the excellent Displaced Gamers YouTube
             | channel, for example[2].
             | 
             | Also, read the book Code by Charles Petzold.
             | 
             | [1] https://tcrf.net/Proto:M.C._Kids#Level_Changes
             | 
             | [2] https://www.youtube.com/watch?v=zGdpst_6k9k
        
             | yoyohello13 wrote:
             | I think Nand 2 Tetris [1] is a really good way to get a
             | good intro to this stuff at a basic level without too much
             | friction with tools. You essentially start with a nand
             | gate, and eventually build up a whole computer including a
             | Java-like programming language.
             | 
             | [1]: https://www.nand2tetris.org/
        
               | rjhallsted wrote:
               | I've been meaning to get to Nand2Tetris, it looks really
               | interesting.
        
           | aquova wrote:
           | That was more or less my experience. I got the original Game
           | Boy working well, and quite a few Game Boy Color games, but
           | it eventually devolved into debugging CPU timing issues and
           | edge cases with sprite bugs. At some point I realized that I
           | had gained all of the knowledge I had wished to learn and
           | since my own emulator was never really going to do anything
           | that hundreds of others weren't already doing better I moved
           | on. I will say it was a good learning experience however.
           | Chip-8 is a good start, but there are lots of concepts that
           | emulating a Game Boy will require that Chip-8 does not.
        
             | jmholla wrote:
             | I'd recommend maybe trying something simpler, like a
             | Motorola 6811 or a MIPS processor. Their instruction sets
             | are pretty simple and straightforward. But, I can see how
             | that might not be as fulfilling.
        
         | laputan_machine wrote:
         | The first emulator I wrote was for a virtual machine called the
         | CHIP-8. I used CowGod's reference, it was a fun experience!
         | 
         | http://devernay.free.fr/hacks/chip8/C8TECH10.HTM#2.1
        
           | tombert wrote:
           | I forgot about CHIP-8. That might be a good starting point.
           | Thanks for reminding me.
        
             | anthk wrote:
             | Try JimTCL, it uses SDL2 for "GUI"'s instead of TK, but
             | it's as compatible (at code level, not TCL extensions,
             | Jimsh uses its own ones) as TCL 8.5 so most stuff will work
             | as is.
             | 
             | If you look at the examples, you'll find that writing a
             | Chip8 emulator with JimTCL it's a breeze.
             | 
             | https://github.com/msteveb/jimtcl
        
       | ngcc_hk wrote:
       | How it compares with the 12 years old javascript (my most
       | beloved) simulator with detail explanation I wonder :
       | https://imrannazar.com/GameBoy-Emulation-in-JavaScript:-The-...
        
       ___________________________________________________________________
       (page generated 2022-01-12 23:00 UTC)