summaryrefslogtreecommitdiff
path: root/src/Dolphin/GBA
diff options
context:
space:
mode:
Diffstat (limited to 'src/Dolphin/GBA')
-rw-r--r--src/Dolphin/GBA/GBA.c109
-rw-r--r--src/Dolphin/GBA/GBAGetProcessStatus.c25
-rw-r--r--src/Dolphin/GBA/GBARead.c42
-rw-r--r--src/Dolphin/GBA/GBAWrite.c42
-rw-r--r--src/Dolphin/GBA/GBAXfer.c163
5 files changed, 381 insertions, 0 deletions
diff --git a/src/Dolphin/GBA/GBA.c b/src/Dolphin/GBA/GBA.c
new file mode 100644
index 0000000..bb89f2e
--- /dev/null
+++ b/src/Dolphin/GBA/GBA.c
@@ -0,0 +1,109 @@
+#include "dolphin/GBAPriv.h"
+
+static GBASecParams SecParams[4];
+GBA __GBA[4];
+BOOL __GBAReset = FALSE;
+
+static BOOL OnReset(BOOL);
+
+static OSResetFunctionInfo ResetFunctionInfo = {
+ OnReset,
+ 127
+};
+
+void ShortCommandProc(s32 chan) {
+ GBA* gba;
+ gba = &__GBA[chan];
+
+ if (gba->result != 0) {
+ return;
+ }
+
+ if (gba->dst[0] != 0 || gba->dst[1] != 4) {
+ gba->result = 1;
+ return;
+ }
+
+ gba->status[0] = gba->dst[2] & GBA_JSTAT_MASK;
+}
+
+void GBAInit() {
+ s32 i;
+ GBA* gba;
+ for (i = 0; i < 4; ++i) {
+ gba = &__GBA[i];
+ gba->delay = OSMicrosecondsToTicks(60);
+ OSInitThreadQueue(&gba->thread_queue);
+ gba->param = &SecParams[i];
+
+ // ASSERTMSG((u32) gba->param % 32 == 0)
+ }
+
+ OSInitAlarm();
+ DSPInit();
+ __GBAReset = FALSE;
+
+ OSRegisterResetFunction(&ResetFunctionInfo);
+}
+
+s32 GBAGetStatusAsync(s32 chan, u8* status, GBACallback callback) {
+ GBA* gba;
+ s32 ret;
+ gba = &__GBA[chan];
+ if (gba->callback != NULL) {
+ ret = GBA_BUSY;
+ } else {
+ gba->command = 0;
+ gba->status = status;
+ gba->callback = callback;
+ ret = __GBATransfer(chan, 1, 3, ShortCommandProc);
+ }
+
+ return ret;
+}
+
+
+s32 GBAGetStatus(s32 chan, u8* status) {
+ s32 ret;
+ ret = GBAGetStatusAsync(chan, status, __GBASyncCallback);
+
+ if (ret != GBA_READY) {
+ return ret;
+ }
+
+ return __GBASync(chan);
+}
+
+
+s32 GBAResetAsync(s32 chan, u8* status, GBACallback callback) {
+ GBA* gba;
+ s32 ret;
+ gba = &__GBA[chan];
+ if (gba->callback != NULL) {
+ ret = GBA_BUSY;
+ } else {
+ gba->command = 0xFF;
+ gba->status = status;
+ gba->callback = callback;
+ ret = __GBATransfer(chan, 1, 3, ShortCommandProc);
+ }
+
+ return ret;
+}
+
+
+s32 GBAReset(s32 chan, u8* status) {
+ s32 ret;
+
+ ret = GBAResetAsync(chan, status, __GBASyncCallback);
+ if (ret != GBA_READY) {
+ return ret;
+ }
+
+ return __GBASync(chan);
+}
+
+BOOL OnReset(BOOL) {
+ __GBAReset = TRUE;
+ return TRUE;
+}
diff --git a/src/Dolphin/GBA/GBAGetProcessStatus.c b/src/Dolphin/GBA/GBAGetProcessStatus.c
new file mode 100644
index 0000000..38d8c38
--- /dev/null
+++ b/src/Dolphin/GBA/GBAGetProcessStatus.c
@@ -0,0 +1,25 @@
+#include "dolphin/GBAPriv.h"
+
+s32 GBAGetProcessStatus(s32 chan, u8* percentp) {
+ GBA* gba;
+ s32 ret;
+ BOOL enabled;
+
+ gba = &__GBA[chan];
+ enabled = OSDisableInterrupts();
+
+ if (gba->jboot_callback == NULL) {
+ if (gba->callback == NULL) {
+ ret = 0;
+ } else {
+ ret = 2;
+ }
+ } else {
+ ret = 2;
+
+ }
+
+ OSRestoreInterrupts(enabled);
+
+ return ret;
+}
diff --git a/src/Dolphin/GBA/GBARead.c b/src/Dolphin/GBA/GBARead.c
new file mode 100644
index 0000000..ab19bbb
--- /dev/null
+++ b/src/Dolphin/GBA/GBARead.c
@@ -0,0 +1,42 @@
+#include "dolphin/GBAPriv.h"
+
+void ReadProc(s32 chan) {
+ GBA* gba;
+ gba = &__GBA[chan];
+
+ if (gba->result == 0) {
+ memcpy(gba->buffer, &gba->dst, 4);
+ gba->status[0] = gba->_09 & GBA_JSTAT_MASK;
+ }
+}
+
+s32 GBAReadAsync(s32 chan, u8* dst, u8* status, GBACallback callback) {
+ GBA* gba;
+ s32 ret;
+
+ gba = &__GBA[chan];
+
+ if (gba->callback != NULL) {
+ ret = 2;
+ } else {
+ gba->command = 0x14;
+ gba->buffer = dst;
+ gba->status = status;
+ gba->callback = callback;
+ ret = __GBATransfer(chan, 1, 5, ReadProc);
+ }
+
+ return ret;
+}
+
+
+s32 GBARead(s32 chan, u8* dst, u8* status) {
+ s32 tmp;
+ s32 ret;
+ ret = GBAReadAsync(chan, dst, status, __GBASyncCallback);
+ if (ret != GBA_READY) {
+ return ret;
+ }
+
+ return __GBASync(chan);
+}
diff --git a/src/Dolphin/GBA/GBAWrite.c b/src/Dolphin/GBA/GBAWrite.c
new file mode 100644
index 0000000..f040f92
--- /dev/null
+++ b/src/Dolphin/GBA/GBAWrite.c
@@ -0,0 +1,42 @@
+#include "dolphin/GBAPriv.h"
+
+void WriteProc(s32 chan) {
+ GBA* gba;
+ gba = &__GBA[chan];
+
+ if (gba->result != 0) {
+ return;
+ }
+
+ gba->status[0] = gba->dst[0] & GBA_JSTAT_MASK;
+}
+
+s32 GBAWriteAsync(s32 chan, u8* src, u8* status, GBACallback callback) {
+ GBA* gba;
+ s32 ret;
+ gba = &__GBA[chan];
+
+ if (gba->callback != NULL) {
+ ret = GBA_BUSY;
+ } else {
+ gba->command = 0x15;
+ memcpy(gba->src, src, 4);
+ gba->buffer = src;
+ gba->status = status;
+ gba->callback = callback;
+ ret = __GBATransfer(chan, 5, 1, WriteProc);
+ }
+
+ return ret;
+}
+
+
+s32 GBAWrite(s32 chan, u8* src, u8* status) {
+ s32 ret;
+ s32 tmp;
+ ret = GBAWriteAsync(chan, src, status, __GBASyncCallback);
+ if (ret != GBA_READY) {
+ return ret;
+ }
+ return __GBASync(chan);
+}
diff --git a/src/Dolphin/GBA/GBAXfer.c b/src/Dolphin/GBA/GBAXfer.c
new file mode 100644
index 0000000..c88ffd1
--- /dev/null
+++ b/src/Dolphin/GBA/GBAXfer.c
@@ -0,0 +1,163 @@
+#include "dolphin/GBAPriv.h"
+#include "dolphin/sipriv.h"
+
+void __GBAHandler(s32 chan, u32 sr, OSContext* context) {
+ int tmp;
+ GBA* gba;
+ OSContext tmpCtx;
+ GBACallback callback;
+ GBATransferCallback xferCallback;
+ gba = &__GBA[chan];
+ if (__GBAReset != 0) {
+ return;
+ }
+
+ if ((sr & 0xf)) {
+ gba->result = 1;
+ } else {
+ gba->result = 0;
+ }
+
+ if (gba->_38 != NULL) {
+ xferCallback = gba->_38;
+ gba->_38 = NULL;
+ xferCallback(chan);
+ }
+
+ if (gba->callback == NULL) {
+ return;
+ }
+
+ OSClearContext(&tmpCtx);
+ OSSetCurrentContext(&tmpCtx);
+ callback = gba->callback;
+ gba->callback = NULL;
+ callback(chan, gba->result);
+ OSClearContext(&tmpCtx);
+ OSSetCurrentContext(context);
+}
+
+void __GBASyncCallback(s32 chan, s32 ret) { OSWakeupThread(&__GBA[chan].thread_queue); }
+
+#ifdef FULL_FRANK
+/* This actually does match, but has an epilogue swap */
+s32 __GBASync(s32 chan) {
+ GBA* gba;
+ s32 enabled;
+ s32 ret;
+ gba = &__GBA[chan];
+
+ enabled = OSDisableInterrupts();
+ while (gba->callback != NULL) {
+ OSSleepThread(&gba->thread_queue);
+ }
+
+ ret = gba->result;
+ OSRestoreInterrupts(enabled);
+
+ return ret;
+}
+#else
+extern void OSSleepThread();
+/* clang-format off */
+#pragma push
+#pragma optimization_level 0
+#pragma optimizewithasm off
+asm s32 __GBASync(s32 chan) {
+ nofralloc
+ mflr r0
+ lis r4, __GBA@ha
+ stw r0, 4(r1)
+ slwi r3, r3, 8
+ addi r0, r4, __GBA@l
+ stwu r1, -0x18(r1)
+ stw r31, 0x14(r1)
+ add r31, r0, r3
+ stw r30, 0x10(r1)
+ bl OSDisableInterrupts
+ mr r30, r3
+ b lbl_803CAD50
+lbl_803CAD48:
+ addi r3, r31, 0x24
+ bl OSSleepThread
+lbl_803CAD50:
+ lwz r0, 0x1c(r31)
+ cmplwi r0, 0
+ bne lbl_803CAD48
+ lwz r31, 0x20(r31)
+ mr r3, r30
+ bl OSRestoreInterrupts
+ mr r3, r31
+ lwz r0, 0x1c(r1)
+ lwz r31, 0x14(r1)
+ lwz r30, 0x10(r1)
+ addi r1, r1, 0x18
+ mtlr r0
+ blr
+}
+/* clang-format on */
+#pragma pop
+#endif
+
+void TypeAndStatusCallback(s32 chan, u32 type) {
+ s32 tmp;
+ GBA* gba;
+ OSContext* context;
+ GBACallback callback;
+ GBATransferCallback xferCallback;
+ OSContext tmpContext;
+ gba = &__GBA[chan];
+ if (__GBAReset != 0) {
+ return;
+ }
+
+ if ((type & 0xFF) != 0 || (type & 0xffff0000) != 0x40000) {
+ gba->result = GBA_NOT_READY;
+ } else {
+ if (SITransfer(chan, &gba->command, gba->_0c, gba->dst, gba->_10, __GBAHandler, gba->delay)) {
+ return;
+ }
+ gba->result = GBA_BUSY;
+ }
+
+ if (gba->_38 != NULL) {
+ xferCallback = gba->_38;
+ gba->_38 = NULL;
+ xferCallback(chan);
+ }
+
+ if (gba->callback != NULL) {
+ context = OSGetCurrentContext();
+ OSClearContext(&tmpContext);
+ OSSetCurrentContext(&tmpContext);
+ callback = gba->callback;
+ gba->callback = NULL;
+ callback(chan, gba->result);
+ OSClearContext(&tmpContext);
+ OSSetCurrentContext(context);
+ __OSReschedule();
+ }
+}
+
+s32 __GBATransfer(s32 chan, s32 w1, s32 w2, GBATransferCallback callback) {
+ s32 enabled;
+ GBA* gba;
+ gba = &__GBA[chan];
+ enabled = OSDisableInterrupts();
+ gba->_38 = callback;
+ gba->_0c = w1;
+ gba->_10 = w2;
+ SIGetTypeAsync(chan, TypeAndStatusCallback);
+ OSRestoreInterrupts(enabled);
+
+ return GBA_READY;
+}
+
+OSTime __GBASetDelay(s32 chan, OSTime delay) {
+ OSTime oldDelay;
+ GBA* gba;
+ gba = &__GBA[chan];
+ oldDelay = gba->delay;
+ gba->delay = delay;
+ return oldDelay;
+}