mirror of
https://gitlab.com/ryandwyer/perfect-dark
synced 2026-06-09 04:29:29 -04:00
748 lines
21 KiB
C
748 lines
21 KiB
C
#include <ultra64.h>
|
|
#include "constants.h"
|
|
#include "bss.h"
|
|
#include "lib/debughud.h"
|
|
#include "lib/mema.h"
|
|
#include "lib/memp.h"
|
|
#include "data.h"
|
|
#include "types.h"
|
|
|
|
/**
|
|
* mema - memory (ad hoc) allocation system.
|
|
*
|
|
* Mema's heap is 300KB and is itself allocated out of memp's stage pool.
|
|
* Memp resets its stage pool each time a new stage is loaded, which means mema
|
|
* is also reset each time a stage is loaded.
|
|
*
|
|
* Unlike memp, mema supports freeing of individual allocations. This makes it
|
|
* a good system to use when the allocation is somewhat temporary and should be
|
|
* freed without having to load a new stage. It's used by the (inaccessible)
|
|
* Perfect Head editor, file listings and room code.
|
|
*
|
|
* Mema tracks what has been allocated by storing references to free spaces in
|
|
* its spaces array. The allocations themselves are not referenced. When
|
|
* initialising the spaces array, the first element is set to the entire heap
|
|
* and the remaining elements are set to 0.
|
|
*
|
|
* This creates a bit of a terminology problem. Just remember that a memaspace
|
|
* is not an allocation; it's a free space that is available for allocation.
|
|
*
|
|
* Due to the ability to free individual allocations, both the heap and the
|
|
* spaces array can become fragmented. Mema supports defragmenting the spaces
|
|
* array: entries are ordered by address, and back to back entries are merged.
|
|
* The data in the heap itself is never moved, as that would require updating
|
|
* pointers throughout the game code which mema cannot do.
|
|
*/
|
|
|
|
#define MAX_SPACES 124
|
|
|
|
struct memaspace {
|
|
s32 addr;
|
|
u32 size;
|
|
};
|
|
|
|
/**
|
|
* This structure contains dummy entries before and after the spaces array.
|
|
* These are used as start and end markers, but could have been avoided by
|
|
* using loop counters (eg. a typical i < numspaces loop).
|
|
*/
|
|
struct memaheap {
|
|
u32 unk000;
|
|
struct memaspace start;
|
|
struct memaspace spaces[MAX_SPACES];
|
|
struct memaspace end1;
|
|
struct memaspace end2;
|
|
};
|
|
|
|
s32 g_MemaHeapStart;
|
|
s32 g_MemaHeapSize;
|
|
struct memaheap g_MemaHeap;
|
|
|
|
void memaSwap(struct memaspace *a, struct memaspace *b)
|
|
{
|
|
u32 tempaddr = a->addr;
|
|
u32 tempsize = a->size;
|
|
a->addr = b->addr;
|
|
a->size = b->size;
|
|
b->addr = tempaddr;
|
|
b->size = tempsize;
|
|
}
|
|
|
|
void memaMerge(struct memaspace *a, struct memaspace *b)
|
|
{
|
|
a->size += b->size;
|
|
b->addr = 0;
|
|
b->size = 0;
|
|
}
|
|
|
|
bool memaDefragPass(struct memaheap *heap)
|
|
{
|
|
bool merged = false;
|
|
struct memaspace *prev = &heap->start;
|
|
struct memaspace *curr = &heap->spaces[0];
|
|
struct memaspace *last = &heap->spaces[MAX_SPACES - 1];
|
|
u32 addr = 0;
|
|
|
|
while (curr <= last) {
|
|
if (curr->size != 0) {
|
|
if (curr->addr < addr) {
|
|
memaSwap(curr, prev);
|
|
}
|
|
|
|
if (prev->size + addr == curr->addr) {
|
|
memaMerge(prev, curr);
|
|
curr = prev;
|
|
merged = true;
|
|
}
|
|
|
|
prev = curr;
|
|
addr = curr->addr;
|
|
}
|
|
|
|
curr++;
|
|
}
|
|
|
|
return merged;
|
|
}
|
|
|
|
void memaDefrag(void)
|
|
{
|
|
while (memaDefragPass(&g_MemaHeap));
|
|
}
|
|
|
|
/**
|
|
* Defrag the spaces list in an attempt to free up any slot.
|
|
*
|
|
* If none can be found, return the smallest run of free space so it can be
|
|
* overwritten by the caller.
|
|
*/
|
|
struct memaspace *memaMakeSlot(struct memaheap *heap)
|
|
{
|
|
struct memaspace *curr = &heap->spaces[0];
|
|
struct memaspace *best;
|
|
u32 min;
|
|
s32 i;
|
|
|
|
// Do 124 passes over the list. This ensures the list is in order by the
|
|
// end. Though in most cases it's roughly in order anyway, and the excessive
|
|
// looping is just wasting CPU cycles. In reality this situation probably
|
|
// never occurs.
|
|
for (i = 0; i < MAX_SPACES; i++) {
|
|
while (curr <= &heap->spaces[MAX_SPACES - 1]) {
|
|
if (curr->size == 0) {
|
|
return curr;
|
|
}
|
|
|
|
if ((u32)curr[1].addr < (u32)curr[0].addr) {
|
|
memaSwap(&curr[0], &curr[1]);
|
|
}
|
|
|
|
if (curr[1].addr == curr[0].size + curr[0].addr) {
|
|
// Found two that can be merged
|
|
curr[0].size += curr[1].size;
|
|
curr[1].addr = 0;
|
|
curr[1].size = 0;
|
|
|
|
return &curr[1];
|
|
}
|
|
|
|
curr++;
|
|
}
|
|
|
|
curr = &heap->spaces[0];
|
|
}
|
|
|
|
// If this code is reached then the spaces list is so badly and unrepairably
|
|
// fragmented that we can't find any slot to record the free space in.
|
|
// Find the smallest run of free space and use that instead.
|
|
// The caller will overwrite it with its own free allocation, causing the
|
|
// original run of free space to be unusable until the mema heap is reset.
|
|
min = 0xffffffff;
|
|
best = curr;
|
|
|
|
while (curr <= &heap->spaces[MAX_SPACES - 1]) {
|
|
if (curr->size < min) {
|
|
best = curr;
|
|
min = curr->size;
|
|
}
|
|
|
|
curr++;
|
|
}
|
|
|
|
return best;
|
|
}
|
|
|
|
void _memaFree(s32 addr, s32 size)
|
|
{
|
|
// Choose an index in the spaces array which we'll mark a space as free,
|
|
// based on how far into the heap the allocation is. This is a rough
|
|
// estimate and doesn't need to be any particular index, but the defrag
|
|
// function tries to order the spaces by address so the closer we get to it
|
|
// the less work the defrag function will have to do should it be called.
|
|
s32 index = (addr - g_MemaHeapStart) * MAX_SPACES / g_MemaHeapSize;
|
|
struct memaspace *curr = &g_MemaHeap.spaces[index];
|
|
|
|
// If the entry is taken, keep moving forward until a zero is found.
|
|
while (curr->size != 0) {
|
|
curr++;
|
|
}
|
|
|
|
// If we reached the end of the spaces list, go backwards instead
|
|
if (curr->addr == -1) {
|
|
curr = &g_MemaHeap.spaces[index];
|
|
|
|
while (curr->size != 0) {
|
|
curr--;
|
|
}
|
|
|
|
if (curr->addr == 0) {
|
|
curr = memaMakeSlot(&g_MemaHeap);
|
|
}
|
|
}
|
|
|
|
// Mark this space as free
|
|
curr->addr = addr;
|
|
curr->size = size;
|
|
}
|
|
|
|
void memaInit(void)
|
|
{
|
|
// empty
|
|
}
|
|
|
|
void memaHeapInit(void *heapaddr, u32 heapsize)
|
|
{
|
|
struct memaspace *space;
|
|
|
|
#if VERSION >= VERSION_NTSC_1_0
|
|
// Adding an amount to the heap size here means that mema can allocate past
|
|
// the end of its heap. This would overflow into the gun names language
|
|
// file. Maybe this code was intended to be temporary while a developer
|
|
// figured out how much memory was needed, but they forgot to remove it?
|
|
// @dangerous
|
|
heapsize += 0x8e0;
|
|
#endif
|
|
|
|
g_MemaHeap.unk000 = 0;
|
|
|
|
g_MemaHeap.start.addr = 0;
|
|
g_MemaHeap.start.size = 0;
|
|
|
|
g_MemaHeap.end1.addr = 0xffffffff;
|
|
g_MemaHeap.end1.size = 0;
|
|
g_MemaHeap.end2.addr = 0xffffffff;
|
|
g_MemaHeap.end2.size = 0xffffffff;
|
|
|
|
for (space = &g_MemaHeap.spaces[0]; space <= &g_MemaHeap.spaces[MAX_SPACES - 1]; space++) {
|
|
space->addr = 0;
|
|
space->size = 0;
|
|
}
|
|
|
|
g_MemaHeap.spaces[0].addr = g_MemaHeapStart = (u32)heapaddr;
|
|
g_MemaHeap.spaces[0].size = g_MemaHeapSize = heapsize;
|
|
}
|
|
|
|
/**
|
|
* Example printout of figures:
|
|
*
|
|
* Mem Info
|
|
* memp: MP_LF_LEV
|
|
* F: 0 722352
|
|
* S: 972080 3668704
|
|
* Over: 2946352
|
|
* memp: MP_LF_ETER
|
|
* F: 0 0
|
|
* S: 601728 0
|
|
* mema:
|
|
* LF: 391728
|
|
* Audio Free: 13184
|
|
*
|
|
* Where two figures are shown in one line, the left refers to onboard memory
|
|
* and the right refers to expansion pak memory.
|
|
*
|
|
* F means free.
|
|
* S means size.
|
|
*
|
|
* "Over" shows how much it's over 4MB, if they were to try to fit the game into
|
|
* onboard memory only. This shows "Free" if under 4MB.
|
|
*
|
|
* The ETER (permanent) pool has 0 free space because it's shrunk to fit once
|
|
* the permanent allocations are done during startup. This pool fits entirely
|
|
* in onboard memory, so the expansion size is 0.
|
|
*/
|
|
void memaPrint(void)
|
|
{
|
|
s32 onboard;
|
|
s32 expansion;
|
|
s32 line = 1;
|
|
s32 over;
|
|
char buffer[124];
|
|
|
|
memaDefragPass(&g_MemaHeap);
|
|
|
|
#if VERSION < VERSION_NTSC_1_0
|
|
if (debugIsMemInfoEnabled()) {
|
|
dhudSetFgColour(0xff, 0xff, 0xff, 0xff);
|
|
dhudSetBgColour(0, 0, 0, 0xff);
|
|
|
|
dhudSetPos(30, line);
|
|
dhudPrintString("Mem Info");
|
|
line++;
|
|
|
|
dhudSetPos(30, line);
|
|
dhudPrintString("memp: MP_LF_LEV");
|
|
line++;
|
|
|
|
onboard = mempGetPoolFree(MEMPOOL_STAGE, MEMBANK_ONBOARD);
|
|
expansion = mempGetPoolFree(MEMPOOL_STAGE, MEMBANK_EXPANSION);
|
|
sprintf(buffer, "F: %d %d", onboard, expansion);
|
|
dhudSetPos(31, line);
|
|
dhudPrintString(buffer);
|
|
line++;
|
|
|
|
onboard = mempGetPoolSize(MEMPOOL_STAGE, MEMBANK_ONBOARD);
|
|
expansion = mempGetPoolSize(MEMPOOL_STAGE, MEMBANK_EXPANSION);
|
|
sprintf(buffer, "S: %d %d", onboard, expansion);
|
|
dhudSetPos(31, line);
|
|
dhudPrintString(buffer);
|
|
line++;
|
|
|
|
over = mempGetPoolSize(MEMPOOL_STAGE, MEMBANK_EXPANSION)
|
|
- mempGetPoolFree(MEMPOOL_STAGE, MEMBANK_EXPANSION)
|
|
- mempGetPoolFree(MEMPOOL_STAGE, MEMBANK_ONBOARD);
|
|
|
|
if (over >= 0) {
|
|
sprintf(buffer, "Over: %d", over);
|
|
} else {
|
|
sprintf(buffer, "Free: %d", -over);
|
|
}
|
|
|
|
dhudSetPos(31, line);
|
|
dhudPrintString(buffer);
|
|
line++;
|
|
|
|
dhudSetPos(30, line);
|
|
dhudPrintString("memp: MP_LF_ETER");
|
|
line++;
|
|
|
|
onboard = mempGetPoolFree(MEMPOOL_PERMANENT, MEMBANK_ONBOARD);
|
|
expansion = mempGetPoolFree(MEMPOOL_PERMANENT, MEMBANK_EXPANSION);
|
|
sprintf(buffer, "F: %d %d", onboard, expansion);
|
|
dhudSetPos(31, line);
|
|
dhudPrintString(buffer);
|
|
line++;
|
|
|
|
onboard = mempGetPoolSize(MEMPOOL_PERMANENT, MEMBANK_ONBOARD);
|
|
expansion = mempGetPoolSize(MEMPOOL_PERMANENT, MEMBANK_EXPANSION);
|
|
sprintf(buffer, "S: %d %d", onboard, expansion);
|
|
dhudSetPos(31, line);
|
|
dhudPrintString(buffer);
|
|
line++;
|
|
|
|
dhudSetPos(30, line);
|
|
dhudPrintString("mema:");
|
|
line++;
|
|
|
|
sprintf(buffer, "LF: %d", memaGetLongestFree());
|
|
dhudSetPos(31, line);
|
|
dhudPrintString(buffer);
|
|
line++;
|
|
|
|
sprintf(buffer, "Audio Free: %d", g_SndHeap.base + (g_SndHeap.len - (u32)g_SndHeap.cur));
|
|
dhudSetPos(30, line);
|
|
dhudPrintString(buffer);
|
|
line++;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if VERSION >= VERSION_NTSC_1_0
|
|
GLOBAL_ASM(
|
|
glabel memaAlloc
|
|
/* 12ab0: 27bdffd0 */ addiu $sp,$sp,-48
|
|
/* 12ab4: afb2001c */ sw $s2,0x1c($sp)
|
|
/* 12ab8: afb10018 */ sw $s1,0x18($sp)
|
|
/* 12abc: 00809025 */ or $s2,$a0,$zero
|
|
/* 12ac0: afb50028 */ sw $s5,0x28($sp)
|
|
/* 12ac4: afb00014 */ sw $s0,0x14($sp)
|
|
/* 12ac8: 3c11800a */ lui $s1,%hi(g_MemaHeap+0xc)
|
|
/* 12acc: 3c078009 */ lui $a3,%hi(g_Is4Mb)
|
|
/* 12ad0: afbf002c */ sw $ra,0x2c($sp)
|
|
/* 12ad4: afb40024 */ sw $s4,0x24($sp)
|
|
/* 12ad8: afb30020 */ sw $s3,0x20($sp)
|
|
/* 12adc: 26319484 */ addiu $s1,$s1,%lo(g_MemaHeap+0xc)
|
|
/* 12ae0: 2404ffff */ addiu $a0,$zero,-1
|
|
/* 12ae4: 00004025 */ or $t0,$zero,$zero
|
|
/* 12ae8: 24e70af0 */ addiu $a3,$a3,%lo(g_Is4Mb)
|
|
/* 12aec: 00008025 */ or $s0,$zero,$zero
|
|
/* 12af0: 2415ffff */ addiu $s5,$zero,-1
|
|
/* 12af4: 24060001 */ addiu $a2,$zero,0x1
|
|
/* 12af8: 24050010 */ addiu $a1,$zero,0x10
|
|
.L00012afc:
|
|
/* 12afc: 8e230004 */ lw $v1,0x4($s1)
|
|
/* 12b00: 26100001 */ addiu $s0,$s0,0x1
|
|
/* 12b04: 0072082b */ sltu $at,$v1,$s2
|
|
/* 12b08: 14200011 */ bnez $at,.L00012b50
|
|
/* 12b0c: 00721023 */ subu $v0,$v1,$s2
|
|
/* 12b10: 8e2e0000 */ lw $t6,0x0($s1)
|
|
/* 12b14: 0044082b */ sltu $at,$v0,$a0
|
|
/* 12b18: 12ae000f */ beq $s5,$t6,.L00012b58
|
|
/* 12b1c: 00000000 */ nop
|
|
/* 12b20: 1020000b */ beqz $at,.L00012b50
|
|
/* 12b24: 2c410040 */ sltiu $at,$v0,0x40
|
|
/* 12b28: 00402025 */ or $a0,$v0,$zero
|
|
/* 12b2c: 1420000a */ bnez $at,.L00012b58
|
|
/* 12b30: 02204025 */ or $t0,$s1,$zero
|
|
/* 12b34: 90ef0000 */ lbu $t7,0x0($a3)
|
|
/* 12b38: 0012c082 */ srl $t8,$s2,0x2
|
|
/* 12b3c: 0058082b */ sltu $at,$v0,$t8
|
|
/* 12b40: 10cf0003 */ beq $a2,$t7,.L00012b50
|
|
/* 12b44: 00000000 */ nop
|
|
/* 12b48: 14200003 */ bnez $at,.L00012b58
|
|
/* 12b4c: 00000000 */ nop
|
|
.L00012b50:
|
|
/* 12b50: 1605ffea */ bne $s0,$a1,.L00012afc
|
|
/* 12b54: 26310008 */ addiu $s1,$s1,0x8
|
|
.L00012b58:
|
|
/* 12b58: 55000027 */ bnezl $t0,.L00012bf8
|
|
/* 12b5c: 8d030000 */ lw $v1,0x0($t0)
|
|
/* 12b60: 8e390004 */ lw $t9,0x4($s1)
|
|
/* 12b64: 00008025 */ or $s0,$zero,$zero
|
|
/* 12b68: 24140008 */ addiu $s4,$zero,0x8
|
|
/* 12b6c: 0332082b */ sltu $at,$t9,$s2
|
|
/* 12b70: 10200006 */ beqz $at,.L00012b8c
|
|
/* 12b74: 3c13800a */ lui $s3,%hi(g_MemaHeap)
|
|
/* 12b78: 8e29000c */ lw $t1,0xc($s1)
|
|
.L00012b7c:
|
|
/* 12b7c: 26310008 */ addiu $s1,$s1,0x8
|
|
/* 12b80: 0132082b */ sltu $at,$t1,$s2
|
|
/* 12b84: 5420fffd */ bnezl $at,.L00012b7c
|
|
/* 12b88: 8e29000c */ lw $t1,0xc($s1)
|
|
.L00012b8c:
|
|
/* 12b8c: 8e2a0000 */ lw $t2,0x0($s1)
|
|
/* 12b90: 26739478 */ addiu $s3,$s3,%lo(g_MemaHeap)
|
|
/* 12b94: 56aa0017 */ bnel $s5,$t2,.L00012bf4
|
|
/* 12b98: 02204025 */ or $t0,$s1,$zero
|
|
/* 12b9c: 3c11800a */ lui $s1,%hi(g_MemaHeap+0xc)
|
|
/* 12ba0: 26319484 */ addiu $s1,$s1,%lo(g_MemaHeap+0xc)
|
|
.L00012ba4:
|
|
/* 12ba4: 0c0049bc */ jal memaDefragPass
|
|
/* 12ba8: 02602025 */ or $a0,$s3,$zero
|
|
/* 12bac: 26100001 */ addiu $s0,$s0,0x1
|
|
/* 12bb0: 1614fffc */ bne $s0,$s4,.L00012ba4
|
|
/* 12bb4: 00000000 */ nop
|
|
/* 12bb8: 8e6b0010 */ lw $t3,0x10($s3)
|
|
/* 12bbc: 0172082b */ sltu $at,$t3,$s2
|
|
/* 12bc0: 50200007 */ beqzl $at,.L00012be0
|
|
/* 12bc4: 8e2d0000 */ lw $t5,0x0($s1)
|
|
/* 12bc8: 8e2c000c */ lw $t4,0xc($s1)
|
|
.L00012bcc:
|
|
/* 12bcc: 26310008 */ addiu $s1,$s1,0x8
|
|
/* 12bd0: 0192082b */ sltu $at,$t4,$s2
|
|
/* 12bd4: 5420fffd */ bnezl $at,.L00012bcc
|
|
/* 12bd8: 8e2c000c */ lw $t4,0xc($s1)
|
|
/* 12bdc: 8e2d0000 */ lw $t5,0x0($s1)
|
|
.L00012be0:
|
|
/* 12be0: 56ad0004 */ bnel $s5,$t5,.L00012bf4
|
|
/* 12be4: 02204025 */ or $t0,$s1,$zero
|
|
/* 12be8: 1000000b */ b .L00012c18
|
|
/* 12bec: 00001025 */ or $v0,$zero,$zero
|
|
/* 12bf0: 02204025 */ or $t0,$s1,$zero
|
|
.L00012bf4:
|
|
/* 12bf4: 8d030000 */ lw $v1,0x0($t0)
|
|
.L00012bf8:
|
|
/* 12bf8: 8d0f0004 */ lw $t7,0x4($t0)
|
|
/* 12bfc: 00727021 */ addu $t6,$v1,$s2
|
|
/* 12c00: 01f2c023 */ subu $t8,$t7,$s2
|
|
/* 12c04: ad0e0000 */ sw $t6,0x0($t0)
|
|
/* 12c08: 17000002 */ bnez $t8,.L00012c14
|
|
/* 12c0c: ad180004 */ sw $t8,0x4($t0)
|
|
/* 12c10: ad000000 */ sw $zero,0x0($t0)
|
|
.L00012c14:
|
|
/* 12c14: 00601025 */ or $v0,$v1,$zero
|
|
.L00012c18:
|
|
/* 12c18: 8fbf002c */ lw $ra,0x2c($sp)
|
|
/* 12c1c: 8fb00014 */ lw $s0,0x14($sp)
|
|
/* 12c20: 8fb10018 */ lw $s1,0x18($sp)
|
|
/* 12c24: 8fb2001c */ lw $s2,0x1c($sp)
|
|
/* 12c28: 8fb30020 */ lw $s3,0x20($sp)
|
|
/* 12c2c: 8fb40024 */ lw $s4,0x24($sp)
|
|
/* 12c30: 8fb50028 */ lw $s5,0x28($sp)
|
|
/* 12c34: 03e00008 */ jr $ra
|
|
/* 12c38: 27bd0030 */ addiu $sp,$sp,0x30
|
|
);
|
|
#else
|
|
GLOBAL_ASM(
|
|
glabel memaAlloc
|
|
/* 13324: 27bdffd0 */ addiu $sp,$sp,-48
|
|
/* 13328: afb2001c */ sw $s2,0x1c($sp)
|
|
/* 1332c: afb10018 */ sw $s1,0x18($sp)
|
|
/* 13330: 00809025 */ or $s2,$a0,$zero
|
|
/* 13334: afb50028 */ sw $s5,0x28($sp)
|
|
/* 13338: afb00014 */ sw $s0,0x14($sp)
|
|
/* 1333c: 3c11800a */ lui $s1,0x800a
|
|
/* 13340: afbf002c */ sw $ra,0x2c($sp)
|
|
/* 13344: afb40024 */ sw $s4,0x24($sp)
|
|
/* 13348: afb30020 */ sw $s3,0x20($sp)
|
|
/* 1334c: 2631c404 */ addiu $s1,$s1,-15356
|
|
/* 13350: 2404ffff */ addiu $a0,$zero,-1
|
|
/* 13354: 00002825 */ or $a1,$zero,$zero
|
|
/* 13358: 00008025 */ or $s0,$zero,$zero
|
|
/* 1335c: 2415ffff */ addiu $s5,$zero,-1
|
|
/* 13360: 24060010 */ addiu $a2,$zero,0x10
|
|
.NB00013364:
|
|
/* 13364: 8e230004 */ lw $v1,0x4($s1)
|
|
/* 13368: 26100001 */ addiu $s0,$s0,0x1
|
|
/* 1336c: 0072082b */ sltu $at,$v1,$s2
|
|
/* 13370: 1420000e */ bnez $at,.NB000133ac
|
|
/* 13374: 00721023 */ subu $v0,$v1,$s2
|
|
/* 13378: 8e2e0000 */ lw $t6,0x0($s1)
|
|
/* 1337c: 0044082b */ sltu $at,$v0,$a0
|
|
/* 13380: 00127882 */ srl $t7,$s2,0x2
|
|
/* 13384: 12ae000b */ beq $s5,$t6,.NB000133b4
|
|
/* 13388: 00000000 */ sll $zero,$zero,0x0
|
|
/* 1338c: 10200007 */ beqz $at,.NB000133ac
|
|
/* 13390: 2c410040 */ sltiu $at,$v0,0x40
|
|
/* 13394: 00402025 */ or $a0,$v0,$zero
|
|
/* 13398: 14200006 */ bnez $at,.NB000133b4
|
|
/* 1339c: 02202825 */ or $a1,$s1,$zero
|
|
/* 133a0: 004f082b */ sltu $at,$v0,$t7
|
|
/* 133a4: 14200003 */ bnez $at,.NB000133b4
|
|
/* 133a8: 00000000 */ sll $zero,$zero,0x0
|
|
.NB000133ac:
|
|
/* 133ac: 1606ffed */ bne $s0,$a2,.NB00013364
|
|
/* 133b0: 26310008 */ addiu $s1,$s1,0x8
|
|
.NB000133b4:
|
|
/* 133b4: 54a00027 */ bnezl $a1,.NB00013454
|
|
/* 133b8: 8ca30000 */ lw $v1,0x0($a1)
|
|
/* 133bc: 8e380004 */ lw $t8,0x4($s1)
|
|
/* 133c0: 00008025 */ or $s0,$zero,$zero
|
|
/* 133c4: 24140008 */ addiu $s4,$zero,0x8
|
|
/* 133c8: 0312082b */ sltu $at,$t8,$s2
|
|
/* 133cc: 10200006 */ beqz $at,.NB000133e8
|
|
/* 133d0: 3c13800a */ lui $s3,0x800a
|
|
/* 133d4: 8e39000c */ lw $t9,0xc($s1)
|
|
.NB000133d8:
|
|
/* 133d8: 26310008 */ addiu $s1,$s1,0x8
|
|
/* 133dc: 0332082b */ sltu $at,$t9,$s2
|
|
/* 133e0: 5420fffd */ bnezl $at,.NB000133d8
|
|
/* 133e4: 8e39000c */ lw $t9,0xc($s1)
|
|
.NB000133e8:
|
|
/* 133e8: 8e280000 */ lw $t0,0x0($s1)
|
|
/* 133ec: 2673c3f8 */ addiu $s3,$s3,-15368
|
|
/* 133f0: 56a80017 */ bnel $s5,$t0,.NB00013450
|
|
/* 133f4: 02202825 */ or $a1,$s1,$zero
|
|
/* 133f8: 3c11800a */ lui $s1,0x800a
|
|
/* 133fc: 2631c404 */ addiu $s1,$s1,-15356
|
|
.NB00013400:
|
|
/* 13400: 0c004b24 */ jal memaDefragPass
|
|
/* 13404: 02602025 */ or $a0,$s3,$zero
|
|
/* 13408: 26100001 */ addiu $s0,$s0,0x1
|
|
/* 1340c: 1614fffc */ bne $s0,$s4,.NB00013400
|
|
/* 13410: 00000000 */ sll $zero,$zero,0x0
|
|
/* 13414: 8e690010 */ lw $t1,0x10($s3)
|
|
/* 13418: 0132082b */ sltu $at,$t1,$s2
|
|
/* 1341c: 50200007 */ beqzl $at,.NB0001343c
|
|
/* 13420: 8e2b0000 */ lw $t3,0x0($s1)
|
|
/* 13424: 8e2a000c */ lw $t2,0xc($s1)
|
|
.NB00013428:
|
|
/* 13428: 26310008 */ addiu $s1,$s1,0x8
|
|
/* 1342c: 0152082b */ sltu $at,$t2,$s2
|
|
/* 13430: 5420fffd */ bnezl $at,.NB00013428
|
|
/* 13434: 8e2a000c */ lw $t2,0xc($s1)
|
|
/* 13438: 8e2b0000 */ lw $t3,0x0($s1)
|
|
.NB0001343c:
|
|
/* 1343c: 56ab0004 */ bnel $s5,$t3,.NB00013450
|
|
/* 13440: 02202825 */ or $a1,$s1,$zero
|
|
/* 13444: 1000000b */ beqz $zero,.NB00013474
|
|
/* 13448: 00001025 */ or $v0,$zero,$zero
|
|
/* 1344c: 02202825 */ or $a1,$s1,$zero
|
|
.NB00013450:
|
|
/* 13450: 8ca30000 */ lw $v1,0x0($a1)
|
|
.NB00013454:
|
|
/* 13454: 8cad0004 */ lw $t5,0x4($a1)
|
|
/* 13458: 00726021 */ addu $t4,$v1,$s2
|
|
/* 1345c: 01b27023 */ subu $t6,$t5,$s2
|
|
/* 13460: acac0000 */ sw $t4,0x0($a1)
|
|
/* 13464: 15c00002 */ bnez $t6,.NB00013470
|
|
/* 13468: acae0004 */ sw $t6,0x4($a1)
|
|
/* 1346c: aca00000 */ sw $zero,0x0($a1)
|
|
.NB00013470:
|
|
/* 13470: 00601025 */ or $v0,$v1,$zero
|
|
.NB00013474:
|
|
/* 13474: 8fbf002c */ lw $ra,0x2c($sp)
|
|
/* 13478: 8fb00014 */ lw $s0,0x14($sp)
|
|
/* 1347c: 8fb10018 */ lw $s1,0x18($sp)
|
|
/* 13480: 8fb2001c */ lw $s2,0x1c($sp)
|
|
/* 13484: 8fb30020 */ lw $s3,0x20($sp)
|
|
/* 13488: 8fb40024 */ lw $s4,0x24($sp)
|
|
/* 1348c: 8fb50028 */ lw $s5,0x28($sp)
|
|
/* 13490: 03e00008 */ jr $ra
|
|
/* 13494: 27bd0030 */ addiu $sp,$sp,0x30
|
|
);
|
|
#endif
|
|
|
|
//void *memaAlloc(u32 size)
|
|
//{
|
|
// u32 addr;
|
|
// u32 diff;
|
|
// s32 i;
|
|
//
|
|
// struct memaspace *curr = &g_MemaHeap.spaces[0];
|
|
// u32 bestdiff = 0xffffffff;
|
|
// struct memaspace *best = NULL;
|
|
//
|
|
// // Iterate up to the first 16 spaces, looking for the
|
|
// // smallest space that will accommodate the requested size.
|
|
// for (i = 0; i < 16; i++) {
|
|
// if (curr->size >= size) {
|
|
// if (curr->addr == 0xffffffff) {
|
|
// // Reached the end
|
|
// break;
|
|
// }
|
|
//
|
|
// diff = curr->size - size;
|
|
//
|
|
// if (diff < bestdiff) {
|
|
// bestdiff = diff;
|
|
// best = curr;
|
|
//
|
|
// // Stop looking if the space is small enough
|
|
//#if VERSION >= VERSION_NTSC_1_0
|
|
// if (diff < 64 || (IS8MB() && diff < size / 4))
|
|
//#else
|
|
// if (diff < 64 || diff < size / 4)
|
|
//#endif
|
|
// {
|
|
// break;
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// curr++;
|
|
// }
|
|
//
|
|
// if (best == NULL) {
|
|
// // Keep iterating until we find a space that is big enough to fit.
|
|
// // The last space is marked as size 0xffffffff which prevents this loop
|
|
// // from iterating past the end of the spaces array.
|
|
// while (curr->size < size) {
|
|
// curr++;
|
|
// }
|
|
//
|
|
// if (curr->addr == 0xffffffff) {
|
|
// // There was no space, so attempt to free up some space
|
|
// // by doing several defrag passes
|
|
// for (i = 0; i < 8; i++) {
|
|
// memaDefragPass(&g_MemaHeap);
|
|
// }
|
|
//
|
|
// curr = &g_MemaHeap.spaces[0];
|
|
//
|
|
// while (curr->size < size) {
|
|
// curr++;
|
|
// }
|
|
//
|
|
// if (curr->addr == 0xffffffff) {
|
|
// return NULL;
|
|
// }
|
|
// }
|
|
//
|
|
// best = curr;
|
|
// }
|
|
//
|
|
// addr = best->addr;
|
|
// best->addr += size;
|
|
// best->size -= size;
|
|
//
|
|
// if (best->size == 0) {
|
|
// best->addr = 0;
|
|
// }
|
|
//
|
|
// return (void *)addr;
|
|
//}
|
|
|
|
/**
|
|
* Grow the allocation which currently *ends at* the given address.
|
|
*/
|
|
s32 memaGrow(s32 addr, u32 amount)
|
|
{
|
|
struct memaspace *curr = &g_MemaHeap.spaces[0];
|
|
|
|
while (curr->addr != -1) {
|
|
if (curr->addr == addr && curr->size >= amount) {
|
|
goto found;
|
|
}
|
|
|
|
curr++;
|
|
}
|
|
|
|
return 0;
|
|
|
|
found:
|
|
curr->addr += amount;
|
|
curr->size -= amount;
|
|
|
|
if (curr->size == 0) {
|
|
curr->addr = 0;
|
|
}
|
|
|
|
return addr;
|
|
}
|
|
|
|
void memaFree(void *addr, s32 size)
|
|
{
|
|
_memaFree((u32)addr, size);
|
|
}
|
|
|
|
void mema00012cd4(void)
|
|
{
|
|
// empty
|
|
}
|
|
|
|
/**
|
|
* Find and return the largest amount of contiguous free space in the pool.
|
|
* ie. the biggest allocation that mema can currently make.
|
|
*/
|
|
s32 memaGetLongestFree(void)
|
|
{
|
|
struct memaspace *curr;
|
|
s32 biggest = 0;
|
|
|
|
memaDefrag();
|
|
|
|
curr = &g_MemaHeap.spaces[0];
|
|
|
|
while (curr->addr != -1) {
|
|
if (curr->size > biggest) {
|
|
biggest = curr->size;
|
|
}
|
|
|
|
curr++;
|
|
}
|
|
|
|
if (biggest) {
|
|
return biggest;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool memaRealloc(s32 addr, u32 oldsize, u32 newsize)
|
|
{
|
|
if (newsize > oldsize) {
|
|
if (!memaGrow(addr + oldsize, newsize - oldsize)) {
|
|
return false;
|
|
}
|
|
} else if (oldsize > newsize) {
|
|
memaFree((void *)(addr + newsize), oldsize - newsize);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
u32 memaGetSize(void)
|
|
{
|
|
return g_MemaHeapSize;
|
|
}
|