Merge pull request #42 from tehzz/introloader

Decomp intro loader
This commit is contained in:
Revo
2023-01-08 14:37:04 -05:00
committed by GitHub
8 changed files with 464 additions and 6 deletions

3
.gitignore vendored
View File

@@ -20,3 +20,6 @@ undefined_syms_auto.txt
# qemu-irix compilers
tools/ido5.3_compiler/
tools/ido7.1_compiler/
# diffing directory
expected/

View File

@@ -36,7 +36,9 @@ O_FILES := $(foreach file,$(C_FILES),$(BUILD_DIR)/$(file:.c=.c.o)) \
$(foreach file,$(S_FILES),$(BUILD_DIR)/$(file:.s=.s.o)) \
$(foreach file,$(DATA_FILES),$(BUILD_DIR)/$(file:.bin=.bin.o)) \
DEP_FILES := $(O_FILES:.o=.d)
DECOMP_C_OBJS := $(filter %.c.o,$(filter-out $(BUILD_DIR)/src/libultra%,$(O_FILES)))
DEP_FILES := $(O_FILES:.o=.d) $(DECOMP_C_OBJS:.o=.asmproc.d)
SPLAT_YAML := splat.yaml
SPLAT = $(PYTHON) tools/n64splat/split.py $(SPLAT_YAML)
@@ -245,7 +247,6 @@ build/src/libultra/io/gbpakreadwrite.c.o: CC := $(CC_OLD)
build/src/libultra/io/gbpakselectbank.c.o: CC := $(CC_OLD)
# run ASM-processor on non-libultra source files
DECOMP_C_OBJS := $(filter %.c.o,$(filter-out $(BUILD_DIR)/src/libultra%,$(O_FILES)))
$(DECOMP_C_OBJS): CC := $(ASMPROC) $(ASMPROC_FLAGS) $(CC) -- $(AS) $(ASFLAGS) --
# turn off syntax checking errors for libultra

View File

@@ -2,6 +2,6 @@
def apply(config, args):
config['baseimg'] = 'baserom.z64'
config['myimg'] = 'pokemonstadium.z64'
config['mapfile'] = 'build/pokemonstadium.map'
config['myimg'] = 'build/pokestadium.z64'
config['mapfile'] = 'build/pokestadium.map'
config['source_directories'] = ['.']

View File

@@ -28,7 +28,7 @@
// global typings
typedef unsigned long uintptr_t;
// cast thru uintptr_t for integer to pointer casts
#define INT2VOID(i) ((void *)(uintptr_t)(i))
#define SCREEN_WIDTH 320

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, asm] # intro loader
- [0x2EC0, c, intro_loader] # intro loader
- [0x3640, asm] #
- [0x3A80, asm] # transition loader
- [0x3FB0, asm] # PRES-JPEG decoder

319
src/intro_loader.c Normal file
View File

@@ -0,0 +1,319 @@
#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

51
src/intro_loader.h Normal file
View File

@@ -0,0 +1,51 @@
#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_ */

84
utils/m2ctx.py Executable file
View File

@@ -0,0 +1,84 @@
#!/usr/bin/env python3
import argparse
import os
import shutil
import sys
import subprocess
from pathlib import Path
# Project-specific
# assuming that this is in tools
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
ROOT_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, ".."))
CPP_FLAGS = [
"-undef",
"-D__sgi",
"-D_LANGUAGE_C",
"-DF3DEX_GBI_2",
"-DNDEBUG",
"-D_MIPS_SZLONG=32",
"-DSCRIPT(...)={}"
"-D__attribute__(...)=",
"-D__asm__(...)=",
"-DGLOBAL_ASM(...)=",
"-ffreestanding",
"-nostdinc",
"-Iinclude",
"-Iinclude/PR",
"-Iinclude/audio",
"-Isrc"
]
def import_c_file(in_file) -> str:
in_file = os.path.relpath(in_file, ROOT_DIR)
# Prefer clang as C preprocessor if installed on the system
if shutil.which('clang') is not None:
cpp = ['clang', '-E', '-P', '-x', 'c', '-Wno-trigraphs']
else:
cpp = ['gcc', '-E', '-P']
cpp_getdefines = [*cpp, "-dM", *CPP_FLAGS, in_file]
cpp_procfile = [*cpp, *CPP_FLAGS, in_file]
out_text = ""
try:
out_text += subprocess.check_output(cpp_getdefines, cwd=ROOT_DIR, encoding="utf-8")
out_text += subprocess.check_output(cpp_procfile, cwd=ROOT_DIR, encoding="utf-8")
except subprocess.CalledProcessError:
print(
"Failed to preprocess input file, when running command:\n",
cpp_getdefines,
file=sys.stderr,
)
sys.exit(1)
if not out_text:
print("Output is empty - aborting")
sys.exit(1)
return out_text
def main():
parser = argparse.ArgumentParser(
description="Create a context file which can be used for m2c"
)
parser.add_argument(
"c_file",
help="File from which to create context",
)
parser.add_argument(
"ctx_file",
nargs='?',
help="save context to file if present, otherwise print to stdout"
)
args = parser.parse_args()
output = import_c_file(args.c_file)
if args.ctx_file is not None:
with open(os.path.join(ROOT_DIR, args.ctx_file), "w", encoding="UTF-8") as f:
f.write(output)
else:
print(output)
if __name__ == "__main__":
main()