[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)