Skip to content
MegaMech edited this page Feb 26, 2023 · 41 revisions

Segments can be very confusing especially for those with poor memory retention. As such, this page hopes to explain this in an easily refreshable manner.

  • Data - Geometry, object models, animations, course paths, textures, audio, etc.
  • Displaylist- A list of commands sent to the N64 graphics processor (rsp and rdp). Synonymous to a function or block of code.

All of these elements need to be loaded from the cartridge and placed into ram. The confusing part is how the game magically knows where to find this data on cartridge. In essence, it's very simple.

mk64 creates sixteen segments labelled 0x0 to 0xF.

During compile, the linker gathers all the pieces of the program and puts them together. While doing so, it generates symbols, each containing a rom address. The games memory code calculates the size of the data by subtracting the rom end address from the rom start address. This value gets aligned to the next sixteen bytes. A global variable always points to the next free memory location. This pointers current address is saved prior to adding the data's size to it so that it points to the next free location (for next time the game loads data from the rom).

Finally the meat and potatoes, set_segment_base_addr is passed a hard-coded segment value between 0-16 along with the location of memory free for writing. This address is saved to the segment table array after having its segment removed: 0x08. Only saving the actual offset of the address allows some fancy tricks. The get_segment_base_addr adds the 0x08 back.

Example: Inspecting the following rom address in a hex editor displays MIO0 in the text panel. This compressed data contains course geography vertex data.

_mario_raceway_vertexSegmentRomStart = 0x88FA10
_mario_raceway_vertexSegmentRomEnd = 0x89B510
size   = end      - start
0xBB00 = 0x89B510 - 0x88FA10
align16(0xBB00)
0xBB00 = (0xBB00 + 0xF) AND NOT F (NOT F is FFFFFFFFFFFFFFF0)

Examples of align16 at work:
align16(0xBB01) = 0xBB10, align16(0xBB0F) = 0xBB10, align16(0xBB10) = 0xBB10, align16(0xBB11) = 0xBB20

Aligning ensures that the next chunk of data is placed on a 0x00 boundary and not an oddball number such as 0x03.

Data is copied to ram and its segment base addr is set:
gSegmentTable[segment] addr & 0x1FFFFFFF;
gSegmentTable[0xF] 0x802887A8 & 0x1FFFFFFF; // Address saved as 002887A8

Now, if the game has a texture saved at a known offset, ex: 0x210. We can take the value in the segment table and add 0x210. If you add the segment number of 0x08, you now have the textures location in memory.

Segmented addresses are necessary because the N64 only has four megabytes of memory. The console cannot load all twenty courses at the same time. This means the memory needs to be re-used. This is called an overlay. It's unknown as to where an overlay will end up in memory. As such, the addresses for the data cannot be hard-coded. There will be conflicts and crashes. The work around is using a segmented address. Instead of using an address such as 0x8017BA58, 0x060000000 is used. Now all the data uses neatly placed offsets such as 0x210. If the memory address is known for a segment then a texture can be had just by adding its offset to that address. For example lets call get_segment_base_addr(0x06):

gSegmentTable[0x06] | 0x80000000
0x802887A8 = 0x002887A8 | 0x80000000

Now to find the texture add 0x210 to 0x802887A8. All of these steps are done on the fly using functions and macros.

This concept references actors like so:

s32 segment = SEGMENT_NUMBER2(D_06013F78);
s32 offset = SEGMENT_OFFSET(D_06013F78);
struct ActorSpawnData *data = VIRTUAL_TO_PHYSICAL2(gSegmentTable[segment] + offset);

The segment variable contains: 0x06 The offset variable contains: 0x13F78 gSegmentTable[segment] contains: 0x802887A8 then has 0x13F78 added to it. VIRTUAL_TO_PHYSICAL adds the 0x80 to the address and returns a pointer to the data. The term virtual corresponds to a segmented address whereas physical refers to an actual memory address. Virtual is a fake representation. Remember that physical memory always begins with 0x80.

The goal here is to eventually describe what's in each segment and where to find it in the code-base.

Seg Desc
0 General Purpose; contains the game code addressed as 0x80000000 ex 0x8029E158
1 ?
2 Unknown data
3 Common and Course Specific Textures loaded by func_8029E158. Sets data to segment F for extraction.
4 Course meshes for collision and graphics
5 Course Textures
6 Course data overlay consisting of displaylists, textures, models, actor spawn locations, and path data.
7 Unpacked displaylists which reference course mesh data.
8 ?
9 Course offsets for texture lists and a jump table consisting of segment 06 display list.
A ?
B ?
C ?
D ?
E ?
F Temporary buffer for course mesh MIO0 and packed dlists / Course collisions table (44 byte entries)
Clone this wiki locally