mirror of
https://github.com/pret/pokestadium.git
synced 2026-03-22 01:34:25 -05:00
192 lines
6.0 KiB
C
192 lines
6.0 KiB
C
#include <ultra64.h>
|
|
#include "memory.h"
|
|
|
|
// seems to allocate a pool area, and init it's MainPool struct?
|
|
// the other file is memory_main.c but this one is memory.c?
|
|
|
|
/**
|
|
* Allocate a memory pool from the main pool. This pool supports arbitrary
|
|
* order for allocation/freeing.
|
|
* Return NULL if there is not enough space in the main pool.
|
|
*/
|
|
struct MemoryPool* mem_pool_try_init(u32 size, s32 side) {
|
|
struct MainPoolBlock* block;
|
|
struct MemoryPool* ret;
|
|
|
|
size = ALIGN4(size);
|
|
block = main_pool_alloc(size, side);
|
|
if (block != NULL) {
|
|
ret = mem_pool_init(block, size);
|
|
}
|
|
return ret; //! UB: Uninitialized return if the earlier call is not done.
|
|
}
|
|
|
|
/**
|
|
* Perform the actual mem pool init. This is called by the earlier function.
|
|
* In earlier EAD titles, this was part of mem_pool_try_init.
|
|
*/
|
|
// TODO: This function is strange, it cant be using MemoryPool, as it allocates
|
|
// more variables than the MemoryPool struct, and it doesnt line up. Whats going
|
|
// on with these structs?
|
|
struct MainPool* mem_pool_init(struct MainPool* pool, s32 size) {
|
|
s32 aligned_size =
|
|
ALIGN4(size - 3) - 0x28; // whats the deal with 0x28? this size doesnt match any known pool struct.
|
|
void* listHeadL = &pool->listHeadL;
|
|
|
|
pool->available = aligned_size;
|
|
pool->start = listHeadL;
|
|
pool->end = listHeadL;
|
|
pool->listHeadL = NULL;
|
|
pool->listHeadR = aligned_size;
|
|
osCreateMesgQueue(&pool->queue, &pool->msgs[0], 1);
|
|
osSendMesg(&pool->queue, NULL, 0);
|
|
return pool;
|
|
}
|
|
|
|
/**
|
|
* Allocate from a memory pool. Return NULL if there is not enough space.
|
|
*/
|
|
void* mem_pool_alloc(struct MainPool* node, s32 size) {
|
|
struct MemoryBlock* freeBlock;
|
|
void* addr;
|
|
|
|
osRecvMesg(&node->queue, 0, 1);
|
|
|
|
addr = NULL;
|
|
size = ALIGN4(size) + sizeof(struct MemoryBlock);
|
|
freeBlock = (struct MemoryBlock*)&node->end;
|
|
|
|
while (freeBlock->next != NULL) {
|
|
if (freeBlock->next->size >= size) {
|
|
addr = (u8*)freeBlock->next + sizeof(struct MemoryBlock); // get data after header
|
|
if (freeBlock->next->size - size <= sizeof(struct MemoryBlock)) {
|
|
freeBlock->next = freeBlock->next->next;
|
|
} else {
|
|
struct MemoryBlock* newBlock = (struct MemoryBlock*)((u8*)freeBlock->next + size);
|
|
newBlock->size = freeBlock->next->size - size; // set size
|
|
newBlock->next = freeBlock->next->next;
|
|
freeBlock->next->size = size; // set size
|
|
freeBlock->next = newBlock;
|
|
}
|
|
break;
|
|
}
|
|
freeBlock = freeBlock->next;
|
|
}
|
|
osSendMesg(&node->queue, 0, 0);
|
|
return addr;
|
|
}
|
|
|
|
/**
|
|
* Free a block that was allocated using mem_pool_alloc.
|
|
*/
|
|
void mem_pool_free(struct MemoryPool* pool, void* addr) {
|
|
struct MemoryBlock* block;
|
|
struct MemoryBlock* freeList;
|
|
|
|
if (addr != NULL) {
|
|
osRecvMesg(&pool->queue, NULL, 1);
|
|
block = (struct MemoryBlock*)((u8*)addr - sizeof(struct MemoryBlock));
|
|
freeList = pool->freeList.next;
|
|
if (pool->freeList.next == NULL) {
|
|
pool->freeList.next = block;
|
|
block->next = NULL;
|
|
} else if (block < pool->freeList.next) {
|
|
if ((u32)pool->freeList.next == ((u32)block + (u32)block->size)) {
|
|
block->size += ((u32)freeList->size);
|
|
block->next = freeList->next;
|
|
pool->freeList.next = block;
|
|
} else {
|
|
block->next = pool->freeList.next;
|
|
pool->freeList.next = block;
|
|
}
|
|
} else {
|
|
while (freeList->next != NULL) {
|
|
if (freeList < block && block < freeList->next) {
|
|
break;
|
|
}
|
|
freeList = freeList->next;
|
|
}
|
|
if (((u32)freeList + (u32)freeList->size) == (u32)block) {
|
|
freeList->size += block->size;
|
|
block = freeList;
|
|
} else {
|
|
block->next = freeList->next;
|
|
freeList->next = block;
|
|
}
|
|
if (block->next != NULL && (u32)block->next == ((u32)block + (u32)block->size)) {
|
|
block->size = (u32)block->size + (u32)block->next->size;
|
|
block->next = block->next->next;
|
|
}
|
|
}
|
|
osSendMesg(&pool->queue, NULL, 0);
|
|
}
|
|
}
|
|
|
|
void* func_80002D10(u32 size, s32 side) {
|
|
struct MainPoolBlock* block;
|
|
void* ptr = NULL;
|
|
|
|
size = ALIGN4(size);
|
|
ptr = 0;
|
|
block = main_pool_alloc(size, side);
|
|
if (block != NULL) {
|
|
ptr = func_80002DA4(block, size);
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
void func_80002D60(struct MemoryBlock* block) {
|
|
s32 size = ALIGN16(block->size + 0x10);
|
|
|
|
main_pool_realloc(block, size);
|
|
block->next = (void*)(size - 0x10);
|
|
}
|
|
|
|
void* func_80002DA4(struct MainPoolState* block, s32 size) {
|
|
void* temp_v1 = (void*)((u8*)block + 0x10);
|
|
|
|
block->listHeadL = 0;
|
|
block->freeSpace = ((size & ~3) - 0x10); // this doesnt match an ALIGN4 macro or whatnot
|
|
block->listHeadR = temp_v1;
|
|
block->prev = temp_v1;
|
|
return block;
|
|
}
|
|
|
|
s32 func_80002DCC(struct MainPoolState* state, s32 arg1, s32 arg2) {
|
|
s32 temp_a2;
|
|
s32 temp_a3;
|
|
s32 var_v0;
|
|
s32 ret = 0;
|
|
|
|
if (arg2 > 0) {
|
|
var_v0 = (((s32)state->prev + (s32)arg2) - 1) & ~(arg2 - 1);
|
|
} else {
|
|
var_v0 = state->prev;
|
|
}
|
|
temp_a2 = (var_v0 - (s32)state->prev) + arg1;
|
|
if (temp_a2 > 0) {
|
|
temp_a3 = (s32)state->listHeadL + temp_a2;
|
|
if ((s32)state->freeSpace >= temp_a3) {
|
|
ret = var_v0;
|
|
state->prev = (s32)((s32)state->prev + temp_a2);
|
|
state->listHeadL = temp_a3;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void func_80002E3C(struct MainPoolState* state, s32 size) {
|
|
if ((s32)state->freeSpace >= size) {
|
|
state->listHeadL = size;
|
|
state->prev = (void*)((s32)state->listHeadR + size);
|
|
}
|
|
}
|
|
|
|
void func_80002E64(struct MainPoolState* state) {
|
|
void* mem = (u8*)((u32)state + sizeof(struct MainPoolState));
|
|
|
|
state->listHeadL = 0;
|
|
state->listHeadR = mem;
|
|
state->prev = mem;
|
|
}
|