[HN Gopher] Writing a Game Boy Emulator in OCaml
       ___________________________________________________________________
        
       Writing a Game Boy Emulator in OCaml
        
       Author : ibobev
       Score  : 205 points
       Date   : 2025-07-04 09:34 UTC (13 hours ago)
        
 (HTM) web link (linoscope.github.io)
 (TXT) w3m dump (linoscope.github.io)
        
       | le-mark wrote:
       | This is a very nice write up of not only Ocaml but also gameboy
       | emulator implementation. Great job and thank you to the author!
       | 
       | As an aside I've always thought it would be awesome to create a
       | single page app with an assembler editor and
       | assembler/linker/loader to enable doing gameboy homebrew in the
       | browser. I think it would be a great, accessible embedded
       | development teaching opportunity.
        
         | binji wrote:
         | rgbds-live is more-or-less this same idea, with an embedded
         | version of RGBDS: https://gbdev.io/rgbds-live/
        
       | noobcoder wrote:
       | ah nice ! great use of functors, GADTs
       | 
       | I wanna compare a CHIP 8 or NES emulator or port CAMLBOY to WASM
       | using ocaml-wasm
        
         | hydroxideOH- wrote:
         | It should already be possible to run CAMLBOY on WASM because of
         | the new WASM backend of js_of_ocaml (wasm_of_ocaml).
        
       | droolboy wrote:
       | I know it's a long shot, but does anyone know of a tutorial for
       | the sound of a game boy emulator? Most of these tutorials never
       | cover that piece and when I try it on my own I find it hard to
       | properly implement or even understand the reference material well
       | enough to implement on my own.
        
         | jofzar wrote:
         | https://youtu.be/a52p6ji1WZs maybe?
        
         | wez470 wrote:
         | https://nightshade256.github.io/2021/03/27/gb-sound-emulatio...
         | is pretty good
        
         | t0mek wrote:
         | Not a tutorial per-se, but here are 2 slides describing how
         | I've done it:
         | 
         | https://www.slideshare.net/slideshow/emulating-game-boy-in-j...
         | 
         | Essentially, there are 4 channels, each providing a number 0-15
         | on every tick. Emulator should mix them together (arithmetic
         | average), scale up to 0-255 and feed to the sound buffer,
         | adjusting the tick rate (4.19MHz) to the sound output rate
         | (e.g.: 22 kHz) - taking every ~190 value (4.19MHz / 22 kHz) is
         | a good start.
         | 
         | Now the 0..15 value that should be produced by each channel
         | depends on its characteristics, but it's well documented:
         | 
         | https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware
         | 
         | Channels 1 and 2 produce square waves, so a bunch of low (0)
         | and high (15) values, with optional volume envelope (gradually
         | going down from 15 to 0 on the "high" part of the square) and
         | frequency sweep (alternating 0s and 15s slower or faster).
         | 
         | Channel 3 allows an arbitrary waveform, read from the memory.
         | 
         | Channel 4 is a random noise, generated by the LSFR.
         | 
         | See SoundModeX.java for the reference:
         | 
         | https://github.com/trekawek/coffee-gb/tree/master/src/main/j...
        
       | brunojppb wrote:
       | Beautiful write-up! Thanks for sharing this. I want to write a
       | game boy emulator in Rust and your blogpost really inspired me to
       | kick this off. I'm bookmarking this.
        
       | mtlynch wrote:
       | Excellent writeup and cool project.
       | 
       | Needs a (2022).
        
       | numlock86 wrote:
       | Cool. The demo runs way too fast, though. The throttle checkbox
       | doesn't really change it. Unchecking it, if anything, makes it
       | run slower. It runs at 240 fps with throttle and at 180 fps
       | without. With the throttle checbox active one second are already
       | about four seconds in the emulator. I suspect this is related to
       | the screen refresh rate, which is 240Hz in my case.
        
         | chickenzzzzu wrote:
         | probably they are calling requestAnimationFrame() and then not
         | accounting for deltaTime?
        
       | derefr wrote:
       | Would anyone here assert that there's any particular programming
       | language that's better for writing emulators, virtual machines,
       | bytecode interpreters, etc?
       | 
       | Where, when I say "better", I'm not so much talking about getting
       | results that are particularly efficient/performant; nor in making
       | fewer implementation errors... but more in terms of the
       | experience of implementing an emulator in this particular
       | language, being more rewarding, intuitive, and/or teaching you
       | more about both emulators and the language.
       | 
       | I ask because I know that this sort of language exists in other
       | domains. Erlang, for example, is particularly rewarding to
       | implement a "soft-realtime nine-nines-of-uptime distributed
       | system" in. The language, its execution semantics, its runtime,
       | and its core libraries, were all co-designed to address this
       | particular problem domain. Using Erlang "for what it's for" can
       | thus teach you a lot _about_ distributed systems (due to the
       | language /runtime/etc guiding your hand toward its own idiomatic
       | answers to distributed-systems problems -- which usually _are_
       | "best practice" solutions in theory as well); and can lead you to
       | a much-deeper understanding of Erlang (exploring all its corners,
       | discovering all the places where the language designers
       | considered the problems you'd be having and set you up for
       | success) than you'd get by trying to use it to solve problems in
       | some other domain.
       | 
       | Is there a language like that... but where the "problem domain"
       | that the language's designers were targeting, was "describing
       | machines in code"?
        
         | chickenzzzzu wrote:
         | C89
        
         | johnnyjeans wrote:
         | sml, specifically the MLTon dialect. It's good for all the same
         | reasons ocaml is good, it's just a much better version of the
         | ML-language in my opinion.
         | 
         | I think the only thing that ocaml has that I miss in sml is
         | applicative functors, but in the end that just translates to
         | slightly different module styles.
        
           | wk_end wrote:
           | Can you expand on what makes SML better, in your eyes, than
           | OCaml?
           | 
           | IMO: it's certainly "simpler" and "cleaner" (although it's
           | been a while but IIRC the treatment of things like equality
           | and arithmetic is hacky in its own way), which I think causes
           | some people to prefer SML over aesthetics, but TBH I feel
           | like many of OCaml's features missing in SML are quite
           | useful. You mentioned applicative functors, but there's also
           | things like labelled arguments, polymorphic variants, GADTs,
           | even the much-maligned object system that have their place.
           | Is there anything SML really brings to the table besides the
           | omission of features like this?
        
             | johnnyjeans wrote:
             | > the treatment of things like equality and arithmetic is
             | hacky in its own way
             | 
             | mlton allows you to use a keyword to get the same facility
             | for function overloading that is used for addition and
             | equality. it's disabled by default for hygienic reasons,
             | function overloading shouldn't be abused.
             | 
             | https://baturin.org/code/mlton-overload/
             | 
             | > labelled arguments
             | 
             | generally speaking if my functions are large enough for
             | this to matter, i'd rather be passing around refs to
             | structures so refactoring is easier.
             | 
             | > polymorphic variants
             | 
             | haven't really missed them.
             | 
             | > GADTs
             | 
             | afaik being able to store functors inside of modules would
             | fix this (and I think sml/nj supports this), but SML's type
             | system is more than capable of expressing virtual machines
             | in a comfortable way with normal ADTs. if i wanted to get
             | that cute with the type system, i'd probably go the whole
             | country mile and reach for idris.
             | 
             | > even the much-maligned object system that have their
             | place
             | 
             | never used it.
             | 
             | > Is there anything SML really brings to the table besides
             | the omission of features like this?
             | 
             | mlton is whole-program optimizing (and very good at it)[1],
             | has a much better FFI[2][3], is much less opinionated as a
             | language, and the parallelism is about 30 years ahead[4].
             | the most important feature to me is that sml is more
             | comfortable to use over ocaml. being nicer syntactically
             | matters, and that increases in proportion with the amount
             | of code you have to read and write. you dont go hiking in
             | flip flops. as a knock-on effect, that simplicitly in sml
             | ends up with a language that allows for a lot more
             | mechanical sympathy.
             | 
             | all of these things combine for me, as an engineer, to
             | what's fundamentally a more pragmatic language. the french
             | have peculiar taste in programming languages, marseille
             | prolog is also kind of weird. ocaml feels quirky in the
             | same way as a french car, and i don't necessarily want that
             | from a tool.
             | 
             | [1] - http://www.mlton.org/Performance
             | 
             | [2] - http://www.mlton.org/ForeignFunctionInterface
             | 
             | [3] - http://www.mlton.org/MLNLFFIGen
             | 
             | [4] - https://sss.cs.purdue.edu/projects/multiMLton/mML/Doc
             | umentat...
        
               | vkazanov wrote:
               | I love, love, love StandardML.
               | 
               | I respect the sheer power of what mlton does. The
               | language itself is clean, easy to understand, reads
               | better than anything else out there, and is also well-
               | formalised. I read (enjoyed!) the tiger book before I
               | knew anything about SML.
               | 
               | Sadly, this purism (not as in Haskell but as a vision) is
               | what probably killed it. MLTon or not, the language
               | needed to evolve, expand, rework the stdlib, etc.
               | 
               | But authors were just not interested in the boring part
               | of language maintenance.
        
               | johnnyjeans wrote:
               | What are your thoughts on basis[1] and successorml[2]?
               | 
               | [1] - http://www.mlton.org/MLBasis
               | 
               | [2] - https://smlfamily.github.io/successor-ml/
        
           | makeset wrote:
           | I remember working through Appel's compiler textbook in
           | school, in SML and Java editions side by side, and the SML
           | version was of course laughably more concise. It felt like
           | cheating, because it practically was.
        
         | corysama wrote:
         | Well, there's always https://pypi.org/project/rpython/
        
         | foobiekr wrote:
         | C is probably the best language for this.
        
           | filleduchaos wrote:
           | I quite frankly disagree. From personal experience I don't
           | think there's any mainstream programming language that _in
           | itself_ teaches you anything much about emulating systems
           | like the Game Boy or NES - in fact, I 'd go so far as to say
           | that none of them even at least yield elegant _and accurate_
           | implementations.
           | 
           | People write "production-grade" emulators in C because it's
           | fast, not because it's uniquely suited to the domain as a
           | language.
        
           | IshKebab wrote:
           | C isn't really the best language for anything anymore. Maybe
           | as a compilation target for other languages.
        
         | wk_end wrote:
         | Verilog?
         | 
         | ...just kidding (maybe).
         | 
         | Assuming we're talking about a pure interpreter, pretty much
         | anything that makes it straightforward to work with bytes
         | and/or arrays is going to work fine. I probably wouldn't
         | recommend Haskell, just because most operations are going to
         | involve imperatively mutating the state of the machine, so pure
         | FP won't win you much.
         | 
         | The basic process of interpretation is just: "read an opcode,
         | then dispatch on it". You'll probably have some memory address
         | space to maintain. And that's kind of it? Most languages can do
         | that fine. So your preference should be based on just about
         | everything else: how comfortable are you using it, how much do
         | you like its abilities to interface with your host platform,
         | how much do you like type checking, and so on.
        
         | grg0 wrote:
         | Haskell excels at DSLs and the sort of data manipulation needed
         | in compilers. OCaml, Lisp, and really any language with support
         | for ADTs and such things do the trick as well. You can even try
         | hard with modern C++ and variant types and such, but it won't
         | be as pretty.
         | 
         | Of course, if you actually want to run games on the emulator, C
         | or C++ is where the game is. I suppose Rust would work too, but
         | I can't speak much for its low-level memory manipulation.
        
           | wk_end wrote:
           | Haskell and OCaml are excellent for _compilers_ , because -
           | as you suggest - you end up building, walking, and
           | transforming tree data structures where sum types are really
           | useful. Lisp is an odd suggestion there, as it doesn't really
           | have any built-in support for this sort of thing.
           | 
           | At any rate, that's not really the case when building an
           | emulator or bytecode interpreter. And Haskell ends up being
           | mostly a liability here, because most work is just going to
           | be imperatively modifying your virtual machine's state.
        
             | materielle wrote:
             | I'd also point out, that even in the compiler space, there
             | are basically no production compilers written in Haskell
             | and OCaml.
             | 
             | I believe those two languages themselves self-host. So not
             | saying it's impossible. And I have no clue about the
             | technical merits.
             | 
             | But if you look around programming forums, there's this
             | ideas that"Ocaml is one of the leading languages for
             | compiler writers", which seems to be a completely made up
             | statistic.
        
               | runevault wrote:
               | I don't know that many production compilers are in them,
               | but how much of that is compilers tending towards self
               | hosting once they get far enough along these days? My
               | understanding is early Rust compilers were written in
               | Ocaml, but they transitioned to Rust to self-host.
        
             | kqr wrote:
             | > And Haskell ends up being mostly a liability here,
             | because most work is just going to be imperatively
             | modifying your virtual machine's state.
             | 
             | That sounds odd to me. Haskell is great for managing state,
             | since it makes it possible to do so in a much more
             | controlled manner than non-pure languages.
        
               | grg0 wrote:
               | Yeah, I don't understand what the "liability" here is. I
               | never claimed it was going to be optimal, and I already
               | pointed out C/C++ as the only reasonable choice if you
               | actually want to run games on the thing and get as much
               | performance as possible. But manipulating the machine
               | state in Haskell is otherwise perfect. Code will look
               | like equations, everything becomes trivially testable and
               | REPLable, and you'd even get a free time machine from the
               | immutability of the data, which makes debugging easy.
        
               | wk_end wrote:
               | If you're effectively _always_ in a stateful monad,
               | Haskell 's purity offers nothing. Code _doesn 't_ look
               | like equations, things _aren 't_ trivially testable and
               | REPLable, you don't get a free time machine, and there's
               | syntactic overhead from things like lifting or writes to
               | deeply nested structures and arrays, since the language
               | doesn't have built-in syntactic support for them.
        
               | kqr wrote:
               | On the other hand, it _does_ have support for things like
               | side-effectful traversals, folds, side effects
               | conditional on value existing, etc. In most other
               | languages you have to write lower-level code to
               | accomplish the same thing.
        
             | whateveracct wrote:
             | Haskell isn't a liability for that lol
        
         | alaaalawi wrote:
         | one of the options for fast iterations would be Forth. in its
         | circles, it famous for generation targets and cross compiling
         | between archs. seaech the net you shold find plenty.
        
         | UncleOxidant wrote:
         | OCaml doesn't seem like a bad choice here. Haven't played with
         | it much, but I wonder if Racket might be a good choice as well?
        
         | alaaalawi wrote:
         | Also another option for fun in the browser Elm. check out
         | similar older project https://github.com/Malax/elmboy
        
       ___________________________________________________________________
       (page generated 2025-07-04 23:00 UTC)