~/labs/workshops/gba-firered/01-arquitetura-do-gba
The GBA architectureThe hardware, ARM7TDMI CPU, and console memory map.
Before opening any tool, you need a mental model of the console. Reverse engineering becomes much easier when you know where code lives, where data lives, and how the CPU sees all of it.
The hardware in one sentence
The Game Boy Advance is a small computer with a 32-bit ARM7TDMI processor running at about 16.78 MHz, little memory, a 240 by 160 pixel screen, and a cartridge that contains the game ROM.
CPU ARM7TDMI, 32-bit, ~16.78 MHz
Screen 240 x 160 pixels
EWRAM 256 KB of "external" RAM (slower)
IWRAM 32 KB of "internal" RAM (faster)
ROM the cartridge, up to 32 MB, read-only
The ARM7TDMI processor
All game logic runs on this CPU. It has characteristics that define everything we will do later:
- It is RISC. Instructions are simple and fixed-size.
- It is little endian. The least significant byte comes first in memory.
- It has 16 visible general-purpose and control registers.
- It executes two instruction sets: ARM (32-bit) and Thumb (16-bit).
Chapter 02 focuses only on ARM and Thumb, because that is where the intimidating part lives at first. For now, keep one idea: the game is a giant sequence of those instructions, and the CPU reads them one at a time.
The memory map
The CPU accesses everything through addresses. Each type of memory lives in a fixed address range. This is the map you will use all the time:
0x00000000 BIOS internal console code
0x02000000 EWRAM work RAM, 256 KB
0x03000000 IWRAM fast RAM, 32 KB
0x04000000 hardware registers (video, sound, input, DMA, timers)
0x05000000 Palette RAM colors
0x06000000 VRAM video data (tiles, maps, bitmaps)
0x07000000 OAM sprite attributes
0x08000000 ROM the game cartridge, mapped here
Two ranges matter most for this workshop:
0x08000000 is where the game ROM appears. Fixed code and data.
0x02000000 is where the current game state lives. HP, position, battle.
The general rule is easy to remember:
ROM (0x08...) = what the game is. It does not change while you play.
EWRAM (0x02...) = what is happening now. It changes every frame.
When we want to understand logic, we look at ROM. When we want to find a live value such as HP, we search EWRAM. Those two worlds meet when an instruction from ROM writes a value into EWRAM. Finding that moment is the core of game reverse engineering.
The ROM mapped at 0x08000000
This is the point that confuses people most at first, so it is worth stopping on.
The file PokemonFireRed.gba on disk starts at offset 0. But when the console
boots, it maps that entire file starting at address 0x08000000. So byte 0 of the
file becomes address 0x08000000, byte 0x100 of the file becomes 0x08000100, and so
on.
The conversion is direct:
memory address = file offset + 0x08000000
file offset = memory address - 0x08000000
Example:
address 0x08012345 -> offset 0x00012345 in the file
You will use this in every patch. Ghidra shows addresses like 0x08xxxxxx, but to edit the file on disk you need the offset, which is the address minus 0x08000000.
Looking at the first ROM bytes
You can confirm all of this without any special tool, just with xxd. The first
four ROM bytes are the first opcode the CPU executes:
xxd -g 1 -l 4 rom/PokemonFireRed.gba
Output:
00000000: 7f 00 00 ea
Those four bytes, read as a 32-bit ARM instruction in little endian, become a
jump. In chapter 02 we decode it byte by byte. For now, trust this: it is the
instruction b 0x08000204, a branch that skips the header and enters the real
code.
The ROM also stores a header with the game title. It is at offset 0xA0:
xxd -g 1 -s 0xa0 -l 32 rom/PokemonFireRed.gba
Output, reading the ASCII column on the right:
POKEMON FIRE
BPRE
The code BPRE identifies Pokemon FireRed USA. If your ROM shows this, it is the
right version for the workshop.
Video and sprites, at a high level
You do not need to master GBA video to make the patches in this workshop, but it helps to know the names so you do not get lost when they appear:
Backgrounds background layers, built with tiles stored in VRAM.
Sprites moving objects (the player, Pokemon in battle).
OAM the list that says where each sprite is on screen.
Palette RAM the colors used by tiles and sprites.
The screen is redrawn from top to bottom several times per second. At the end of each complete draw there is a small interval called VBlank. The game uses that moment to update graphics safely. That is why the game’s main loop always ends by waiting for VBlank, as you will see in chapter 04.
Interruptions, at a high level
An interrupt is a hardware signal to the CPU that something happened, for example “I finished drawing the screen” or “the player pressed a link button.” The CPU stops what it is doing, handles the signal in a specific routine, and then returns.
On the GBA, the FireRed routine that handles those signals is near the start of
the ROM, and in the workshop map it is called intr_main. You do not need to
reverse it entirely. What matters is understanding that it exists to synchronize
video, sound, input, and timers.
Why FireRed is a good target
It is worth closing the chapter with the reason for the choice:
ARM/Thumb well supported by Ghidra, so the disassembly is clean.
Direct ROM less boot complexity than something like an N64.
Clear data strings, Pokemon tables, items, and maps are readable.
Fast feedback walk in grass, open a shop, battle. You can test a patch immediately.
Good debugger mGBA has a debug server that talks to GDB.
What to take from this chapter
- The CPU is a 32-bit little-endian ARM7TDMI.
- Each type of memory lives in a fixed address range.
- The ROM appears at 0x08000000. Game state lives in EWRAM, at 0x02000000.
- file offset = address - 0x08000000.
- The game is a sequence of ARM and Thumb instructions. That is the next chapter.