diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..80f93b0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +out \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 3e904f3..7923a40 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -3,7 +3,6 @@ { "name": "Linux", "compilerPath": "${DEVKITPPC}/bin/powerpc-eabi-cpp", - "cppStandard": "c++11", "includePath": [ "${workspaceFolder}/include/**", "${DEVKITPPC}/include/**", @@ -15,7 +14,12 @@ "browse": { "limitSymbolsToIncludedHeaders": true, "databaseFilename": "" - } + }, + "cStandard": "c99", + "configurationProvider": "ms-vscode.makefile-tools", + "defines": [ + "VERSION=2" + ] } ], "version": 4 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..d68a79f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "files.associations": { + "*.h": "c", + "*.c": "c" + }, + "editor.autoIndent": "full", + "editor.tabSize": 2, + "editor.formatOnSave": true +} \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..111481b --- /dev/null +++ b/Makefile @@ -0,0 +1,52 @@ +CC := powerpc-eabi-gcc +CFLAGS := -D VERSION=${VERSION} -Os -I. -Wa,-mregnames,-mgekko -Wall -fno-asynchronous-unwind-tables -fno-unwind-tables + +AS := powerpc-eabi-as +ASFLAGS := -mregnames -mgekko + +OD := powerpc-eabi-objdump +ODFLAGS := -EB -D -b binary -m powerpc:750 -M gekko --full-content + +LD := powerpc-eabi-ld + +OBJCOPY := powerpc-eabi-objcopy +PYTHON := python3 + +SRC_DIR := source +INC_DIR := include +OUT_DIR := out +OBJ_DIR := obj + +LD_FILE := sms.ld +OUT_MAP := main.map + +OUT_MAIN := main.out +OUT_BIN := main.bin +OUT_ASM := main.asm + +SRC_FILES := $(wildcard source/*.c) +OBJ_FILES := $(SRC_FILES:.c=.o) + +OBJS := main.o card.o +blockCount := 7 + +all: $(OUT_DIR)/$(OUT_BIN) $(OUT_DIR)/$(OUT_ASM) + +$(OUT_DIR)/$(OUT_ASM): $(OUT_DIR)/$(OUT_BIN) + $(OD) $(ODFLAGS) $(OUT_DIR)/${OUT_BIN} > $(OUT_DIR)/$(OUT_ASM) + +$(OUT_DIR)/$(OUT_BIN): $(OUT_DIR)/$(OUT_MAIN) + $(OBJCOPY) -O binary $< $@ + +$(OUT_DIR)/$(OUT_MAIN): $(OBJ_FILES) $(LD_FILE) $(OUT_DIR) + $(LD) -o $@ -T $(LD_FILE) -Map $(OUT_DIR)/$(OUT_MAP) -r $(OBJ_FILES) + +$(OBJ_FILES): $(SRC_FILES) + $(CC) $(CFLAGS) -I $(INC_DIR) -o $@ -c $(@:.o=.c) + +$(OUT_DIR): + mkdir -p $@ + +.PHONY: clean +clean: + $(RM) -rv $(OUT_DIR) $(OBJ_FILES) \ No newline at end of file diff --git a/ReadFile-C2.s b/ReadFile-C2.s deleted file mode 100644 index 40764f5..0000000 --- a/ReadFile-C2.s +++ /dev/null @@ -1,80 +0,0 @@ - .file "ReadFile.c" - .machine ppc - .section ".text" - .globl onReadOptionBlock - .type onReadOptionBlock, @function -onReadOptionBlock: -.LFB0: - stwu 1,-32(1) - #mflr 0 - stmw 27,12(1) - lis 29,0x817f - ori 29,29,0xe800 - lis 28,0xabcd - lwz 9,0(29) - ori 28,28,0x1234 - #stw 0,36(1) - mr 30,3 - cmpw 0,9,28 - mr 31,4 - beq- 0,.L3 - lis 9,mount_@ha - li 4,1 - la 9,mount_@l(9) - mtctr 9 - bctrl - cmpwi 0,3,0 - bne- 0,.L3 - lis 9,CARDOpen@ha - la 9,CARDOpen@l(9) - lwz 3,0(30) - mr 5,31 - bl .LC0 - .string "gct" - .section ".text" - .align 2 -.LC0: mflr 4 - mtctr 9 - bctrl - cmpwi 0,3,0 - bne- 0,.L3 - lis 27,0x817f - lis 9,CARDRead@ha - la 9,CARDRead@l(9) - ori 27,27,0xa800 - li 6,0 - li 5,16384 - mr 4,27 - mr 3,31 - mtctr 9 - bctrl - cmpwi 0,3,0 - bne- 0,.L5 - lwz 9,0(27) - xoris 10,9,0xff2f - cmpwi 0,10,-16162 - bne 0,.L5 - lis 10,0x817f - ori 10,10,0xa804 - lwz 10,0(10) - cmpw 0,10,9 - bne+ 0,.L5 - stw 28,0(29) -.L5: - lis 9,CARDClose@ha - mr 3,31 - la 9,CARDClose@l(9) - mtctr 9 - bctrl -.L3: - lis 9,open_@ha - mr 4,31 - la 9,open_@l(9) - mr 3,30 - mtctr 9 - bctrl - lmw 27,12(1) - addi 1,1,32 -.LFE0: - .size onReadOptionBlock, .-onReadOptionBlock - .ident "GCC: (devkitPPC release 41) 12.1.0" diff --git a/ReadFile.c b/ReadFile.c deleted file mode 100644 index 4910aaa..0000000 --- a/ReadFile.c +++ /dev/null @@ -1,68 +0,0 @@ -#include - -typedef struct { - char pad[20]; -} CARDFileInfo; -typedef struct { - int slot; -} TCardManager; - -/** For NTSC-J 1.0: - * - * mount_ 80107b50 - * open_ 801072f4 - * CARDOpen 800a3cac - * CARDRead 800a4640 - * CARDClose 800a3e24 - * - * onReadOptionBlock 801069f4 - */ - -typedef int bool; -int mount_(TCardManager *this, bool); -int open_(TCardManager *this, CARDFileInfo*); -int CARDOpen(int slot, const char *fileName, CARDFileInfo*); -int CARDRead(CARDFileInfo *fileInfo, void *buf, unsigned long size, unsigned long offset); -int CARDClose(CARDFileInfo *fileInfo); - -#define fileName "gct" -#define dst ((void*)0x817FA800) -#define size 0x4000 // 2 blocks -#define magicAddr (dst+size) -#define magic 0xabcd1234 -int onReadOptionBlock(TCardManager *this, CARDFileInfo *fileInfo) { - int rc; - - // if magic is correct -> already loaded -> do not load again - if (*(unsigned int*)(magicAddr) == magic) goto orig; - - // mount - if ((rc = mount_(this, 1))) goto orig; - - // open file - if ((rc = CARDOpen(this->slot, fileName, fileInfo))) { - // TODO error handling - // if (rc == -4) // file not exists - goto orig; - } - - // read file to memory - if ((rc = CARDRead(fileInfo, dst, size, 0))) { - // should not fail if (dst, size) is properly set - } else { - // everything is good => apply gecko code - // TODO entry - // ((void(*)())0x817f4000)(); - if (*(uint32_t*)(dst) == 0x00d0c0de && *(uint32_t*)(dst+4) == 0x00d0c0de) { - // is gct - *(uint32_t*)(magicAddr) = magic; // set magic to enable gecko code - } - } - - // close file - CARDClose(fileInfo); - -orig: - // original function call - return open_(this, fileInfo); -} diff --git a/ReadFile.ld b/ReadFile.ld deleted file mode 100644 index 2f109f3..0000000 --- a/ReadFile.ld +++ /dev/null @@ -1,4 +0,0 @@ -$$ = 0; - -/* TCardManager::cmdLoop() */ -$C2$onReadOptionBlock = 0x801069f4; diff --git a/example/.gitignore b/example/.gitignore deleted file mode 100644 index 69976f7..0000000 --- a/example/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.o -*.out -*.bin -*.gci -*.map diff --git a/example/Makefile b/example/Makefile deleted file mode 100644 index 3ba7aec..0000000 --- a/example/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -CC = powerpc-eabi-gcc -AS = powerpc-eabi-as -LD = powerpc-eabi-ld -OBJCOPY = powerpc-eabi-objcopy -CFLAGS = -Os -I. -Wa,-mregnames,-mgekko -Wall -fno-asynchronous-unwind-tables -fno-unwind-tables -ASFLAGS = -mregnames -mgekko -PYTHON = python3 - -OBJS = _start.o gameLoop.o qfsync.o -LDFILE = sms.ld -MAPOUT = gci.map - -GCI = 01-GMSJ-gct.gci -OBJOUT = a.out -OBJBIN = a.bin -blockCount = 7 - -all: $(GCI) - -$(GCI): $(OBJBIN) - $(PYTHON) make-gci.py $(blockCount) $< $@ - -$(OBJOUT): $(OBJS) | $(LDFILE) - $(LD) -o $@ -T $(LDFILE) -Map $(MAPOUT) $^ -$(OBJBIN): $(OBJOUT) - $(OBJCOPY) -O binary $^ $@ - - -.PHONY: clean -clean: - rm -f *.gci*.out *.bin *.o *.map diff --git a/example/_start.s b/example/_start.s deleted file mode 100644 index 64a6c5e..0000000 --- a/example/_start.s +++ /dev/null @@ -1,38 +0,0 @@ -.include "./macros.s" - -.macro .rwbl src dst - li32 r3, \src - li32 r4, \dst - bl replace_with_bl -.endm - -.globl _start -_start: # right after gci loaded into RAM - mflr r11 # need to make sure r11 is not destroyed - -## replace original instruction @src with `bl dst` -## TODO version - .rwbl 0x800f9a10, _gameLoop - .rwbl 0x800ecde0, _getQFSync - -## return - mtlr r11 - blr - -/** - * r3 = address of original code - * r4 = address of practice code function - */ -replace_with_bl: -## bl from r3 to r4 - sub r4, r4, r3 - rlwinm r4, r4, 0, 6, 29 - oris r4, r4, 0x4800 - ori r4, r4, 0x1 - stw r4, 0(r3) -## invalidate cache - dcbst 0, r3 - sync - icbi 0, r3 - isync - blr diff --git a/example/gameLoop.c b/example/gameLoop.c deleted file mode 100644 index a7b44dd..0000000 --- a/example/gameLoop.c +++ /dev/null @@ -1,18 +0,0 @@ -#include - -typedef struct { - uint8_t qfsync : 2; -} CodeConfig; -extern CodeConfig config; - -void _gameLoop(void *gamePad) { - // original function - TMarioGamePad_read(gamePad); - - // check the controller input - uint16_t btn = JUTGamePad_mPadStatus.button; - config.qfsync = - btn == (PRESS_B | PRESS_DL) ? 2 : // 4x - btn == (PRESS_B | PRESS_DR) ? 3 : // 8x - 0; // 1x -} diff --git a/example/macros.s b/example/macros.s deleted file mode 100644 index 50d0f05..0000000 --- a/example/macros.s +++ /dev/null @@ -1,4 +0,0 @@ -.macro li32 reg val - lis \reg, \val@h - ori \reg, \reg, \val@l -.endm diff --git a/example/main.c b/example/main.c deleted file mode 100644 index 17d985d..0000000 --- a/example/main.c +++ /dev/null @@ -1,3 +0,0 @@ -int f(int x) { - return x*x; -} diff --git a/example/qfsync.s b/example/qfsync.s deleted file mode 100644 index 99eacfd..0000000 --- a/example/qfsync.s +++ /dev/null @@ -1,8 +0,0 @@ -.globl _getQFSync -_getQFSync: - lis r12, 0x8180 - lwz r12, -0x4000(r12) - rlwinm. r12, r12, 2, 0x3 - li r3, 600 - slw r3, r3, r12 - blr diff --git a/example/sms.h b/example/sms.h deleted file mode 100644 index 24db64e..0000000 --- a/example/sms.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef SMS_H -#define SMS_H - -#include - -void TMarioGamePad_read(void*); - -typedef struct { - uint16_t button; - int8_t stickX; - int8_t stickY; - int8_t substickX; - int8_t substickY; - uint8_t triggerLeft; - uint8_t triggerRight; - uint8_t analogA; - uint8_t analogB; - int8_t err; -} PADStatus; -extern PADStatus JUTGamePad_mPadStatus; -#define PRESS_START 0x1000 -#define PRESS_Y 0x0800 -#define PRESS_X 0x0400 -#define PRESS_B 0x0200 -#define PRESS_A 0x0100 -#define PRESS_L 0x0040 -#define PRESS_R 0x0020 -#define PRESS_Z 0x0010 -#define PRESS_DU 0x0008 -#define PRESS_DD 0x0004 -#define PRESS_DR 0x0002 -#define PRESS_DL 0x0001 - -#endif diff --git a/example/sms.ld b/example/sms.ld deleted file mode 100644 index 73e590d..0000000 --- a/example/sms.ld +++ /dev/null @@ -1,14 +0,0 @@ -SECTIONS { - . = 0x817F0000; - .init : { _start.o } - .text : { *(.text) } - .rodata : { *(.rodata) } - .data : { *(.data) } - .bss : { *(.bss) } -} - -/** TODO version */ -TMarioGamePad_read = 0x800fba58; -JUTGamePad_mPadStatus = 0x80400d50; - -config = 0x817fc000; diff --git a/gecko-gosub.s b/gecko-gosub.s deleted file mode 100644 index 8dc9fdc..0000000 --- a/gecko-gosub.s +++ /dev/null @@ -1,10 +0,0 @@ -.set dst, 0x817fa800 - -## backup r15 (pointer to current gecko instruction) at dst-4 - add r0, r15, r4 - lis r3, dst-4@ha - stwu r0, dst-4@l(r3) -## update r15 = dst + 8(header) - r4(this C0 code size) - addi r15, r3, 4+8 - sub r15, r15, r4 - blr diff --git a/gecko-jump.s b/gecko-jump.s deleted file mode 100644 index 5e049f5..0000000 --- a/gecko-jump.s +++ /dev/null @@ -1,29 +0,0 @@ -.set gpApplication, 0x803e6000 # TODO version -.set dst, 0x817fb000 - -## TODO prevent softlock: check app state >= 4 - lis r5, gpApplication+8@ha - lbz r5, gpApplication+8@l(r5) - cmplwi r5, 4 - bltlr -## r5 = 00D0C0DE - lis r5, 0x00D0 - ori r5, r5, 0xC0DE -## check if code is loaded (check header) - lis r3, dst@ha -### first 00D0C0DE -### r3 = &dst - lwzu r0, dst@l(r3) - cmplw r0, r5 - bnelr -### second 00D0C0DE - lwz r0, 4(r3) - cmplw r0, r5 - bnelr -## backup r15 (pointer to current gecko instruction) at dst-4 - add r0, r15, r4 - stw r0, -4(r3) -## update r15 = dst + 8(header) - r4(this C0 code size) - addi r15, r3, 8 - sub r15, r15, r4 - blr diff --git a/gecko-return.s b/gecko-return.s deleted file mode 100644 index 94a0114..0000000 --- a/gecko-return.s +++ /dev/null @@ -1,8 +0,0 @@ -.set dst, 0x817fa800 - -## restore r15 (pointer to current gecko instruction) from dst-4 - lis r3, dst-4@ha - lwz r15, dst-4@l(r3) -## update r15 = restored r15 - r4(this C0 code size) - sub r15, r15, r4 - blr diff --git a/include/card.h b/include/card.h new file mode 100644 index 0000000..b34ce1d --- /dev/null +++ b/include/card.h @@ -0,0 +1,11 @@ + + +#include "gcn.h" +#include "sms.h" + +#ifndef __CARD_H__ +#define __CARD_H__ + +bool loadCard(TCardManager *cm, CARDFileInfo *fileInfo, char *fileName, u32 *dst); + +#endif \ No newline at end of file diff --git a/include/gcn.h b/include/gcn.h new file mode 100644 index 0000000..cc22ee2 --- /dev/null +++ b/include/gcn.h @@ -0,0 +1,33 @@ +#include + +#include "typedefs.h" + +#ifndef __GCN_H__ +#define __GCN_H__ + +#define CARD_SLOT_A 0 +#define CARD_SLOT_B 1 + +#define MEM1_START 0x8000000 +#define MEM1_END 0x81800000 + +typedef struct CARDFileInfo +{ + s32 chan; + s32 fileNo; + + s32 offset; + s32 length; + u16 iBlock; +} CARDFileInfo; + +// typedef void (*CARDCallback)(s32 chan, s32 result); + +s32 CARDOpen(s32 slot, const char *fileName, CARDFileInfo *fileInfo); +s32 CARDRead(CARDFileInfo *fileInfo, void *addr, s32 length, s32 offset); +s32 CARDClose(CARDFileInfo *fileInfo); +// s32 CARDProbeEx(s32 chan, s32 *memSize, s32 *sectorSize); +// s32 CARDMount(s32 chan, void *workArea, CARDCallback detachCallback); +s32 CARDUnmount(s32 chan); + +#endif \ No newline at end of file diff --git a/include/sms.h b/include/sms.h new file mode 100644 index 0000000..e42aef7 --- /dev/null +++ b/include/sms.h @@ -0,0 +1,26 @@ +#ifndef __SMS_H__ +#define __SMS_H__ + +/** For NTSC-J 1.0: + * + * mount_ 80107b50 + * open_ 801072f4 + * CARDOpen 800a3cac + * CARDRead 800a4640 + * CARDClose 800a3e24 + * + * onReadOptionBlock 801069f4 + */ + +// static void *gpApplication = (void *)0x803e9700; +// static void *gpCardManager = (void *)0x8040a2b4; + +typedef struct +{ + int slot; +} TCardManager; + +int mount_(TCardManager *this, bool); +int open_(TCardManager *this, CARDFileInfo *fileInfo); + +#endif \ No newline at end of file diff --git a/include/typedefs.h b/include/typedefs.h new file mode 100644 index 0000000..1df7887 --- /dev/null +++ b/include/typedefs.h @@ -0,0 +1,15 @@ +#ifndef __TYPEDEF_H__ +#define __TYPEDEF_H__ + +typedef int bool; + +typedef unsigned long long u64; +typedef signed long long s64; +typedef unsigned int u32; +typedef signed int s32; +typedef unsigned short u16; +typedef signed short s16; +typedef unsigned char u8; +typedef signed char s8; + +#endif \ No newline at end of file diff --git a/example/make-gci.py b/make-gci.py similarity index 100% rename from example/make-gci.py rename to make-gci.py diff --git a/sms.ld b/sms.ld new file mode 100644 index 0000000..4046c1f --- /dev/null +++ b/sms.ld @@ -0,0 +1,14 @@ +mount_ = 0x80107b50; +open_ = 0x801072f4; +CARDOpen = 0x800a3cac; +CARDRead = 0x800a4640; +CARDClose = 0x800a3e24; + +SECTIONS { + /* . = 0x817fa000; */ + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + .bss : { *(.bss) } + .sdata : { *(.sdata) } +} diff --git a/source/card.c b/source/card.c new file mode 100644 index 0000000..ba21269 --- /dev/null +++ b/source/card.c @@ -0,0 +1,25 @@ +#include "gcn.h" +#include "sms.h" + +bool loadCard(TCardManager *cm, CARDFileInfo *fileInfo, char *fileName, u32 *dst) +{ + // Mount the card + if (!mount_(cm, 1)) + return -1; + + // Open the card + if (!CARDOpen(cm->slot, fileName, fileInfo)) + return -1; + + // Too many codes + if (fileInfo->length > (MEM1_END - (u32)dst)) + return -1; + + // Read codes into destination address + if (CARDRead(fileInfo, dst, fileInfo->length, 0)) + return -1; + + // Done + CARDClose(fileInfo); + return 0; +} diff --git a/source/main.c b/source/main.c new file mode 100644 index 0000000..c4e2700 --- /dev/null +++ b/source/main.c @@ -0,0 +1,39 @@ +#include "gcn.h" +#include "card.h" + +#if VERSION == 1 +#define FILENAME "GCT_GMSE01" +#elif VERSION == 2 +#define FILENAME "GCT_GMSJ01" +#elif VERSION == 3 +#define FILENAME "GCT_GMSP01" +#elif VERSION == 4 +#define FILENAME "GCT_GMSJ0A" +#endif + +// Memory space reserved for Gecko codes to store their state +// data, based on the current usage +// See: https://github.com/BitPatty/gctGenerator/blob/375ba5eb73e50894d4e765fdfddbe004e3b4949d/Readme.md#reserved-memory +// Range: 0x817F0000 - 0x817F1000 +#define ADDR_GECKO_HEAP_START 0x817F0000 +#define ADDR_GECKO_HEAP_SIZE 0x00001000 +#define ADDR_GECKO_HEAP_END (ADDR_GECKO_HEAP_START + ADDR_GECKO_HEAP_SIZE) +#define PTR_FLG_LOADED (bool *)ADDR_GECKO_HEAP_END +#define GECKO_CODE_START (ADDR_GECKO_HEAP_END + sizeof(*PTR_FLG_LOADED)) + +void loadCodes(TCardManager *cm, CARDFileInfo *fileInfo) +{ + *PTR_FLG_LOADED = -1; + + if (loadCard(cm, fileInfo, FILENAME, (void *)GECKO_CODE_START)) + *PTR_FLG_LOADED = 0; +} + +// int onReadOptionBlock(TCardManager *this, CARDFileInfo *fileInfo) +// { +// if (*PTR_FLG_LOADED) +// return open_(this, fileInfo); + +// loadCodes(this, fileInfo); +// return open_(this, fileInfo); +// }