document and rename intro_loader to memory

This commit is contained in:
RevoSucks
2023-08-26 18:44:11 -04:00
parent 7c5f5aec97
commit 08cfada6bd
18 changed files with 519 additions and 441 deletions

View File

@@ -1,5 +1,5 @@
#ifndef _FUNCTIONS_H
#define _FUNCTIONS_H
#ifndef _FUNCTIONS_H_
#define _FUNCTIONS_H_
#include "ultra64.h"
@@ -12,10 +12,11 @@ extern void _bcopy(void *, void *, u32);
// 3640.s
extern void* func_80002AF8(s32, void*);
// 3A80.s
// 3A80.c
extern uintptr_t convert_addr_to_virt_addr(uintptr_t addr);
extern void func_80002F58(void);
extern void *func_80002FDC(s32);
extern void func_80003004(void *); // type unknown
extern void func_80003004(void *);
// 3FB0.s
extern void func_80003B30(void *, s32, s32, s32); // types unknown

View File

@@ -40,8 +40,8 @@
#include "ultra64/thread.h"
#include "functions.h"
#include "macros.h"
#include "functions.h"
#include "variables.h"
#endif

View File

@@ -36,7 +36,7 @@ segments:
- [0x1F70, bin, noppad_1F70] # Extra nop align like earlier. Weird
- [0x1F80, c, dp_intro] # dp intro code
- [0x28E0, c, memmap]
- [0x2EC0, c, intro_loader] # intro loader
- [0x2EC0, c, memory]
- [0x3640, asm] #
- [0x3A80, c]
- [0x3FB0, asm] # PRES-JPEG decoder

View File

