Add Gamecube support (#102)

* updated gzinject to use cadmic's iso support

* first part

* changes

* fixed gzinject issues (cadmic)

* fixed issue where last scene doesn't get its romend

* fixed small "issue" with iso terminal printing

* better safeguard for f3dex3

* fixed libultra issues (thanks to cadmic)

* revert unwanted change

* small fix
This commit is contained in:
Yanis
2024-05-08 11:58:56 +02:00
committed by GitHub
parent 521cbb3f3f
commit 4b0858ec14
39 changed files with 5283 additions and 225 deletions

3
.gitignore vendored
View File

@@ -31,11 +31,14 @@ build/*/cache/
*.map
*.dump
*.wad
*.iso
out.txt
*.ram
*.bin
F3DEX3/*.code
F3DEX3/*.data
wadextract/
isoextract/
# Tool artifacts
tools/mipspro7.2_compiler/

View File

@@ -40,6 +40,17 @@ RUN_CC_CHECK := 1
CFLAGS ?=
CPPFLAGS ?=
CFLAGS_IDO ?=
TARGET ?=
ifeq ($(TARGET),wad)
CFLAGS := -DCONSOLE_WIIVC -fno-reorder-blocks -fno-optimize-sibling-calls
CPPFLAGS := -DCONSOLE_WIIVC
else ifeq ($(TARGET),iso)
CFLAGS := -DCONSOLE_GC -fno-reorder-blocks -fno-optimize-sibling-calls
CPPFLAGS := -DCONSOLE_GC
endif
ifeq ($(COMPILER),gcc)
CFLAGS += -DCOMPILER_GCC -DNON_MATCHING -DAVOID_UB
@@ -104,28 +115,34 @@ endif
ifeq ($(VERSION),hackeroot-mq)
CFLAGS += -DENABLE_HACKEROOT=1
CPPFLAGS += -DENABLE_HACKEROOT=1
CFLAGS_IDO += -DENABLE_HACKEROOT=1
OPTFLAGS := -Os
ifeq ($(RELEASE),1)
CFLAGS += -DRELEASE_ROM=1 -DOOT_DEBUG=0
CPPFLAGS += -DRELEASE_ROM=1 -DOOT_DEBUG=0
CFLAGS_IDO += -DOOT_DEBUG=0
else
CFLAGS += -DRELEASE_ROM=0 -DOOT_DEBUG=1
CPPFLAGS += -DRELEASE_ROM=0 -DOOT_DEBUG=1
CFLAGS_IDO += -DRELEASE_ROM=0 -DOOT_DEBUG=1
endif
else
ifeq ($(DEBUG),1)
CFLAGS += -DOOT_DEBUG=1
CPPFLAGS += -DOOT_DEBUG=1
CFLAGS_IDO += -DOOT_DEBUG=1
OPTFLAGS := -O2
else
CFLAGS += -DNDEBUG -DOOT_DEBUG=0
CPPFLAGS += -DNDEBUG -DOOT_DEBUG=0
CFLAGS_IDO += -DNDEBUG -DOOT_DEBUG=0
OPTFLAGS := -O2 -g3
endif
CFLAGS += -DENABLE_HACKEROOT=0
CPPFLAGS += -DENABLE_HACKEROOT=0
CFLAGS_IDO += -DENABLE_HACKEROOT=0
endif
# Override optimization flags if using GDB
@@ -137,6 +154,7 @@ endif
# Note: this won't be used if not using HackerOoT
CFLAGS += -DPACKAGE_VERSION='$(PACKAGE_VERSION)' -DCOMPRESS_$(COMPRESSION_TYPE)=1
CPPFLAGS += -DPACKAGE_VERSION='$(PACKAGE_VERSION)' -DCOMPRESS_$(COMPRESSION_TYPE)=1
CFLAGS_IDO += -DPACKAGE_VERSION='$(PACKAGE_VERSION)' -DCOMPRESS_$(COMPRESSION_TYPE)=1
OPTFLAGS += -ffast-math -fno-unsafe-math-optimizations
ifeq ($(OS),Windows_NT)
@@ -207,6 +225,8 @@ ZAPD := tools/ZAPD/ZAPD.out
FADO := tools/fado/fado.elf
PYTHON ?= $(VENV)/bin/python3
FLIPS := tools/Flips/flips
GZINJECT := tools/gzinject/gzinject
CC_IDO := tools/ido_recomp/linux/5.3/cc
# Command to replace path variables in the spec file. We can't use the C
# preprocessor for this because it won't substitute inside string literals.
@@ -232,10 +252,12 @@ else
endif
ROMC := $(ROM:.z64=-compressed-$(COMPRESSION).z64)
WAD := $(ROM:.z64=.wad)
ISO := $(ROM:.z64=.iso)
BPS := $(ROM:.z64=.bps)
ELF := $(ROM:.z64=.elf)
MAP := $(ROM:.z64=.map)
LDSCRIPT := $(ROM:.z64=.ld)
DMA_CONFIG_FILE := dma_config.txt
# description of ROM segments
SPEC := spec
@@ -290,6 +312,36 @@ ifeq ($(COMPILER),gcc)
$(BUILD_DIR)/src/overlays/actors/ovl_En_Part/%.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/overlays/actors/ovl_Item_B_Heart/%.o: OPTFLAGS := -O0
$(BUILD_DIR)/src/overlays/actors/ovl_Bg_Mori_Hineri/%.o: OPTFLAGS := -O0
# library overrides for Gamecube
ifeq ($(TARGET),iso)
MIPS_VERSION_IDO := -mips2
CFLAGS_IDO += -G 0 -non_shared -fullwarn -verbose -Xcpluscomm $(INC) -Wab,-r4300_mul -woff 516,609,649,838,712
$(BUILD_DIR)/src/libultra/io/viswapbuf.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/libultra/io/viswapbuf.o: MIPS_VERSION := $(MIPS_VERSION_IDO)
$(BUILD_DIR)/src/libultra/io/viswapbuf.o: CFLAGS := $(CFLAGS_IDO)
$(BUILD_DIR)/src/libultra/io/viswapbuf.o: CC := $(CC_IDO)
$(BUILD_DIR)/src/libultra/gu/sinf.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/libultra/gu/sinf.o: MIPS_VERSION := $(MIPS_VERSION_IDO)
$(BUILD_DIR)/src/libultra/gu/sinf.o: CFLAGS := $(CFLAGS_IDO)
$(BUILD_DIR)/src/libultra/gu/sinf.o: CC := $(CC_IDO)
$(BUILD_DIR)/src/libultra/gu/cosf.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/libultra/gu/cosf.o: MIPS_VERSION := $(MIPS_VERSION_IDO)
$(BUILD_DIR)/src/libultra/gu/cosf.o: CFLAGS := $(CFLAGS_IDO)
$(BUILD_DIR)/src/libultra/gu/cosf.o: CC := $(CC_IDO)
$(BUILD_DIR)/src/libultra/gu/perspective.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/libultra/gu/perspective.o: MIPS_VERSION := $(MIPS_VERSION_IDO)
$(BUILD_DIR)/src/libultra/gu/perspective.o: CFLAGS := $(CFLAGS_IDO)
$(BUILD_DIR)/src/libultra/gu/perspective.o: CC := $(CC_IDO)
$(BUILD_DIR)/src/libultra/os/getmemsize.o: OPTFLAGS := -O1
$(BUILD_DIR)/src/libultra/os/getmemsize.o: MIPS_VERSION := $(MIPS_VERSION_IDO)
$(BUILD_DIR)/src/libultra/os/getmemsize.o: CFLAGS := $(CFLAGS_IDO)
$(BUILD_DIR)/src/libultra/os/getmemsize.o: CC := $(CC_IDO)
$(BUILD_DIR)/src/libultra/os/aisetnextbuf.o: OPTFLAGS := -O1
$(BUILD_DIR)/src/libultra/os/aisetnextbuf.o: MIPS_VERSION := $(MIPS_VERSION_IDO)
$(BUILD_DIR)/src/libultra/os/aisetnextbuf.o: CFLAGS := $(CFLAGS_IDO)
$(BUILD_DIR)/src/libultra/os/aisetnextbuf.o: CC := $(CC_IDO)
endif
endif
#### Main Targets ###
@@ -314,11 +366,24 @@ wad:
ifeq ("$(wildcard baseroms/$(VERSION)/common-key.bin)", "")
$(error Please provide the common-key.bin file.)
endif
$(V)$(MAKE) compress CFLAGS="-DCONSOLE_WIIVC $(CFLAGS) -fno-reorder-blocks -fno-optimize-sibling-calls" CPPFLAGS="-DCONSOLE_WIIVC $(CPPFLAGS)"
$(V)tools/gzinject/gzinject -a inject -r 1 -k baseroms/$(VERSION)/common-key.bin -w baseroms/$(VERSION)/basewad.wad -m $(ROMC) -o $(WAD) -t "HackerOoT" -i NHOE -p tools/gzinject/patches/NACE.gzi -p tools/gzinject/patches/gz_default_remap.gzi
$(V)$(MAKE) compress TARGET=wad
$(V)$(GZINJECT) -a inject -r 1 -k baseroms/$(VERSION)/common-key.bin -w baseroms/$(VERSION)/basewad.wad -m $(ROMC) -o $(WAD) -t "HackerOoT" -i NHOE -p tools/gzinject/patches/NACE.gzi -p tools/gzinject/patches/gz_default_remap.gzi
$(V)$(RM) -r wadextract/
$(call print,Success!)
iso:
$(V)$(MAKE) compress TARGET=iso
$(call print,Patching ISO...)
$(V)$(PYTHON) tools/gc_utility.py -v $(VERSION) -c $(COMPRESSION)
$(V)$(GZINJECT) -a extract -s baseroms/$(VERSION)/baseiso.iso
$(V)cp $(BUILD_DIR)/$(DMA_CONFIG_FILE) isoextract/zlj_f.tgc/$(DMA_CONFIG_FILE)
$(V)cp $(ROMC) isoextract/zlj_f.tgc/zlj_f.n64
$(V)$(RM) -r isoextract/S_*.tgc/ isoextract/zlj_f.tgc/*.thp
$(V)$(FLIPS) --apply tools/gamecube.bps isoextract/zlj_f.tgc/main.dol isoextract/zlj_f.tgc/main.dol
$(V)$(GZINJECT) -a pack -s $(ISO)
$(V)$(RM) -r isoextract/
$(call print,Success!)
clean:
$(V)$(RM) -r $(BUILD_DIR)
$(call print,Success!)
@@ -391,7 +456,7 @@ verify:
$(V)$(MAKE) rom
@md5sum $(ROM)
.PHONY: all rom compress clean assetclean distclean venv setup run wad patch f3dex3 verify
.PHONY: all rom compress clean assetclean distclean venv setup run wad iso patch f3dex3 verify
.DEFAULT_GOAL := rom
#### Various Recipes ####

View File

@@ -141,6 +141,11 @@
#define ENABLE_MOTION_BLUR false
#endif
#ifdef CONSOLE_GC
#undef ENABLE_F3DEX3
#define ENABLE_F3DEX3 false
#endif
/**
* Default settings if not using HackerOoT mode

View File

@@ -284,3 +284,9 @@ extern struct GraphicsContext* __gfxCtx;
#endif
#define IS_DEBUG_CAM_ENABLED (IS_CAMERA_DEBUG_ENABLED ? gDebugCamEnabled : false)
#ifdef __GNUC__
#define NO_REORDER __attribute__((section(".data"))) __attribute__((no_reorder))
#else
#define NO_REORDER
#endif

View File

@@ -1,10 +1,10 @@
#include "global.h"
__OSThreadTail __osThreadTail = { NULL, OS_PRIORITY_THREADTAIL };
OSThread* __osRunQueue = (OSThread*)&__osThreadTail;
OSThread* __osActiveQueue = (OSThread*)&__osThreadTail;
OSThread* __osRunningThread = NULL;
OSThread* __osFaultedThread = NULL;
NO_REORDER __OSThreadTail __osThreadTail = { NULL, OS_PRIORITY_THREADTAIL };
NO_REORDER OSThread* __osRunQueue = (OSThread*)&__osThreadTail;
NO_REORDER OSThread* __osActiveQueue = (OSThread*)&__osThreadTail;
NO_REORDER OSThread* __osRunningThread = NULL;
NO_REORDER OSThread* __osFaultedThread = NULL;
void __osDequeueThread(OSThread** queue, OSThread* thread) {
register OSThread** a2 = queue;

View File

@@ -10,7 +10,7 @@
/* 0x20 */ ROM_NAME("THE LEGEND OF ZELDA")
/* 0x34 */ PADDING(7)
#ifdef CONSOLE_WIIVC
#if (defined CONSOLE_WIIVC) || (defined CONSOLE_GC)
/* 0x3B */ MEDIUM(CARTRIDGE_EXPANDABLE)
#else
/* 0x3B */ MEDIUM(CARTRIDGE)
@@ -19,7 +19,7 @@
/* 0x3C */ GAME_ID("ZL")
/* 0x3E */ REGION(US)
#ifdef CONSOLE_WIIVC
#if (defined CONSOLE_WIIVC) || (defined CONSOLE_GC)
/* 0x3F */ GAME_REVISION(0)
#else
/* 0x3F */ GAME_REVISION(15)

View File

@@ -13,8 +13,9 @@ def symInfoMain():
parser.add_argument("-e", "--expected", dest="use_expected", action="store_true", help="use the map file in expected/build/ instead of build/")
args = parser.parse_args()
mapFile = f"oot-{args.oot_version}.map" if args.oot_version != "hackeroot-mq" else "hackeroot-mq.map"
BUILTMAP = Path("build") / args.oot_version / f"oot-{args.oot_version}.map"
BUILTMAP = Path("build") / args.oot_version / mapFile
mapPath = BUILTMAP
if args.use_expected:

BIN
tools/gamecube.bps Normal file

Binary file not shown.

99
tools/gc_utility.py Executable file
View File

@@ -0,0 +1,99 @@
#!/usr/bin/env python3
import argparse
import mapfile_parser
import sys
from io import StringIO
from pathlib import Path
from dataclasses import dataclass
# from https://stackoverflow.com/a/16571630
class Capturing(list):
def __enter__(self):
self._stdout = sys.stdout
sys.stdout = self._stringio = StringIO()
return self
def __exit__(self, *args):
self.extend(self._stringio.getvalue().splitlines())
del self._stringio # free up some memory
sys.stdout = self._stdout
@dataclass
class DmaInfo:
name: str
index: int
@dataclass
class DmaEntry:
vromStart: str
vromEnd: str
romStart: str
romEnd: str
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="gamecube utility")
parser.add_argument("-v", "--version", help="OoT Version", default="hackeroot-mq")
parser.add_argument("-c", "--codec", help="Compression Codec", default="yaz")
args = parser.parse_args()
VERSION = args.version
DMATABLE_PATH = f"build/{VERSION}/dmadata_table_spec.h"
ROM_PATH = f"build/{VERSION}/{'oot-' if VERSION != 'hackeroot-mq' else ''}{VERSION}-compressed{'-' + args.codec if VERSION == 'hackeroot-mq' else ''}.z64"
sceneFiles: list[DmaInfo] = []
otherFiles: list[DmaInfo] = []
allFiles: list[DmaInfo] = []
with open(DMATABLE_PATH, "r") as file:
dmaTable = file.readlines()
for i, dmaEntry in enumerate(dmaTable):
entryName = dmaEntry.removeprefix("DEFINE_DMA_ENTRY(").removesuffix(")").split(", ")[0]
allFiles.append(DmaInfo(entryName, i))
if entryName.endswith("_scene"):
sceneFiles.append(DmaInfo(entryName, i))
if entryName in { "code", "ovl_title", "vr_fine1_static", "elf_message_field", "elf_message_ydan"}:
otherFiles.append(DmaInfo(entryName, i))
i = sceneFiles[-1].index
entryName = dmaTable[i + 1].removeprefix("DEFINE_DMA_ENTRY(").removesuffix(")").split(", ")[0]
sceneFiles.append(DmaInfo(entryName, i + 1))
mapFile = f"oot-{VERSION}.map" if VERSION != "hackeroot-mq" else "hackeroot-mq.map"
BUILTMAP = Path("build") / VERSION / mapFile
mapPath = BUILTMAP
with Capturing() as stdout:
ret = mapfile_parser.frontends.sym_info.doSymInfo(mapPath, "gDmaDataTable")
assert ret == 0
split = stdout[0].removesuffix(")").split("(")[1].split(", ")
dmaVrom = split[1]
dmaSize = split[2]
with open(ROM_PATH, "rb") as file:
file.seek(int(dmaVrom.removeprefix('VROM: '), 16))
rom_data = bytearray(file.read(int(dmaSize.removeprefix('SIZE: '), 16)))
temp: list[bytearray] = []
for i in range(0, len(rom_data), 16):
temp.append(rom_data[i:i + 16])
dmaTable: list[DmaEntry] = []
for data in temp:
dmaTable.append(
DmaEntry(
f"0x{int.from_bytes(data[:4], byteorder='big', signed=False):08X}",
f"0x{int.from_bytes(data[4:8], byteorder='big', signed=False):08X}",
f"0x{int.from_bytes(data[8:12], byteorder='big', signed=False):08X}",
f"0x{int.from_bytes(data[12:16], byteorder='big', signed=False):08X}",
)
)
output = f"{(len(otherFiles) + 1) * 16:016}" # scene offset
for info in otherFiles:
entry = dmaTable[info.index]
output += f"{int(entry.romStart, 16):016}"
for info in sceneFiles:
entry = dmaTable[info.index]
output += f"{int(entry.romStart, 16):016}"
with open("build/" + VERSION + "/dma_config.txt", "w") as file:
file.write(output)

