Background information

From ZeldaHacking Wiki
Jump to navigation Jump to search

Many of the pages on this wiki will assume that you understand the concepts presented on this page.

Basic knowledge

Numbers

If you don't know what hexadecimal is, here's the quick version: it's a number using the digits 0-9 as well as a-f. So long as you understand the distinction between hexadecimal and decimal, and can convert between them with a calculator, that is usually enough.

Hexadecimal numbers are prefixed with $, ie. $1f. Numbers prefixed with % are binary, ie. %10001000. Numbers prefixed with nothing are usually decimal (there are a few exceptions which will be explained).

You should also know that using 0x for hexadecimal numbers is more common in general, ie. 0x1f. However, most assemblers (including WLA) don't support this syntax.

Example

%00011110 = $1e = 30

Breaking down bytes into bits

There are many data structures involving specific bits in a byte. Take this example from data/ages/treasureObjectData.s:

; Data format:
; b0: bit 7    = next 2 bytes are a pointer
;     bits 4-6 = spawn mode
;     bit 3    = ?
;     bits 0-2 = grab mode
; b1: Parameter (value of 'c' to pass to "giveTreasure")
; b2: Low text ID on pickup ($ff for no text; high byte of ID is always $00)
; b3: Graphics to use. (Gets copied to object's subid, so graphics are determined by the
;     corresponding value for interaction $60 in data/interactionData.s.)

This is describing the format of 4 bytes. For example, these 2 rows in the same file define data for the switch hook and long hook, conforming to the above description:

treasureObjectData0a:
	.db $38 $01 $30 $1f
	.db $38 $02 $28 $1f

The format of bytes 1-3 are relatively straightforward (just byte values), but byte 0 has a specific format. Let's break down the format of byte 0, which has value $38 for both rows above. We will convert the byte into binary to see the value of its individual bits:

$38 = %00111000
       ^^^^^^^^
  Bit  76543210

bit 7    = 0
bits 4-6 = %011 = 3
bit 3    = 1
bits 0-2 = %000 = 0

So, cross-referencing this with the documentation at the top of the file, the "spawn mode" (bits 4-6) is "3", and the "grab mode" (bits 0-2) is "0".

Bitmasks

A "bitmask" is simply a byte which has some particular bits set, and whose individual bits have meaning.

As an example, take the spinner object (INTERAC_SPINNER), the one which turns red or blue. The documentation has this to say about it:

; Spinny thing that forces you to move in a clockwise or counterclockwise direction.
; The direction of the spinner is actually determined by wSpinnerState. This is
; initialized when entering a dungeon; search for the "@initialSpinnerValues" label.
;
; @subid_00-01{Red or blue spinner}
; @subid_02{Arrow indicating spinner direction}
; @X{Bitmask for wSpinnerState; each spinner in a dungeon should use a unique bit.}
; @postype{short}

Let's focus on the "X" parameter here which is described as a "bitmask". It says that "each spinner in a dungeon should use a unique bit", meaning that the X parameter should have at least one bit set.

So, we could set the "X" parameter to value $01, which would satisfy this requirement by setting the lowest bit in the byte. Value $00 would not work as no bits are set with this value.

For reference, the following 8 hexadecimal each represent one unique bit when converted to binary, and therefore would be valid values to use for the spinner's X parameter:

$01 $02 $04 $08 $10 $20 $40 $80

You can combine values with a bitwise OR. For example, $01 | $02 = $03. This would set the two lowermost bits. However, there is no reason to do that in this particular case, as the spinner only requires one bit in order to remember its state.

Advanced topics

Memory

You may find it helpful to get acquainted with the gameboy memory map (aka "address space"), especially if you're doing assembly hacking. Important parts:

  • $0000-$3fff: ROM Bank 0. This is the first 16KB of your ROM file.
  • $4000-$7fff: Switchable ROM Bank. This is a 16KB chunk of your ROM file. The program can decide which chunk it references at any given time.
  • $a000-$bfff: External RAM (SRAM). This is your save file.
  • $c000-$cfff: Work RAM (WRAM) Bank 0. 4KB of RAM which can be used for variables.
  • $d000-$dfff: Switchable WRAM Bank. This references a 4KB chunk of the gameboy's RAM (of 32KB total). The program can decide which chunk it references at any given time.
  • $ff80-$fffe: High RAM (HRAM). 127 bytes of RAM that can be accessed slightly more quickly than WRAM.

The important takeaways: addresses $0000-$7fff reference your ROM, and they are read-only. Variables are stored in WRAM ($c000-$dfff) and HRAM ($ff80-$fffe).

Banks

As you can see in the memory map above, both ROM and WRAM have "switchable banks". The gameboy's address space goes from $0000-$ffff, which is only 64KB. Since the oracle ROMs are at least 1MB large, this means only a portion of the ROM can be visible in the address space. So, the switchable ROM bank is used to reference a varying portion of the ROM.

Notation

Most ROM addresses will be given in terms of their bank number and their location in the address space.

Example: the "parseObjectData" function at 12:55b7 (ROM address $495b7) is responsible for loading the room's objects.

RAM addresses are treated similarly. The RAM bank is a number from 0-7. The RAM bank may be omitted when talking about bank 0 (since addresses from $c000-$cfff are implicitly bank 0).

Example: The current room's layout is stored at $cf00. There is a copy of it at 03:df00.

These addresses will not always have $ or 0x prefixed to them. This is because when writing addresses, it makes no sense to put them in anything but hexadecimal format. This applies to the bank number as well.

Conversion

Given a ROM bank number and an address in memory, convert it to an offset in your ROM with the following formula:

romAddress = bank * 0x4000 + (memoryAddress & 0x3fff)

And the reverse:

memoryAddress = (romAddress & 0x3fff) + 0x4000 (for bank 0, omit the + $4000)

bank = (romAddress / 0x4000) (ignore remainder)

Useful links

  • The Gameboy, a hardware autopsy - A great video explaining the basics of the Gameboy CPU. (See part 2 for memory mapping and banking)
  • Gameboy Pan Docs - Comprehensive documentation on the Gameboy's inner workings.
  • Gbdev Wiki - Contains a wikified version of the pandocs as well as some gb-z80 programming tutorials.
  • Gameboy CPU Manual - Much of the contents are the same as the pandocs, but this focuses more heavily on the CPU, explaining the instructions in more detail.