Add recovered structures for GBA (found in DWARF data)

This commit is contained in:
Phillip Stephens 2023-02-12 18:37:08 -08:00
parent f26e5d41d3
commit d9533cb84b
9 changed files with 158 additions and 135 deletions

View File

@ -244,8 +244,9 @@ lbl_803C98C4:
/* 803C98D0 003C6830 7C 08 03 A6 */ mtlr r0 /* 803C98D0 003C6830 7C 08 03 A6 */ mtlr r0
/* 803C98D4 003C6834 4E 80 00 20 */ blr /* 803C98D4 003C6834 4E 80 00 20 */ blr
OnReset: .fn OnReset, local
/* 803C98D8 003C6838 38 00 00 01 */ li r0, 1 /* 803C98D8 003C6838 38 00 00 01 */ li r0, 1
/* 803C98DC 003C683C 90 0D B1 58 */ stw r0, __GBAReset@sda21(r13) /* 803C98DC 003C683C 90 0D B1 58 */ stw r0, __GBAReset@sda21(r13)
/* 803C98E0 003C6840 38 60 00 01 */ li r3, 1 /* 803C98E0 003C6840 38 60 00 01 */ li r3, 1
/* 803C98E4 003C6844 4E 80 00 20 */ blr /* 803C98E4 003C6844 4E 80 00 20 */ blr
.endfn OnReset

View File

