Heyho! Welcome to the first post of my series "TLMBoy", which is about writing a Game Boy Emulator with SystemC TLM-2.0.
So, if you always wanted to write a GameBoy Emulator or learn SystemC TLM-2.0, you found the right place!
I guess writing a Game Boy emulator is nothing innovative (there are currently more than 2000 Game Boy emulators on Github) and writing Software with SystemC isn't exiciting either. But to the best of my knowledge, no one ever tried to combine these two! The result of my attempt can be found in my Github Repository.
There's no need to worry if you don't know what SystemC is, or have no clue how a Game Boy works. The only prerequisite is some C++ knowledge as SystemC is library for C++. This means you should definetely know what a pointer is, but you don't need to pull off some quadruple-singleton-polymorphic-macro C++ stunts. Also some really basic knowledge of computer architecture is assumed.
The following tutorials will use Linux as an operating system. However, all dependencies we are using are also available for Windows, so this should work out as well in theory. Nevertheless, rather than running on native Windows, I recommend installing WSL, which is a Microsoft-made emulator for Linux on Windows.
Literature, Tutorials, other Emulators
Before we begin with anything technical, I want to clarify that most of the Game Boy's technical details and interna presented in
this post series are from third-party sources. It's now more than thirty years since the release of the initial Game Boy,
and a lot of people spend a lot of time reverse-engineering, writing emulators, or creating tests in their spare time!
Most of this work is a valuable source of information that makes programming a Game Boy emulator quite enjoyable.
The most complete summary of anything Game Boy emulator related can be found in this Github repo (awesome-gbdev). Besides that, I often used the gbemu Github as a reference implementation. This open-source emulator was pretty helpful at some points, especially when I had very detailed questions about certain things.
Anyway, I guess most people know what a Game Boy is, but not many have heard of SystemC yet, so let's get started with a short introduction to SystemC.
Behind the ominous term SystemC there is actually only a simple library for C++. I have the impression that it is often sold more like a language based on C++ rather than a library.
This is why in the following, I'll try to avoid macros whenever it is possible. Luckily we can rearrange the same code to an equivalent with less macros:
But simply put: SystemC is just a C++ library for so-called discrete-event simulation (DES).
These kind of simulations can be used to model systems where events happen at discrete points in time (woooooosh).
For example, a traffic light could easily be modeled with SystemC. You turn on different lights at discrete points in time and then turn them off again at another certain time. Although implementing a traffic light is feasible with SystemC, the focus of SystemC is put on modeling digital circuits like CPUs, busses, memories, and so on. So, all the stuff a Game Boy consists of!
Some years ago, SystemC was extended by the TLM library (Transaction-Level Modelling), which basically allowed modeling on a higher abstraction level, thus increasing the simulation performance and making things easier to code. The current version of TLM is 2; this is why the term SystemC TLM-2.0 is often used. We'll just keep using "SystemC" as a term for "SystemC TLM-2.0" in the following.
A mentionable sidenote about SystemC is its
by the IEEE (Institute of Electrical and Electronics Engineers, basically the Jedi High Council of electrical engineers).
Many companies in the field of electronic system-level (ESL) design have adopted this standard.
Thus, knowing SystemC might look nice on your curriculum vitae!
In my personal oppinion, the best way to learn SystemC is to use it as most concepts are quite straight forward. To get familar with it, I can really recommend the tutorials of Doulos and asic-world. But you can also read a book like SystemC: From the Ground Up if you want (I personally learned more from the tutorials).
The Game Boy - An Overview
In this section we'll take a look the at general design of the Game Boy from a high-level perspective.
Obviously we need to know what we want to model with SystemC before we start with the actual modeling.
So, let's take a look at the following image that provides a rough overview of the Game Boy's components:
- 1. Screen
- A for today's standard super low-resolution, monochromatic LCD-screen with 160x144 pixels.
- 2. Joy Pad
- 8 buttons (left, right, top, bottom, A, B, START, SELECT) allow the user to control the Game Boy.
- 3. SoC (System on a Chip)
- The heart of the Game Boy is a Sharp LR35902 SoC running at 4.19 MHz. It crams multiple components such as CPU, PPU and APU into one chip.
- 4. CPU (Central Processing Unit)
- The Game Boy uses a Sharp SM83 as its CPU. It uses a modified version of the Z80 instruction set that will be explained in a following post. Note, the CPU is often imprecisely referred to as "LR35902". As you can see from the schematics and the bullet point above: LR35902 is the SoC, SM83 is the CPU which is a part of the SoC.
- 5. PPU (Pixel Processing Unit)
- Basically some kind of very basic graphics card that helps bringing the pixels on screen.
- 6. APU (Audio Processing Unit)
- The APU creates the Game Boy's signature sound using different kinds sound devices such as pulse wave generators or noise generators.
- 7. boot-ROM
- A 256 Byte boot-ROM needed startup the Game Boy and verify the legal correctness of your cartridge. The story behind the boot-ROM is actually quite interesting and will be highlighted in another post.
- 8. Serial I/O
Besides these components there is also:
- Allows you to plugin a link cable and transfer Pokémon from A to B.
- A cartridge is not just a simple memory to store your favorite game. It can extend the RAM and uses interesting methods to circumvent the Game Boy's small address space.
- The Game Boy has multiple memories to achieve different things. There's a VRAM to store pixel data, a general-purpose RAM for computations, and there aforementioned boot-ROM that initializes the Game Boy on start up.
- Internal timer that can be used to generate interrupts at regular intervals, for example to measure time.
- DMA Controller
- Short for Direct Memory Access Controller. It's some very basic processing unit that only serves the purpose of shoveling data from A to B.
Nevertheless, the modularity of the Game Boy makes it easy to split the implementation into multiple independent parts. And there are already a lot of things that can be achieved by implementing a subset of the components listed above. For instance, booting up the Game Boy (the part where the Nintendo logo scrolls down) doesn't need an APU, a timer, or serial I/O.
This makes programming an emulator a pleasant project where you can enjoy a sense of achievement every now and then! In fact, seeing the Nintendo logo scroll down for the first time invoked a feeling of success that I had never felt before in my coding career 😀.