@@ -1,6 +1,6 @@
#include <ultra64.h>
#include "memmap.h"
#include "intro_loader.h"
#include "memory.h"
extern s32 D_80068B90;
extern u8 D_80104BB0[];
@@ -11,23 +11,33 @@ s32 func_80002A40(s32, s32);
void func_80002BD0(s32, void *); // type unknown
s32 func_80007A58(void);
uintptr_t func_80002E80(uintptr_t addr) {
uintptr_t retaddr = 0x00000000;
/*
* Convert any valid address to its virtual (KSEG0) counterpart.
*/
uintptr_t convert_addr_to_virt_addr(uintptr_t addr) {
uintptr_t retaddr = 0x00000000; // any invalid cases are treated as NULL return.
// convert physical (in installed memory range) to virtual.
if (addr < (size_t) osMemSize) {
retaddr = addr | 0x80000000;
// convert segmented to virtual.
} else if (addr < 0x10000000U) {
retaddr = Memmap_GetSegmentVaddr(addr);
// convert a fragment pre-relocated address to a post-relocated virtual address.
} else if ((addr >= 0x81000000U) && (addr < 0x90000000U)) { // is the address in fragment space? convert it to its post-relocated address.
retaddr = Memmap_GetFragmentVaddr(addr);
// pass-through addresses that are already virtual (in installed memory range)
} else if ((addr >= 0x80000000U) && (addr < (uintptr_t) (osMemSize + 0x80000000U))) {
retaddr = addr;
}
return retaddr;
}
// HAL memcpy?
void func_80002F28(u32* dest, u32* src, int size) {
/*
* Copy memory from one address to the other. (why is this function not in HAL_libc?)
*/
void HAL_Memcpy(u32* dest, u32* src, int size) {
while (size --> 0) {
*(dest++) = *(src++);
}
@@ -36,9 +46,9 @@ void func_80002F28(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)) {
func_800022C0(&D_80104BB0, 0x80600000);
main_pool_init(&D_80104BB0, 0x80600000);
} else {
func_800022C0(&D_80104BB0, 0x80400000);
main_pool_init(&D_80104BB0, 0x80400000);
D_80068B90 = 0;
}
func_80003860();
@@ -53,8 +63,7 @@ void func_80003004(void *arg0) {
func_80002BD0(D_800A60B0, arg0);
}
// HAL_DrawRect
void func_8000302C(Gfx** dlist, s32 ulx, s32 lrx, u16 color) {
void HAL_DrawRect(Gfx** dlist, s32 ulx, s32 lrx, u16 color) {
s32 uly = 0xF;
s32 lry = 0x11;
Gfx *gfx = *dlist;
@@ -72,48 +81,49 @@ void func_8000302C(Gfx** dlist, s32 ulx, s32 lrx, u16 color) {
*dlist = gfx;
}
void func_8000310C(Gfx** dlist)
{
struct Unk800A6070 * sp54 = func_80002A30();
s32 temp_s1 = func_80002764() - D_80068B90;
void func_8000310C(Gfx** dlist) {
struct MainPool *pool = main_pool_get_pool();
s32 temp_s1 = main_pool_get_available() - D_80068B90;
if (temp_s1 >= 0)
{
u32 coord = 0x1E;
s32 sp48 = ((u32) ( K0_TO_PHYS(sp54->unk20)) >> 0xF) + coord;
s32 sp44 = ((u32) ( K0_TO_PHYS(sp54->unk28)) >> 0xF) + coord;
s32 sp40 = ((u32) ( K0_TO_PHYS(sp54->unk2C) - D_80068B90) >> 0xF) + coord;
s32 sp3C = ((u32) ( K0_TO_PHYS(sp54->unk24) - D_80068B90) >> 0xF) + coord;
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;
func_8000302C(dlist, coord, sp48, 0xFBCB);
func_8000302C(dlist, sp48, sp44, 0xFFCB);
func_8000302C(dlist, sp44, sp40, 0x2ABF);
func_8000302C(dlist, sp40, sp3C, 0xFFCB);
HAL_Printf(coord, 0x14, "MEM: +%XH (+%dK)", temp_s1, temp_s1 / 1024);
HAL_DrawRect(dlist, base, sp48, 0xFBCB);
HAL_DrawRect(dlist, sp48, sp44, 0xFFCB);
HAL_DrawRect(dlist, sp44, sp40, 0x2ABF);
HAL_DrawRect(dlist, sp40, sp3C, 0xFFCB);
HAL_Printf(base, 0x14, "MEM: +%XH (+%dK)", temp_s1, temp_s1 / 1024);
}
else
{
u32 coord = 0x1E;
s32 sp34 = ((u32) ( K0_TO_PHYS(sp54->unk20)) >> 0xF) + coord;
s32 sp30 = ((u32) ( K0_TO_PHYS(sp54->unk28)) >> 0xF) + coord;
s32 sp2C = ((u32) ( K0_TO_PHYS(sp54->unk2C) - D_80068B90) >> 0xF) + coord;
s32 sp28 = ((u32) ( K0_TO_PHYS(sp54->unk24) - D_80068B90) >> 0xF) + coord;
func_8000302C(dlist, coord, sp34, 0xFBCB);
func_8000302C(dlist, sp34, sp2C, 0xFFCB);
func_8000302C(dlist, sp2C, sp30, 0xF94B);
func_8000302C(dlist, sp30, sp28, 0xFFCB);
HAL_Printf(coord, 0x14, "MEM: -%XH (-%dK)", -temp_s1, -temp_s1 / 1024);
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;
HAL_DrawRect(dlist, base, sp34, 0xFBCB);
HAL_DrawRect(dlist, sp34, sp2C, 0xFFCB);
HAL_DrawRect(dlist, sp2C, sp30, 0xF94B);
HAL_DrawRect(dlist, sp30, sp28, 0xFFCB);
HAL_Printf(base, 0x14, "MEM: -%XH (-%dK)", -temp_s1, -temp_s1 / 1024);
}
}
void func_8000330C(u64 * dest, u32 arg1) {
while( arg1 --> 0 ) {
/*
* Clear memory address area.
*/
void HAL_Memclear(u64* dest, u32 size) {
while( size --> 0 ) {
*(dest++) = -1;
}
}
s32 func_80003348(u64* arg0)
{
s32 func_80003348(u64* arg0) {
s32 ret = 0;
while (*(arg0++) == 0x8040000080400000)

View File

@@ -2,7 +2,7 @@
#include <PR/os_internal_reg.h>
#include "dp_intro.h"
#include "fragments.h"
#include "intro_loader.h"
#include "memory.h"
#include "dp_intro.h"
struct UnkInputStruct8000D738 {
@@ -40,9 +40,6 @@ void func_81206D9C(void);
void func_81206E64(void);
void func_81206F38(void);
// from 3A80.c
extern uintptr_t func_80002E80(uintptr_t addr);
void func_80005370(struct UnkStruct800AA660 *);
void func_80004454(u32, void *, void *);
char func_8000B318(char);
@@ -50,7 +47,7 @@ s32 func_800044F4(void *, void *, s32, s32);
s32 func_8000484C(s32, s32);
void func_8000D5C0(void* unused) {
void (*func)(void *) = func_80002E80(&func_81206F38);
void (*func)(void *) = convert_addr_to_virt_addr(&func_81206F38);
__osSetFpcCsr(0x01000C01);
func_80004CC0(D_800AA664, 0, 1);
@@ -66,8 +63,8 @@ void func_8000D5C0(void* unused) {
}
void func_8000D678(void *unused) {
void (*func1)(void *func) = func_80002E80(&func_81206D9C);
void (*func2)(void *func) = func_80002E80(&func_81206E64);
void (*func1)(void *func) = convert_addr_to_virt_addr(&func_81206D9C);
void (*func2)(void *func) = convert_addr_to_virt_addr(&func_81206E64);
__osSetFpcCsr(0x01000C01);
func_80004CC0(D_800AA660, 0, 1);
@@ -87,9 +84,9 @@ void func_8000D678(void *unused) {
void func_8000D738(struct UnkInputStruct8000D738* arg0) {
s32 temp_v0;
func_80002784(0x4742454D);
D_800AA660 = (void*)func_800025C4(0x2210, 0);
D_800AA664 = (void*)func_800025C4(0x21E0, 0);
main_pool_push_state('GBEM');
D_800AA660 = (void*)main_pool_alloc_node_no_func(0x2210, 0);
D_800AA664 = (void*)main_pool_alloc_node_no_func(0x21E0, 0);
func_80004454(((u32) ((u32) &fragment1_TEXT_START & 0x0FF00000) >> 0x14) - 0x10, &fragment1_ROM_START, &fragment1_ROM_END);
temp_v0 = func_800044F4(&D_3BA190, &D_3CB130, 1, 1);
D_800AA660->unk21FC = func_8000484C(temp_v0, 0);
@@ -118,5 +115,5 @@ void func_8000D8DC(struct UnkInputStruct8000D738* arg0) {
func_80005370(D_800AA664);
osDestroyThread(&D_800AA660->thread);
osDestroyThread(&D_800AA664->thread);
func_80002838(0x4742454D);
main_pool_pop_state('GBEM');
}

View File

@@ -79,7 +79,8 @@ u16 gCrashScreenUnlockInputs[] = {
};
void crash_screen_sleep(s32 ms) {
u64 cycles = (ms * 1000LL) * 3000ULL / 64ULL;
u64 cycles = OS_USEC_TO_CYCLES(ms * 1000LL); // why not just do OS_NSEC_TO_CYCLES and not multiply by 1000LL?
osSetTime(0);
while (osGetTime() < cycles) {
}
@@ -222,22 +223,18 @@ void crash_screen_print_fpr(s32 x, s32 y, s32 regNum, void *addr) {
}
}
void crash_screen_print_fpcsr(u32 value) {
void crash_screen_print_fpcsr(u32 fpcsr) {
s32 i;
u32 flag = 0x20000;
u32 bit = 1 << 17;
crash_screen_printf(30, 155, "FPCSR:%08XH", value);
crash_screen_printf(30, 155, "FPCSR:%08XH", fpcsr);
for (i = 0; i < 6;) {
if (value & flag) {
for (i = 0; i < 6; i++) {
if (fpcsr & bit) {
crash_screen_printf(132, 155, "(%s)", gFPCSRFaultCauses[i]);
break;
do {} while (0);
}
i++;
flag >>= 1;
bit >>= 1;
}
}

View File

@@ -53,12 +53,11 @@ size_t HAL_Strcmp(char* dest, char* src) {
* this value for every byte across a given specified size. Return the original
* pointer used.
*/
char* HAL_Memset(char* dest, s32 c, s32 nsize) {
char* HAL_Memset(char* dest, s32 c, u32 nsize) {
char* newDest = dest;
// While the size is not 0, keep decrementing. Oddly, HAL seems to have
// xor'd the result instead of checking the logical result.
while((nsize-- == 0) ^ 1) {
// While the size is not 0, keep decrementing.
while( nsize --> 0 ) {
*newDest++ = c;
}
return dest;

View File

@@ -4,6 +4,6 @@
char* HAL_Strcpy(char* dest, char* src);
char* HAL_Strcpy2(char *dest, char* src);
size_t HAL_Strcmp(char* dest, char* src);
char* HAL_Memset(char* dest, s32 c, s32 nsize);
char* HAL_Memset(char* dest, s32 c, u32 nsize);
#endif // _HAL_LIBC_

View File

@@ -1,319 +0,0 @@
#include <ultra64.h>
#include <macros.h>
#include "intro_loader.h"
// local to this file
extern struct Unk800A6070 D_800A6070;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
void func_800022C0(void *arg0, void *arg1) {
D_800A6070.unk20 = (void *)(ALIGN16((uintptr_t)arg0) + 0x10);
D_800A6070.unk24 = (void *)(((uintptr_t)arg1 & ~0xF) - 0x10);
D_800A6070.unk1C = (uintptr_t)D_800A6070.unk24 - (uintptr_t)D_800A6070.unk20;
D_800A6070.unk30 = NULL;
D_800A6070.unk28 = D_800A6070.unk20 - 1;
D_800A6070.unk28->unk00 = NULL;
D_800A6070.unk28->unk04 = NULL;
D_800A6070.unk28->unk08 = NULL;
D_800A6070.unk28->unk0C = 0;
D_800A6070.unk2C = D_800A6070.unk24;
D_800A6070.unk2C->unk00 = NULL;
D_800A6070.unk2C->unk04 = NULL;
D_800A6070.unk28->unk08 = NULL;
D_800A6070.unk28->unk0C = 0;
osCreateMesgQueue(&D_800A6070.queue, D_800A6070.msgs, ARRAY_COUNT(D_800A6070.msgs));
osSendMesg(&D_800A6070.queue, NULL, OS_MESG_NOBLOCK);
}
struct UnkNodeThing *func_80002380(u32 arg0, s32 arg1) {
struct UnkNodeThing *node;
struct UnkNodeThing *ret;
arg0 = ALIGN16(arg0) + sizeof(struct UnkNodeThing);
ret = NULL;
if ((arg0 != 0) && (D_800A6070.unk1C >= (uintptr_t)arg0)) {
if (arg1 == 0) {
D_800A6070.unk1C -= (uintptr_t)arg0;
node = (void *)((uintptr_t)D_800A6070.unk28 + (uintptr_t)arg0);
D_800A6070.unk28->unk04 = node;
node->unk00 = D_800A6070.unk28;
node->unk04 = NULL;
node->unk08 = 0;
node->unk0C = 0;
ret = D_800A6070.unk28;
D_800A6070.unk28 = node;
ret = ret + 1;
} else if (arg1 == 1) {
D_800A6070.unk1C -= (uintptr_t)arg0;
node = (void *)((uintptr_t)D_800A6070.unk2C - (uintptr_t)arg0);
D_800A6070.unk2C->unk00 = node;
node->unk04 = D_800A6070.unk2C;
node->unk00 = NULL;
node->unk08 = 0;
node->unk0C = 0;
D_800A6070.unk2C = node;
ret = node + 1;
}
}
return ret;
}
uintptr_t func_80002430(struct UnkNodeThing *arg0, s32 arg1);
#ifdef NON_MATCHING
uintptr_t func_80002430(struct UnkNodeThing *arg0, s32 arg1) {
// struct UnkNodeThing *node;
struct UnkNodeThing *otherNode;
struct UnkNodeThing *prev;
uintptr_t priorAddr;
priorAddr = (uintptr_t)(arg0 - 1); // v1
if (priorAddr < (uintptr_t)D_800A6070.unk28) {
do {
prev = D_800A6070.unk28->unk00; // t6
D_800A6070.unk28 = prev;
if (arg1) {
if (prev->unk08 != NULL) {
prev->unk08(prev + 1, prev->unk0C);
}
}
D_800A6070.unk1C = D_800A6070.unk1C + (uintptr_t)D_800A6070.unk28->unk04 - (uintptr_t)D_800A6070.unk28;
D_800A6070.unk28->unk04 = NULL;
} while (priorAddr != (uintptr_t)D_800A6070.unk28);
} else {
otherNode = D_800A6070.unk2C;
if (priorAddr >= (uintptr_t)otherNode && priorAddr >= (uintptr_t)otherNode) {
do {
if (arg1) {
if (otherNode->unk08 != NULL) {
otherNode->unk08(otherNode + 1, otherNode->unk0C);
otherNode = D_800A6070.unk2C;
}
}
prev = otherNode->unk04;
D_800A6070.unk2C = prev;
D_800A6070.unk1C = D_800A6070.unk1C + (uintptr_t)prev - (uintptr_t)prev->unk00;
prev->unk00 = NULL;
otherNode = D_800A6070.unk2C;
} while (priorAddr >= (uintptr_t)otherNode);
}
}
return func_80002764();
}
#else
#pragma GLOBAL_ASM("asm/nonmatchings/intro_loader/func_80002430.s")
#endif
struct UnkNodeThing *func_8000254C(u32 arg0, s32 arg1, s32 arg2, void *arg3) {
struct UnkNodeThing *node;
osRecvMesg(&D_800A6070.queue, NULL, OS_MESG_BLOCK);
node = func_80002380(arg0, arg1);
if (node != NULL) {
func_80002A14(node, arg2, arg3);
}
osSendMesg(&D_800A6070.queue, NULL, OS_MESG_NOBLOCK);
return node;
}
struct UnkNodeThing *func_800025C4(u32 arg0, s32 arg1) {
struct UnkNodeThing *node;
osRecvMesg(&D_800A6070.queue, NULL, OS_MESG_BLOCK);
node = func_80002380(arg0, arg1);
osSendMesg(&D_800A6070.queue, NULL, OS_MESG_NOBLOCK);
return node;
}
void func_80002620(struct UnkNodeThing *arg0) {
if (arg0 != NULL) {
osRecvMesg(&D_800A6070.queue, NULL, OS_MESG_BLOCK);
func_80002430(arg0, 1);
osSendMesg(&D_800A6070.queue, NULL, OS_MESG_NOBLOCK);
}
func_80002764();
}
#ifdef NON_MATCHING
struct UnkNodeThing *func_80002680(struct UnkNodeThing *arg0, uintptr_t arg1) {
uintptr_t diff;
struct UnkNodeThing *sp28;
struct UnkNodeThing *prior;
struct UnkNodeThing *priorPrev;
s32 sp20;
void *sp1C;
sp28 = NULL;
osRecvMesg(&D_800A6070.queue, NULL, OS_MESG_BLOCK);
// temp_v1 = arg0 - 0x10;
prior = arg0 - 1;
// temp_a0 = temp_v1->unk4;
priorPrev = prior->unk04;
// temp_v0 = temp_a0 - arg0;
diff = (uintptr_t)priorPrev - (uintptr_t)arg0;
if (D_800A6070.unk28 == priorPrev) {
// uintptr_t aligned;
// temp_a3 = (arg1 + 0xF) & ~0xF;
// aligned = ALIGN16(arg1);
arg1 = ALIGN16(arg1);
// if (temp_v0 < temp_a3) {
if (diff >= arg1 || D_800A6070.unk1C >= (arg1 - diff)) {
sp20 = prior->unk0C;
sp1C = prior->unk08;
func_80002430(arg0, 0);
sp28 = func_80002380(arg1, 0);
func_80002A14(sp28, sp20, sp1C);
}
}
osSendMesg(&D_800A6070.queue, NULL, OS_MESG_NOBLOCK);
return sp28;
}
#else
#pragma GLOBAL_ASM("asm/nonmatchings/intro_loader/func_80002680.s")
#endif
// this is a weird type, so maybe it should be cast into UnkNodeThing?
uintptr_t func_80002764(void) {
s32 val = (s32)D_800A6070.unk1C - sizeof(struct UnkNodeThing);
if (val < 0) {
val = 0;
}
return val;
}
void func_80002784(s32 arg0) {
struct UnkNodeThing *node;
struct UnkNodeThing *sp20; // prev?
struct UnkNodeThing *sp1C; // data?
uintptr_t sp18; // next?
osRecvMesg(&D_800A6070.queue, NULL, OS_MESG_BLOCK);
sp18 = D_800A6070.unk1C;
sp20 = D_800A6070.unk28;
sp1C = D_800A6070.unk2C;
node = func_80002380(0x10, 0);
if (node != NULL) {
(node-1)->unk0C = arg0;
node->unk0C = (uintptr_t)D_800A6070.unk30;
node->unk00 = (struct UnkNodeThing *) sp18;
node->unk04 = sp20;
node->unk08 = (void *) sp1C;
D_800A6070.unk30 = node;
}
osSendMesg(&D_800A6070.queue, NULL, OS_MESG_NOBLOCK);
func_80002764();
}
void func_80002838(struct UnkNodeThing *arg0) {
struct UnkNodeThing *node;
struct UnkNodeThing *s0;
void *s2, *s3;
s0 = arg0;
osRecvMesg(&D_800A6070.queue, NULL, OS_MESG_BLOCK);
while (TRUE) {
node = D_800A6070.unk30;
s2 = node->unk04;
s3 = node->unk08;
D_800A6070.unk1C = (uintptr_t)node->unk00;
D_800A6070.unk30 = INT2VOID(node->unk0C);
if (s0 == NULL) { break; }
// odd non-matching, but it works
node = node - 1;
if ((uintptr_t)s0 == (uintptr_t)node->unk0C) { break; }
if (D_800A6070.unk30 == NULL) { break; }
}
s0 = D_800A6070.unk2C;
while ((uintptr_t)s3 > (uintptr_t)s0) {
if (s0->unk08 != NULL) {
s0->unk08(s0 + 1, s0->unk0C);
}
s0 = s0->unk04;
}
s0 = D_800A6070.unk28->unk00;
while ((uintptr_t)s2 <= (uintptr_t)s0) {
if (s0->unk08 != NULL) {
s0->unk08(s0 + 1, s0->unk0C);
}
s0 = s0->unk00;
}
D_800A6070.unk28 = s2;
D_800A6070.unk2C = s3;
osSendMesg(&D_800A6070.queue, NULL, OS_MESG_NOBLOCK);
func_80002764();
}
#ifdef MIPS_TO_C
// unused function?
struct UnkNodeThing *func_80002960(uintptr_t arg0, s32 *arg1) {
struct UnkNodeThing *node; // v0?
struct UnkNodeThing *otherNode;
node = D_800A6070.unk28->unk00;
while (node != NULL) {
otherNode = node->unk04;
if (arg0 >= (uintptr_t)(node + 1) && arg0 < (uintptr_t)otherNode) {
if (arg1 != NULL) {
*arg1 = node->unk0C;
}
return (node + 1);
}
node = node->unk00;
}
// L800029B8
node = D_800A6070.unk2C;
otherNode = node->unk04;
while (otherNode != NULL) {
if (arg0 >= (uintptr_t)(node + 1) && arg0 < (uintptr_t)otherNode) {
if (arg1 != NULL) {
*arg1 = node->unk0C;
}
return node + 1;
}
node = otherNode;
otherNode = otherNode->unk04;
}
// L80002A08
return NULL;
}
#else
#pragma GLOBAL_ASM("asm/nonmatchings/intro_loader/func_80002960.s")
#endif
void func_80002A14(struct UnkNodeThing *arg0, s32 arg1, void *arg2) {
struct UnkNodeThing *node = INT2VOID((uintptr_t)arg0 - sizeof(struct UnkNodeThing));
node->unk08 = arg2;
node->unk0C = arg1;
}
uintptr_t func_80002A24(struct UnkNodeThing *arg0) {
struct UnkNodeThing *prior = arg0 - 1;
return (uintptr_t)prior->unk04 - (uintptr_t)arg0;
}
struct Unk800A6070 *func_80002A30(void) {
return &D_800A6070;
}
#pragma GCC diagnostic pop

View File

@@ -1,51 +0,0 @@
#ifndef _SRC_INTRO_LOADER_H_
#define _SRC_INTRO_LOADER_H_
#include <PR/ultratypes.h>
#include <PR/os.h>
#include <macros.h>
struct UnkNodeThing {
/* 0x00 */ struct UnkNodeThing *unk00;
/* 0x04 */ struct UnkNodeThing *unk04;
// this looks like it can be any type of pointer?
// or are there multiple list node types in a union?
/* 0x08 */ void (*unk08)(struct UnkNodeThing *, s32);
/* 0x0C */ s32 unk0C;
}; // sizeof == 0x10
// "known" types for +08 and +0C:
// fn pointer
// void (*unk08)(struct UnkNodeThing *, s32
// s32 unk0C
// more nodes
// struct UnkNodeThing *unk08
// struct UnkNodeThing *unk0C
struct Unk800A6070 {
/* 0x00 */ OSMesg msgs[1];
/* 0x04 */ OSMesgQueue queue;
/* 0x1C */ uintptr_t unk1C;
// these pointers might be to different variants of this struct
// or, they could be to different lists...
/* 0x20 */ struct UnkNodeThing *unk20;
/* 0x24 */ struct UnkNodeThing *unk24;
/* 0x28 */ struct UnkNodeThing *unk28;
/* 0x2C */ struct UnkNodeThing *unk2C;
/* 0x30 */ struct UnkNodeThing *unk30;
}; // sizeof >= 0x34
// functions
void func_800022C0(void *arg0, void *arg1);
struct UnkNodeThing *func_8000254C(u32 arg0, s32 arg1, s32 arg2, void *arg3);
struct UnkNodeThing *func_800025C4(u32 arg0, s32 arg1);
void func_80002620(struct UnkNodeThing *arg0);
struct UnkNodeThing *func_80002680(struct UnkNodeThing *arg0, uintptr_t arg1);
uintptr_t func_80002764(void);
void func_80002784(s32 arg0);
void func_80002838(struct UnkNodeThing *arg0);
void func_80002A14(struct UnkNodeThing *, s32, void *);
uintptr_t func_80002A24(struct UnkNodeThing *arg0);
struct Unk800A6070 *func_80002A30(void);
#endif /* _SRC_INTRO_LOADER_H_ */

373
src/memory.c Normal file
View File

@@ -0,0 +1,373 @@
#include <ultra64.h>
#include <macros.h>
#include "memory.h"
extern struct MainPool gMemPool; // gMemPool
/**
* 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) {
gMemPool.start = (void *)(ALIGN16((uintptr_t)start) + 16);
gMemPool.end = (void *)(ALIGN16((uintptr_t)end - 15) - 16);
gMemPool.available = (uintptr_t)gMemPool.end - (uintptr_t)gMemPool.start;
gMemPool.mainState = NULL;
gMemPool.listHeadL = ((u8*)gMemPool.start - sizeof(struct MainPoolBlock));
gMemPool.listHeadL->prev = NULL;
gMemPool.listHeadL->next = NULL;
gMemPool.listHeadL->func = NULL;
gMemPool.listHeadL->arg = 0;
gMemPool.listHeadR = gMemPool.end;
gMemPool.listHeadR->prev = NULL;
gMemPool.listHeadR->next = NULL;
gMemPool.listHeadL->func = NULL;
gMemPool.listHeadL->arg = 0;
osCreateMesgQueue(&gMemPool.queue, gMemPool.msgs, ARRAY_COUNT(gMemPool.msgs));
osSendMesg(&gMemPool.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.
*/
struct MainPoolBlock *main_pool_alloc(u32 size, u32 side) {
struct MainPoolBlock *newListHead;
void *addr = NULL;
size = ALIGN16(size) + sizeof(struct MainPoolBlock);
if (size != 0 && gMemPool.available >= size) {
if (side == MEMORY_POOL_LEFT) {
gMemPool.available -= size;
newListHead = (void *)((uintptr_t)gMemPool.listHeadL + size);
gMemPool.listHeadL->next = newListHead;
newListHead->prev = gMemPool.listHeadL;
newListHead->next = NULL;
newListHead->func = 0;
newListHead->arg = 0;
addr = ((u8*)gMemPool.listHeadL + sizeof(struct MainPoolBlock));
gMemPool.listHeadL = newListHead;
} else if (side == MEMORY_POOL_RIGHT) {
gMemPool.available -= size;
newListHead = (void *)((uintptr_t)gMemPool.listHeadR - size);
gMemPool.listHeadR->prev = newListHead;
newListHead->next = gMemPool.listHeadR;
newListHead->prev = NULL;
newListHead->func = 0;
newListHead->arg = 0;
gMemPool.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 < gMemPool.listHeadL) {
do {
block = (gMemPool.listHeadL = gMemPool.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 ((!(&gMemPool)) && (!(&gMemPool)))
{
}
}
}
gMemPool.available += ((uintptr_t)gMemPool.listHeadL->next - (uintptr_t)gMemPool.listHeadL);
gMemPool.listHeadL->next = NULL;
} while (oldListHead != gMemPool.listHeadL);
} else {
block = gMemPool.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 = gMemPool.listHeadR;
}
}
block = (gMemPool.listHeadR = block->next);
gMemPool.available += ((uintptr_t)block - (uintptr_t)block->prev);
block->prev = NULL;
block = gMemPool.listHeadR;
} while (oldListHead >= gMemPool.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(&gMemPool.queue, NULL, OS_MESG_BLOCK);
node = main_pool_alloc(size, side);
if (node != NULL) {
main_pool_set_func(node, arg, func);
}
osSendMesg(&gMemPool.queue, NULL, OS_MESG_NOBLOCK);
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(&gMemPool.queue, NULL, OS_MESG_BLOCK);
node = main_pool_alloc(size, side);
osSendMesg(&gMemPool.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(&gMemPool.queue, NULL, OS_MESG_BLOCK);
main_pool_free(addr, 1);
osSendMesg(&gMemPool.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(&gMemPool.queue, NULL, OS_MESG_BLOCK);
if (prior->next == gMemPool.listHeadL) {
size_t diff = ((uintptr_t)prior->next - (uintptr_t)addr);
size = ALIGN16(size);
if (diff >= size || gMemPool.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(&gMemPool.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 = gMemPool.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(&gMemPool.queue, NULL, OS_MESG_BLOCK);
// retrieve the space and head pointers.
available = gMemPool.available;
listHeadL = gMemPool.listHeadL;
listHeadR = gMemPool.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 = gMemPool.mainState;
state->freeSpace = available;
state->listHeadL = listHeadL;
state->listHeadR = listHeadR;
// add the newly allocated state.
gMemPool.mainState = state;
}
osSendMesg(&gMemPool.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(&gMemPool.queue, NULL, OS_MESG_BLOCK);
do {
node = gMemPool.mainState;
listHeadL = node->listHeadL;
listHeadR = node->listHeadR;
gMemPool.available = node->freeSpace;
gMemPool.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(gMemPool.mainState != NULL);
argptr = gMemPool.listHeadR;
while ((uintptr_t)listHeadR > (uintptr_t)argptr) {
if (argptr->func != NULL) {
argptr->func(argptr + 1, argptr->arg);
}
argptr = argptr->next;
}
argptr = gMemPool.listHeadL->prev;
while ((uintptr_t)listHeadL <= (uintptr_t)argptr) {
if (argptr->func != NULL) {
argptr->func(argptr + 1, argptr->arg);
}
argptr = argptr->prev;
}
gMemPool.listHeadL = listHeadL;
gMemPool.listHeadR = listHeadR;
osSendMesg(&gMemPool.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 = gMemPool.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 = gMemPool.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.
*/
uintptr_t main_pool_get_block_dist(struct MainPoolBlock *block) {
struct MainPoolState *state = ((u8*)block - sizeof(struct MainPoolBlock));
return (uintptr_t)state->listHeadL - (uintptr_t)block;
}
/**
* Return the pointer to the static memory pool area.
*/
struct MainPool *main_pool_get_pool(void) {
return &gMemPool;
}

52
src/memory.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef _MEMORY_H_
#define _MEMORY_H_
#include <PR/ultratypes.h>
#include <PR/os.h>
#include <macros.h>
#define MEMORY_POOL_LEFT 0
#define MEMORY_POOL_RIGHT 1
struct MainPoolState {
/* 0x00 */ u32 freeSpace;
/* 0x04 */ struct MainPoolBlock *listHeadL;
/* 0x08 */ struct MainPoolBlock *listHeadR;
/* 0x0C */ struct MainPoolState *prev;
};
struct MainPoolBlock {
/* 0x00 */ struct MainPoolBlock *prev;
/* 0x04 */ struct MainPoolBlock *next;
/* 0x08 */ void (*func)(struct MainPoolBlock *block, s32 arg);
/* 0x0C */ s32 arg; // passed into func as the 2nd argument.
};
struct MainPool {
/* 0x00 */ OSMesg msgs[1];
/* 0x04 */ OSMesgQueue queue;
/* 0x1C */ size_t available;
/* 0x20 */ struct MainPoolBlock *start;
/* 0x24 */ struct MainPoolBlock *end;
/* 0x28 */ struct MainPoolBlock *listHeadL;
/* 0x2C */ struct MainPoolBlock *listHeadR;
/* 0x30 */ struct MainPoolState *mainState;
};
// functions
void main_pool_init(void *start, void *end);
struct MainPoolBlock *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);
u32 main_pool_try_free(struct MainPoolBlock *addr);
struct MainPoolBlock *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);
struct MainPool *main_pool_get_pool(void);
#endif /* _MEMORY_H_ */

View File

@@ -563,4 +563,23 @@ HAL_Printf = 0x80008154;
print_profiler_metrics = 0x8000A0FC;
clear_profiler_data = 0x8000A21C;
draw_profiler_bar_cpu_keep_max = 0x80009630;
Yay0_Decompress = 0x8000B7F0;
Yay0_Decompress = 0x8000B7F0;
convert_addr_to_virt_addr = 0x80002E80;
HAL_Memcpy = 0x80002F28;
HAL_DrawRect = 0x8000302C;
HAL_Memclear = 0x8000330C;
UnkHeapThing = 0x80104BC0;
gMemPool = 0x800A6070;
main_pool_alloc = 0x80002380;
main_pool_get_available = 0x80002764;
main_pool_free = 0x80002430;
main_pool_set_func = 0x80002A14;
main_pool_alloc_node = 0x8000254C;
main_pool_alloc_node_no_func = 0x800025C4;
main_pool_try_free = 0x80002620;
main_pool_realloc = 0x80002680;
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;