From CloudModding OoT Wiki
Jump to: navigation, search

Ocarina of Time's dynamic content is loaded on the "main heap"

Allocation Structures

There are at least two different structures used to manage dynamic memory allocation in the Zelda 64 engine.

Block List

The block list structure allows for memory to be allocated and reclaimed arbitrarily. The main disadvantage to block lists are "memory bubbles", or spaces with gaps of free space that can sometimes be too small to be allocated to, that can pop up over time. To mitigate this, longer living/less volatile data is allocated to the tail end (higher address) of the block list.

Block List Reference Structure

Main Heap Block List Reference
NTSC 1.08012BAA0
NTSC 1.18012BC60
PAL 1.180129B00

The Block List Reference "owns" the block list data structure. It structure seems to be in the following form, but it's full length is unknown.

/* 0x00 */ void* HeapStartA; // pointer to the allocated heap space, and pointer to the first node in the heap
/* 0x04 */ void* HeapStartB; // pointer passed in when allocating the block list. This is possibly used for re-mapping, but is the same as A
/* 0x08 */ s32 size; // is the size of the heap.

Block List Node

The block list node is 0x10 bytes long, with an optional extra 0x18 bytes of data for debugging purposes, for a total allocated size of either 0x10 in the Gamecube releases, or 0x30 bytes in the N64 releases and the Debug Rom.

/* 0x00 */ s16 MAGIC_NUMBER = 0x7373; //Magic Number used to identify the start of the node list. Possibly meant for viewing the struct in memory or integrity checking the list
/* 0x02 */ s16 is_free; //denotes whether the block is free for re-allocation (1 for yes, 0 for no)
/* 0x04 */ s32 size;    //size of the block memory being managed, not including the node itself
/* 0x08 */ node* next;  //pointer to the next node in the heap
/* 0x0C */ node* prev;  //pointer to the previous node in the heap
/* 0x10 */ char* sourceName; //
/* 0x14 */ s32 //?
/* 0x18 */ s32 threadId; //thread responsible for creating the node
/* 0x1C */ blocklist* parent;  //pointer to the block list reference structure (or head)
/* 0x20 */ OSTime creationTime; //Time node was created


Debug Rom

See also: Function Map

NTSC 1.0

800005A0 //???, low level function, calls 800A1C50

800A1C50 //Main boot routine?, calls 80051B50
1C54 LUI	V0, 0x8012
1C58 ADDIU	V0, V0, 0xD2A0 (V0 = 8011D2A0)
1C5C SW 	RA, 0x001C(SP)

1C94 JAL	800AD410 //DD boot routine

1CC4 JAL	800AD488 //Zeroes 80121210 if 80121211 is zero

1CFC JAL	800CD390 //Allocates heap?

1D04 JAL	80051B50

800AD410 //Disk Drive boot routine (called by A1C50)
//Writes to 80121211, possibly stores whether the dd can be loaded from
D418 LUI	T6, 0x8012
D41C LBU	T6, 0x1210(T6)
D420 LUI	V0, 0x00B9
D424 ADDIU	A1, V0, 0xAD30 //A1 = B8AD30, or the disk drive code file start
D428 BNEZ	T6, 800AD478 
D42C LUI	A0, 0x801C
D430 LUI	T7, 0x00BA
D434 ADDIU	T7, T7, 0xDA40 //T7 = B9DA40, or disk drive code file end
D438 SUBU	A2, T7, A1 //A2 = file size

D43C JAL	800000DF0 //DMA read function
D440 ADDIU	A0, A0, 0x6E80 //A0 = 801C6E80, or the heap start?

80051B50 //???, calls 800CDA20
1B58 JAL	800CDA20
1B5C ADDIU	A0, R0, 0x15D4 //Size of block?

800CD320 //? Checks state of 80105430
D320 LUI	V0, 0x8010
D324 LW 	V0, 0x5430(V0)//load from 80105430

D32C SW 	S0, 0x0014(SP)
D330 SW 	S1, 0x0018(SP)
D334 LUI	S0, 0x8010
D338 SW 	RA, 0x001C(SP)
D33C ADDIU	S0, S0, 0x5430 //S0 = 80105430
D340 BEQ	V0, R0, 0x800CD374
D344 OR 	S1, R0, R0 //S1 = 0

D388 JR 	RA

800CD390 //Allocates main heap 
//A0 = Block start (801C6E60)
//A1 = Block size (001EE1A0)
//starts by moving A0/A1 into A1/A2
D3A4 LUI	A0, 0x8013
D3A8 JAL	800CDD90
D3AC ADDIU	A0, 0xBAA0 //A0 = 8012BAA0
D3B0 JAL	800CD320

800CDD90 //Creates a Mem LL node, and attaches it to some structure
//A0 = ? (8012BAA0)
//A1 = ? (801C6E60)
//A2 = ? (001EE1A0)
DD90 ADDIU	V0, A1, 0x000F
DD94 ADDIU	AT, R0, 0xFFF0 //AT = -0x10
DD98 AND	V0, V0, AT //V0 is aligned
DD9C SUBU	T6, V0, A1 //Store delta
DDA0 SUBU	A2, A2, T6 //if not aligned, sub size?
DDA4 AND	A2, A2, AT //Round down size to nearest 0x10
DDA8 ADDIU	T7, A2, 0xFFD0 //T2 = allocated block size - size of mem ll node
DDAC ADDIU	T8, R0, 0x0001 //T1 = 1, block is free for subdivision
DDB0 ADDIU	T9, R0, 0x7373 //Mem LL "header"?
//populate the node
DDB4 SW 	R0, 0x0008(V0)
DDB8 SW 	R0, 0x000C(V0)
DDBC SW 	T7, 0x0004(V0)
DDC0 SH 	T8, 0x0002(V0)
DDC4 SH 	T9, 0x0000(V0)
DDC8 SW 	V0, 0x0000(A0) //store the re-mapped address
DDCC SW 	A1, 0x0004(A0) //stores the original address sent into the function
DDD4 SW 	A2, 0x0008(A0) //stores block size

800CDA20 //Allocates block on the main? heap
//A0 = Space to allocate

DA28 SW 	A0, 0x0020(SP) //Store allocate space for later
DA2C JAL	80003CC0 //some very low-level function
DA30 ADDIU	A0, R0, 0x0001
DA34 LUI	A0, 0x8013

DA3C ADDIU	A0, A0, 0xBAA0 //A0 = 12BAA0
DA40 JAL	800CE060
DA44 LW 	A1, 0x0020(SP) //A1 = allocate space

800CE060 //Function related to creating the ll nodes. Called before 0CE2B4 func
//A0 = ptr to struct related to initializing the space
//A1 = space size, not adjusted for alignment?
E06C LW 	A2, 0x0000(A0)//load first word in struct
E070 ADDIU	T0, R0, 0xFFF0 //T0 = -0x10
E074 ADDIU	T6, A1, 0x000F

800CE2B4 //Function related to populating a ll?
//A0 = Some special pointer (8011BEF0)
//A1 = ? (points to a ll)

E2BC BEQ	A1, R0, 800CE3D4
E2C0 OR 	A3, A0, R0 //A3 = 12BAA0 (what is this space)