Hacker News new | comments | show | ask | jobs | submit login
Writing a Game Boy emulator (cturt.github.io)
242 points by tosh 7 days ago | hide | past | web | favorite | 47 comments

I mentioned this already in another thread, but if you are interested in emulating hardware or just how CPUs and hardware work in general, writing a Game Boy emulator is about the most fun and educational project you can take.

The Game Boy hardware is, on its surface, extremely simple (as an example, there is no “operating system”, only a 256 byte (!) boot ROM that pretty much only serves to display and validate the Nintendo logo shown at start), and it has a vast library of games available for it that make use of that hardware to varying degrees.

This means that you can get really good results really fast. Especially the earlier games, like Tetris, don’t rely on fine grained implementation details too much, so even a sloppy, quickly put together emulation can run them well.

But if you then strive for accuracy or just being able to run more complex games, you can take things to almost arbitrarily detailed levels of this somewhat “fractal” complexity, uncovering and implementing all sorts of interesting hardware intricacies.

Contrast this with even slightly more recent game consoles, where you will have a lot of busywork ahead of you to even get the system past any reasonable definition of “booting”, without any gratifying visual feedback. With the Game Boy on the other hand, getting to a game’s title screen, with working buttons and all, is actually pretty simple.

I actually started C programming on Game Boy back in the days, but for me the Game Boy Advance really hit the sweet spot. ARM (nicer instruction set) and all of the close-to-the-metal characteristics you name above.

If you want to write a complete emulator, I can imagine that the Game Boy Advance can be a bit more of an undertaking with the different alternative graphics modes.

A gba emulator is my dream project. Gosh I've wanted to sit down and do it forever!

There are some really nice ones out there too. There are a few js-based ones that can run in the browser!

So, how does one guy not familiar with this low level stuff, nor with GB internals or those 8-bit processors starts writing an emulator like this? Is there any suggested road one could follow, or something like that?

Learning how to program a similar 8bit processor in assembly is the first step. Z80 is closest as the Game Boy CPU is based on that (though Z80 has some more features), but any relatively common 8bit CPU such as 8080 or the different 6502 will give you enough context. If you've done assembly already, this is trivial, if not, those CPUs are a good place to start and not hard. I'd say that merely getting a feel for the basics are enough.

