diff --git a/.gitignore b/.gitignore index 751300219..6b545ab7a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +__pycache__ tools/mwcc_compiler/*.* tools/elf2dol *.exe diff --git a/Makefile b/Makefile index b8bf2cc2d..7a60d3f32 100644 --- a/Makefile +++ b/Makefile @@ -62,6 +62,7 @@ OBJCOPY := $(DEVKITPPC)/bin/powerpc-eabi-objcopy CC := $(WINE) tools/mwcc_compiler/2.0/mwcceppc.exe LD := $(WINE) tools/mwcc_compiler/2.7/mwldeppc.exe PPROC := python tools/postprocess.py +GLBLASM := python tools/inlineasm/globalasm.py ELF2DOL := tools/elf2dol SHA1SUM := sha1sum ASMDIFF := ./asmdiff.sh @@ -121,4 +122,5 @@ $(OBJ_DIR)/%.o: %.c $(OBJ_DIR)/%.o: %.cpp $(CC) $(PREPROCESS) -o $*.cp $< + $(GLBLASM) $*.cp $(CC) $(CFLAGS) -c -o $@ $*.cp diff --git a/obj_files.mk b/obj_files.mk index d9a42d105..8609e9337 100644 --- a/obj_files.mk +++ b/obj_files.mk @@ -49,7 +49,7 @@ TEXT_O_FILES := \ $(OBJ_DIR)/asm/Core/x/xPar.o \ $(OBJ_DIR)/asm/Core/x/xParCmd.o \ $(OBJ_DIR)/asm/Core/x/xParGroup.o \ - $(OBJ_DIR)/asm/Core/x/xParMgr.o \ + $(OBJ_DIR)/src/Core/x/xParMgr.o \ $(OBJ_DIR)/asm/Core/x/xPartition.o \ $(OBJ_DIR)/asm/Core/x/xpkrsvc.o \ $(OBJ_DIR)/asm/Core/x/xQuickCull.o \ diff --git a/src/Core/x/xParMgr.cpp b/src/Core/x/xParMgr.cpp index 7578f99f3..20e476540 100644 --- a/src/Core/x/xParMgr.cpp +++ b/src/Core/x/xParMgr.cpp @@ -1 +1,9 @@ -#include "xParMgr.h" \ No newline at end of file +#include "xParMgr.h" + +#pragma GLOBAL_ASM("asm/Core/x/xParMgr.s", "xParMgrInit__Fv") + +#pragma GLOBAL_ASM("asm/Core/x/xParMgr.s", "xParMgrKillAllParticles__Fv") + +#pragma GLOBAL_ASM("asm/Core/x/xParMgr.s", "xParMgrUpdate__Ff") + +#pragma GLOBAL_ASM("asm/Core/x/xParMgr.s", "xParMgrRender__Fv") diff --git a/tools/inlineasm/globalasm.py b/tools/inlineasm/globalasm.py new file mode 100644 index 000000000..11416c76b --- /dev/null +++ b/tools/inlineasm/globalasm.py @@ -0,0 +1,46 @@ +import argparse +from pathlib import Path +from helpers import * +import os + +info = """globalasm.py: + +Inserts assembly directly into CPP source. +Specified by #pragma GLOBAL_ASM(assemblyFilePath, functionName) +""" + +parser = argparse.ArgumentParser(description=info) +parser.add_argument("cpFile", help="The .cp file to process") + +def run(): + + args = parser.parse_args() + cpPath = Path(args.cpFile) + cpText = open(cpPath).read() + matches = getPragmaMatches(cpText) + + if len(matches) == 0: + return + + for match in matches: + + replace = match[0] + args = getPragmaArgs(match[1]) + asmPath = Path(args[0]) + asmFileText = open(asmPath).read() + + funcToImport = args[1] + funcs = getAsmFunctions(asmFileText) + # check to see if function argument given is in the file + if funcToImport + ":" not in funcs: + error(funcToImport + " is undefined in " + str(asmPath)) + + asmBlock = getAsmFunctionBlock(asmFileText, funcToImport + ":") + codeBytes = blockToBytes(asmBlock) + newSource = "" + newSource = writeCode(newSource, funcToImport, codeBytes) + cpText = cpText.replace(replace, newSource) + + open(cpPath, "w").write(cpText) + +run() \ No newline at end of file diff --git a/tools/inlineasm/helpers.py b/tools/inlineasm/helpers.py new file mode 100644 index 000000000..5e296c6bd --- /dev/null +++ b/tools/inlineasm/helpers.py @@ -0,0 +1,73 @@ +import re + +pragmaRegex = r"(#pragma\sGLOBAL_ASM\((.*)\))" + +def getPragmaMatches(fileText): + matches = re.findall(pragmaRegex, fileText) + return matches + +# Arguments are processed outside of the regex to keep it simple +# and support any changes we may make in the future +def getPragmaArgs(argString): + args = argString.split(",") + args = map(str.strip, args) + args = map(lambda x: x.replace("\"", ""), args) + return list(args) + +labelRegex = r".+:" + +def getLabels(fileText): + matches = re.findall(labelRegex, fileText) + return matches + +def getAsmFunctions(fileText): + matches = getLabels(fileText) + return list(filter(lambda x: "lbl_" not in x, matches)) + +def getAsmFunctionBlock(fileText, label): + data = [] + found = False + for line in fileText.splitlines(): + if label in line: + found = True + continue + if found: + data.append(line.strip()) + if len(line) == 0: + break + return data + +def filterBlockCode(block): + return list(filter(lambda x: "/*" in x, block)) + +def codeLineToBytes(line): + d = line.split() + b = "0x" + "".join(d[3:7]) + return b + +def blockToBytes(block): + code = filterBlockCode(block) + return list(map(codeLineToBytes, code)) + +def bytesToString(byteLine): + return "opword" + " " + byteLine + +funcTemplate = """extern "C" { +asm void {name}() { +nofralloc +{data} +}}""" + +def writeCode(source, funcName, codeBytes): + source += "\n" + t = funcTemplate.replace("{name}", funcName) + bs = list(map(bytesToString, codeBytes)) + t = t.replace("{data}", "\n".join(bs)) + source += t + "\n" + + return source + +def error(text): + print("Error during #pragma processing:") + print(text) + exit(69) \ No newline at end of file