View File

@@ -261,7 +261,8 @@ __pycache__/
*.pyc
# Testing File
*.Wad
*.wad
*.iso
TestExtract/
*.exe
*.stackdump
@@ -271,9 +272,10 @@ TestExtract/
Debug/
CppProperties.json
wadextract/
isoextract/
*.o
Makefile
config.*
gzinject
*.zip
autom4te.cache/
autom4te.cache/

View File

@@ -1,30 +1,57 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <malloc.h>
#include <string.h>
#include "doltool.h"
#include "gzinject.h"
void dol_parse_header(dol_hdr_t* hdr, uint8_t *data) {
memcpy(hdr,data,sizeof(*hdr));
for(int i=0;i<7;i++){
hdr->text_size[i] = REVERSEENDIAN32(hdr->text_size[i]);
hdr->text_offset[i] = REVERSEENDIAN32(hdr->text_offset[i]);
hdr->text_loading[i] = REVERSEENDIAN32(hdr->text_loading[i]);
}
for(int i=0;i<11;i++){
hdr->data_size[i] = REVERSEENDIAN32(hdr->data_size[i]);
hdr->data_offset[i] = REVERSEENDIAN32(hdr->data_offset[i]);
hdr->data_loading[i] = REVERSEENDIAN32(hdr->data_loading[i]);
}
hdr->bss_loading = REVERSEENDIAN32(hdr->bss_loading);
hdr->bss_size = REVERSEENDIAN32(hdr->bss_size);
hdr->entry = REVERSEENDIAN32(hdr->entry);
}
size_t dol_compute_size(dol_hdr_t* hdr){
size_t max_end_offset = 0;
for(int i=0;i<7;i++){
if(hdr->text_offset[i] + hdr->text_size[i] > max_end_offset){
max_end_offset = hdr->text_offset[i] + hdr->text_size[i];
}
}
for(int i=0;i<11;i++){
if(hdr->data_offset[i] + hdr->data_size[i] > max_end_offset){
max_end_offset = hdr->data_offset[i] + hdr->data_size[i];
}
}
return max_end_offset;
}
void dol_load(doltool_ctxt_t *ctxt, uint8_t **file_data, uint32_t *file_size){
ctxt->file_data = file_data;
ctxt->file_size = file_size;
memcpy(&ctxt->hdr,*(ctxt->file_data),sizeof(ctxt->hdr));
dol_parse_header(&ctxt->hdr,*(ctxt->file_data));
for(int i=0;i<7;i++){
ctxt->hdr.text_size[i] = REVERSEENDIAN32(ctxt->hdr.text_size[i]);
ctxt->hdr.text_offset[i] = REVERSEENDIAN32(ctxt->hdr.text_offset[i]);
ctxt->hdr.text_loading[i] = REVERSEENDIAN32(ctxt->hdr.text_loading[i]);
if(ctxt->hdr.text_size[i]>0){
ctxt->text_sections[i] = *(ctxt->file_data) + ctxt->hdr.text_offset[i];
}
}
for(int i=0;i<11;i++){
ctxt->hdr.data_size[i] = REVERSEENDIAN32(ctxt->hdr.data_size[i]);
ctxt->hdr.data_offset[i] = REVERSEENDIAN32(ctxt->hdr.data_offset[i]);
ctxt->hdr.data_loading[i] = REVERSEENDIAN32(ctxt->hdr.data_loading[i]);
if(ctxt->hdr.data_size[i]>0){
ctxt->data_sections[i] = *(ctxt->file_data) + ctxt->hdr.data_offset[i];
}
@@ -70,6 +97,9 @@ size_t dol_save(doltool_ctxt_t *ctxt){
ctxt->hdr.data_offset[i] = REVERSEENDIAN32(ctxt->hdr.data_offset[i]);
ctxt->hdr.data_loading[i] = REVERSEENDIAN32(ctxt->hdr.data_loading[i]);
}
ctxt->hdr.bss_loading = REVERSEENDIAN32(ctxt->hdr.bss_loading);
ctxt->hdr.bss_size = REVERSEENDIAN32(ctxt->hdr.bss_size);
ctxt->hdr.entry = REVERSEENDIAN32(ctxt->hdr.entry);
uint8_t *new_data = malloc(totalsize);
if(!new_data){
@@ -96,4 +126,4 @@ size_t dol_save(doltool_ctxt_t *ctxt){
*(ctxt->file_size) = totalsize;
}
return totalsize;
}
}

View File

@@ -24,8 +24,11 @@ typedef struct{
uint32_t *file_size;
} doltool_ctxt_t;
void dol_parse_header(dol_hdr_t* hdr, uint8_t *data);
size_t dol_compute_size(dol_hdr_t* hdr);
void dol_load(doltool_ctxt_t *ctxt, uint8_t **file_data, uint32_t *file_size);
void dol_inject(doltool_ctxt_t *ctxt, uint8_t *text, size_t size, uint32_t loading_addr);
size_t dol_save(doltool_ctxt_t *ctxt);
#endif
#endif

630
tools/gzinject/src/gcm.c Normal file

File diff suppressed because it is too large Load Diff

12
tools/gzinject/src/gcm.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef GCM_H_
#define GCM_H_
#include "gzinject.h"
extern uint32_t GCM_HEADER_SIZE;
extern uint32_t TGC_HEADER_SIZE;
int create_gcm_archive(const char *dir, const char *output);
int extract_gcm_archive(const char *input, const char* outdir);
#endif

View File

@@ -71,12 +71,21 @@ static int gzi_cmd_apply_patch(gzi_ctxt_t *ctxt, int pos){
uint8_t *p;
switch(curfile){
case GZI_FILE_TMD:
if (ctxt->tmd == NULL) {
return -1;
}
p = ctxt->tmd;
break;
case GZI_FILE_TIK:
if (ctxt->tik == NULL) {
return -1;
}
p = ctxt->tik;
break;
case GZI_FILE_CERT:
if (ctxt->cert == NULL) {
return -1;
}
p = ctxt->cert;
break;
default:
@@ -215,4 +224,4 @@ int gzi_init(gzi_ctxt_t *ctxt, uint8_t **files, uint32_t *filesizes, int filecnt
int gzi_destroy(gzi_ctxt_t *ctxt){
if(ctxt->codes) free(ctxt->codes);
return 1;
}
}

File diff suppressed because it is too large Load Diff

BIN
tools/ido_recomp/linux/5.3/as0 Executable file

Binary file not shown.

BIN
tools/ido_recomp/linux/5.3/as1 Executable file

Binary file not shown.

BIN
tools/ido_recomp/linux/5.3/cc Executable file

Binary file not shown.

BIN
tools/ido_recomp/linux/5.3/cfe Executable file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More