mirror of
https://github.com/pret/pokestadium.git
synced 2026-04-25 16:14:57 -05:00
commit
cfb34ef5de
|
|
@ -9,9 +9,6 @@ extern s32 func_8005A990(OSPiHandle *);
|
|||
// bcopy.s
|
||||
extern void _bcopy(void *, void *, u32);
|
||||
|
||||
// 3640.s
|
||||
extern void* func_80002AF8(s32, void*);
|
||||
|
||||
// 3A80.c
|
||||
extern uintptr_t convert_addr_to_virt_addr(uintptr_t addr);
|
||||
extern void func_80002F58(void);
|
||||
|
|
|
|||
|
|
@ -3,4 +3,14 @@
|
|||
|
||||
#include "ultra64.h"
|
||||
|
||||
#define POOL_END_4MB 0x80400000
|
||||
#define POOL_END_6MB 0x80600000
|
||||
|
||||
/*
|
||||
* Dynamic heap with an indetermate amount of space. This pool can either end at 4MB or
|
||||
* 6MB depending on osMemSize, which is really strange as it should be using the whole
|
||||
* 8MB of the expansion pak.
|
||||
*/
|
||||
extern u8 gPool[1];
|
||||
|
||||
#endif
|
||||
|
|
|
|||
18
splat.yaml
18
splat.yaml
|
|
@ -36,8 +36,8 @@ segments:
|
|||
- [0x1F70, bin, noppad_1F70] # Extra nop align like earlier. Weird
|
||||
- [0x1F80, c, dp_intro] # dp intro code
|
||||
- [0x28E0, c, memmap]
|
||||
- [0x2EC0, c, memory]
|
||||
- [0x3640, asm] #
|
||||
- [0x2EC0, c, memory_main] # handles the main global pool
|
||||
- [0x3640, c, memory] # memory_pool
|
||||
- [0x3A80, c]
|
||||
- [0x3FB0, asm] # PRES-JPEG decoder
|
||||
- [0x5580, asm] # there's a split here according to PAL
|
||||
|
|
@ -325,6 +325,8 @@ segments:
|
|||
- [0x68020, bin] # rest of rom part 1
|
||||
|
||||
# .data is somewhere in here
|
||||
- [0x69790, .data, 3A80]
|
||||
- [0x697A0, bin, rom_data_697A0]
|
||||
- [0x6A1B0, .data, crash_screen]
|
||||
- [0x6A3B0, .data, profiler]
|
||||
- [0x6A3D0, .data, gb_tower]
|
||||
|
|
@ -416,7 +418,7 @@ segments:
|
|||
- {vram: 0x8007F190, type: .bss, name: main}
|
||||
- {vram: 0x80081900, type: .bss, name: rsp}
|
||||
- {vram: 0x80083CA0, type: .bss, name: unk_bss}
|
||||
- {vram: 0x800A6070, type: .bss, name: memory}
|
||||
- {vram: 0x800A6070, type: .bss, name: memory_main}
|
||||
- {vram: 0x800A60B0, type: .bss, name: unk_bss_4}
|
||||
- {vram: 0x800A7320, type: .bss, name: controller}
|
||||
- {vram: 0x800A7420, type: .bss, name: unk_bss_3}
|
||||
|
|
@ -429,6 +431,16 @@ segments:
|
|||
- {vram: 0x80103950, type: .bss, name: libultra/io/vimgr}
|
||||
- {vram: 0x80104b70, type: .bss, name: libultra/io/conteepread}
|
||||
- [0x7F980]
|
||||
|
||||
- name: heap
|
||||
type: code
|
||||
bss_size: 0x0 # This heap extends to the end of RAM.
|
||||
start: 0x7F980
|
||||
vram: 0x80104BB0
|
||||
subsegments:
|
||||
# .bss
|
||||
- {vram: 0x80104BB0, type: .bss, name: heap}
|
||||
- [0x7F980]
|
||||
|
||||
# Probably the GB Tower Emulator. This fragment is built very strangely.
|
||||
- name: fragment1
|
||||
|
|
|
|||
45
src/3A80.c
45
src/3A80.c
|
|
@ -2,16 +2,21 @@
|
|||
#include "memmap.h"
|
||||
#include "memory.h"
|
||||
|
||||
extern s32 D_80068B90;
|
||||
extern u8 D_80104BB0[];
|
||||
extern s32 D_800A60B0;
|
||||
/**
|
||||
* Based on the context of this variable's usage, it appears to be intended to
|
||||
* be non-0 whenever the expansion RAM is in, however it is never initialized
|
||||
* properly. It seems to serve as whereever the new start of memory will be
|
||||
* located whenever plugged in, but its only functional with the debug profiler.
|
||||
* It will, however, allocate a much bigger pool if set to non-0.
|
||||
*/
|
||||
s32 gExpansionRAMStart = FALSE;
|
||||
|
||||
extern struct MainPool **gMainPool; // gMainPool
|
||||
|
||||
void func_80003860(void);
|
||||
s32 func_80002A40(s32, s32);
|
||||
void func_80002BD0(s32, void *); // type unknown
|
||||
s32 func_80007A58(void);
|
||||
|
||||
/*
|
||||
/**
|
||||
* Convert any valid address to its virtual (KSEG0) counterpart.
|
||||
*/
|
||||
uintptr_t convert_addr_to_virt_addr(uintptr_t addr) {
|
||||
|
|
@ -45,22 +50,24 @@ void HAL_Memcpy(u32* dest, u32* src, int size) {
|
|||
|
||||
void func_80002F58(void) {
|
||||
// wat? mem sizes are only ever 0x400000 or 0x800000. This check makes no sense.
|
||||
if ((D_80068B90 != 0) && ((u32) osMemSize > 0x600000U)) {
|
||||
main_pool_init(&D_80104BB0, 0x80600000);
|
||||
// Effectively, it checks if the expansion RAM is in. But why not just use all
|
||||
// of it, or at least do the correct check of osMemSize == 0x800000?
|
||||
if ((gExpansionRAMStart != 0) && ((u32) osMemSize > 0x600000U)) {
|
||||
main_pool_init(&gPool, POOL_END_6MB);
|
||||
} else {
|
||||
main_pool_init(&D_80104BB0, 0x80400000);
|
||||
D_80068B90 = 0;
|
||||
main_pool_init(&gPool, POOL_END_4MB);
|
||||
gExpansionRAMStart = 0;
|
||||
}
|
||||
func_80003860();
|
||||
D_800A60B0 = func_80002A40(0x10000, 0);
|
||||
gMainPool = mem_pool_try_init(0x10000, 0);
|
||||
}
|
||||
|
||||
void *func_80002FDC(s32 arg0) {
|
||||
return func_80002AF8(D_800A60B0, arg0);
|
||||
void *func_80002FDC(s32 size) {
|
||||
return mem_pool_alloc(gMainPool, size);
|
||||
}
|
||||
|
||||
void func_80003004(void *arg0) {
|
||||
func_80002BD0(D_800A60B0, arg0);
|
||||
mem_pool_free(gMainPool, arg0);
|
||||
}
|
||||
|
||||
void HAL_DrawRect(Gfx** dlist, s32 ulx, s32 lrx, u16 color) {
|
||||
|
|
@ -83,15 +90,15 @@ void HAL_DrawRect(Gfx** dlist, s32 ulx, s32 lrx, u16 color) {
|
|||
|
||||
void func_8000310C(Gfx** dlist) {
|
||||
struct MainPool *pool = main_pool_get_pool();
|
||||
s32 temp_s1 = main_pool_get_available() - D_80068B90;
|
||||
s32 temp_s1 = main_pool_get_available() - gExpansionRAMStart;
|
||||
|
||||
if (temp_s1 >= 0)
|
||||
{
|
||||
s32 base = 30;
|
||||
s32 sp48 = ((u32) ( K0_TO_PHYS(pool->start)) >> 15) + base;
|
||||
s32 sp44 = ((u32) ( K0_TO_PHYS(pool->listHeadL)) >> 15) + base;
|
||||
s32 sp40 = ((u32) ( K0_TO_PHYS(pool->listHeadR) - D_80068B90) >> 15) + base;
|
||||
s32 sp3C = ((u32) ( K0_TO_PHYS(pool->end) - D_80068B90) >> 15) + base;
|
||||
s32 sp40 = ((u32) ( K0_TO_PHYS(pool->listHeadR) - gExpansionRAMStart) >> 15) + base;
|
||||
s32 sp3C = ((u32) ( K0_TO_PHYS(pool->end) - gExpansionRAMStart) >> 15) + base;
|
||||
|
||||
HAL_DrawRect(dlist, base, sp48, 0xFBCB);
|
||||
HAL_DrawRect(dlist, sp48, sp44, 0xFFCB);
|
||||
|
|
@ -104,8 +111,8 @@ void func_8000310C(Gfx** dlist) {
|
|||
s32 base = 30;
|
||||
s32 sp34 = ((u32) ( K0_TO_PHYS(pool->start)) >> 15) + base;
|
||||
s32 sp30 = ((u32) ( K0_TO_PHYS(pool->listHeadL)) >> 15) + base;
|
||||
s32 sp2C = ((u32) ( K0_TO_PHYS(pool->listHeadR) - D_80068B90) >> 15) + base;
|
||||
s32 sp28 = ((u32) ( K0_TO_PHYS(pool->end) - D_80068B90) >> 15) + base;
|
||||
s32 sp2C = ((u32) ( K0_TO_PHYS(pool->listHeadR) - gExpansionRAMStart) >> 15) + base;
|
||||
s32 sp28 = ((u32) ( K0_TO_PHYS(pool->end) - gExpansionRAMStart) >> 15) + base;
|
||||
HAL_DrawRect(dlist, base, sp34, 0xFBCB);
|
||||
HAL_DrawRect(dlist, sp34, sp2C, 0xFFCB);
|
||||
HAL_DrawRect(dlist, sp2C, sp30, 0xF94B);
|
||||
|
|
|
|||
3
src/heap.c
Normal file
3
src/heap.c
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#include <ultra64.h>
|
||||
|
||||
u8 gPool[1]; // unk determinate size.
|
||||
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
void __osPackEepReadData(u8 address);
|
||||
OSPifRam __osEepPifRam;
|
||||
s32 __osEepromRead16K;
|
||||
|
||||
#define CONT_RANGE_ERROR -1
|
||||
|
||||
|
|
@ -37,12 +36,14 @@ s32 osEepromRead(OSMesgQueue *mq, u8 address, u8 *buffer)
|
|||
// @bug: Should be > EEP16K_MAXBLOCKS
|
||||
if (address >= EEP16K_MAXBLOCKS) {
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
// __osEepromRead16K support seems to have been removed from this particular
|
||||
// revision.
|
||||
//__osEepromRead16K = -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (1);
|
||||
ret = CONT_NO_RESPONSE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
501
src/memory.c
501
src/memory.c
|
|
@ -1,373 +1,194 @@
|
|||
#include <ultra64.h>
|
||||
#include <macros.h>
|
||||
#include "memory.h"
|
||||
|
||||
static struct MainPool sMemPool;
|
||||
// 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?
|
||||
|
||||
/**
|
||||
* Initialize the main memory pool. This pool is conceptually a pair of stacks
|
||||
* that grow inward from the left and right. It therefore only supports
|
||||
* freeing the object that was most recently allocated from a side.
|
||||
* 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.
|
||||
*/
|
||||
void main_pool_init(void *start, void *end) {
|
||||
sMemPool.start = (void *)(ALIGN16((uintptr_t)start) + 16);
|
||||
sMemPool.end = (void *)(ALIGN16((uintptr_t)end - 15) - 16);
|
||||
sMemPool.available = (uintptr_t)sMemPool.end - (uintptr_t)sMemPool.start;
|
||||
sMemPool.mainState = NULL;
|
||||
struct MemoryPool *mem_pool_try_init(u32 size, s32 side) {
|
||||
struct MainPoolBlock *block;
|
||||
struct MemoryPool *ret;
|
||||
|
||||
sMemPool.listHeadL = ((u8*)sMemPool.start - sizeof(struct MainPoolBlock));
|
||||
sMemPool.listHeadL->prev = NULL;
|
||||
sMemPool.listHeadL->next = NULL;
|
||||
sMemPool.listHeadL->func = NULL;
|
||||
sMemPool.listHeadL->arg = 0;
|
||||
|
||||
sMemPool.listHeadR = sMemPool.end;
|
||||
sMemPool.listHeadR->prev = NULL;
|
||||
sMemPool.listHeadR->next = NULL;
|
||||
sMemPool.listHeadL->func = NULL;
|
||||
sMemPool.listHeadL->arg = 0;
|
||||
|
||||
osCreateMesgQueue(&sMemPool.queue, sMemPool.msgs, ARRAY_COUNT(sMemPool.msgs));
|
||||
osSendMesg(&sMemPool.queue, NULL, OS_MESG_NOBLOCK);
|
||||
size = ALIGN4(size);
|
||||
block = main_pool_alloc_node_no_func(size, side);
|
||||
if (block != NULL) {
|
||||
ret = mem_pool_init(block, size);
|
||||
}
|
||||
return ret; //! UB: Uninitialized return if the earlier call is not done.
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
struct MainPoolBlock *main_pool_alloc(u32 size, u32 side) {
|
||||
struct MainPoolBlock *newListHead;
|
||||
void *addr = NULL;
|
||||
// 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;
|
||||
|
||||
size = ALIGN16(size) + sizeof(struct MainPoolBlock);
|
||||
if (size != 0 && sMemPool.available >= size) {
|
||||
if (side == MEMORY_POOL_LEFT) {
|
||||
sMemPool.available -= size;
|
||||
newListHead = (void *)((uintptr_t)sMemPool.listHeadL + size);
|
||||
sMemPool.listHeadL->next = newListHead;
|
||||
newListHead->prev = sMemPool.listHeadL;
|
||||
newListHead->next = NULL;
|
||||
newListHead->func = 0;
|
||||
newListHead->arg = 0;
|
||||
addr = ((u8*)sMemPool.listHeadL + sizeof(struct MainPoolBlock));
|
||||
sMemPool.listHeadL = newListHead;
|
||||
} else if (side == MEMORY_POOL_RIGHT) {
|
||||
sMemPool.available -= size;
|
||||
newListHead = (void *)((uintptr_t)sMemPool.listHeadR - size);
|
||||
sMemPool.listHeadR->prev = newListHead;
|
||||
newListHead->next = sMemPool.listHeadR;
|
||||
newListHead->prev = NULL;
|
||||
newListHead->func = 0;
|
||||
newListHead->arg = 0;
|
||||
sMemPool.listHeadR = newListHead;
|
||||
addr = ((u8*)newListHead + sizeof(struct MainPoolBlock));
|
||||
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 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.
|
||||
* Free a block that was allocated using mem_pool_alloc.
|
||||
*/
|
||||
u32 main_pool_free(void *addr, u32 runBlockFunc) {
|
||||
struct MainPoolBlock *block = (struct MainPoolBlock *)((u8 *)addr - sizeof(struct MainPoolBlock));
|
||||
struct MainPoolBlock *oldListHead = (struct MainPoolBlock *)((u8 *)addr - sizeof(struct MainPoolBlock));
|
||||
|
||||
if (oldListHead < sMemPool.listHeadL) {
|
||||
do {
|
||||
block = (sMemPool.listHeadL = sMemPool.listHeadL->prev);
|
||||
if (runBlockFunc) {
|
||||
// TODO: Fakematch
|
||||
void (*func)(struct MainPoolBlock *, u32) = block->func;
|
||||
if (func != 0) {
|
||||
block->func(block + 1, block->arg);
|
||||
// TODO: fake here too
|
||||
if ((!(&sMemPool)) && (!(&sMemPool)))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
sMemPool.available += ((uintptr_t)sMemPool.listHeadL->next - (uintptr_t)sMemPool.listHeadL);
|
||||
sMemPool.listHeadL->next = NULL;
|
||||
} while (oldListHead != sMemPool.listHeadL);
|
||||
} else {
|
||||
block = sMemPool.listHeadR;
|
||||
if (oldListHead >= block && oldListHead >= block) {
|
||||
do {
|
||||
if (runBlockFunc) {
|
||||
void (*func)(struct MainPoolBlock *, u32) = block->func;
|
||||
if (func != NULL) {
|
||||
func(block + 1, block->arg);
|
||||
block = sMemPool.listHeadR;
|
||||
}
|
||||
}
|
||||
block = (sMemPool.listHeadR = block->next);
|
||||
sMemPool.available += ((uintptr_t)block - (uintptr_t)block->prev);
|
||||
block->prev = NULL;
|
||||
block = sMemPool.listHeadR;
|
||||
} while (oldListHead >= sMemPool.listHeadR);
|
||||
}
|
||||
}
|
||||
|
||||
return main_pool_get_available();
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually allocate and initialize a block given a size and side and its
|
||||
* function+arguments.
|
||||
*/
|
||||
struct MainPoolBlock *main_pool_alloc_node(u32 size, s32 side, s32 arg, void *func) {
|
||||
struct MainPoolBlock *node;
|
||||
|
||||
osRecvMesg(&sMemPool.queue, NULL, OS_MESG_BLOCK);
|
||||
node = main_pool_alloc(size, side);
|
||||
if (node != NULL) {
|
||||
main_pool_set_func(node, arg, func);
|
||||
}
|
||||
osSendMesg(&sMemPool.queue, NULL, OS_MESG_NOBLOCK);
|
||||
void mem_pool_free(struct MemoryPool* pool, void* addr) {
|
||||
struct MemoryBlock* block;
|
||||
struct MemoryBlock* freeList;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as above but no function/argument is set.
|
||||
*/
|
||||
struct MainPoolBlock *main_pool_alloc_node_no_func(u32 size, s32 side) {
|
||||
struct MainPoolBlock *node;
|
||||
|
||||
osRecvMesg(&sMemPool.queue, NULL, OS_MESG_BLOCK);
|
||||
node = main_pool_alloc(size, side);
|
||||
osSendMesg(&sMemPool.queue, NULL, OS_MESG_NOBLOCK);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to free a block of memory that was allocated from the pool. Return
|
||||
* the new available amount of the pool.
|
||||
*/
|
||||
u32 main_pool_try_free(struct MainPoolBlock *addr) {
|
||||
if (addr != NULL) {
|
||||
osRecvMesg(&sMemPool.queue, NULL, OS_MESG_BLOCK);
|
||||
main_pool_free(addr, 1);
|
||||
osSendMesg(&sMemPool.queue, NULL, OS_MESG_NOBLOCK);
|
||||
}
|
||||
|
||||
return main_pool_get_available();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize a block of memory that was allocated from the left side of the pool.
|
||||
* If the block is increasing in size, it must be the most recently allocated
|
||||
* block from the left side.
|
||||
* The block does not move.
|
||||
*/
|
||||
struct MainPoolBlock *main_pool_realloc(void *addr, size_t size) {
|
||||
struct MainPoolBlock *prior = (struct MainPoolBlock *)((u8 *)addr - sizeof(struct MainPoolBlock));
|
||||
void *newaddr = NULL;
|
||||
|
||||
osRecvMesg(&sMemPool.queue, NULL, OS_MESG_BLOCK);
|
||||
|
||||
if (prior->next == sMemPool.listHeadL) {
|
||||
size_t diff = ((uintptr_t)prior->next - (uintptr_t)addr);
|
||||
size = ALIGN16(size);
|
||||
if (diff >= size || sMemPool.available >= (size - diff)) {
|
||||
s32 arg = prior->arg;
|
||||
void *func = prior->func;
|
||||
main_pool_free(addr, 0);
|
||||
newaddr = main_pool_alloc(size, 0);
|
||||
main_pool_set_func(newaddr, arg, func);
|
||||
}
|
||||
}
|
||||
osSendMesg(&sMemPool.queue, NULL, OS_MESG_NOBLOCK);
|
||||
return newaddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the amount of available memory to use in the pool.
|
||||
*/
|
||||
u32 main_pool_get_available(void) {
|
||||
s32 available = sMemPool.available - sizeof(struct MainPoolBlock);
|
||||
|
||||
if (available < 0) {
|
||||
available = 0;
|
||||
}
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push pool state, to be restored later. Return the amount of free space left
|
||||
* in the pool.
|
||||
*/
|
||||
u32 main_pool_push_state(u32 arg) {
|
||||
struct MainPoolState *state;
|
||||
struct MainPoolBlock *listHeadL;
|
||||
struct MainPoolBlock *listHeadR;
|
||||
uintptr_t available;
|
||||
|
||||
osRecvMesg(&sMemPool.queue, NULL, OS_MESG_BLOCK);
|
||||
|
||||
// retrieve the space and head pointers.
|
||||
available = sMemPool.available;
|
||||
listHeadL = sMemPool.listHeadL;
|
||||
listHeadR = sMemPool.listHeadR;
|
||||
|
||||
state = (void*)main_pool_alloc(sizeof(struct MainPoolState), 0);
|
||||
if (state != NULL) {
|
||||
/**
|
||||
* Why is this line here? What this line is doing is backing the pointer up to the
|
||||
* previous block before this one. in the block alloc function, addr is determined
|
||||
* by the head plus the size of the block struct, meaning it is returning the
|
||||
* pointer to the head.
|
||||
*/
|
||||
((struct MainPoolBlock *)((u8*)state-sizeof(struct MainPoolBlock)))->arg = arg;
|
||||
|
||||
// now that the previous block's argument is set, set the newly allocated state's
|
||||
// fields.
|
||||
state->prev = sMemPool.mainState;
|
||||
state->freeSpace = available;
|
||||
state->listHeadL = listHeadL;
|
||||
state->listHeadR = listHeadR;
|
||||
|
||||
// add the newly allocated state.
|
||||
sMemPool.mainState = state;
|
||||
}
|
||||
osSendMesg(&sMemPool.queue, NULL, OS_MESG_NOBLOCK);
|
||||
return main_pool_get_available();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore pool state from a previous call to main_pool_push_state. Return the
|
||||
* amount of free space left in the pool.
|
||||
*/
|
||||
u32 main_pool_pop_state(u32 arg) {
|
||||
struct MainPoolState *node;
|
||||
struct MainPoolBlock *argptr;
|
||||
void *listHeadL;
|
||||
void *listHeadR;
|
||||
struct MainPoolState *state;
|
||||
|
||||
argptr = (u32)arg;
|
||||
osRecvMesg(&sMemPool.queue, NULL, OS_MESG_BLOCK);
|
||||
|
||||
do {
|
||||
node = sMemPool.mainState;
|
||||
listHeadL = node->listHeadL;
|
||||
listHeadR = node->listHeadR;
|
||||
sMemPool.available = node->freeSpace;
|
||||
sMemPool.mainState = node->prev;
|
||||
|
||||
// was the argument passed in 0?
|
||||
if (argptr == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// odd reuse of the variable, but what this is doing is backing the ptr up to the
|
||||
// pool block. Thus, to check the arg variable on the pool block located before the state,
|
||||
// we will need to cast the next if check.
|
||||
node = (void*)((u8*)node - sizeof(struct MainPoolState));
|
||||
|
||||
if ((uintptr_t)argptr == (uintptr_t)((struct MainPoolBlock *)node)->arg) {
|
||||
// we found the block with the matching string! break.
|
||||
break;
|
||||
}
|
||||
} while(sMemPool.mainState != NULL);
|
||||
|
||||
argptr = sMemPool.listHeadR;
|
||||
while ((uintptr_t)listHeadR > (uintptr_t)argptr) {
|
||||
if (argptr->func != NULL) {
|
||||
argptr->func(argptr + 1, argptr->arg);
|
||||
}
|
||||
argptr = argptr->next;
|
||||
}
|
||||
|
||||
argptr = sMemPool.listHeadL->prev;
|
||||
while ((uintptr_t)listHeadL <= (uintptr_t)argptr) {
|
||||
if (argptr->func != NULL) {
|
||||
argptr->func(argptr + 1, argptr->arg);
|
||||
}
|
||||
argptr = argptr->prev;
|
||||
}
|
||||
|
||||
sMemPool.listHeadL = listHeadL;
|
||||
sMemPool.listHeadR = listHeadR;
|
||||
osSendMesg(&sMemPool.queue, NULL, OS_MESG_NOBLOCK);
|
||||
return main_pool_get_available();
|
||||
}
|
||||
|
||||
/*
|
||||
* Unused function. Seems at first glance to check for an address within some
|
||||
* range, and then return the pointer to its data after the block. Perhaps?
|
||||
* Without this being called, its hard to tell the correct context of this
|
||||
* function.
|
||||
*/
|
||||
void *main_pool_search(uintptr_t addr, s32 *argPtr) {
|
||||
struct MainPoolBlock *node;
|
||||
struct MainPoolBlock *otherNode;
|
||||
|
||||
node = sMemPool.listHeadL->prev;
|
||||
while (node != NULL) {
|
||||
int isAddrLater = (addr >= ((uintptr_t) ((u8*)node + sizeof(struct MainPoolBlock))));
|
||||
otherNode = node->next;
|
||||
// seems to be checking for an addr within a block region? Since this function
|
||||
// is unused, we wont be able to check for the intended context of what could
|
||||
// call this function.
|
||||
if (isAddrLater && addr < ((uintptr_t)otherNode & 0xFFFFFFFF)) {
|
||||
if (argPtr != NULL) {
|
||||
*argPtr = node->arg;
|
||||
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;
|
||||
}
|
||||
// return the pointer to its block contents.
|
||||
return (void*)((u8*)(node) + sizeof(struct MainPoolBlock));
|
||||
}
|
||||
node = node->prev;
|
||||
}
|
||||
|
||||
// we've searched thr prev linked list. Now lets go through the next linked list.
|
||||
node = sMemPool.listHeadR;
|
||||
otherNode = node->next;
|
||||
while (otherNode != NULL) {
|
||||
int isAddrLater = (addr >= ((uintptr_t) ((u8*)node + sizeof(struct MainPoolBlock))));
|
||||
struct MainPoolBlock *new_var = otherNode; // bit of a fakematch to force the move reload.
|
||||
// same as above.
|
||||
if (isAddrLater && (addr < ((uintptr_t)new_var & 0xFFFFFFFF))) {
|
||||
if (argPtr != NULL) {
|
||||
*argPtr = node->arg;
|
||||
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;
|
||||
}
|
||||
// return the pointer to its block contents.
|
||||
return (void*)((u8*)(node) + sizeof(struct MainPoolBlock));
|
||||
}
|
||||
otherNode = (node = otherNode)->next;
|
||||
osSendMesg(&pool->queue, NULL, 0);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the block function and its argument(s) for a given block.
|
||||
*/
|
||||
void main_pool_set_func(void *block, s32 arg, void *func) {
|
||||
struct MainPoolBlock *node = (void*)((uintptr_t)block - sizeof(struct MainPoolBlock));
|
||||
node->func = func;
|
||||
node->arg = arg;
|
||||
void *func_80002D10(u32 size, s32 side) {
|
||||
struct MainPoolBlock* block;
|
||||
void *ptr = NULL;
|
||||
|
||||
size = ALIGN4(size);
|
||||
ptr = 0;
|
||||
block = main_pool_alloc_node_no_func(size, side);
|
||||
if (block != NULL) {
|
||||
ptr = func_80002DA4(block, size);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance offset from the block's state listHeadL pointer to the current block.
|
||||
*/
|
||||
uintptr_t main_pool_get_block_dist(struct MainPoolBlock *block) {
|
||||
struct MainPoolState *state = ((u8*)block - sizeof(struct MainPoolBlock));
|
||||
void func_80002D60(struct MemoryBlock* block) {
|
||||
s32 size = ALIGN16(block->size + 0x10);
|
||||
|
||||
return (uintptr_t)state->listHeadL - (uintptr_t)block;
|
||||
main_pool_realloc(block, size);
|
||||
block->next = (void*)(size - 0x10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the pointer to the static memory pool area.
|
||||
*/
|
||||
struct MainPool *main_pool_get_pool(void) {
|
||||
return &sMemPool;
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
41
src/memory.h
41
src/memory.h
|
|
@ -8,8 +8,9 @@
|
|||
#define MEMORY_POOL_LEFT 0
|
||||
#define MEMORY_POOL_RIGHT 1
|
||||
|
||||
// structs for the main pool.
|
||||
struct MainPoolState {
|
||||
/* 0x00 */ u32 freeSpace;
|
||||
/* 0x00 */ s32 freeSpace;
|
||||
/* 0x04 */ struct MainPoolBlock *listHeadL;
|
||||
/* 0x08 */ struct MainPoolBlock *listHeadR;
|
||||
/* 0x0C */ struct MainPoolState *prev;
|
||||
|
|
@ -33,20 +34,46 @@ struct MainPool {
|
|||
/* 0x30 */ struct MainPoolState *mainState;
|
||||
};
|
||||
|
||||
// functions
|
||||
// structs used for the smaller pools allocated from the global pool.
|
||||
struct MemoryBlock {
|
||||
/* 0x00 */ struct MemoryBlock *next;
|
||||
/* 0x04 */ u32 size;
|
||||
};
|
||||
|
||||
struct MemoryPool {
|
||||
/* 0x00 */ OSMesg msgs[1];
|
||||
/* 0x04 */ OSMesgQueue queue;
|
||||
/* 0x1C */ size_t available;
|
||||
/* 0x20 */ struct MemoryBlock *firstBlock;
|
||||
/* 0x24 */ struct MemoryBlock freeList;
|
||||
};
|
||||
|
||||
void main_pool_init(void *start, void *end);
|
||||
struct MainPoolBlock *main_pool_alloc(u32 size, u32 side);
|
||||
void *main_pool_alloc(u32 size, u32 side);
|
||||
u32 main_pool_free(void *addr, u32 runBlockFunc);
|
||||
struct MainPoolBlock *main_pool_alloc_node(u32 size, s32 side, s32 arg, void *func);
|
||||
struct MainPoolBlock *main_pool_alloc_node_no_func(u32 size, s32 side);
|
||||
void *main_pool_alloc_node(u32 size, s32 side, s32 arg, void *func);
|
||||
void *main_pool_alloc_node_no_func(u32 size, s32 side);
|
||||
u32 main_pool_try_free(struct MainPoolBlock *addr);
|
||||
struct MainPoolBlock *main_pool_realloc(void *addr, size_t size);
|
||||
void *main_pool_realloc(void *addr, size_t size);
|
||||
u32 main_pool_get_available(void);
|
||||
u32 main_pool_push_state(u32 arg);
|
||||
u32 main_pool_pop_state(u32 arg);
|
||||
void *main_pool_search(uintptr_t addr, s32 *argPtr);
|
||||
void main_pool_set_func(void *block, s32 arg, void *func);
|
||||
uintptr_t main_pool_get_block_dist(struct MainPoolBlock *block);
|
||||
size_t main_pool_get_block_dist(struct MainPoolBlock *block);
|
||||
struct MainPool *main_pool_get_pool(void);
|
||||
|
||||
// 3640.s
|
||||
struct MemoryPool *mem_pool_try_init(u32 size, s32 side);
|
||||
struct MainPool* mem_pool_init(struct MainPool *pool, s32 size);
|
||||
void *mem_pool_alloc(struct MainPool *node, s32 size);
|
||||
|
||||
void mem_pool_free(struct MemoryPool* pool, void* addr);
|
||||
void *func_80002D10(u32 size, s32 side);
|
||||
void func_80002D60(struct MemoryBlock* block);
|
||||
void* func_80002DA4(struct MainPoolState* block, s32 size);
|
||||
s32 func_80002DCC(struct MainPoolState* state, s32 arg1, s32 arg2);
|
||||
void func_80002E3C(struct MainPoolState* state, s32 size);
|
||||
void func_80002E64(struct MainPoolState* state);
|
||||
|
||||
#endif /* _MEMORY_H_ */
|
||||
|
|
|
|||
373
src/memory_main.c
Normal file
373
src/memory_main.c
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
#include <ultra64.h>
|
||||
#include <macros.h>
|
||||
#include "memory.h"
|
||||
|
||||
static struct MainPool sMemPool;
|
||||
|
||||
/**
|
||||
* Initialize the main memory pool. This pool is conceptually a pair of stacks
|
||||
* that grow inward from the left and right. It therefore only supports
|
||||
* freeing the object that was most recently allocated from a side.
|
||||
*/
|
||||
void main_pool_init(void *start, void *end) {
|
||||
sMemPool.start = (void *)(ALIGN16((uintptr_t)start) + 16);
|
||||
sMemPool.end = (void *)(ALIGN16((uintptr_t)end - 15) - 16);
|
||||
sMemPool.available = (uintptr_t)sMemPool.end - (uintptr_t)sMemPool.start;
|
||||
sMemPool.mainState = NULL;
|
||||
|
||||
sMemPool.listHeadL = ((u8*)sMemPool.start - sizeof(struct MainPoolBlock));
|
||||
sMemPool.listHeadL->prev = NULL;
|
||||
sMemPool.listHeadL->next = NULL;
|
||||
sMemPool.listHeadL->func = NULL;
|
||||
sMemPool.listHeadL->arg = 0;
|
||||
|
||||
sMemPool.listHeadR = sMemPool.end;
|
||||
sMemPool.listHeadR->prev = NULL;
|
||||
sMemPool.listHeadR->next = NULL;
|
||||
sMemPool.listHeadL->func = NULL;
|
||||
sMemPool.listHeadL->arg = 0;
|
||||
|
||||
osCreateMesgQueue(&sMemPool.queue, sMemPool.msgs, ARRAY_COUNT(sMemPool.msgs));
|
||||
osSendMesg(&sMemPool.queue, NULL, OS_MESG_NOBLOCK);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void *main_pool_alloc(u32 size, u32 side) {
|
||||
struct MainPoolBlock *newListHead;
|
||||
void *addr = NULL;
|
||||
|
||||
size = ALIGN16(size) + sizeof(struct MainPoolBlock);
|
||||
if (size != 0 && sMemPool.available >= size) {
|
||||
if (side == MEMORY_POOL_LEFT) {
|
||||
sMemPool.available -= size;
|
||||
newListHead = (void *)((uintptr_t)sMemPool.listHeadL + size);
|
||||
sMemPool.listHeadL->next = newListHead;
|
||||
newListHead->prev = sMemPool.listHeadL;
|
||||
newListHead->next = NULL;
|
||||
newListHead->func = 0;
|
||||
newListHead->arg = 0;
|
||||
addr = ((u8*)sMemPool.listHeadL + sizeof(struct MainPoolBlock));
|
||||
sMemPool.listHeadL = newListHead;
|
||||
} else if (side == MEMORY_POOL_RIGHT) {
|
||||
sMemPool.available -= size;
|
||||
newListHead = (void *)((uintptr_t)sMemPool.listHeadR - size);
|
||||
sMemPool.listHeadR->prev = newListHead;
|
||||
newListHead->next = sMemPool.listHeadR;
|
||||
newListHead->prev = NULL;
|
||||
newListHead->func = 0;
|
||||
newListHead->arg = 0;
|
||||
sMemPool.listHeadR = newListHead;
|
||||
addr = ((u8*)newListHead + sizeof(struct MainPoolBlock));
|
||||
}
|
||||
}
|
||||
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.
|
||||
*/
|
||||
u32 main_pool_free(void *addr, u32 runBlockFunc) {
|
||||
struct MainPoolBlock *block = (struct MainPoolBlock *)((u8 *)addr - sizeof(struct MainPoolBlock));
|
||||
struct MainPoolBlock *oldListHead = (struct MainPoolBlock *)((u8 *)addr - sizeof(struct MainPoolBlock));
|
||||
|
||||
if (oldListHead < sMemPool.listHeadL) {
|
||||
do {
|
||||
block = (sMemPool.listHeadL = sMemPool.listHeadL->prev);
|
||||
if (runBlockFunc) {
|
||||
// TODO: Fakematch
|
||||
void (*func)(struct MainPoolBlock *, u32) = block->func;
|
||||
if (func != 0) {
|
||||
block->func(block + 1, block->arg);
|
||||
// TODO: fake here too
|
||||
if ((!(&sMemPool)) && (!(&sMemPool)))
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
sMemPool.available += ((uintptr_t)sMemPool.listHeadL->next - (uintptr_t)sMemPool.listHeadL);
|
||||
sMemPool.listHeadL->next = NULL;
|
||||
} while (oldListHead != sMemPool.listHeadL);
|
||||
} else {
|
||||
block = sMemPool.listHeadR;
|
||||
if (oldListHead >= block && oldListHead >= block) {
|
||||
do {
|
||||
if (runBlockFunc) {
|
||||
void (*func)(struct MainPoolBlock *, u32) = block->func;
|
||||
if (func != NULL) {
|
||||
func(block + 1, block->arg);
|
||||
block = sMemPool.listHeadR;
|
||||
}
|
||||
}
|
||||
block = (sMemPool.listHeadR = block->next);
|
||||
sMemPool.available += ((uintptr_t)block - (uintptr_t)block->prev);
|
||||
block->prev = NULL;
|
||||
block = sMemPool.listHeadR;
|
||||
} while (oldListHead >= sMemPool.listHeadR);
|
||||
}
|
||||
}
|
||||
|
||||
return main_pool_get_available();
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually allocate and initialize a block given a size and side and its
|
||||
* function+arguments.
|
||||
*/
|
||||
void *main_pool_alloc_node(u32 size, s32 side, s32 arg, void *func) {
|
||||
struct MainPoolBlock *node;
|
||||
|
||||
osRecvMesg(&sMemPool.queue, NULL, OS_MESG_BLOCK);
|
||||
node = main_pool_alloc(size, side);
|
||||
if (node != NULL) {
|
||||
main_pool_set_func(node, arg, func);
|
||||
}
|
||||
osSendMesg(&sMemPool.queue, NULL, OS_MESG_NOBLOCK);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as above but no function/argument is set.
|
||||
*/
|
||||
void *main_pool_alloc_node_no_func(u32 size, s32 side) {
|
||||
struct MainPoolBlock *node;
|
||||
|
||||
osRecvMesg(&sMemPool.queue, NULL, OS_MESG_BLOCK);
|
||||
node = main_pool_alloc(size, side);
|
||||
osSendMesg(&sMemPool.queue, NULL, OS_MESG_NOBLOCK);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to free a block of memory that was allocated from the pool. Return
|
||||
* the new available amount of the pool.
|
||||
*/
|
||||
u32 main_pool_try_free(struct MainPoolBlock *addr) {
|
||||
if (addr != NULL) {
|
||||
osRecvMesg(&sMemPool.queue, NULL, OS_MESG_BLOCK);
|
||||
main_pool_free(addr, 1);
|
||||
osSendMesg(&sMemPool.queue, NULL, OS_MESG_NOBLOCK);
|
||||
}
|
||||
|
||||
return main_pool_get_available();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize a block of memory that was allocated from the left side of the pool.
|
||||
* If the block is increasing in size, it must be the most recently allocated
|
||||
* block from the left side.
|
||||
* The block does not move.
|
||||
*/
|
||||
void *main_pool_realloc(void *addr, size_t size) {
|
||||
struct MainPoolBlock *prior = (struct MainPoolBlock *)((u8 *)addr - sizeof(struct MainPoolBlock));
|
||||
void *newaddr = NULL;
|
||||
|
||||
osRecvMesg(&sMemPool.queue, NULL, OS_MESG_BLOCK);
|
||||
|
||||
if (prior->next == sMemPool.listHeadL) {
|
||||
size_t diff = ((uintptr_t)prior->next - (uintptr_t)addr);
|
||||
size = ALIGN16(size);
|
||||
if (diff >= size || sMemPool.available >= (size - diff)) {
|
||||
s32 arg = prior->arg;
|
||||
void *func = prior->func;
|
||||
main_pool_free(addr, 0);
|
||||
newaddr = main_pool_alloc(size, MEMORY_POOL_LEFT);
|
||||
main_pool_set_func(newaddr, arg, func);
|
||||
}
|
||||
}
|
||||
osSendMesg(&sMemPool.queue, NULL, OS_MESG_NOBLOCK);
|
||||
return newaddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the amount of available memory to use in the pool.
|
||||
*/
|
||||
u32 main_pool_get_available(void) {
|
||||
s32 available = sMemPool.available - sizeof(struct MainPoolBlock);
|
||||
|
||||
if (available < 0) {
|
||||
available = 0;
|
||||
}
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push pool state, to be restored later. Return the amount of free space left
|
||||
* in the pool.
|
||||
*/
|
||||
u32 main_pool_push_state(u32 arg) {
|
||||
struct MainPoolState *state;
|
||||
struct MainPoolBlock *listHeadL;
|
||||
struct MainPoolBlock *listHeadR;
|
||||
uintptr_t available;
|
||||
|
||||
osRecvMesg(&sMemPool.queue, NULL, OS_MESG_BLOCK);
|
||||
|
||||
// retrieve the space and head pointers.
|
||||
available = sMemPool.available;
|
||||
listHeadL = sMemPool.listHeadL;
|
||||
listHeadR = sMemPool.listHeadR;
|
||||
|
||||
state = main_pool_alloc(sizeof(struct MainPoolState), MEMORY_POOL_LEFT);
|
||||
if (state != NULL) {
|
||||
/**
|
||||
* Why is this line here? What this line is doing is backing the pointer up to the
|
||||
* previous block before this one. in the block alloc function, addr is determined
|
||||
* by the head plus the size of the block struct, meaning it is returning the
|
||||
* pointer to the head.
|
||||
*/
|
||||
((struct MainPoolBlock *)((u8*)state-sizeof(struct MainPoolBlock)))->arg = arg;
|
||||
|
||||
// now that the previous block's argument is set, set the newly allocated state's
|
||||
// fields.
|
||||
state->prev = sMemPool.mainState;
|
||||
state->freeSpace = available;
|
||||
state->listHeadL = listHeadL;
|
||||
state->listHeadR = listHeadR;
|
||||
|
||||
// add the newly allocated state.
|
||||
sMemPool.mainState = state;
|
||||
}
|
||||
osSendMesg(&sMemPool.queue, NULL, OS_MESG_NOBLOCK);
|
||||
return main_pool_get_available();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore pool state from a previous call to main_pool_push_state. Return the
|
||||
* amount of free space left in the pool.
|
||||
*/
|
||||
u32 main_pool_pop_state(u32 arg) {
|
||||
struct MainPoolState *node;
|
||||
struct MainPoolBlock *argptr;
|
||||
void *listHeadL;
|
||||
void *listHeadR;
|
||||
struct MainPoolState *state;
|
||||
|
||||
argptr = (u32)arg;
|
||||
osRecvMesg(&sMemPool.queue, NULL, OS_MESG_BLOCK);
|
||||
|
||||
do {
|
||||
node = sMemPool.mainState;
|
||||
listHeadL = node->listHeadL;
|
||||
listHeadR = node->listHeadR;
|
||||
sMemPool.available = node->freeSpace;
|
||||
sMemPool.mainState = node->prev;
|
||||
|
||||
// was the argument passed in 0?
|
||||
if (argptr == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// odd reuse of the variable, but what this is doing is backing the ptr up to the
|
||||
// pool block. Thus, to check the arg variable on the pool block located before the state,
|
||||
// we will need to cast the next if check.
|
||||
node = (void*)((u8*)node - sizeof(struct MainPoolState));
|
||||
|
||||
if ((uintptr_t)argptr == (uintptr_t)((struct MainPoolBlock *)node)->arg) {
|
||||
// we found the block with the matching string! break.
|
||||
break;
|
||||
}
|
||||
} while(sMemPool.mainState != NULL);
|
||||
|
||||
argptr = sMemPool.listHeadR;
|
||||
while ((uintptr_t)listHeadR > (uintptr_t)argptr) {
|
||||
if (argptr->func != NULL) {
|
||||
argptr->func(argptr + 1, argptr->arg);
|
||||
}
|
||||
argptr = argptr->next;
|
||||
}
|
||||
|
||||
argptr = sMemPool.listHeadL->prev;
|
||||
while ((uintptr_t)listHeadL <= (uintptr_t)argptr) {
|
||||
if (argptr->func != NULL) {
|
||||
argptr->func(argptr + 1, argptr->arg);
|
||||
}
|
||||
argptr = argptr->prev;
|
||||
}
|
||||
|
||||
sMemPool.listHeadL = listHeadL;
|
||||
sMemPool.listHeadR = listHeadR;
|
||||
osSendMesg(&sMemPool.queue, NULL, OS_MESG_NOBLOCK);
|
||||
return main_pool_get_available();
|
||||
}
|
||||
|
||||
/*
|
||||
* Unused function. Seems at first glance to check for an address within some
|
||||
* range, and then return the pointer to its data after the block. Perhaps?
|
||||
* Without this being called, its hard to tell the correct context of this
|
||||
* function.
|
||||
*/
|
||||
void *main_pool_search(uintptr_t addr, s32 *argPtr) {
|
||||
struct MainPoolBlock *node;
|
||||
struct MainPoolBlock *otherNode;
|
||||
|
||||
node = sMemPool.listHeadL->prev;
|
||||
while (node != NULL) {
|
||||
int isAddrLater = (addr >= ((uintptr_t) ((u8*)node + sizeof(struct MainPoolBlock))));
|
||||
otherNode = node->next;
|
||||
// seems to be checking for an addr within a block region? Since this function
|
||||
// is unused, we wont be able to check for the intended context of what could
|
||||
// call this function.
|
||||
if (isAddrLater && addr < ((uintptr_t)otherNode & 0xFFFFFFFF)) {
|
||||
if (argPtr != NULL) {
|
||||
*argPtr = node->arg;
|
||||
}
|
||||
// return the pointer to its block contents.
|
||||
return (void*)((u8*)(node) + sizeof(struct MainPoolBlock));
|
||||
}
|
||||
node = node->prev;
|
||||
}
|
||||
|
||||
// we've searched thr prev linked list. Now lets go through the next linked list.
|
||||
node = sMemPool.listHeadR;
|
||||
otherNode = node->next;
|
||||
while (otherNode != NULL) {
|
||||
int isAddrLater = (addr >= ((uintptr_t) ((u8*)node + sizeof(struct MainPoolBlock))));
|
||||
struct MainPoolBlock *new_var = otherNode; // bit of a fakematch to force the move reload.
|
||||
// same as above.
|
||||
if (isAddrLater && (addr < ((uintptr_t)new_var & 0xFFFFFFFF))) {
|
||||
if (argPtr != NULL) {
|
||||
*argPtr = node->arg;
|
||||
}
|
||||
// return the pointer to its block contents.
|
||||
return (void*)((u8*)(node) + sizeof(struct MainPoolBlock));
|
||||
}
|
||||
otherNode = (node = otherNode)->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the block function and its argument(s) for a given block.
|
||||
*/
|
||||
void main_pool_set_func(void *block, s32 arg, void *func) {
|
||||
struct MainPoolBlock *node = (void*)((uintptr_t)block - sizeof(struct MainPoolBlock));
|
||||
node->func = func;
|
||||
node->arg = arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance offset from the block's state listHeadL pointer to the current block.
|
||||
*/
|
||||
size_t main_pool_get_block_dist(struct MainPoolBlock *block) {
|
||||
struct MainPoolState *state = ((u8*)block - sizeof(struct MainPoolBlock));
|
||||
|
||||
return (size_t)((uintptr_t)state->listHeadL - (uintptr_t)block);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the pointer to the static memory pool area.
|
||||
*/
|
||||
struct MainPool *main_pool_get_pool(void) {
|
||||
return &sMemPool;
|
||||
}
|
||||
|
|
@ -582,4 +582,11 @@ main_pool_push_state = 0x80002784;
|
|||
main_pool_pop_state = 0x80002838;
|
||||
main_pool_get_pool = 0x80002A30;
|
||||
main_pool_get_block_dist = 0x80002A24;
|
||||
main_pool_search = 0x80002960;
|
||||
main_pool_search = 0x80002960;
|
||||
text_bss_VRAM = 0x8007ED80;
|
||||
gHeap = 0x80104BB0;
|
||||
gMainPool = 0x800A60B0;
|
||||
mem_pool_try_init = 0x80002A40;
|
||||
mem_pool_init = 0x80002A88;
|
||||
mem_pool_alloc = 0x80002AF8;
|
||||
mem_pool_free = 0x80002BD0;
|
||||
Loading…
Reference in New Issue
Block a user