mirror of
https://github.com/zeldaret/tww.git
synced 2026-06-19 15:20:36 -04:00
Merge pull request #81 from TakaRikka/dolgba
most of dolphin GBA lib done
This commit is contained in:
+14
-6
@@ -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(
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user