Reverse Engineering a Gameboy Advance game: Understanding the Mischievous DMA — Part 2

Bruno Macabeus
4 min readAug 8, 2019

--

This post is part of a series entitled Reverse Engineering a Gameboy Advance Game. Read the introduction here. Read the previous post here.

If you like this content, you may like the Code Crafters courses. Learn how to build your own BitTorrent, SQLite, and other crazy things. Subscribe using my link to pay me for a coffee!

As we saw before, stretching the bridge altering the memory in VRAM only lasted for a single frame. Let’s understand why this happens and how we can keep our tiles alive!

The first step is to better understand the section of memory we’re messing with, in this case VRAM (0600~0601). For this, I spent some time “playing” with it to see how it behaved. For example, if it stored the entire level or just the area the player is seeing, and if the VRAM stored only the tiles or anything else. For the moment, we need to use our creativity and deduce, from the small amount of information we have, what this region represents, what purpose that byte serves, and so on.

GIF showing the changes in VRAM as we move around the level

While analyzing it, I came to the conclusion that this section only stores what the player is currently seeing. In other words, every frame of the game it pulls, from some other section which stores the entire level, the portion which the player can see. Therefore, we need to write our tiles to the source which the VRAM consumes! But that raises some questions: why does it work like this? How does it write to VRAM every frame? And where is the source with the entire level located?

So I studied a bit more about the GBA to be able to answer these questions. I was lost for some time, until I eventually found an excellent manual about the GBA!
In it, when explaining how the tiles work, it says that a good approach for updating the VRAM, which is where the tiles are shown, is to use DMA (Direct Memory Access). It’s a resource many computers have, and it’s very useful for quickly copying a continuous portion of memory from one section to another.
Speaking more technically, DMA is a hardware resource which allows access to memory independently of the CPU (without needing locks, for example).

In practice, one section of memory stores the entire level, while, using DMA, the necessary bytes are copied to VRAM. This makes sense, so the VRAM only serves to present the tiles which will be shown on the screen at that moment, and the use of DMA prevents lag during the transition.

When I say that DMA is very mischievous, it’s because many times during the reverse engineering process, it will alter values in a way that is difficult to understand, and it can be difficult to know where the new values came from. There are times when we swear that it’s an instruction which wrote a certain value when in reality it’s the DMA, or when we think it was the DMA when it was actually an instruction that did it.

Thankfully, No$GBA has a very useful feature for debugging DMA, the TTY Debug Window. It shows logs of the DMA. Thus, when we advance one frame in the game, we get the following logs:

DMA3: 03000900 0600E000 80000400
DMA3: 03001100 0600E800 80000400
DMA3: 03004DB0 0600F000 80000200
DMA3: 03004800 07000000 84000048

Various reads and writes were performed by the DMA… cool…
And since we know the bytes referring to the bridge start at 0600F1AD, the closest write to that address is this operation:

DMA3: 03004DB0 0600F000 80000200

That is, we need to look at 03004DB0, which is the source of the data in VRAM. Very cool!
This byte is in a section of memory called Fast WRAM (0300:256kb), and it’s very useful for storing data which will be read frequently — exactly the case when updating the tiles every frame. It is also called IWRAM, but I’ll continue to use Fast WRAM, which is the term used in No$GBA.

Section of the memory which is read by the DMA. The highlighted byte is the start of the bridge.

Going to this section of memory, the first thing we can see is that it really looks like a tilemap, since there are a lot of zeros and continuous bytes of the same values. And notice: looking a bit further down, we find our bridge, starting at address 030045FD!
Would stretching our bridge here work? Let’s try…

Region of memory after our modification

And look, it worked! The bridge is stretched! The DMA now copies the values we wrote from Fast WRAM to VRAM on every frame, so the bridge stays alive!

However, we have an unexpected problem… it’s a “phantom”! It’s visible, but the physics aren’t applied to it, meaning the character passes right through it. How bizarre.

Why are the tiles we created visible but without physics, appearing as phantoms? And how can we apply physics to them?

Next post: Understanding the physics of the game

--

--

No responses yet