In the last article we started fleshing out the memory map for Donkey Kong. We learned how to identify sections of ROM versus sections of RAM and began poking around with general game variables in memory. We can do a lot armed with this knowledge, but occasionally we’re going to have to dig a bit deeper and further flesh out a game’s memory map to learn more about it.
In this article we’ll focus our efforts towards understanding more of the memory map. We’ll be taking a look at variables relating to the game’s entities as well as the frame buffer.
The Frame Buffer
Let’s start with the frame buffer since that’s probably easier to identify compared to variables responsible for controlling game entities. Before we start rooting through the memory view in MAME looking for the frame buffer let’s quickly recap what a frame buffer is as well as what it does.
When video games draw to our system’s screen all of that graphical data is stored in a section of memory known as the frame buffer. By storing image data in memory rather than just drawing pixels as they are needed it’s possible to achieve a more stable image and the programmers don’t need to concern themselves with display timing issues. It also tends to be pretty efficient since games typically do not need to refresh the entire frame buffer in order to change the image on the screen.
So what are we looking for in a frame buffer? Generally speaking there are a few things that we can look for to determine the boundaries of the frame buffer. Contents of the frame buffer don’t change radically frame by frame, however they will look pretty different between screen transitions.
For example the background image in Donkey Kong during a barrel stage doesn’t really change until the level ends. When the level does end, however, the contents of the background change pretty dramatically. Knowing this we can examine memory using the MAME debugger’s memory view and look for large areas of memory that basically only change during screen transitions.
One good way to regularly observe screen transitions in memory is to put the game into attract mode and scroll through the memory view in the MAME debugger. Once again we’re looking for large, contiguous areas of memory that pretty much only change with the screen transitions during attract mode.
We already know from the work we did in the previous article that the memory range of 0x0000-0x3FFF is an area of read-only memory so we can skip right past these addresses and continue scrolling onward. Around 0x6000-0x712F we see lots of patches of small areas of memory that appear to be constantly changing so this area is likely not of interest to us right now. We hit something interesting around 0x7400, however:
Sandwiched between two large slices of null (0x00) bytes we can see a large chunk of memory set to specific values that apparently only change when the screen does. Since we’ve exhausted most of the used memory space in our search this section of memory stands a pretty good chance of being the frame buffer that we’re looking for.
Supposing that this region is our frame buffer is all well and good but at the end of the day we’re going to need some proof. How exactly can we go about proving that this is our frame buffer? The simplest way that I can think of is the same way we tested our credits variable in the previous article: we overwrite the region of memory with a predetermined value and observe the result.
You see most games represent images in frame buffers as a set of tiles. Often times these tiles are pieces of the game’s background and the game renders the sprites on top of tiles. These tiles are represented by byte values in RAM so changing the values in the frame buffer should result in a change of the background image.
So let’s go ahead and start overwriting this section with null bytes and see what happens. First we’ll halt execution of the game by issuing the ‘gv’ command, which will cause the debugger to halt the game after the next frame has finished writing to the screen. Next we’ll go ahead and write our null bytes like so:
As you can see I’ve filled roughly half of the memory region with null bytes. We don’t have to look very far to see these changes in action. If we take a look at the screen we’ll notice that it looks like the following:
It looks like roughly half of the screen has been covered in zeroes, which is in line with what we would expect. As far as proof goes I’d say that this is pretty definitive. Based on what we can see here we can be pretty sure that the frame buffer spans memory addresses 0x7400-0x7800.
We’ll come back to messing around with the frame buffer in later articles. If you’re curious to find out all the tile values or how the screen is laid out in memory I encourage you to play around with setting various values and observing the output on the screen.
Game entity variables
Game entity variables are probably the most difficult variables to pinpoint. For one thing changes to game entity variables might not be immediately apparent like our frame buffer earlier or those changes may not have an obvious effect on the entity being edited. For another thing finding individual game entity variables is sort of like finding a needle in a haystack since you’re generally looking for a handful of bytes out of thousands. So what’s a reverse engineer to do?
Well, I’m going to be honest with you guys here, this is where a lot of the drudgery of reverse engineering arcade games comes into play. Success in this area generally boils down to the will to persevere in terms of toggling byte values in memory over and over again. I know that doesn’t sound terribly exciting but that’s generally how it is.
Fortunately we’re not totally in trouble in terms of lack of techniques when searching for game entity variables. One of the easier things that we can do is scan the memory map like we did for the frame buffer but look for repeating patterns in memory. The basic idea here is that similar game entities or objects in a game will likewise be structured similarly. It’s also not unusual to see game entities organized contiguously in memory so repeating patterns in memory are a good place to start.
Instead of simulating lots of work I’m just going to take you guys directly to an area of memory I’ve studied before. We’ll leave the drudgery for another day and jump straight into variables relating to barrels.
If you stare at memory long enough during the attract mode for Donkey Kong you might see this section of memory jump out at you:
There’s a little bit of variation here between these different 32 byte chunks of memory that are highlighted, but the general structure of these chunks appear to be similar. The first byte of each of these structures seems like a logical place to start messing around with so let’s go ahead and do that.
You may have noticed that the first byte of these structures appears to toggle between the values 0x00 and 0x01 during the game’s attract mode. Since these memory locations start with the value 0x00 let’s detect when it initially toggles to 0x01 and then set it to 0x00 to see what happens.
First let’s take a look at what values that first byte is actually set to during the attract mode. We’ll be using the first byte of the first offset at 0x6700. To monitor every write to this address we’ll set a watchpoint for it with the following command:
wpset 0x6700, 1, w
This command sets a watchpoint for address 0x6700 that is one byte wide and only trips on write operations at this address. Let’s continue through the attract mode and let the watchpoint do the heavy lifting for us. If you haven’t done so already resume the game with the ‘go’ command. After the attract mode starts you should notice a watchpoint is tripped that looks like the following:
Here we can see that 0x6700 has been written to when the code at address 0xF68 was executed and that the value of 0x6700 was set to 0x00. Let’s continue through the rest of the attract mode with the ‘go’ command and observe the rest of the values this byte is set to:
It looks like the byte at address 0x6700 is actually set to three values: 0x00, 0x02, and 0x01 in that order. After viewing the first attract mode in its entirety we can already see this pattern emerges repeatedly. If you stared at the game while observing when the watchpoints trigger you probably noticed that these values corresponded with certain events occurring within the attract mode.
For instance you may have noticed that when 0x6700 was set to 0x02 that it appears that Donkey Kong is attempting to throw a barrel. You may also have noticed that not long after the barrel is set to 0x01 it appears the barrel is rolling. Lastly you may have noticed that when 0x6700 is set back to zero the barrel appears to despawn after it reaches the oil barrel at the end of the level.
Alright, so what happens when we go from the value 0x02 directly to 0x00? Let’s change the value in our memory view at the appropriate watchpoint and find out:
First we wait for the watchpoint where we transition from the value 0x02 and 0x01. We’re basically going to overwrite that value to be 0x00 which effectively will skip that 0x01 value. Let’s go ahead and advance the game one frame with the ‘gv’ command. You should see the following on the screen:
Alright, here we can see donkey kong attempting to roll the barrel. Let’s advance another frame:
Here we see that the barrel appears to be deployed. Let’s advance the game several frames just to be sure that’s the case:
We can see that the barrel Donkey Kong just threw eventually disappears and he grabs for another barrel! So what’s happening here?
This behavior is a pretty strong indicator that the first byte of each of these regions of memory we’re looking at is some kind of status indicator. A status of 0x02 apparently means that Donkey Kong is trying to fetch that particular barrel to throw it and 0x01 and 0x00 appear to control whether the barrel is enabled or disabled.
Lots of different entity and general game variables can be discovered and manipulated like this using watchpoints and the memory address. We’ll certainly be examining more of both in future articles but for an added exercise I would recommend setting breakpoints on the rest of the first barrel’s variables and see what manipulating them does. Doing so should offer a lot of insight into variables such as barrel type and which direction the barrel is traveling.
So at this point we’ve seen pretty much all the examples we need to see in order to start discovering different regions of memory and tinkering around with their values. We also learned a few tricks for locating certain types of variables even if they may be a fair bit of work. The next steps we’ll take with reverse engineering Donkey Kong will focus on relying more on cutting down on this work by examining disassembled code for clues into how memory is used.
In the next article we’ll be using watchpoints to view related disassembled code in order to give us clues as to how memory is used.
I’d like to take a moment to thank my friend Ray who was generous enough to send me a pretty difficult to find board for my Sinistar restoration that I’ve been working on recently. Thanks Ray and I apologize for making you wait so long for this article!