1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
|
#include <libultraship.h>
#include <libultra/types.h>
#include <align_asset_macro.h>
#include <macros.h>
#include <string.h>
#include <common_structs.h>
#include <segments.h>
#include <decode.h>
#include <stubs.h>
#include "memory.h"
#include "main.h"
#include "code_800029B0.h"
#include "defines.h"
#include "course_offsets.h"
#include "engine/tracks/Track.h"
#include "engine/editor/Editor.h"
#include <stdio.h>
#include "port/Game.h"
s32 sGfxSeekPosition;
s32 sPackedSeekPosition;
static u8 sMemoryPool[0xFFFFFFF]; // Stock memory pool size: 0xAB630
uintptr_t sPoolEnd = sMemoryPool + sizeof(sMemoryPool);
uintptr_t sPoolFreeSpace;
struct MainPoolBlock* sPoolListHeadL;
struct MainPoolBlock* sPoolListHeadR;
struct MainPoolState* gMainPoolState = NULL;
struct UnkStruct_802B8CD4 D_802B8CD4[] = { 0 };
s32 D_802B8CE4 = 0; // pad
s32 memoryPadding[2];
#define PRINT_MEMPOOL \
printf("\nPool Start: %p, Pool End: %p, size: 0x%lX\ngNextFreeMemoryAddress: 0x%lX\n\n", (void*) sMemoryPool, \
(void*) (sMemoryPool + sizeof(sMemoryPool)), \
(unsigned long) (((sMemoryPool + sizeof(sMemoryPool)) - sMemoryPool)), \
(unsigned long) gNextFreeMemoryAddress)
/**
* @brief Returns the address of the next available memory location and updates the memory pointer
* to reference the next location of available memory based provided size to allocate.
* @param size of memory to allocate.
* @return Address of free memory
*/
void* get_next_available_memory_addr(uintptr_t size) {
uintptr_t freeSpace = (uintptr_t) gNextFreeMemoryAddress;
size = ALIGN16(size);
gNextFreeMemoryAddress += size;
if (gNextFreeMemoryAddress > sPoolEnd) {
printf("[memory.c] get_next_available_memory_addr(): Memory Pool Out of Bounds! Out of memory!\n");
PRINT_MEMPOOL;
}
return (void*) freeSpace;
}
static uintptr_t get_texture2(size_t offset, const course_texture* textures) {
if (!((offset >= 0x5000000) && (offset < 0x6000000))) {
return NULL;
}
size_t totalOffset = 0x5000000;
while (textures->addr) {
if (totalOffset == offset) {
return (uintptr_t) (textures->addr);
}
totalOffset += textures->data_size;
textures++;
}
printf("memory.c: get_texture()\n TEXTURE NOT FOUND DURING DISPLAYLIST EXTRACT\n");
printf(" offset: 0x%zX\n", offset);
return NULL;
}
/**
* @brief Sets the starting location for allocating memory and calculates pool size.
*
* Default memory size, 701.984 Kilobytes.
*/
void initialize_memory_pool() {
uintptr_t poolStart = sMemoryPool;
// uintptr_t sPoolEnd = sMemoryPool + sizeof(sMemoryPool);
bzero(sMemoryPool, sizeof(sMemoryPool));
poolStart = ALIGN16(poolStart);
// Truncate to a 16-byte boundary.
sPoolEnd &= ~0xF;
gFreeMemorySize = (sPoolEnd - poolStart) - 0x10;
gNextFreeMemoryAddress = poolStart;
PRINT_MEMPOOL;
}
/**
* @brief Allocates memory and adjusts gFreeMemorySize.
*/
void* allocate_memory(size_t size) {
uintptr_t freeSpace;
size = ALIGN16(size);
if (gFreeMemorySize < size) {
printf("[memory.c] allocate_memory(): gFreeMemorySize below zero!\n");
printf("gFreeMemorySize before alloc: 0x%zX (requested: 0x%zX)\n", gFreeMemorySize, size);
PRINT_MEMPOOL;
}
gFreeMemorySize -= size;
freeSpace = (uintptr_t) gNextFreeMemoryAddress;
gNextFreeMemoryAddress += size;
if (gNextFreeMemoryAddress > sPoolEnd) {
printf("[memory.c] allocate_memory(): Memory Pool Out of Bounds! Out of memory!\n");
PRINT_MEMPOOL;
}
return (void*) freeSpace;
}
UNUSED void func_802A7D54(s32 arg0, s32 arg1) {
gD_80150158[arg0].unk0 = arg0;
gD_80150158[arg0].unk8 = arg1;
}
/**
* @brief Allocate and DMA.
*/
void* load_data(uintptr_t startAddr, uintptr_t endAddr) {
void* allocated;
uintptr_t size = endAddr - startAddr;
allocated = allocate_memory(size);
if (allocated != 0) {
dma_copy((u8*) allocated, (u8*) startAddr, size);
}
return (void*) allocated;
}
UNUSED void main_pool_init(uintptr_t start, uintptr_t end) {
start = ALIGN16(start);
end = ALIGN16(end - 15);
sPoolFreeSpace = (end - start) - 16;
sPoolListHeadL = (struct MainPoolBlock*) start;
sPoolListHeadR = (struct MainPoolBlock*) end;
sPoolListHeadL->prev = NULL;
sPoolListHeadL->next = NULL;
sPoolListHeadR->prev = NULL;
sPoolListHeadR->next = NULL;
}
/**
* Allocate a block of memory from the pool of given size, and from the
* specified side of the pool (MEMORY_POOL_LEFT or MEMORY_POOL_RIGHT).
* If there is not enough space, return NULL.
*/
UNUSED void* main_pool_alloc(uintptr_t size, uintptr_t side) {
struct MainPoolBlock* newListHead;
void* addr = NULL;
size = ALIGN16(size) + 8;
if (sPoolFreeSpace >= size) {
sPoolFreeSpace -= size;
if (side == MEMORY_POOL_LEFT) {
newListHead = (struct MainPoolBlock*) ((u8*) sPoolListHeadL + size);
sPoolListHeadL->next = newListHead;
newListHead->prev = sPoolListHeadL;
addr = (u8*) sPoolListHeadL + 8;
sPoolListHeadL = newListHead;
} else {
newListHead = (struct MainPoolBlock*) ((u8*) sPoolListHeadR - size);
sPoolListHeadR->prev = newListHead;
newListHead->next = sPoolListHeadR;
sPoolListHeadR = newListHead;
addr = (u8*) sPoolListHeadR + 8;
}
}
return addr;
}
/**
* Free a block of memory that was allocated from the pool. The block must be
* the most recently allocated block from its end of the pool, otherwise all
* newer blocks are freed as well.
* Return the amount of free space left in the pool.
*/
UNUSED uintptr_t main_pool_free(void* addr) {
struct MainPoolBlock* block = (struct MainPoolBlock*) ((u8*) addr - 8);
struct MainPoolBlock* oldListHead = (struct MainPoolBlock*) ((u8*) addr - 8);
if (oldListHead < sPoolListHeadL) {
while (oldListHead->next != NULL) {
oldListHead = oldListHead->next;
}
sPoolListHeadL = block;
sPoolListHeadL->next = NULL;
sPoolFreeSpace += (uintptr_t) oldListHead - (uintptr_t) sPoolListHeadL;
} else {
while (oldListHead->prev != NULL) {
oldListHead = oldListHead->prev;
}
sPoolListHeadR = block->next;
sPoolListHeadR->prev = NULL;
sPoolFreeSpace += (uintptr_t) sPoolListHeadR - (uintptr_t) oldListHead;
}
return sPoolFreeSpace;
}
// main_pool_realloc
UNUSED void* main_pool_realloc(void* addr, uintptr_t size) {
void* newAddr = NULL;
struct MainPoolBlock* block = (struct MainPoolBlock*) ((u8*) addr - 8);
if (block->next == sPoolListHeadL) {
main_pool_free(addr);
newAddr = main_pool_alloc(size, MEMORY_POOL_LEFT);
}
return newAddr;
}
UNUSED uintptr_t main_pool_available(void) {
return sPoolFreeSpace - 8;
}
UNUSED uintptr_t main_pool_push_state(void) {
struct MainPoolState* prevState = gMainPoolState;
uintptr_t freeSpace = sPoolFreeSpace;
struct MainPoolBlock* lhead = sPoolListHeadL;
struct MainPoolBlock* rhead = sPoolListHeadR;
gMainPoolState = main_pool_alloc(sizeof(*gMainPoolState), MEMORY_POOL_LEFT);
gMainPoolState->freeSpace = freeSpace;
gMainPoolState->listHeadL = lhead;
gMainPoolState->listHeadR = rhead;
gMainPoolState->prev = prevState;
return sPoolFreeSpace;
}
/**
* Restore pool state from a previous call to main_pool_push_state. Return the
* amount of free space left in the pool.
*/
UNUSED uintptr_t main_pool_pop_state(void) {
sPoolFreeSpace = gMainPoolState->freeSpace;
sPoolListHeadL = gMainPoolState->listHeadL;
sPoolListHeadR = gMainPoolState->listHeadR;
gMainPoolState = gMainPoolState->prev;
return sPoolFreeSpace;
}
// similar to sm64 dma_read
UNUSED void* func_802A80B0(u8* dest, u8* srcStart, u8* srcEnd) {
void* addr;
uintptr_t size = srcStart - dest;
addr = main_pool_alloc(size, (uintptr_t) srcEnd);
if (addr != 0) {
osInvalDCache(addr, size);
osPiStartDma(&gDmaIoMesg, OS_MESG_PRI_NORMAL, OS_READ, (uintptr_t) dest, addr, size, &gDmaMesgQueue);
osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
}
return addr;
}
uintptr_t MIO0_0F(u8* arg0, uintptr_t arg1, uintptr_t arg2) {
uintptr_t oldHeapEndPtr;
void* temp_v0;
arg1 = ALIGN16(arg1);
arg2 = ALIGN16(arg2);
oldHeapEndPtr = gHeapEndPtr;
temp_v0 = (void*) gNextFreeMemoryAddress;
osInvalDCache(temp_v0, arg1);
#ifdef TARGET_N64
osPiStartDma(&gDmaIoMesg, 0, 0, (uintptr_t) &_other_texturesSegmentRomStart[SEGMENT_OFFSET(arg0)], temp_v0, arg1,
&gDmaMesgQueue);
#endif
osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, 1);
mio0decode((u8*) temp_v0, (u8*) oldHeapEndPtr);
gHeapEndPtr += arg2;
return oldHeapEndPtr;
}
/* To help verify if ptrs are pointing within segments see gfx_pc.cpp gfx_step() */
uintptr_t vtxSegEnd;
uintptr_t dlSegEnd;
uintptr_t texSegEnd;
size_t texSegSize;
Gfx* testaaa;
u8* load_lakitu_tlut_x64(const char** textureList, size_t length) {
// Calculate lakitu texture size to allocate
size_t size = 0;
for (size_t i = 0; i < length; i++) {
size += ResourceGetTexSizeByName(textureList[i]);
}
u8* textures = (u8*) gNextFreeMemoryAddress;
gNextFreeMemoryAddress += size;
size_t offset = 0;
for (size_t i = 0; i < length; i++) {
u8* tex = (u8*) LOAD_ASSET_RAW(textureList[i]);
size_t texSize = ResourceGetTexSizeByName(textureList[i]);
// printf("\nTEX SIZE: %X\n\n", texSize);
memcpy(&textures[offset], tex, texSize);
offset += texSize;
}
return textures;
}
/**
* @brief Loads & DMAs track data. Vtx, textures, displaylists, etc.
* @param trackId
*/
void load_track(s32 trackId) {
printf("Loading Track %d\n", trackId);
gNextFreeMemoryAddress = gFreeMemoryResetAnchor;
CM_CleanWorld();
LoadTrack();
Editor_SetLevelDimensions(gTrackMinX, gTrackMaxX, gTrackMinZ, gTrackMaxZ, gTrackMinY, gTrackMaxY);
}
|