From 6452c4ae658fb533d6ce5b32f87f6a8b27013111 Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Mon, 25 Sep 2023 21:59:26 -0700 Subject: [PATCH] most of dolphin GBA lib done --- configure.py | 20 +- include/dolphin/dsp.h | 70 +++++ include/dolphin/gba/GBA.h | 65 +++++ include/dolphin/gba/GBAPriv.h | 80 ++++++ src/dolphin/gba/GBA.c | 93 +++++++ src/dolphin/gba/GBAGetProcessStatus.c | 39 +++ src/dolphin/gba/GBAJoyBoot.c | 385 ++++++++++++++++++++++++++ src/dolphin/gba/GBARead.c | 40 +++ src/dolphin/gba/GBAWrite.c | 37 +++ src/dolphin/gba/GBAXfer.c | 121 ++++++++ 10 files changed, 944 insertions(+), 6 deletions(-) create mode 100644 include/dolphin/dsp.h create mode 100644 include/dolphin/gba/GBA.h create mode 100644 include/dolphin/gba/GBAPriv.h create mode 100644 src/dolphin/gba/GBA.c create mode 100644 src/dolphin/gba/GBAGetProcessStatus.c create mode 100644 src/dolphin/gba/GBAJoyBoot.c create mode 100644 src/dolphin/gba/GBARead.c create mode 100644 src/dolphin/gba/GBAWrite.c create mode 100644 src/dolphin/gba/GBAXfer.c diff --git a/configure.py b/configure.py index 8c0b18f6d..c074ce8e5 100644 --- a/configure.py +++ b/configure.py @@ -169,6 +169,14 @@ cflags_runtime = [ "-inline deferred,auto", ] +# Dolphin library flags +cflags_dolphin = [ + *cflags_base, + "-use_lmw_stmw on", + "-str reuse,pool,readonly", + "-inline auto", +] + # Framework flags cflags_framework = [ *cflags_base, @@ -222,8 +230,8 @@ def JSystemLib(lib_name, objects): def DolphinLib(lib_name, objects): return { "lib": lib_name, - "mw_version": "GC/1.3.2", - "cflags": cflags_runtime, # TODO check + "mw_version": "GC/1.2.5n", + "cflags": cflags_dolphin, # TODO check "host": False, "objects": objects, } @@ -722,11 +730,11 @@ config.libs = [ "gba", [ Object(NonMatching, "dolphin/gba/GBA.c"), - Object(NonMatching, "dolphin/gba/GBAGetProcessStatus.c"), + Object(Matching, "dolphin/gba/GBAGetProcessStatus.c"), Object(NonMatching, "dolphin/gba/GBAJoyBoot.c"), - Object(NonMatching, "dolphin/gba/GBARead.c"), - Object(NonMatching, "dolphin/gba/GBAWrite.c"), - Object(NonMatching, "dolphin/gba/GBAXfer.c"), + Object(Matching, "dolphin/gba/GBARead.c"), + Object(Matching, "dolphin/gba/GBAWrite.c"), + Object(Matching, "dolphin/gba/GBAXfer.c"), ], ), JSystemLib( diff --git a/include/dolphin/dsp.h b/include/dolphin/dsp.h new file mode 100644 index 000000000..534ab88cd --- /dev/null +++ b/include/dolphin/dsp.h @@ -0,0 +1,70 @@ +#ifndef _DOLPHIN_DSP +#define _DOLPHIN_DSP + +#include "dolphin/os/OS.h" +#include "dolphin/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DSP_TASK_FLAG_CLEARALL 0x00000000 +#define DSP_TASK_FLAG_ATTACHED 0x00000001 +#define DSP_TASK_FLAG_CANCEL 0x00000002 + +#define DSP_TASK_STATE_INIT 0 +#define DSP_TASK_STATE_RUN 1 +#define DSP_TASK_STATE_YIELD 2 +#define DSP_TASK_STATE_DONE 3 + +typedef void (*DSPCallback)(void* task); + +typedef struct STRUCT_DSP_TASK { + vu32 state; + vu32 priority; + vu32 flags; + u16* iram_mmem_addr; + u32 iram_length; + u32 iram_addr; + + u16* dram_mmem_addr; + u32 dram_length; + u32 dram_addr; + + u16 dsp_init_vector; + u16 dsp_resume_vector; + + DSPCallback init_cb; + DSPCallback res_cb; + DSPCallback done_cb; + DSPCallback req_cb; + + struct STRUCT_DSP_TASK* next; + struct STRUCT_DSP_TASK* prev; + + OSTime t_context; + OSTime t_task; + +} DSPTaskInfo; + +void DSPInit(); +void DSPReset(); +void DSPHalt(); +void DSPSendMailToDSP(u32 mail); +u32 DSPCheckMailToDSP(); +u32 DSPCheckMailFromDSP(); +u32 DSPGetDMAStatus(); + +DSPTaskInfo* DSPAddTask(DSPTaskInfo* task); + +void __DSP_exec_task(DSPTaskInfo* curr, DSPTaskInfo* next); +void __DSP_boot_task(DSPTaskInfo* task); +void __DSP_remove_task(DSPTaskInfo* task); +void __DSP_add_task(DSPTaskInfo* task); +void __DSP_debug_printf(const char* fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif // _DOLPHIN_DSP \ No newline at end of file diff --git a/include/dolphin/gba/GBA.h b/include/dolphin/gba/GBA.h new file mode 100644 index 000000000..155ec3691 --- /dev/null +++ b/include/dolphin/gba/GBA.h @@ -0,0 +1,65 @@ +#ifndef _DOLPHIN_GBA +#define _DOLPHIN_GBA + +#include "dolphin/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GBA_CHAN0 0 +#define GBA_CHAN1 1 +#define GBA_CHAN2 2 +#define GBA_CHAN3 3 +#define GBA_MAX_CHAN 4 + +#define GBA_ALL_KEY_MASK 0x03ff +#define GBA_A_BUTTON 0x0001 +#define GBA_B_BUTTON 0x0002 +#define GBA_SELECT_BUTTON 0x0004 +#define GBA_START_BUTTON 0x0008 +#define GBA_R_KEY 0x0010 +#define GBA_L_KEY 0x0020 +#define GBA_U_KEY 0x0040 +#define GBA_D_KEY 0x0080 +#define GBA_R_BUTTON 0x0100 +#define GBA_L_BUTTON 0x0200 + +#define GBA_JSTAT_MASK 0x3a +#define GBA_JSTAT_FLAGS_SHIFT 4 +#define GBA_JSTAT_FLAGS_MASK 0x30 +#define GBA_JSTAT_PSF1 0x20 +#define GBA_JSTAT_PSF0 0x10 +#define GBA_JSTAT_SEND 0x08 +#define GBA_JSTAT_RECV 0x02 + +#define GBA_READY 0 +#define GBA_NOT_READY 1 +#define GBA_BUSY 2 +#define GBA_JOYBOOT_UNKNOWN_STATE 3 +#define GBA_JOYBOOT_ERR_INVALID 4 + +#define GBA_JOYBOOT_PROGRAM_SIZE_MAX 0x40000 + +#define GBA_JOYBOOT_BOOTPARAM_OFFSET 0xc8 +#define GBA_JOYBOOT_BOOTPARAM_SIZE 0x18 +typedef void (*GBACallback)(s32 chan, s32 ret); +void GBAInit(void); +s32 GBAGetStatus(s32 chan, u8* status); +s32 GBAGetStatusAsync(s32 chan, u8* status, GBACallback callback); +s32 GBAReset(s32 chan, u8* status); +s32 GBAResetAsync(s32 chan, u8* status, GBACallback callback); +s32 GBAGetProcessStatus(s32 chan, u8* percentp); +s32 GBARead(s32 chan, u8* dst, u8* status); +s32 GBAReadAsync(s32 chan, u8* dst, u8* status, GBACallback callback); +s32 GBAWrite(s32 chan, u8* src, u8* status); +s32 GBAWriteAsync(s32 chan, u8* src, u8* status, GBACallback callback); +s32 GBAJoyBoot(s32 chan, s32 palette_color, s32 palette_speed, u8* programp, s32 length, + u8* status); +s32 GBAJoyBootAsync(s32 chan, s32 palette_color, s32 palette_speed, u8* programp, s32 length, + u8* status, GBACallback callback); +#ifdef __cplusplus +} +#endif + +#endif // _DOLPHIN_GBA \ No newline at end of file diff --git a/include/dolphin/gba/GBAPriv.h b/include/dolphin/gba/GBAPriv.h new file mode 100644 index 000000000..5864df891 --- /dev/null +++ b/include/dolphin/gba/GBAPriv.h @@ -0,0 +1,80 @@ +#ifndef _DOLPHIN_GBAPRIV +#define _DOLPHIN_GBAPRIV + +#include "dolphin/types.h" + +#include "dolphin/dsp.h" +#include "dolphin/gba/GBA.h" +#include "dolphin/os/OS.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*GBATransferCallback)(s32 chan); + +typedef struct GBASecParam { + u8 readbuf[4]; + s32 paletteColor; + s32 paletteSpeed; + s32 length; + u32* out; + u8 _padding0[12]; + u32 keyA; + s32 keyB; + u8 _padding1[24]; +} GBASecParam; + +typedef struct GBABootInfo { + s32 paletteColor; + s32 paletteSpeed; + u8* programp; + s32 length; + u8* status; + GBACallback callback; + u8 readbuf[4]; + u8 writebuf[4]; + int i; + OSTick start; + OSTime begin; + int firstXfer; + int curOffset; + u32 crc; + u32 dummyWord[7]; + u32 keyA; + s32 keyB; + u32 initialCode; + int realLength; +} GBABootInfo; + +typedef struct GBAControl { + u8 output[5]; + u8 input[5]; + s32 outputBytes; + s32 inputBytes; + u8* status; + u8* ptr; + GBACallback callback; + s32 ret; + OSThreadQueue threadQueue; + OSTime delay; + GBATransferCallback proc; + GBABootInfo bootInfo; + DSPTaskInfo task; + GBASecParam* param; +} GBAControl; + +extern GBAControl __GBA[4]; +extern BOOL __GBAReset; + +void __GBAHandler(s32 chan, u32 error, OSContext* context); +void __GBASyncCallback(s32 chan, s32 ret); +s32 __GBASync(s32 chan); +OSTime __GBASetDelay(s32 chan, OSTime delay); +s32 __GBATransfer(s32 chan, s32 w1, s32 w2, GBATransferCallback callback); + +#ifdef __cplusplus +} +#endif + +#endif // _DOLPHIN_GBAPRIV \ No newline at end of file diff --git a/src/dolphin/gba/GBA.c b/src/dolphin/gba/GBA.c new file mode 100644 index 000000000..f2dd2c8b8 --- /dev/null +++ b/src/dolphin/gba/GBA.c @@ -0,0 +1,93 @@ +#include "dolphin/gba/GBAPriv.h" + +static GBASecParam SecParams[4]; +GBAControl __GBA[4]; +BOOL __GBAReset = FALSE; + +static s32 OnReset(s32); + +static OSResetFunctionInfo ResetFunctionInfo = {OnReset, 127}; + +static void ShortCommandProc(s32 chan) { + GBAControl* gba; + gba = &__GBA[chan]; + + if (gba->ret != 0) { + return; + } + + if (gba->input[0] != 0 || gba->input[1] != 4) { + gba->ret = 1; + return; + } + + gba->status[0] = gba->input[2] & GBA_JSTAT_MASK; +} + +void GBAInit() { + GBAControl* gba; + s32 chan; + + for (chan = 0; chan < 4; ++chan) { + gba = &__GBA[chan]; + gba->delay = OSMicrosecondsToTicks(60); + OSInitThreadQueue(&gba->threadQueue); + gba->param = &SecParams[chan]; + } + + OSInitAlarm(); + + __GBAReset = FALSE; + OSRegisterResetFunction(&ResetFunctionInfo); +} + +s32 GBAGetStatusAsync(s32 chan, u8* status, GBACallback callback) { + GBAControl* gba; + gba = &__GBA[chan]; + if (gba->callback != NULL) { + return GBA_BUSY; + } + + gba->output[0] = 0; + gba->status = status; + gba->callback = callback; + return __GBATransfer(chan, 1, 3, ShortCommandProc); +} + +s32 GBAGetStatus(s32 chan, u8* status) { + GBAControl* gba = &__GBA[chan]; + + s32 ret = GBAGetStatusAsync(chan, status, __GBASyncCallback); + if (ret != GBA_READY) { + return ret; + } + return __GBASync(chan); +} + +s32 GBAResetAsync(s32 chan, u8* status, GBACallback callback) { + GBAControl* gba = &__GBA[chan]; + s32 ret; + if (gba->callback != NULL) { + return GBA_BUSY; + } + gba->output[0] = 0xFF; + gba->status = status; + gba->callback = callback; + return __GBATransfer(chan, 1, 3, ShortCommandProc); +} + +s32 GBAReset(s32 chan, u8* status) { + GBAControl* gba = &__GBA[chan]; + s32 ret; + + ret = GBAResetAsync(chan, status, __GBASyncCallback); + if (ret != GBA_READY) { + return ret; + } + return __GBASync(chan); +} + +s32 OnReset(s32) { + __GBAReset = TRUE; + return TRUE; +} \ No newline at end of file diff --git a/src/dolphin/gba/GBAGetProcessStatus.c b/src/dolphin/gba/GBAGetProcessStatus.c new file mode 100644 index 000000000..c8bf442c5 --- /dev/null +++ b/src/dolphin/gba/GBAGetProcessStatus.c @@ -0,0 +1,39 @@ +#include "dolphin/gba/GBAPriv.h" + +s32 GBAGetProcessStatus(s32 chan, u8* percentp) { + BOOL enabled; // r26 + s32 ret; // r29 + GBAControl* gba; // r25 + GBABootInfo* bootInfo; // r31 + u8 percent; // r30 + OSTime t; // r27 + + gba = &__GBA[chan]; + bootInfo = &__GBA[chan].bootInfo; + + if (gba->callback != NULL || bootInfo->callback != NULL) { + ret = 2; + + if (bootInfo->callback != NULL) { + percent = (bootInfo->curOffset * 100) / bootInfo->realLength; + if (bootInfo->begin != 0) { + t = OSGetTime() - bootInfo->begin; + if (OSTicksToMilliseconds(t) < 5500) { + percent = (percent * t) / OSMillisecondsToTicks(5500ll); + } + + if (percent >= 100) { + percent = 100; + } + } + + if (percentp != NULL) { + *percentp = percent; + } + } + } else { + ret = 0; + } + + return ret; +} diff --git a/src/dolphin/gba/GBAJoyBoot.c b/src/dolphin/gba/GBAJoyBoot.c new file mode 100644 index 000000000..6d85b4b21 --- /dev/null +++ b/src/dolphin/gba/GBAJoyBoot.c @@ -0,0 +1,385 @@ +#include "dolphin/gba/GBAPriv.h" + +static volatile u8 D54[] = { + 0x18, 0xFC, 0xC0, 0x80, 0x7f, 0x40, 0x3f, 0x01, 0x00, 0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x64, + 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x4b, 0x61, 0x77, 0x61, 0x73, 0x65, 0x64, 0x6f, 0x00, + 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xAC, 0xC4, 0xF8, 0x08, 0x10, 0xBF, 0x18, +}; + +static void F23(s32 chan, s32 ret); +static void F25(s32 chan, s32 ret); +static void F27(s32 chan, s32 ret); +static void F29(s32 chan, s32 ret); +static void F31(s32 chan, s32 ret); +static void F33(s32 chan, s32 ret); +static void F35(s32 chan, s32 ret); +static void F37(s32 chan, s32 ret); +static void F39(s32 chan, s32 ret); + +static u32 F72(u32 crc, u32 src, vu8* keyp) { + int i; // r31 + int poly = + (keyp[0x13] << 8) + ((keyp[0x15] + (keyp[0x18] - (keyp[0x18] << 4))) - keyp[0x10]); // r30 + for (i = keyp[1]; i > keyp[11]; --i) { + if ((src ^ crc) & 1) { + crc >>= 1; + crc ^= poly; + } else { + crc >>= 1; + } + + src >>= 1; + } + + return crc; +} + +static u32 F95(u32 src, vu8* keyp) { + src = (src * ((keyp[3] << keyp[0x16]) | + ((keyp[1] | (keyp[4] << keyp[0x11])) | (keyp[4] << keyp[0x18])))) - + (keyp[7] - keyp[6]); + return src; +} + +static void F104(s32 chan, s32 ret) { + GBABootInfo* bootInfo; + GBACallback callback; + + bootInfo = &__GBA[chan].bootInfo; + bootInfo->begin = 0; + if (bootInfo->callback != NULL) { + callback = bootInfo->callback; + bootInfo->callback = NULL; + callback(chan, ret); + } +} + +s32 GBAJoyBootAsync(s32 chan, s32 paletteColor, s32 paletteSpeed, u8* programp, s32 length, + u8* status, GBACallback callback) { + int ret; + GBABootInfo* bootInfo = &__GBA[chan].bootInfo; + u8 percent; + if (chan & ~3) { + return GBA_JOYBOOT_ERR_INVALID; + } else if (length == 0 || GBA_JOYBOOT_PROGRAM_SIZE_MAX < length) { + return GBA_JOYBOOT_ERR_INVALID; + } else if (paletteSpeed < -4 || paletteSpeed > 4) { + return GBA_JOYBOOT_ERR_INVALID; + } else if (paletteColor < 0 || paletteColor > 6) { + return GBA_JOYBOOT_ERR_INVALID; + } else if (programp[0xac] * programp[0xad] * programp[0xae] * programp[0xaf] == 0) { + return GBA_JOYBOOT_ERR_INVALID; + } + + ret = GBAGetProcessStatus(chan, &percent); + if (ret != 0) { + return ret; + } + + bootInfo->paletteColor = paletteColor; + bootInfo->paletteSpeed = paletteSpeed; + bootInfo->programp = programp; + bootInfo->length = length; + bootInfo->status = status; + bootInfo->callback = callback; + bootInfo->curOffset = D54[8]; + ret = GBAGetStatusAsync(chan, bootInfo->status, F23); + if (ret != GBA_READY) { + bootInfo->callback = NULL; + } + + return ret; +} + +static void F23(s32 chan, s32 ret) { + GBAControl* gba; + GBABootInfo* bootInfo; + + gba = &__GBA[chan]; + bootInfo = &__GBA[chan].bootInfo; + + if (ret != GBA_READY || (ret = GBAResetAsync(chan, bootInfo->status, F25)) != GBA_READY) { + F104(chan, ret); + } + + gba->ret = ret; +} + +static void F25(s32 chan, s32 ret) { + GBAControl* gba = &__GBA[chan]; + GBABootInfo* bootInfo = &__GBA[chan].bootInfo; + + if (ret == GBA_READY && *bootInfo->status != D54[37]) { + ret = GBA_JOYBOOT_UNKNOWN_STATE; + } + + if (ret != GBA_READY || (ret = GBAGetStatusAsync(chan, bootInfo->status, F27))) { + F104(chan, ret); + } + + gba->ret = ret; +} + +static void F27(s32 chan, s32 ret) { + GBAControl* gba = &__GBA[chan]; + GBABootInfo* bootInfo = &__GBA[chan].bootInfo; + + if (ret == GBA_READY && *bootInfo->status != D54[0]) { + ret = GBA_JOYBOOT_UNKNOWN_STATE; + } + + if (ret != GBA_READY || (ret = GBAReadAsync(chan, bootInfo->readbuf, bootInfo->status, F29))) { + F104(chan, ret); + } + + gba->ret = ret; +} + +// NONMATCHING +static void F29(s32 chan, s32 ret) { + GBAControl* gba = &__GBA[chan]; + GBABootInfo* bootInfo = &__GBA[chan].bootInfo; + + if (ret == GBA_READY) { + __GBAX02(chan, bootInfo->readbuf); + } else { + F104(chan, ret); + } + + gba->ret = ret; +} + +void __GBAX01(s32 chan, s32 ret) { + GBAControl* gba = &__GBA[chan]; + GBABootInfo* bootInfo = &__GBA[chan].bootInfo; + int val200; + + if (ret == GBA_READY) { + bootInfo->keyA = gba->param->keyA; + bootInfo->keyB = gba->param->keyB; + if (bootInfo->readbuf[3] == 0 || bootInfo->readbuf[2] == 0 || + (bootInfo->keyA & (D54[5] << 9)) == 0 || bootInfo->readbuf[1] == 0 || + (bootInfo->keyA >> 15) == 0 || bootInfo->readbuf[0] == 0) + { + ret = GBA_JOYBOOT_UNKNOWN_STATE; + } else { + bootInfo->i = ~D54[36] & bootInfo->length + D54[36]; + val200 = D54[20] << D54[33]; + + if (bootInfo->i < val200) { + bootInfo->i = val200; + } + + bootInfo->realLength = bootInfo->i; + bootInfo->i -= val200; + bootInfo->i >>= D54[32]; + bootInfo->writebuf[0] = (u8)(bootInfo->keyB >> 0); + bootInfo->writebuf[1] = (u8)(bootInfo->keyB >> 8); + bootInfo->writebuf[3] = (u8)(bootInfo->keyB >> 24); + bootInfo->writebuf[2] = (u8)(bootInfo->keyB >> 16); + bootInfo->crc = (D54[38] + 1) << D54[34]; + bootInfo->curOffset = D54[8]; + bootInfo->begin = OSGetTime(); + bootInfo->firstXfer = TRUE; + ret = GBAWriteAsync(chan, bootInfo->writebuf, bootInfo->status, F31); + } + } + + if (ret != GBA_READY) { + F104(chan, ret); + } + gba->ret = ret; +} + +static void F31(s32 chan, s32 ret) { + GBAControl* gba; + GBABootInfo* bootInfo; + u32 writeWord; + + gba = &__GBA[chan]; + bootInfo = &__GBA[chan].bootInfo; + + if (ret == GBA_READY) { + if (bootInfo->firstXfer != FALSE) { + bootInfo->firstXfer = FALSE; + } else if ((*bootInfo->status & D54[20]) == 0 || + (*bootInfo->status & D54[42]) >> D54[33] != + (bootInfo->curOffset & D54[33]) >> D54[31]) + { + ret = GBA_JOYBOOT_UNKNOWN_STATE; + goto exit; + } else { + bootInfo->curOffset -= D54[25] - D54[23]; + } + + if (bootInfo->curOffset <= bootInfo->realLength) { + if (bootInfo->curOffset < bootInfo->realLength) { + writeWord = D54[29]; + for (bootInfo->i = D54[29]; bootInfo->i < D54[33]; ++bootInfo->i) { + if (bootInfo->length != 0) { + writeWord |= *(bootInfo->programp++) << (bootInfo->i * D54[37]); + --bootInfo->length; + } + } + + if (bootInfo->curOffset == D54[38]) { + bootInfo->initialCode = writeWord; + } else if (bootInfo->curOffset == D54[39]) { + writeWord = chan << D54[37]; + } + + if (bootInfo->curOffset >= D54[2]) { + bootInfo->crc = F72(bootInfo->crc, writeWord, &D54[19]); + } + + if (bootInfo->curOffset == D54[40] + 0x100) { + bootInfo->dummyWord[0] = writeWord; + } else if (bootInfo->curOffset == D54[1] + 0x100) { + bootInfo->i = D54[7]; + bootInfo->dummyWord[bootInfo->i] = writeWord; + } + } else { + writeWord = bootInfo->crc | (bootInfo->curOffset << 16); + } + + if (bootInfo->curOffset > D54[43]) { + bootInfo->keyA = F95(bootInfo->keyA, &D54[20]); + writeWord ^= bootInfo->keyA; + writeWord ^= -(bootInfo->curOffset + D54[11] * 0x100000); + writeWord ^= (D54[11] | (D54[11] << 24)) | (D54[19] << 16) | (D54[18] << 8); + } + + bootInfo->writebuf[3] = (writeWord >> D54[0]); + bootInfo->writebuf[0] = (writeWord >> D54[30]); + bootInfo->writebuf[1] = (writeWord >> D54[41]); + bootInfo->writebuf[2] = (writeWord >> D54[42]); + + if (bootInfo->curOffset == D54[1] + D54[1]) { + bootInfo->dummyWord[2] = writeWord; + } + + if (bootInfo->i < D54[33]) { + bootInfo->dummyWord[3 - (1 - bootInfo->i)] = writeWord; + bootInfo->dummyWord[5 - bootInfo->i] = + bootInfo->dummyWord[(2 - (1 - bootInfo->i))] * + bootInfo->dummyWord[4 - bootInfo->i]; + bootInfo->dummyWord[5 - (1 - bootInfo->i)] = + bootInfo->dummyWord[((1 - bootInfo->i))] * + bootInfo->dummyWord[1 - (1 - bootInfo->i)]; + bootInfo->dummyWord[7 - bootInfo->i] = bootInfo->dummyWord[(-(1 - bootInfo->i))] * + bootInfo->dummyWord[4 - bootInfo->i]; + } + + ret = GBAWriteAsync(chan, bootInfo->writebuf, bootInfo->status, F31); + } else { + bootInfo->start = OSGetTick(); + ret = GBAReadAsync(chan, bootInfo->readbuf, bootInfo->status, F33); + } + } +exit: + if (ret != GBA_READY) { + F104(chan, ret); + } + + gba->ret = ret; +} +static void F33(s32 chan, s32 ret) { + GBAControl* gba = &__GBA[chan]; + GBABootInfo* bootInfo = &__GBA[chan].bootInfo; + + if (ret == GBA_READY) { + for (bootInfo->i = 33; bootInfo->i < 36; ++bootInfo->i) { + ret = (((bootInfo->readbuf[3] ^ (bootInfo->dummyWord[D54[bootInfo->i]] >> 24)) | + (bootInfo->readbuf[2] ^ (bootInfo->dummyWord[D54[bootInfo->i]] >> 16)) | + (bootInfo->readbuf[1] ^ (bootInfo->dummyWord[D54[bootInfo->i]] >> 8)) | + (bootInfo->readbuf[0] ^ (bootInfo->dummyWord[D54[bootInfo->i]] >> 0))) + << 24); + + if (ret == GBA_READY) { + break; + } + } + + if (ret != GBA_READY) { + ret = GBA_JOYBOOT_UNKNOWN_STATE; + } else { + bootInfo->start = OSGetTick(); + ret = GBAGetStatusAsync(chan, bootInfo->status, F35); + } + } + + if (ret != GBA_READY) { + F104(chan, ret); + } + + gba->ret = ret; +} +static void F35(s32 chan, s32 ret) { + GBAControl* gba = &__GBA[chan]; + GBABootInfo* bootInfo = &__GBA[chan].bootInfo; + + if (ret == 0) { + if (OSSecondsToTicks(10) <= OSGetTick() - bootInfo->start) { + ret = GBA_JOYBOOT_UNKNOWN_STATE; + } else if ((*bootInfo->status & 0x32) != 0) { + ret = GBA_JOYBOOT_UNKNOWN_STATE; + } else if (*bootInfo->status != 8) { + ret = GBAGetStatusAsync(chan, bootInfo->status, F35); + } else { + __GBASetDelay(chan, OSMillisecondsToTicks(8)); + ret = GBAReadAsync(chan, bootInfo->readbuf, bootInfo->status, F37); + __GBASetDelay(chan, OSMicrosecondsToTicks(60)); + } + } + + if (ret != GBA_READY) { + F104(chan, ret); + } + + gba->ret = ret; +} + +static void F37(s32 chan, s32 ret) { + GBAControl* gba = &__GBA[chan]; + GBABootInfo* bootInfo = &__GBA[chan].bootInfo; + + if (ret == GBA_READY) { + if ((((bootInfo->readbuf[3] ^ (bootInfo->initialCode >> 24)) | + (bootInfo->readbuf[2] ^ (bootInfo->initialCode >> 16)) | + (bootInfo->readbuf[1] ^ (bootInfo->initialCode >> 8)) | + (bootInfo->readbuf[0] ^ (bootInfo->initialCode >> 0))) + << 24) != 0) + { + ret = GBA_JOYBOOT_UNKNOWN_STATE; + } else { + ret = GBAWriteAsync(chan, bootInfo->readbuf, bootInfo->status, F39); + } + } + + if (ret != GBA_READY) { + F104(chan, ret); + } + gba->ret = ret; +} + +static void F39(s32 chan, s32 ret) { + GBAControl* gba = &__GBA[chan]; + GBABootInfo* bootInfo = &__GBA[chan].bootInfo; + + if (ret == GBA_READY) { + *bootInfo->status = 0; + } + + F104(chan, ret); + gba->ret = ret; +} + +s32 GBAJoyBoot(s32 chan, s32 paletteColor, s32 paletteSpeed, u8* programp, s32 length, u8* status) { + s32 ret = GBAJoyBootAsync(chan, paletteColor, paletteSpeed, programp, length, status, + __GBASyncCallback); + if (ret != GBA_READY) { + return ret; + } + + return __GBASync(chan); +} \ No newline at end of file diff --git a/src/dolphin/gba/GBARead.c b/src/dolphin/gba/GBARead.c new file mode 100644 index 000000000..9891af43b --- /dev/null +++ b/src/dolphin/gba/GBARead.c @@ -0,0 +1,40 @@ +#include "dolphin/gba/GBAPriv.h" + +static void ReadProc(s32 chan) { + GBAControl* gba; + gba = &__GBA[chan]; + + if (gba->ret == 0) { + memcpy(gba->ptr, gba->input, 4); + gba->status[0] = gba->input[4] & GBA_JSTAT_MASK; + } +} + +s32 GBAReadAsync(s32 chan, u8* dst, u8* status, GBACallback callback) { + GBAControl* gba; + + gba = &__GBA[chan]; + + if (gba->callback != NULL) { + return 2; + } + + gba->output[0] = 0x14; + gba->ptr = dst; + gba->status = status; + gba->callback = callback; + + return __GBATransfer(chan, 1, 5, ReadProc); +} + +s32 GBARead(s32 chan, u8* dst, u8* status) { + s32 tmp; + GBAControl* gba = &__GBA[chan]; + s32 ret; + ret = GBAReadAsync(chan, dst, status, __GBASyncCallback); + if (ret != GBA_READY) { + return ret; + } + + return __GBASync(chan); +} \ No newline at end of file diff --git a/src/dolphin/gba/GBAWrite.c b/src/dolphin/gba/GBAWrite.c new file mode 100644 index 000000000..bbbe20b9a --- /dev/null +++ b/src/dolphin/gba/GBAWrite.c @@ -0,0 +1,37 @@ +#include "dolphin/gba/GBAPriv.h" + +static void WriteProc(s32 chan) { + GBAControl* gba; + gba = &__GBA[chan]; + + if (gba->ret != 0) { + return; + } + + gba->status[0] = gba->input[0] & GBA_JSTAT_MASK; +} + +s32 GBAWriteAsync(s32 chan, u8* src, u8* status, GBACallback callback) { + GBAControl* gba = &__GBA[chan]; + + if (gba->callback != NULL) { + return GBA_BUSY; + } + gba->output[0] = 0x15; + memcpy(&gba->output[1], src, 4); + gba->ptr = src; + gba->status = status; + gba->callback = callback; + return __GBATransfer(chan, 5, 1, WriteProc); +} + +s32 GBAWrite(s32 chan, u8* src, u8* status) { + s32 tmp; + GBAControl* gba = &__GBA[chan]; + s32 ret; + ret = GBAWriteAsync(chan, src, status, __GBASyncCallback); + if (ret != GBA_READY) { + return ret; + } + return __GBASync(chan); +} \ No newline at end of file diff --git a/src/dolphin/gba/GBAXfer.c b/src/dolphin/gba/GBAXfer.c new file mode 100644 index 000000000..c1199a7cb --- /dev/null +++ b/src/dolphin/gba/GBAXfer.c @@ -0,0 +1,121 @@ +#include "dolphin/gba/GBAPriv.h" + +static void __GBAHandler(s32 chan, u32 error, OSContext* context) { + GBAControl* gba; + GBATransferCallback proc; + GBACallback callback; + OSContext exceptionContext; + + gba = &__GBA[chan]; + if (__GBAReset != 0) { + return; + } + + if ((error & 0xf)) { + gba->ret = 1; + } else { + gba->ret = 0; + } + + if (gba->proc != NULL) { + proc = gba->proc; + gba->proc = NULL; + proc(chan); + } + + if (gba->callback == NULL) { + return; + } + + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + callback = gba->callback; + gba->callback = NULL; + callback(chan, gba->ret); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); +} + +void __GBASyncCallback(s32 chan, s32 ret) { + GBAControl* gba = &__GBA[chan]; + OSWakeupThread(&gba->threadQueue); +} + +s32 __GBASync(s32 chan) { + GBAControl* gba; + s32 ret; + s32 enabled; + gba = &__GBA[chan]; + + enabled = OSDisableInterrupts(); + while (gba->callback != NULL) { + OSSleepThread(&gba->threadQueue); + } + + ret = gba->ret; + OSRestoreInterrupts(enabled); + + return ret; +} + +void TypeAndStatusCallback(s32 chan, u32 type) { + GBAControl* gba; + GBATransferCallback proc; + GBACallback callback; + OSContext exceptionContext; + OSContext* context; + + gba = &__GBA[chan]; + + if ((type & 0xFF) != 0 || (type & 0xffff0000) != 0x40000) { + gba->ret = GBA_NOT_READY; + } else { + if (SITransfer(chan, gba->output, gba->outputBytes, gba->input, gba->inputBytes, + __GBAHandler, gba->delay)) + { + return; + } + gba->ret = GBA_BUSY; + } + + if (gba->proc != NULL) { + proc = gba->proc; + gba->proc = NULL; + proc(chan); + } + + if (gba->callback != NULL) { + context = OSGetCurrentContext(); + OSClearContext(&exceptionContext); + OSSetCurrentContext(&exceptionContext); + callback = gba->callback; + gba->callback = NULL; + callback(chan, gba->ret); + OSClearContext(&exceptionContext); + OSSetCurrentContext(context); + __OSReschedule(); + } +} + +s32 __GBATransfer(s32 chan, s32 w1, s32 w2, GBATransferCallback callback) { + s32 enabled; + GBAControl* gba; + gba = &__GBA[chan]; + enabled = OSDisableInterrupts(); + gba->proc = callback; + gba->outputBytes = w1; + gba->inputBytes = w2; + SIGetTypeAsync(chan, TypeAndStatusCallback); + OSRestoreInterrupts(enabled); + + return GBA_READY; +} + +OSTime __GBASetDelay(s32 chan, OSTime delay) { + OSTime oldDelay; + GBAControl* gba; + gba = &__GBA[chan]; + oldDelay = gba->delay; + gba->delay = delay; + return oldDelay; +} \ No newline at end of file