@ -70,8 +70,7 @@ lbl_803F752C:
.section .text, "ax" .section .text, "ax"
.global __F23 .fn F23, local
__F23:
/* 803CAF40 003C7EA0 7C 08 02 A6 */ mflr r0 /* 803CAF40 003C7EA0 7C 08 02 A6 */ mflr r0
/* 803CAF44 003C7EA4 3C 80 80 57 */ lis r4, __GBA@ha /* 803CAF44 003C7EA4 3C 80 80 57 */ lis r4, __GBA@ha
/* 803CAF48 003C7EA8 90 01 00 04 */ stw r0, 4(r1) /* 803CAF48 003C7EA8 90 01 00 04 */ stw r0, 4(r1)
@ -134,9 +133,9 @@ lbl_803CAFFC:
/* 803CB010 003C7F70 38 21 00 20 */ addi r1, r1, 0x20 /* 803CB010 003C7F70 38 21 00 20 */ addi r1, r1, 0x20
/* 803CB014 003C7F74 7C 08 03 A6 */ mtlr r0 /* 803CB014 003C7F74 7C 08 03 A6 */ mtlr r0
/* 803CB018 003C7F78 4E 80 00 20 */ blr /* 803CB018 003C7F78 4E 80 00 20 */ blr
.endfn F23
.global __F25 .fn F25, local
__F25:
/* 803CB01C 003C7F7C 3C 80 80 57 */ lis r4, __GBA@ha /* 803CB01C 003C7F7C 3C 80 80 57 */ lis r4, __GBA@ha
/* 803CB020 003C7F80 7C 08 02 A6 */ mflr r0 /* 803CB020 003C7F80 7C 08 02 A6 */ mflr r0
/* 803CB024 003C7F84 38 84 A1 A0 */ addi r4, r4, __GBA@l /* 803CB024 003C7F84 38 84 A1 A0 */ addi r4, r4, __GBA@l
@ -184,9 +183,9 @@ lbl_803CB0A8:
/* 803CB0B8 003C8018 38 21 00 08 */ addi r1, r1, 8 /* 803CB0B8 003C8018 38 21 00 08 */ addi r1, r1, 8
/* 803CB0BC 003C801C 7C 08 03 A6 */ mtlr r0 /* 803CB0BC 003C801C 7C 08 03 A6 */ mtlr r0
/* 803CB0C0 003C8020 4E 80 00 20 */ blr /* 803CB0C0 003C8020 4E 80 00 20 */ blr
.endfn F25
.global __GBAX02 .fn __GBAX02
__GBAX02:
/* 803CB0C4 003C8024 7C 08 02 A6 */ mflr r0 /* 803CB0C4 003C8024 7C 08 02 A6 */ mflr r0
/* 803CB0C8 003C8028 3C A0 80 57 */ lis r5, __GBA@ha /* 803CB0C8 003C8028 3C A0 80 57 */ lis r5, __GBA@ha
/* 803CB0CC 003C802C 90 01 00 04 */ stw r0, 4(r1) /* 803CB0CC 003C802C 90 01 00 04 */ stw r0, 4(r1)
@ -222,15 +221,15 @@ __GBAX02:
/* 803CB144 003C80A4 3C 04 80 00 */ addis r0, r4, 0x8000 /* 803CB144 003C80A4 3C 04 80 00 */ addis r0, r4, 0x8000
/* 803CB148 003C80A8 90 1F 00 B4 */ stw r0, 0xb4(r31) /* 803CB148 003C80A8 90 1F 00 B4 */ stw r0, 0xb4(r31)
/* 803CB14C 003C80AC 38 00 03 80 */ li r0, 0x380 /* 803CB14C 003C80AC 38 00 03 80 */ li r0, 0x380
/* 803CB150 003C80B0 3C A0 80 3D */ lis r5, __F23@ha /* 803CB150 003C80B0 3C A0 80 3D */ lis r5, F23@ha
/* 803CB154 003C80B4 90 1F 00 B8 */ stw r0, 0xb8(r31) /* 803CB154 003C80B4 90 1F 00 B8 */ stw r0, 0xb8(r31)
/* 803CB158 003C80B8 38 C0 00 00 */ li r6, 0 /* 803CB158 003C80B8 38 C0 00 00 */ li r6, 0
/* 803CB15C 003C80BC 38 00 00 10 */ li r0, 0x10 /* 803CB15C 003C80BC 38 00 00 10 */ li r0, 0x10
/* 803CB160 003C80C0 90 DF 00 BC */ stw r6, 0xbc(r31) /* 803CB160 003C80C0 90 DF 00 BC */ stw r6, 0xbc(r31)
/* 803CB164 003C80C4 38 A5 AF 40 */ addi r5, r5, __F23@l /* 803CB164 003C80C4 38 A5 AF 40 */ addi r5, r5, F23@l
/* 803CB168 003C80C8 3C 80 80 3D */ lis r4, __F25@ha /* 803CB168 003C80C8 3C 80 80 3D */ lis r4, F25@ha
/* 803CB16C 003C80CC B0 1F 00 CC */ sth r0, 0xcc(r31) /* 803CB16C 003C80CC B0 1F 00 CC */ sth r0, 0xcc(r31)
/* 803CB170 003C80D0 38 04 B0 1C */ addi r0, r4, __F25@l /* 803CB170 003C80D0 38 04 B0 1C */ addi r0, r4, F25@l
/* 803CB174 003C80D4 38 7F 00 A8 */ addi r3, r31, 0xa8 /* 803CB174 003C80D4 38 7F 00 A8 */ addi r3, r31, 0xa8
/* 803CB178 003C80D8 90 BF 00 D0 */ stw r5, 0xd0(r31) /* 803CB178 003C80D8 90 BF 00 D0 */ stw r5, 0xd0(r31)
/* 803CB17C 003C80DC 90 DF 00 D4 */ stw r6, 0xd4(r31) /* 803CB17C 003C80DC 90 DF 00 D4 */ stw r6, 0xd4(r31)
@ -244,3 +243,4 @@ __GBAX02:
/* 803CB19C 003C80FC 38 21 00 20 */ addi r1, r1, 0x20 /* 803CB19C 003C80FC 38 21 00 20 */ addi r1, r1, 0x20
/* 803CB1A0 003C8100 7C 08 03 A6 */ mtlr r0 /* 803CB1A0 003C8100 7C 08 03 A6 */ mtlr r0
/* 803CB1A4 003C8104 4E 80 00 20 */ blr /* 803CB1A4 003C8104 4E 80 00 20 */ blr
.endfn __GBAX02

View File