After that, realistically, I would start looking at one of the existing GB emulator write ups, just enough to understand how things fit together. You can get pretty far on the Game Boy e.g. without even implementing interrupts (not sure, I don't think the boot ROM really needs them), so don't hesitate to experiment already.

Finally, have a few references ready (like available opcode tables and the infamous Game Boy CPU pdf that's easy to find), but keeping in mind that they do contain inaccuracies.

A lot of understanding will come while implementing.

Thanks for your advice. Being my first computer a MSX, it's good to know the GameBoy CPU is similar to the Z80. When I read it was a custom Sharp one, I thought it was a completely different world.

> I also had plans to port to Mac OS X, but like with PS2, this proved too difficult since I was unable to install a working C compiler and development environment on Mac OS X.

I am surprised by this statement, as it's generally as easy as xcode-select --install to install the CLT (or failing that, installing full-blown Xcode). Slightly up in the article there is mention of Lion, so maybe this is related.

While this is true, I have a few major gripes with the toolchain that comes with XCode. For instance, I was recently working on a project using C++17 features. It works correctly on linux and windows, but making it compile on macOS was nigh impossible. The clang compiler that comes bundled with macOS has a "special" version that makes it very hard to know where exactly it stands compared to the normal LLVM repository.

Then there's the problem of libraries. You have to use homebrew or whatever to install libraries in /usr/local. Some libraries would conflict with the system though, so you have to fiddle with env variables to make the build system find it.

Overall, building on MacOS/Xcode is a frustrating experience. I ended up installing nixos and using its toolchain for my work...

The documentation for the macOS version of clang seems to be non-existent as well (sans the man/info page - but even that seems incorrect as some flags simply don't work).

    brew install gcc@8
Yeah this part confused me as well.

had brew utterly let me down for gdb recently. had to compile from source and then code sign it. nightmare mode.

That's not really brew's fault -- but perhaps they could streamline this process?

OSX requires binaries to be signed to give them tracing/debugging privileges (or you can use root). It would be nice if Apple made this less painful -- or rather, if they stopped making native development increasingly more painful with every OS release.

agreed. if it's anyone's fault, it's apple's. that's a helluva lot of friction to install a nigh-ubiquitous dev tool.

> if it's anyone's fault, it's apple's.

I'm quite glad random unsigned binaries don't have the right to unilaterally attach to (signed) processes, otherwise the signature would be moot.

I've been developing a Game Boy emulator with a friend as well, and struggling a lot with the poor documentation. There's a very thorough PDF with lots of information online but when it comes to Opcodes (and cpu flags) it's quite inaccurate. Most often than not I have to skim through several github projects to check that the implementations match. (which sometimes don't)

Perhaps we'll start doing a Nintendo64 emulator instead which is more complex but from what I've heard/read has much better documentation.

I've been doing the same thing, with the same .pdf, and hitting the same errors :)

http://gbdev.gg8.se/wiki/articles/Main_Page is my current documentation of choice - which seems to be based on the same .pdf but has a bunch of updates and errors corrected

Ditto. My project is in Zig here: https://github.com/isaachier/gbemu.

Glad I'm not the only one : ) Thanks I'll go check it

The table here: [1] is very accurate. I wasn't able to find any bug either in the cycle counts or the affected flags list during the Coffee GB [2] development.

[1] http://pastraiser.com/cpu/gameboy/gameboy_opcodes.html

[2] https://news.ycombinator.com/item?id=17134668

The table in [1] has 0 in the carry flag for the SRA instructions, is that correct? I thought they shifted the lowest bit into the carry same as SRL.

I think you're right, see [0].

Furthermore E9 is not "JP (HL)" but rather "JP HL". If I remember correctly a few timings or instruction sizes are off as well.

[0]: http://www.devrs.com/gb/files/opcodes.html

Perfect, thank you. I've been using this image but only to cross-check the opcodes values and what they meant.

That can easily be part of the fun (and learning aspect), though: The detective work in researching what the real system does, based on analysis of a real system (if you have one) or just derived from what available software titles do and expect.

Some documentation is good to get you started, but at a certain point it’s the actual software that should be the guiding factor. Inaccurate documentation, which is not uncommon for the Game Boy, can be unnecessarily misleading though (on the other hand, there’s some satisfaction in essentially proving a different behavior, especially if you accept a piece of documentation to be likely inaccurate from the get go).

As far as Nintendo64 goes, https://github.com/yupferris/rustendo64/blob/master/README.m... has a bunch of good documentation links to get started with.

Have you looked at the Pan Docs [0] at all? They're pretty complete, though I've never used them for opcodes.

[0]: http://problemkaputt.de/pandocs.htm#cpuinstructionset

You might want to check Joonas Javanainen's work, who's doing great analysis of the CPU


The mooneye-gb project is the one I've been checking the most to make sure I'm getting things correctly. His work is massive regarding the game boy.

While playing with the result (working emulator) can be exciting, the process of developing itself sounds quite mundane.

It certainly starts off that way, but right about the time you have most of your opcodes written and can start stepping through your code, it becomes very exciting very quickly. "Ooh, now I have Tetris getting far enough that I think it's writing to tile memory; can I display that?" "Neat! I wonder if any other games are getting that far. How hard would it be to get the backgrounds working now?"

Suddenly every game you have in your library becomes puzzle box and either works (yay!) or much more often for a young emulator, breaks in a perplexing way. It creates a really rewarding feedback loop, where tiny changes to timers and status registers can have big sweeping effects on your tests. And all your tests are themselves games, and usually fun to explore anyway.

While programming I don't need to be creative all the time. I find it very pleasing to understand how this systems work and emulate them. I do confess though, that after a while and after understanding them some Opcode families can get a bit boring. But in general I do enjoy emulators very much and don't find them boring at all.

What makes you say that? Writing a Game Boy emulator is essentially implementing a whole computer system, in the case of the Game Boy one that can quickly give you gratifying results, but allows you to dive almost arbitrarily deep.

I’d state the opposite and claim that it’s actually one of the most fun and interesting things I’ve ever undertaken. In fact, I am more interested in the process than the actual product. There are tons of well working Game Boy emulators already.

But you're not creating a new computer system, you're not designing it. You have to exactly follow the specs, and the things mentioned by parent. Seems more like mundane and housekeeping stuff rather than creative.

Implementing a well-documented spec is fairly mundane, but figuring out that spec on your own is a fascinating puzzle. Emulators are full of curious little edge cases that can drive people to the point of obsession.


So? Just because you find it boring and mundane does not mean everyone else does. For me at least, there’s few things more thrilling than learning (and maybe mastering) a new thing. You think new systems start out in a vacuum?

Besides, part of the challenge is that there is no comprehensive spec for the Game Boy, so discovery through research and implementation is part of the process.

In contrast to the creativity that you can exercise along many dimensions of implementing an emulator, riding a bike or laying at a beach with a cocktail is hardly „creative“ at all, yet many people enjoy doing that as well (I certainly do). You said you might even enjoy playing with the resulting emulator, that seems even less creative to me.

Write your own spec. Then just start designing fun virtual machines. Make them do what they are not supposed to do in lieu of the hacker spirit :)

This would make a great undergraduate computer science class. I particularly like where author is somewhat forced by circumstances to fashion their own bespoke tooling. Rapid prototyping of minimal tools is a very real-world developer skillset.

If you are interested in this post, you might want to have a look at an older post on hackernews that gained some traction back then (see https://news.ycombinator.com/item?id=17134668). In contrast to this post, the aforementioned emulator was written in Java instead of C.

This is one of the more unique aspects of my emulator; since most other Game Boy emulators were written in an older C standard, (or an undesirable alternative like C++), they didn't have access to anonymous structs or unions

...unless you use MSVC, which has had that as an extension for a very long time (since MSVC6 at least.) I wonder if MS was the one who got that into C11.

You got to be kidding! The MSVC impl is a incompatible incomplete joke and everyone knows it. Even MS is investing more and more in llvm tooling because of this.

you can have anon structs an unions on gcc:


Honestly, writing a Game Boy emulator was the most instructive project I ever did on how computers work. Probably learned more on that project than from my OS and embedded systems classes combined.

>The Game Boy has eight 8 bit registers: A, B, C, D, E, F, H, and L

Why these letters? I'm assuming I, J and K are reserved for specific uses... is G likewise?

It's less that other letters are reserved, and more that there are only eight general-purpose registers, and four of them already have special meanings.

A is the accumulator, F is flags, and as the sibling comment mentioned, H and L represent the high and low bytes of HL, which is the only 16-bit register you can use for indirect memory access in most instructions. It's also used in some control-flow instructions.

That leaves four remaining registers, which just so happen to fit perfectly into the remaining space: B, C, D, and E. (They can also be accessed as BC and DE with 16-bit instructions.)

The H and L registers are special in that they can be used for indirect addressing: some opcodes will combine H (high) and L (low) into a 16-bit number, interpret that as an address and read from that memory location.

> I used C11's anonymous structs and unions so that I could access individual registers, or grouped registers straight from the root structure: registers.a or registers.af for example.

That's excellent, when I wrote mine I wasn't aware of this feature and used a kludge of macros to handle it instead.

A usefull shortcut not highlighted in the article: Instead of implenting an emulator for the LCD display hardware, the author simply peaked at the frambuffer and dumped the contents.

For most target hardware, this shortcut provides a reasonable approximation of the intended output image. However, some older hardware relied upon specific characteristics of CRT displays to enhance the graphics. For example, some clever developers found that they could create extra colors by swapping the palate during the vertical blanking interval on interlaced NTSC video.

Of course, some of the earliest video game consoles don’t have a framebuffer since RAM was to expensive. For these consoles, you will be stuck writing a video display emulator.

> The GameCube emulator I used for testing, gcube, doesn't support reading files from the memory card

Just curious, why use anything except dolphin for emulating gamecube?

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact