Introduction

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.

SystemC TLM-2.0

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.

The reason is probably SystemC's extensive use of super-duper fancy C++ makros resulting in code which might seem unfamiliar at first. For example, take a look at this code from SystemC's Wikipedia article:
SC_MODULE(adder) {        // module (class) declaration
  sc_in<int> a, b;        // ports
  sc_out<int> sum;

  void do_add() {                   // process
    sum.write(a.read() + b.read()); //or just sum = a + b
  }

  SC_CTOR(adder) {        // constructor
    SC_METHOD(do_add);    // register do_add to kernel
    sensitive << a << b;  // sensitivity list of do_add
  }
};
  
As you can see, there's a lot of macro magic going on there. For example SC_CTOR(adder) is not how a typical constructor of a class looks like. Personally, I'm not a big fan of macros, because if they blow up, it is hard to find the root-cause of the problem. Or to quote the Google C++ Style Guide (which will be our style guide btw) on how to name macro names: You're not really going to define a macro, are you?
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:

struct adder : public sc_module {        // module (class) declaration
  SC_HAS_PROCESS(adder);
  sc_in<int> a, b;        // ports
  sc_out<int> sum;

  void do_add() {                   // process
    sum.write(a.read() + b.read()); //or just sum = a + b
  }

  adder(sc_module_name name) : sc_module(name) {        // constructor
    SC_METHOD(do_add);    // register do_add to kernel
    sensitive << a << b;  // sensitivity list of do_add
  }
};
  


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 standardization 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
    • Allows you to plugin a link cable and transfer Pokémon from A to B.
  • Besides these components there is also:
  • Cartridges
    • 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.
  • Memories
    • 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.
  • Timer
    • 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.
As you can, see there are quite a few components to model! And indeed, coding a Game Boy emulator isn't something you accomplish in one afternoon (telling from my own experience). The reference implementation (gbemu) I use is written in 4,500 SLoC (Software Lines of Code) and it even skips some parts like the APU. Assuming you are some kind of god programmer hitting 100 SLoC per hour, then you still need one week of coding!
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 😀.

Let's get started

The way I want to structure this project is by writing several posts covering the single components of the Game Boy. Here's an overview I of posts that I want to write and that I've written so far: Even though are listed in some order, it's more like a recommendation. As you can see I recommend to start with the CPU, so let's get started with it!.