@ -5,6 +5,7 @@
#include <dolphin/gba.h> #include <dolphin/gba.h>
#include <dolphin/os.h> #include <dolphin/os.h>
#include <dolphin/dsp.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -13,43 +14,60 @@ extern "C" {
typedef void (*GBATransferCallback)(s32 chan); typedef void (*GBATransferCallback)(s32 chan);
typedef struct GBASecParams { typedef struct GBASecParams {
u8 data[0x40]; u8 readbuf[4];
s32 paletteColor;
s32 paletteSpeed;
s32 length;
u32* out;
u8 _padding0[12];
u32 keyA;
s32 keyB;
u8 _padding1[24];
} GBASecParams; } GBASecParams;
typedef struct GBA { typedef struct GBABootInfo {
u8 command; s32 paletteColor;
u8 src[4]; s32 paletteSpeed;
u8 dst[4]; u8* programp;
u8 _09; s32 length;
s8 _0a;
s8 _0b;
s32 _0c;
s32 _10;
u8* status; u8* status;
u8* buffer;
GBACallback callback; GBACallback callback;
s32 result; u8 readbuf[4];
OSThreadQueue thread_queue; u8 writebuf[4];
OSTime delay; int i;
GBATransferCallback _38; OSTick start;
s32 _3c; OSTime begin;
s32 palette_color; int firstXfer;
s32 palette_speed; int curOffset;
u8* program; u32 crc;
s32 program_length; u32 dummyWord[7];
s32 jboot_status; u32 keyA;
GBACallback jboot_callback; u32 keyB;
char data2[0x74u - 0x58u]; u32 initialCode;
u8* challenge_cipher; int realLength;
char data3[0xf8 - 0x78u]; } GBABootInfo;
GBASecParams* param;
char data4[0x100u - 0xfcu];
} GBA;
extern GBA __GBA[4]; 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;
GBASecParams* param;
} GBAControl;
extern GBAControl __GBA[4];
extern BOOL __GBAReset; extern BOOL __GBAReset;
void __GBAHandler(s32 chan, u32 sr, OSContext* context); void __GBAHandler(s32 chan, u32 error, OSContext* context);
void __GBASyncCallback(s32 chan, s32 ret); void __GBASyncCallback(s32 chan, s32 ret);
s32 __GBASync(s32 chan); s32 __GBASync(s32 chan);
OSTime __GBASetDelay(s32 chan, OSTime delay); OSTime __GBASetDelay(s32 chan, OSTime delay);

View File

