oot/src/n64dd/z_n64dd.c

583 lines
14 KiB
C

// Main interface for the 64DD from the rest of the game. Starts background
// threads and provides functions to submit commands to them.
#include "global.h"
#include "fault.h"
#include "n64dd.h"
#include "stack.h"
#include "versions.h"
#include "line_numbers.h"
#pragma increment_block_number "ntsc-1.0:128 ntsc-1.1:128 ntsc-1.2:128 pal-1.0:128 pal-1.1:128"
typedef struct struct_801D9C30 {
/* 0x000 */ s32 unk_000; // disk start
/* 0x004 */ s32 unk_004; // disk end
/* 0x008 */ uintptr_t unk_008; // ram start
/* 0x00C */ uintptr_t unk_00C; // ram end
/* 0x010 */ UNK_PTR unk_010;
/* 0x014 */ char unk_014[0x104];
} struct_801D9C30; // size = 0x118
typedef struct struct_801D9B90 {
/* 0x00 */ OSMesg unk_00[30];
/* 0x78 */ OSMesgQueue unk_78;
/* 0x90 */ IrqMgrClient unk_90;
/* 0x98 */ IrqMgr* unk_98;
} struct_801D9B90; // size = 0x9C
s32 func_801C7A1C(struct_801E0D18* arg0);
void* D_801D2E50 = &B_801DC000;
s32 (*D_801D2E54)(struct_801E0D18*) = func_801C7A1C;
struct_801D9B90 B_801D9B90;
struct_801D9C30 B_801D9C30;
struct_801D9C30* B_801D9D48;
struct_801D9D50 B_801D9D50;
OSMesgQueue B_801D9D80;
OSMesgQueue B_801D9D98;
OSMesg B_801D9DB0[1];
OSMesg B_801D9DB4[1];
volatile u8 B_801D9DB8;
volatile OSTime B_801D9DC0;
s32 B_801D9DC8; // 1 if disk gameName is correct, 2 otherwise
void* B_801D9DCC;
void* B_801D9DD0;
void* B_801D9DD4;
OSThread B_801D9DD8;
STACK(B_801D9F88, 0x1000);
StackEntry B_801DAF88;
STACK(B_801DAFA8, 0x1000);
StackEntry B_801DBFA8;
UNK_TYPE B_801DBFC4; // unused?
u32 func_801C6E80(void) {
#if OOT_NTSC
return LeoDriveExist();
#else
return 0;
#endif
}
void func_801C6EA0(Gfx** gfxP) {
}
void func_801C6EAC(void) {
if (D_80121214 == 0) {
func_800F6BDC();
D_80121214 = 1;
}
}
s32 func_801C6EF0(void) {
return D_80121214 != 0;
}
s32 func_801C6F08(void) {
if (D_80121214 != 0) {
return 1;
}
return 1;
}
void func_801C6F30(void) {
func_801C6EAC();
while (func_801C6F08() == 0) {
Sleep_Usec(16666); // 100000 / 6
}
}
void func_801C6F78(void) {
if (D_80121214 != 0) {
D_80121214 = 0;
func_800F6B3C();
}
}
// boolean
s32 func_801C6FAC(void) {
if (D_80121213 == 0) {
return false;
} else {
D_80121213 = 0;
return true;
}
}
void func_801C6FD8(void) {
while (!func_801C6FAC()) {
Sleep_Usec(16666); // 100000 / 6
}
}
// Adds a HungupAndCrash
void func_801C7018(void) {
if (D_80121213 != 0) {
Fault_AddHungupAndCrash("../z_n64dd.c", LN2(503, 551, 573));
}
D_80121213 = 1;
}
s32 func_801C7064(void) {
B_801D9D50.unk_00 = 5;
return (&func_801C8000)(&B_801D9D50);
}
s32 func_801C7098(void) {
s32 phi_v1;
#if OOT_VERSION < PAL_1_0
if (0) {}
#endif
B_801D9D50.unk_00 = 10;
phi_v1 = (&func_801C8000)(&B_801D9D50);
if (phi_v1 < 0) {
func_800D31A0();
}
return phi_v1;
}
s32 func_801C70E4(void) {
return B_801D9DC8 == 1;
}
// Used by EnMag and FileChoose
s32 func_801C70FC(void) {
return func_801C70E4();
}
void func_801C711C(void* arg) {
static void* B_801DBFC8;
struct_801D9B90* arg0 = (struct_801D9B90*)arg;
s16* sp58;
s32 var_s0;
void* temp_v0;
sp58 = NULL;
arg0->unk_98 = &gIrqMgr;
osCreateMesgQueue(&arg0->unk_78, arg0->unk_00, ARRAY_COUNT(arg0->unk_00));
IrqMgr_AddClient(arg0->unk_98, &arg0->unk_90, &arg0->unk_78);
var_s0 = 0;
do {
osRecvMesg(&arg0->unk_78, (OSMesg*)&sp58, OS_MESG_BLOCK);
switch (*sp58) {
case 1:
temp_v0 = osViGetNextFramebuffer();
if (B_801DBFC8 != temp_v0) {
B_801DBFC8 = temp_v0;
B_801D9DB8 = 1;
}
func_801C8AA8();
break;
case 4:
LeoReset();
break;
case 3:
var_s0 = 1;
break;
}
} while (var_s0 == 0);
IrqMgr_RemoveClient(arg0->unk_98, &arg0->unk_90);
}
#if OOT_VERSION >= NTSC_1_1
void func_801C7B28_ne2(void) {
s32 temp;
if (B_801D9DC0 != 0) {
temp = (osGetTime() - B_801D9DC0) * 64 / 3000;
if (1000000 - temp > 0) {
Sleep_Usec(1000000 - temp);
}
}
}
#endif
void func_801C7268(void) {
s32 pad;
s32 sp20;
s32 sp1C;
sp20 = func_801C6EF0();
if (sp20 == 0) {
func_801C6F30();
}
B_801D9DB8 = 1;
B_801D9DC0 = 0;
if (func_801C7064() == 1) {
func_801C7098();
} else if (B_801D9DC8 != 0) {
B_801D9DC8 = 0;
}
#if OOT_VERSION < NTSC_1_1
if (B_801D9DC0 != 0) {
sp1C = (osGetTime() - B_801D9DC0) * 64 / 3000;
// Remnants from debug statements?
(void)(osGetTime() - B_801D9DC0);
(void)((osGetTime() - B_801D9DC0) * 64 / 3000);
(void)((osGetTime() - B_801D9DC0) * 64 / 3000);
if (1000000 - sp1C > 0) {
Sleep_Usec(1000000 - sp1C);
}
}
#else
if (D_801D2EA8 == 1 || B_801E0F60 == 1 || B_801E0F64 == 1) {
B_801D9DC0 = osGetTime();
}
func_801C7B28_ne2();
#endif
if (sp20 == 0) {
func_801C6F78();
}
}
// Clears framebuffer
void func_801C7438(void* arg0) {
u16* var_v0;
for (var_v0 = (u16*)arg0; var_v0 < (u16*)arg0 + SCREEN_WIDTH * SCREEN_HEIGHT; var_v0++) {
*var_v0 = 1;
}
}
void func_801C746C(void* arg0, void* arg1, void* arg2) {
void* sp2C;
if (arg0 != NULL || arg1 != NULL || arg2 != NULL) {
sp2C = (u8*)osViGetNextFramebuffer() + 0x20000000;
if ((u32)sp2C & 0xFFFFFF) {
if (B_801D9DB8 != 0) {
B_801D9DB8 = 0;
func_801C7438(sp2C);
B_801D9DC0 = osGetTime();
}
if (arg0 != NULL) {
func_801CA1F0(arg0, 96, 32, 192, 16, 11, sp2C, SCREEN_WIDTH);
}
if (arg1 != NULL) {
func_801CA1F0(arg1, 0, 80, 320, 64, 11, sp2C, SCREEN_WIDTH);
}
if (arg2 != NULL) {
func_801CA1F0(arg2, 0, 176, 320, 32, 11, sp2C, SCREEN_WIDTH);
}
#if OOT_VERSION < PAL_1_0
osViBlack(0);
#endif
}
}
}
void func_801C75BC(void* arg0, void* arg1, void* arg2) {
s32 temp;
if (arg0 == NULL && arg1 == NULL && arg2 == NULL) {
return;
}
if (B_801D9DB8) {}
if (arg0 != 0) {
B_801D9DCC = arg0;
}
if (arg1 != 0) {
B_801D9DD0 = arg1;
}
if (arg2 != 0) {
B_801D9DD4 = arg2;
}
func_801C746C(arg0, arg1, arg2);
}
void func_801C761C(void) {
Sleep_Msec(100);
func_801C746C(B_801D9DCC, B_801D9DD0, B_801D9DD4);
}
s32 func_801C7658(void) {
if (D_80121212 != 0) {
return 0;
}
#if OOT_VERSION < PAL_1_0
StackCheck_Init(&B_801DAF88, B_801D9F88, STACK_TOP(B_801D9F88), 0, 0x100, "ddmsg");
osCreateThread(&B_801D9DD8, THREAD_ID_DDMSG, &func_801C711C, &B_801D9B90, STACK_TOP(B_801D9F88), THREAD_PRI_DDMSG);
osStartThread(&B_801D9DD8);
#endif
osCreateMesgQueue(&B_801D9D80, B_801D9DB0, ARRAY_COUNT(B_801D9DB0));
osCreateMesgQueue(&B_801D9D98, B_801D9DB4, ARRAY_COUNT(B_801D9DB4));
StackCheck_Init(&B_801DBFA8, B_801DAFA8, STACK_TOP(B_801DAFA8), 0, 0x100, "n64dd");
B_801D9D50.unk_1C = &B_801D9D80;
B_801D9D50.unk_20 = &B_801D9D98;
B_801D9D50.unk_24 = THREAD_ID_N64DD;
B_801D9D50.unk_28 = STACK_TOP(B_801DAFA8);
B_801D9D50.unk_2C = THREAD_PRI_N64DD;
B_801D9D50.unk_00 = 1;
(&func_801C8000)(&B_801D9D50);
D_80121213 = 1;
func_801C6FD8();
B_801D9D50.unk_00 = 2;
B_801D9D50.unk_10 = 6;
B_801D9D50.unk_14 = &DmaMgr_DmaFromDriveRom;
B_801D9D50.unk_0C = &func_801C75BC;
(&func_801C8000)(&B_801D9D50);
B_801D9D50.unk_00 = 13;
(&func_801C8000)(&B_801D9D50);
#if OOT_VERSION >= PAL_1_0
StackCheck_Init(&B_801DAF88, B_801D9F88, STACK_TOP(B_801D9F88), 0, 0x100, "ddmsg");
osCreateThread(&B_801D9DD8, THREAD_ID_DDMSG, &func_801C711C, &B_801D9B90, STACK_TOP(B_801D9F88), THREAD_PRI_DDMSG);
osStartThread(&B_801D9DD8);
#endif
return 0;
}
s32 func_801C7818(void) {
#if OOT_VERSION >= NTSC_1_1
B_801D9DB8 = 1;
B_801D9DC0 = 0;
#endif
B_801D9D50.unk_00 = 12;
(&func_801C8000)(&B_801D9D50);
while (func_801C81C4() == 0) {
// the number 16666 sounds like it could be 1 frame (at 60 frames per second)
Sleep_Usec(1000000 * 1 / 60);
}
#if OOT_VERSION >= NTSC_1_1
if (D_801D2EA8 == 1 || B_801E0F60 == 1 || B_801E0F64 == 1) {
B_801D9DC0 = osGetTime();
}
func_801C7B28_ne2();
#endif
if (func_801C81C4() != 2) {
func_801C761C();
func_800D31A0();
return -3;
}
func_801C7018();
D_80121212 = 1;
return 0;
}
s32 func_801C78B8(void) {
s32 phi_v1 = func_801C7658();
if (phi_v1 == 0) {
phi_v1 = func_801C7818();
}
return phi_v1;
}
s32 func_801C78F0(void) {
B_801D9D50.unk_00 = 0;
return (&func_801C8000)(&B_801D9D50);
}
void func_801C7920(s32 arg0, void* arg1, s32 arg2) {
B_801D9D50.unk_18 = arg1;
B_801D9D50.unk_1C = (void*)arg0;
B_801D9D50.unk_20 = (void*)arg2;
B_801D9D50.unk_00 = 3;
(&func_801C8000)(&B_801D9D50);
osGetTime();
B_801D9D50.unk_00 = 6;
while ((&func_801C8000)(&B_801D9D50) != 0) {
Sleep_Usec(16666); // 100000 / 6
}
B_801D9D50.unk_00 = 7;
if ((&func_801C8000)(&B_801D9D50) != 0) {
func_800D31A0();
}
}
void func_801C79CC(void* arg0, s32 arg1, s32 arg2) {
B_801D9D50.unk_18 = arg0;
B_801D9D50.unk_1C = (void*)arg1;
B_801D9D50.unk_20 = (void*)arg2;
B_801D9D50.unk_00 = 4;
(&func_801C8000)(&B_801D9D50);
}
void func_801C7A10(LEODiskID* arg0) {
}
// Checks diskId, sets B_801D9DC8 and returns true if diskId is correct
s32 func_801C7A1C(struct_801E0D18* arg0) {
static LEODiskID B_801DBFD0;
static s32 B_801DBFF0; // bool
func_801C7A10(&arg0->diskId);
if (!B_801DBFF0) {
#if OOT_NTSC
if (bcmp(arg0->diskId.gameName, "EZLJ", 4) == 0 || bcmp(arg0->diskId.gameName, "EZLE", 4) == 0)
#else
if (bcmp(arg0->diskId.gameName, "EZLP", 4) == 0)
#endif
{
B_801DBFD0 = arg0->diskId;
B_801DBFF0 = true;
B_801D9DC8 = 1;
} else {
B_801D9DC8 = 2;
}
} else if (bcmp(&B_801DBFD0, &arg0->diskId, sizeof(LEODiskID)) == 0) {
B_801D9DC8 = 1;
} else {
B_801D9DC8 = 2;
}
return B_801D9DC8 == 1;
}
// Translates byte position to LBA and byte offset
s32 func_801C7B48(s32 arg0, s32* arg1, s32* arg2) {
s32 sp2C;
s32 temp_v0_2;
s32 sp24;
s32 sp20;
s32 temp_v0;
temp_v0_2 = LeoByteToLBA(1, arg0 + 1, &sp2C);
if (temp_v0_2 != LEO_ERROR_GOOD) {
return temp_v0_2;
}
sp24 = sp2C - 1;
if (sp2C == 1) {
sp20 = 0;
} else {
temp_v0 = LeoLBAToByte(1, sp24, &sp20);
if (temp_v0 != LEO_ERROR_GOOD) {
return temp_v0;
}
}
*arg1 = sp24 + 1;
*arg2 = arg0 - sp20;
return LEO_ERROR_GOOD;
}
s32 func_801C7BEC(s32 startLBA) {
s32 bytes;
if (LeoLBAToByte(startLBA, 1, &bytes) == LEO_ERROR_GOOD) {
return bytes;
}
return 0;
}
// Copies bytes from disk to arg0
void func_801C7C1C(void* dest, s32 offset, s32 size) {
s32 sp5C;
s32 sp58;
s32 sp54;
s32 sp50;
void* sp4C;
s32 var_s0;
s32 var_s1;
s32 temp_v1_2;
func_801C6FD8();
func_801C6F30();
B_801D9DB8 = 1;
B_801D9DC0 = 0;
func_801C7B48(offset, &sp5C, &sp54);
func_801C7B48(offset + size, &sp58, &sp50);
sp4C = D_801D2E50;
if (sp5C == sp58) {
func_801C7920(sp5C, sp4C, func_801C7BEC(sp5C));
bcopy((u8*)sp4C + sp54, dest, size);
} else {
var_s1 = 0;
func_801C7920(sp5C, sp4C, func_801C7BEC(sp5C));
bcopy((u8*)sp4C + sp54, dest, func_801C7BEC(sp5C) - sp54);
if (sp5C + 1 < sp58) {
for (var_s0 = sp5C + 1; var_s0 < sp58; var_s0++) {
var_s1 += func_801C7BEC(var_s0);
}
func_801C7920(sp5C + 1, (u8*)dest + func_801C7BEC(sp5C) - sp54, var_s1);
}
if (sp50 > 0) {
func_801C7920(sp58, sp4C, func_801C7BEC(sp58));
bcopy((u8*)sp4C, (u8*)dest + func_801C7BEC(sp5C) - sp54 + var_s1, sp50);
}
}
#if OOT_VERSION < NTSC_1_1
if (B_801D9DC0 != 0) {
temp_v1_2 = (osGetTime() - B_801D9DC0) * 64 / 3000;
if (1000000 - temp_v1_2 > 0) {
Sleep_Usec(1000000 - temp_v1_2);
}
}
#else
func_801C7B28_ne2();
#endif
func_801C7018();
func_801C6F78();
}
void func_801C7E78(void) {
}
s32 func_801C7E80(void) {
s32 sp24;
s32 sp20;
s32 sp1C;
uintptr_t sp18;
if (B_801D9D48 != NULL) {
return -1;
}
B_801D9D48 = &B_801D9C30;
func_801C7C1C(B_801D9D48, 0x1060, 0x118);
sp24 = B_801D9D48->unk_004 - B_801D9D48->unk_000;
sp20 = B_801D9D48->unk_00C - B_801D9D48->unk_008;
sp18 = B_801D9D48->unk_008 + sp24;
func_801C7C1C((void*)B_801D9D48->unk_008, B_801D9D48->unk_000, sp24);
bzero((void*)sp18, sp20 - sp24);
func_800AD4C0(B_801D9D48->unk_010);
return 0;
}
s32 func_801C7F24(void) {
uintptr_t temp_a0;
struct_801D9C30* temp_v0;
if (B_801D9D48 == 0) {
return -1;
}
// Function from code
func_800AD51C();
temp_v0 = B_801D9D48;
temp_a0 = temp_v0->unk_008;
bzero((void*)temp_a0, temp_v0->unk_00C - temp_a0);
bzero(B_801D9D48, sizeof(struct_801D9C30));
B_801D9D48 = 0;
return 0;
}
void n64dd_SetDiskVersion(s32 arg0) {
if (arg0 != 0) {
if (B_801D9D48 == 0) {
func_801C7E80();
}
} else if (B_801D9D48 != 0) {
func_801C7F24();
}
}