From 45ccb7fd05ae8d9ca7628b7c4a04c8b86bf61fba Mon Sep 17 00:00:00 2001 From: ProjectRevoTPP Date: Thu, 2 Dec 2021 21:00:42 -0500 Subject: [PATCH] GCC support. --- Makefile | 62 +++++++++--- asm/llmuldiv_gcc.s | 103 ++++++++++++++++++++ include/functions.h | 7 ++ spec | 4 + src/boot/missing_gcc_functions.c | 68 +++++++++++++ src/code/audio_heap.c | 4 +- src/overlays/actors/ovl_En_Tana/z_en_tana.c | 3 + 7 files changed, 237 insertions(+), 14 deletions(-) create mode 100644 asm/llmuldiv_gcc.s create mode 100644 src/boot/missing_gcc_functions.c diff --git a/Makefile b/Makefile index b07fbf2e64..7464af27de 100644 --- a/Makefile +++ b/Makefile @@ -8,10 +8,23 @@ COMPARE ?= 1 NON_MATCHING ?= 0 # If ORIG_COMPILER is 1, compile with QEMU_IRIX and the original compiler ORIG_COMPILER ?= 0 +# If COMPILER is GCC, compile with GCC instead of IDO. +COMPILER ?= ido +# Convert text in source files (.c) to EUC-JP before compilation, but only on GCC. +# This is required in order to preserve debug print functionality on GCC since it +# doesn't seem to recognize EUC-JP marked files without doing this beforehand. +CONV_SOURCE_TEXT ?= 1 + +# If gcc is used, define the NON_MATCHING flag respectively so the files that +# are safe to be used can avoid using GLOBAL_ASM which doesn't work with gcc. +ifeq ($(COMPILER),gcc) + NON_MATCHING := 1 + CPPFLAGS := -DCOMPILER_GCC +endif ifeq ($(NON_MATCHING),1) - CFLAGS := -DNON_MATCHING - CPPFLAGS := -DNON_MATCHING + CFLAGS += -DNON_MATCHING + CPPFLAGS += -DNON_MATCHING COMPARE := 0 endif @@ -41,8 +54,22 @@ else $(error Please install or build mips-linux-gnu) endif -CC := tools/ido_recomp/$(DETECTED_OS)/7.1/cc -CC_OLD := tools/ido_recomp/$(DETECTED_OS)/5.3/cc +# Detect compiler and set variables appropriately. +ifeq ($(COMPILER),gcc) + ifeq ($(CONV_SOURCE_TEXT),1) + CC = iconv -f UTF-8 -t EUC-JP $< | mips-linux-gnu-gcc -x c - + else + CC = mips-linux-gnu-gcc $< + endif + CC_OLD := $(CC) +else +ifeq ($(COMPILER),ido) + CC := tools/ido_recomp/$(DETECTED_OS)/7.1/cc + CC_OLD := tools/ido_recomp/$(DETECTED_OS)/5.3/cc +else +$(error Unsupported compiler. Please use either ido or gcc as the COMPILER variable.) +endif +endif # if ORIG_COMPILER is 1, check that either QEMU_IRIX is set or qemu-irix package installed ifeq ($(ORIG_COMPILER),1) @@ -77,10 +104,17 @@ ZAPD := tools/ZAPD/ZAPD.out OPTFLAGS := -O2 ASFLAGS := -march=vr4300 -32 -Iinclude -MIPS_VERSION := -mips2 -# we support Microsoft extensions such as anonymous structs, which the compiler does support but warns for their usage. Surpress the warnings with -woff. -CFLAGS += -G 0 -non_shared -Xfullwarn -Xcpluscomm $(INC) -Wab,-r4300_mul -woff 649,838,712 +ifeq ($(COMPILER),gcc) + CFLAGS += -c -G 0 -nostdinc -Iinclude -Isrc -Iassets -Ibuild -I. -DNON_MATCHING=1 -DMODDING=1 -DNORMAL_GAMEPLAY=1 -DAVOID_UB=1 -mno-shared -march=vr4300 -mfix4300 -mabi=32 -mhard-float -mdivide-breaks -fno-stack-protector -fno-common -fno-zero-initialized-in-bss -mno-abicalls -fno-strict-aliasing -fno-inline-functions -fno-inline-small-functions -fno-toplevel-reorder -ffreestanding -fwrapv $(CHECK_WARNINGS) -g -mno-explicit-relocs -mno-split-addresses -funsigned-char + MIPS_VERSION := -mips3 + PIPEIN = +else + # we support Microsoft extensions such as anonymous structs, which the compiler does support but warns for their usage. Surpress the warnings with -woff. + CFLAGS += -G 0 -non_shared -Xfullwarn -Xcpluscomm $(INC) -Wab,-r4300_mul -woff 649,838,712 + MIPS_VERSION := -mips2 + PIPEIN = $< +endif ifeq ($(shell getconf LONG_BIT), 32) # Work around memory allocation bug in QEMU @@ -126,6 +160,7 @@ TEXTURE_FILES_OUT := $(foreach f,$(TEXTURE_FILES_PNG:.png=.inc.c),build/$f) \ # create build directories $(shell mkdir -p build/baserom build/assets/text $(foreach dir,$(SRC_DIRS) $(ASM_DIRS) $(ASSET_BIN_DIRS),build/$(dir))) +ifeq ($(COMPILER),ido) build/src/code/fault.o: CFLAGS += -trapuv build/src/code/fault.o: OPTFLAGS := -O2 -g3 build/src/code/fault_drawer.o: CFLAGS += -trapuv @@ -162,6 +197,7 @@ build/src/code/%.o: CC := python3 tools/asm_processor/build.py $(CC) -- $(AS) $( build/src/overlays/%.o: CC := python3 tools/asm_processor/build.py $(CC) -- $(AS) $(ASFLAGS) -- build/assets/%.o: CC := python3 tools/asm_processor/build.py $(CC) -- $(AS) $(ASFLAGS) -- +endif #### Main Targets ### @@ -231,7 +267,7 @@ build/assets/text/nes_message_data_static.o: build/assets/text/message_data.enc. build/assets/text/staff_message_data_static.o: build/assets/text/message_data_staff.enc.h build/assets/%.o: assets/%.c - $(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $< + $(CC) -c $(CFLAGS) -I $( $(@:.o=.s) build/src/%.o: src/%.c - $(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $< + $(CC) -c $(CFLAGS) -I $( $(@:.o=.s) build/src/libultra/libc/ll.o: src/libultra/libc/ll.c - $(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $< + $(CC) -c $(CFLAGS) -I $( $(@:.o=.s) build/src/libultra/libc/llcvt.o: src/libultra/libc/llcvt.c - $(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $< + $(CC) -c $(CFLAGS) -I $( $(@:.o=.s) diff --git a/asm/llmuldiv_gcc.s b/asm/llmuldiv_gcc.s new file mode 100644 index 0000000000..d0a4de7139 --- /dev/null +++ b/asm/llmuldiv_gcc.s @@ -0,0 +1,103 @@ +.include "macro.inc" + +# assembler directives +.set noat # allow manual use of $at +.set noreorder # don't insert nops after branches +.set gp=64 # allow use of 64-bit general purpose registers + +.section .text + +.balign 16 + +/* Copied from Super Mario 64 decomp project */ + +/* -------------------------------------------------------------------------------------- */ +/* need to asm these functions because lib32gcc-7-dev-mips-cross does not exist so we */ +/* cannot naturally link a libgcc variant for this target given this architecture and */ +/* compiler. Until we have a good workaround with a gcc target that doesn't involve */ +/* assuming a 32-bit to 64-bit change, we have to encode these functions as raw assembly */ +/* for it to compile. */ +/* -------------------------------------------------------------------------------------- */ + +/* TODO: Is there a non-insane way to fix this hack that doesn't involve the user compiling */ +/* a library themselves? */ +glabel __umoddi3 + sw $a0, ($sp) + sw $a1, 4($sp) + sw $a2, 8($sp) + sw $a3, 0xc($sp) + ld $t7, 8($sp) + ld $t6, ($sp) + ddivu $zero, $t6, $t7 + bnez $t7, .L80324144 + nop + break 7 +.L80324144: + mfhi $v0 + dsll32 $v1, $v0, 0 + dsra32 $v1, $v1, 0 + jr $ra + dsra32 $v0, $v0, 0 + +glabel __udivdi3 + sw $a0, ($sp) + sw $a1, 4($sp) + sw $a2, 8($sp) + sw $a3, 0xc($sp) + ld $t7, 8($sp) + ld $t6, ($sp) + ddivu $zero, $t6, $t7 + bnez $t7, .L80324180 + nop + break 7 +.L80324180: + mflo $v0 + dsll32 $v1, $v0, 0 + dsra32 $v1, $v1, 0 + jr $ra + dsra32 $v0, $v0, 0 + +glabel __moddi3 + sw $a0, ($sp) + sw $a1, 4($sp) + sw $a2, 8($sp) + sw $a3, 0xc($sp) + ld $t7, 8($sp) + ld $t6, ($sp) + ddivu $zero, $t6, $t7 + bnez $t7, .L803241E8 + nop + break 7 +.L803241E8: + mfhi $v0 + dsll32 $v1, $v0, 0 + dsra32 $v1, $v1, 0 + jr $ra + dsra32 $v0, $v0, 0 + +glabel __divdi3 + sw $a0, ($sp) + sw $a1, 4($sp) + sw $a2, 8($sp) + sw $a3, 0xc($sp) + ld $t7, 8($sp) + ld $t6, ($sp) + ddiv $zero, $t6, $t7 + nop + bnez $t7, .L80324228 + nop + break 7 +.L80324228: + daddiu $at, $zero, -1 + bne $t7, $at, .L80324244 + daddiu $at, $zero, 1 + dsll32 $at, $at, 0x1f + bne $t6, $at, .L80324244 + nop + break 6 +.L80324244: + mflo $v0 + dsll32 $v1, $v0, 0 + dsra32 $v1, $v1, 0 + jr $ra + dsra32 $v0, $v0, 0 diff --git a/include/functions.h b/include/functions.h index f9d730ec54..9f715a1385 100644 --- a/include/functions.h +++ b/include/functions.h @@ -4,7 +4,14 @@ #include "z64.h" f32 fabsf(f32 f); +#ifndef __sgi +#define fabsf __builtin_fabsf +f32 __floatundisf(u32 c); +f64 __floatundidf(u32 c); +unsigned long __udivdi3(unsigned long a, unsigned long b); +#else #pragma intrinsic(fabsf) +#endif f32 sqrtf(f32 f); #pragma intrinsic(sqrtf) f64 sqrt(f64 d); diff --git a/spec b/spec index 8ab5104392..7d9ad24f34 100644 --- a/spec +++ b/spec @@ -109,6 +109,10 @@ beginseg include "build/src/libultra/os/gethwintrroutine.o" include "build/asm/__osSetWatchLo.o" include "build/data/rsp_boot.text.o" +#ifdef COMPILER_GCC + include "build/asm/llmuldiv_gcc.o" + include "build/src/boot/missing_gcc_functions.o" +#endif endseg beginseg diff --git a/src/boot/missing_gcc_functions.c b/src/boot/missing_gcc_functions.c new file mode 100644 index 0000000000..628b59e685 --- /dev/null +++ b/src/boot/missing_gcc_functions.c @@ -0,0 +1,68 @@ +#include "global.h" + +// Define functions needed for the GCC build here. + +// Self-hosted memcmp. +int memcmp(void *s1, const void *s2, size_t n) { + u8 *m1 = (u8 *)s1; + u8 *m2 = (u8 *)s2; + int i; + for (i = 0; i < n; i++) { + if (m1[i] < m2[i]) { + return -1; + } else if (m1[i] > m2[i]) { + return 1; + } + } + return 0; +} + +void *memset(void *str, int c, size_t n) { + u8 *m1 = (u8 *)str; + int i; + for(i = 0; i < n; i++) { + m1[i] = c; + } + return str; +} + +// These functions convert c to an unsigned integer, rounding toward zero. Negative values +// all become zero. +u32 __fixunssfdi(f32 a) { + if (a < 0.0f) + a = 0.0f; + return (u32)a; +} + +u32 __fixunsdfdi(f64 a) { + if (a < 0.0) + a = 0.0; + return (u32)a; +} + +// These functions convert c to a signed integer, rounding toward zero. +s32 __fixsfdi(f32 c) { + return (s32)c; +} + +s32 __fixdfdi(f64 c) { + return (s32)c; +} + +// These functions convert c, a signed integer, to floating point. +f32 __floatdisf(s32 c) { + return (f32)c; +} + +f64 __floatdidf(s32 c) { + return (f64)c; +} + +// These functions convert c, an unsigned integer, to floating point. +f32 __floatundisf(u32 c) { + return (f32)c; +} + +f64 __floatundidf(u32 c) { + return (f64)c; +} diff --git a/src/code/audio_heap.c b/src/code/audio_heap.c index ba398c5c44..2e057163d8 100644 --- a/src/code/audio_heap.c +++ b/src/code/audio_heap.c @@ -1021,7 +1021,9 @@ void* AudioHeap_AllocPermanent(s32 tableType, s32 id, u32 size) { gAudioContext.permanentCache[index].size = size; //! @bug UB: missing return. "ret" is in v0 at this point, but doing an // explicit return uses an additional register. - // return ret; +#ifdef AVOID_UB + return ret; +#endif } void* AudioHeap_AllocSampleCache(u32 size, s32 fontId, void* sampleAddr, s8 medium, s32 cache) { diff --git a/src/overlays/actors/ovl_En_Tana/z_en_tana.c b/src/overlays/actors/ovl_En_Tana/z_en_tana.c index 9e249a8f6a..1562c3551e 100644 --- a/src/overlays/actors/ovl_En_Tana/z_en_tana.c +++ b/src/overlays/actors/ovl_En_Tana/z_en_tana.c @@ -35,6 +35,9 @@ const ActorInit En_Tana_InitVars = { static const char* sShelfTypes[] = { "木の棚", // "Wooden Shelves" "石の棚", // "Stone Shelves" +#ifdef AVOID_UB + "", +#endif }; static const ActorFunc sDrawFuncs[] = {