@ -19,9 +19,7 @@ extern "C" {
typedef void (*DSPCallback)(void* task); typedef void (*DSPCallback)(void* task);
typedef struct DSPTaskInfo DSPTaskInfo; typedef struct STRUCT_DSP_TASK {
typedef struct DSPTaskInfo {
vu32 state; vu32 state;
vu32 priority; vu32 priority;
vu32 flags; vu32 flags;
@ -41,8 +39,8 @@ typedef struct DSPTaskInfo {
DSPCallback done_cb; DSPCallback done_cb;
DSPCallback req_cb; DSPCallback req_cb;
struct DSPTaskInfo* next; struct STRUCT_DSP_TASK* next;
struct DSPTaskInfo* prev; struct STRUCT_DSP_TASK* prev;
OSTime t_context; OSTime t_context;
OSTime t_task; OSTime t_task;

View File

@ -1,7 +1,7 @@
#include "dolphin/GBAPriv.h" #include "dolphin/GBAPriv.h"
static GBASecParams SecParams[4]; static GBASecParams SecParams[4];
GBA __GBA[4]; GBAControl __GBA[4];
BOOL __GBAReset = FALSE; BOOL __GBAReset = FALSE;
static BOOL OnReset(BOOL); static BOOL OnReset(BOOL);
@ -12,29 +12,30 @@ static OSResetFunctionInfo ResetFunctionInfo = {
}; };
void ShortCommandProc(s32 chan) { void ShortCommandProc(s32 chan) {
GBA* gba; GBAControl* gba;
gba = &__GBA[chan]; gba = &__GBA[chan];
if (gba->result != 0) { if (gba->ret != 0) {
return; return;
} }
if (gba->dst[0] != 0 || gba->dst[1] != 4) { if (gba->input[0] != 0 || gba->input[1] != 4) {
gba->result = 1; gba->ret = 1;
return; return;
} }
gba->status[0] = gba->dst[2] & GBA_JSTAT_MASK; gba->status[0] = gba->input[2] & GBA_JSTAT_MASK;
} }
void GBAInit() { void GBAInit() {
s32 i; GBAControl* gba;
GBA* gba; s32 chan;
for (i = 0; i < 4; ++i) {
gba = &__GBA[i]; for (chan = 0; chan < 4; ++chan) {
gba = &__GBA[chan];
gba->delay = OSMicrosecondsToTicks(60); gba->delay = OSMicrosecondsToTicks(60);
OSInitThreadQueue(&gba->thread_queue); OSInitThreadQueue(&gba->threadQueue);
gba->param = &SecParams[i]; gba->param = &SecParams[chan];
// ASSERTMSG((u32) gba->param % 32 == 0) // ASSERTMSG((u32) gba->param % 32 == 0)
} }
@ -47,42 +48,34 @@ void GBAInit() {
} }
s32 GBAGetStatusAsync(s32 chan, u8* status, GBACallback callback) { s32 GBAGetStatusAsync(s32 chan, u8* status, GBACallback callback) {
GBA* gba; GBAControl* gba;
s32 ret;
gba = &__GBA[chan]; gba = &__GBA[chan];
if (gba->callback != NULL) { if (gba->callback != NULL) {
ret = GBA_BUSY; return GBA_BUSY;
} else {
gba->command = 0;
gba->status = status;
gba->callback = callback;
ret = __GBATransfer(chan, 1, 3, ShortCommandProc);
} }
return ret; gba->output[0] = 0;
gba->status = status;
gba->callback = callback;
return __GBATransfer(chan, 1, 3, ShortCommandProc);
} }
s32 GBAGetStatus(s32 chan, u8* status) { s32 GBAGetStatus(s32 chan, u8* status) {
s32 ret; GBAControl* gba = &__GBA[chan];
ret = GBAGetStatusAsync(chan, status, __GBASyncCallback); s32 ret = GBAGetStatusAsync(chan, status, __GBASyncCallback);
return ret != GBA_READY ? ret : __GBASync(chan);
if (ret != GBA_READY) {
return ret;
}
return __GBASync(chan);
} }
s32 GBAResetAsync(s32 chan, u8* status, GBACallback callback) { s32 GBAResetAsync(s32 chan, u8* status, GBACallback callback) {
GBA* gba; GBAControl* gba;
s32 ret; s32 ret;
gba = &__GBA[chan]; gba = &__GBA[chan];
if (gba->callback != NULL) { if (gba->callback != NULL) {
ret = GBA_BUSY; ret = GBA_BUSY;
} else { } else {
gba->command = 0xFF; gba->output[0] = 0xFF;
gba->status = status; gba->status = status;
gba->callback = callback; gba->callback = callback;
ret = __GBATransfer(chan, 1, 3, ShortCommandProc); ret = __GBATransfer(chan, 1, 3, ShortCommandProc);

View File

@ -1,22 +1,35 @@
#include "dolphin/GBAPriv.h" #include "dolphin/GBAPriv.h"
s32 GBAGetProcessStatus(s32 chan, u8* percentp) { s32 GBAGetProcessStatus(s32 chan, u8* percentp) {
GBA* gba; BOOL enabled;
s32 ret; s32 ret; // r29
BOOL enabled; GBAControl * gba; // r25
GBABootInfo * bootInfo; // r31
u8 percent; // r30
OSTime t; // r27
gba = &__GBA[chan]; gba = &__GBA[chan];
bootInfo = &gba->bootInfo;
enabled = OSDisableInterrupts(); enabled = OSDisableInterrupts();
if (gba->jboot_callback == NULL) { if (bootInfo->callback != NULL) {
if (gba->callback == NULL) {
ret = 0;
} else {
ret = 2;
}
} else {
ret = 2; ret = 2;
percent = (bootInfo->curOffset * 100) / bootInfo->realLength;
if (bootInfo->begin != 0) {
t = OSGetTime();
if (t - bootInfo->begin < OSMillisecondsToTicks(5500)) {
percentp = 0;
}
}
if (percentp != NULL) {
*percentp = percent;
}
} else if (gba->callback != NULL) {
ret = 2;
} else {
ret = 0;
} }
OSRestoreInterrupts(enabled); OSRestoreInterrupts(enabled);

View File

@ -1,17 +1,17 @@
#include "dolphin/GBAPriv.h" #include "dolphin/GBAPriv.h"
void ReadProc(s32 chan) { void ReadProc(s32 chan) {
GBA* gba; GBAControl* gba;
gba = &__GBA[chan]; gba = &__GBA[chan];
if (gba->result == 0) { if (gba->ret == 0) {
memcpy(gba->buffer, &gba->dst, 4); memcpy(gba->ptr, gba->input, 4);
gba->status[0] = gba->_09 & GBA_JSTAT_MASK; gba->status[0] = gba->input[4] & GBA_JSTAT_MASK;
} }
} }
s32 GBAReadAsync(s32 chan, u8* dst, u8* status, GBACallback callback) { s32 GBAReadAsync(s32 chan, u8* dst, u8* status, GBACallback callback) {
GBA* gba; GBAControl* gba;
s32 ret; s32 ret;
gba = &__GBA[chan]; gba = &__GBA[chan];
@ -19,8 +19,8 @@ s32 GBAReadAsync(s32 chan, u8* dst, u8* status, GBACallback callback) {
if (gba->callback != NULL) { if (gba->callback != NULL) {
ret = 2; ret = 2;
} else { } else {
gba->command = 0x14; gba->output[0] = 0x14;
gba->buffer = dst; gba->ptr = dst;
gba->status = status; gba->status = status;
gba->callback = callback; gba->callback = callback;
ret = __GBATransfer(chan, 1, 5, ReadProc); ret = __GBATransfer(chan, 1, 5, ReadProc);

View File

@ -1,27 +1,27 @@
#include "dolphin/GBAPriv.h" #include "dolphin/GBAPriv.h"
void WriteProc(s32 chan) { void WriteProc(s32 chan) {
GBA* gba; GBAControl* gba;
gba = &__GBA[chan]; gba = &__GBA[chan];
if (gba->result != 0) { if (gba->ret != 0) {
return; return;
} }
gba->status[0] = gba->dst[0] & GBA_JSTAT_MASK; gba->status[0] = gba->input[0] & GBA_JSTAT_MASK;
} }
s32 GBAWriteAsync(s32 chan, u8* src, u8* status, GBACallback callback) { s32 GBAWriteAsync(s32 chan, u8* src, u8* status, GBACallback callback) {
GBA* gba; GBAControl* gba;
s32 ret; s32 ret;
gba = &__GBA[chan]; gba = &__GBA[chan];
if (gba->callback != NULL) { if (gba->callback != NULL) {
ret = GBA_BUSY; ret = GBA_BUSY;
} else { } else {
gba->command = 0x15; gba->output[0] = 0x15;
memcpy(gba->src, src, 4); memcpy(&gba->output[1], src, 4);
gba->buffer = src; gba->ptr = src;
gba->status = status; gba->status = status;
gba->callback = callback; gba->callback = callback;
ret = __GBATransfer(chan, 5, 1, WriteProc); ret = __GBATransfer(chan, 5, 1, WriteProc);

View File

@ -1,56 +1,56 @@
#include "dolphin/GBAPriv.h" #include "dolphin/GBAPriv.h"
#include "dolphin/sipriv.h" #include "dolphin/sipriv.h"
void __GBAHandler(s32 chan, u32 sr, OSContext* context) { void __GBAHandler(s32 chan, u32 error, OSContext* context) {
int tmp; GBAControl* gba;
GBA* gba; GBATransferCallback proc;
OSContext tmpCtx;
GBACallback callback; GBACallback callback;
GBATransferCallback xferCallback; OSContext exceptionContext;
gba = &__GBA[chan]; gba = &__GBA[chan];
if (__GBAReset != 0) { if (__GBAReset != 0) {
return; return;
} }
if ((sr & 0xf)) { if ((error & 0xf)) {
gba->result = 1; gba->ret = 1;
} else { } else {
gba->result = 0; gba->ret = 0;
} }
if (gba->_38 != NULL) { if (gba->proc != NULL) {
xferCallback = gba->_38; proc = gba->proc;
gba->_38 = NULL; gba->proc = NULL;
xferCallback(chan); proc(chan);
} }
if (gba->callback == NULL) { if (gba->callback == NULL) {
return; return;
} }
OSClearContext(&tmpCtx); OSClearContext(&exceptionContext);
OSSetCurrentContext(&tmpCtx); OSSetCurrentContext(&exceptionContext);
callback = gba->callback; callback = gba->callback;
gba->callback = NULL; gba->callback = NULL;
callback(chan, gba->result); callback(chan, gba->ret);
OSClearContext(&tmpCtx); OSClearContext(&exceptionContext);
OSSetCurrentContext(context); OSSetCurrentContext(context);
} }
void __GBASyncCallback(s32 chan, s32 ret) { OSWakeupThread(&__GBA[chan].thread_queue); } void __GBASyncCallback(s32 chan, s32 ret) { OSWakeupThread(&__GBA[chan].threadQueue); }
s32 __GBASync(s32 chan) { s32 __GBASync(s32 chan) {
GBA* gba; GBAControl* gba;
s32 enabled; s32 enabled;
s32 ret; s32 ret;
gba = &__GBA[chan]; gba = &__GBA[chan];
enabled = OSDisableInterrupts(); enabled = OSDisableInterrupts();
while (gba->callback != NULL) { while (gba->callback != NULL) {
OSSleepThread(&gba->thread_queue); OSSleepThread(&gba->threadQueue);
} }
ret = gba->result; ret = gba->ret;
OSRestoreInterrupts(enabled); OSRestoreInterrupts(enabled);
return ret; return ret;
@ -58,7 +58,7 @@ s32 __GBASync(s32 chan) {
void TypeAndStatusCallback(s32 chan, u32 type) { void TypeAndStatusCallback(s32 chan, u32 type) {
s32 tmp; s32 tmp;
GBA* gba; GBAControl* gba;
OSContext* context; OSContext* context;
GBACallback callback; GBACallback callback;
GBATransferCallback xferCallback; GBATransferCallback xferCallback;
@ -69,17 +69,17 @@ void TypeAndStatusCallback(s32 chan, u32 type) {
} }
if ((type & 0xFF) != 0 || (type & 0xffff0000) != 0x40000) { if ((type & 0xFF) != 0 || (type & 0xffff0000) != 0x40000) {
gba->result = GBA_NOT_READY; gba->ret = GBA_NOT_READY;
} else { } else {
if (SITransfer(chan, &gba->command, gba->_0c, gba->dst, gba->_10, __GBAHandler, gba->delay)) { if (SITransfer(chan, gba->output, gba->outputBytes, gba->input, gba->inputBytes, __GBAHandler, gba->delay)) {
return; return;
} }
gba->result = GBA_BUSY; gba->ret = GBA_BUSY;
} }
if (gba->_38 != NULL) { if (gba->proc != NULL) {
xferCallback = gba->_38; xferCallback = gba->proc;
gba->_38 = NULL; gba->proc = NULL;
xferCallback(chan); xferCallback(chan);
} }
@ -89,7 +89,7 @@ void TypeAndStatusCallback(s32 chan, u32 type) {
OSSetCurrentContext(&tmpContext); OSSetCurrentContext(&tmpContext);
callback = gba->callback; callback = gba->callback;
gba->callback = NULL; gba->callback = NULL;
callback(chan, gba->result); callback(chan, gba->ret);
OSClearContext(&tmpContext); OSClearContext(&tmpContext);
OSSetCurrentContext(context); OSSetCurrentContext(context);
__OSReschedule(); __OSReschedule();
@ -98,12 +98,12 @@ void TypeAndStatusCallback(s32 chan, u32 type) {
s32 __GBATransfer(s32 chan, s32 w1, s32 w2, GBATransferCallback callback) { s32 __GBATransfer(s32 chan, s32 w1, s32 w2, GBATransferCallback callback) {
s32 enabled; s32 enabled;
GBA* gba; GBAControl* gba;
gba = &__GBA[chan]; gba = &__GBA[chan];
enabled = OSDisableInterrupts(); enabled = OSDisableInterrupts();
gba->_38 = callback; gba->proc = callback;
gba->_0c = w1; gba->outputBytes = w1;
gba->_10 = w2; gba->inputBytes = w2;
SIGetTypeAsync(chan, TypeAndStatusCallback); SIGetTypeAsync(chan, TypeAndStatusCallback);
OSRestoreInterrupts(enabled); OSRestoreInterrupts(enabled);
@ -112,7 +112,7 @@ s32 __GBATransfer(s32 chan, s32 w1, s32 w2, GBATransferCallback callback) {
OSTime __GBASetDelay(s32 chan, OSTime delay) { OSTime __GBASetDelay(s32 chan, OSTime delay) {
OSTime oldDelay; OSTime oldDelay;
GBA* gba; GBAControl* gba;
gba = &__GBA[chan]; gba = &__GBA[chan];
oldDelay = gba->delay; oldDelay = gba->delay;
gba->delay = delay; gba->delay = delay;