Merge remote-tracking branch 'refs/remotes/pret/master'

This commit is contained in:
Diegoisawesome
2017-03-04 23:32:12 -06:00
213 changed files with 57369 additions and 61524 deletions

2838
src/battle_ai.c Normal file

File diff suppressed because it is too large Load Diff

528
src/dma3_manager.c Normal file
View File

@@ -0,0 +1,528 @@
#include "global.h"
extern u8 gDma3ManagerLocked;
extern u8 gDma3RequestCursor;
// size is 0x10
struct DmaRequestsStruct
{
/* 0x00 */ u8 *src;
/* 0x04 */ u8 *dest;
/* 0x08 */ u16 size;
/* 0x0A */ u16 mode;
/* 0x0C */ u32 value;
};
extern struct DmaRequestsStruct gDma3Requests[128];
void ClearDma3Requests(void)
{
int i;
gDma3ManagerLocked = TRUE;
gDma3RequestCursor = FALSE;
for(i = 0; i < (u8)ARRAY_COUNT(gDma3Requests); i++)
{
gDma3Requests[i].size = 0;
gDma3Requests[i].src = 0;
gDma3Requests[i].dest = 0;
}
gDma3ManagerLocked = FALSE;
}
#ifdef NONMATCHING
void ProcessDma3Requests(void)
{
// NOTE: the fillerA member of the DMA struct is actually u32 value;
// NOTE: gUnknown_0300001C is just a pointer inside the gDma3Requests structure, not a true symbol; feel free to remove
u16 total_size;
if (gDma3ManagerLocked)
return;
total_size = 0;
// as long as there are DMA requests to process (unless size or vblank is an issue), do not exit
while (gDma3Requests[gDma3RequestCursor].size)
{
total_size += gDma3Requests[gDma3RequestCursor].size;
if (total_size > 0xA000)
return; // don't do too much at once
if (REG_VCOUNT > 224)
return;// we're about to leave vblank, stop
switch (gDma3Requests[gDma3RequestCursor].mode)
{
case 1: // regular 32-bit copy
// _08000C8C
if(gDma3Requests[gDma3RequestCursor].size <= 0x1000)
{
DmaCopy32(3, gDma3Requests[gDma3RequestCursor].src, gDma3Requests[gDma3RequestCursor].dest, gDma3Requests[gDma3RequestCursor].size);
break;
}
while (gDma3Requests[gDma3RequestCursor].size > 0x1000)
{
DmaCopy32(3, gDma3Requests[gDma3RequestCursor].src, gDma3Requests[gDma3RequestCursor].dest, 0x1000);
gDma3Requests[gDma3RequestCursor].src += 0x1000;
gDma3Requests[gDma3RequestCursor].dest += 0x1000;
gDma3Requests[gDma3RequestCursor].size -= 0x1000;
}
DmaCopy32(3, gDma3Requests[gDma3RequestCursor].src, gDma3Requests[gDma3RequestCursor].dest, gDma3Requests[gDma3RequestCursor].size);
break;
case 2: // repeat a single 32-bit value across RAM
// _08000CD0
while (gDma3Requests[gDma3RequestCursor].size > 0x1000)
{
DmaFill32(3, gDma3Requests[gDma3RequestCursor].value, gDma3Requests[gDma3RequestCursor].dest, 0x1000);
gDma3Requests[gDma3RequestCursor].dest += 0x1000;
gDma3Requests[gDma3RequestCursor].size -= 0x1000;
}
DmaFill32(3, gDma3Requests[gDma3RequestCursor].value, gDma3Requests[gDma3RequestCursor].dest, gDma3Requests[gDma3RequestCursor].size);
break;
case 3: // regular 16-bit copy
// _08000D3C
while (gDma3Requests[gDma3RequestCursor].size > 0x1000)
{
DmaCopy16(3, gDma3Requests[gDma3RequestCursor].src, gDma3Requests[gDma3RequestCursor].dest, 0x1000);
gDma3Requests[gDma3RequestCursor].src += 0x1000;
gDma3Requests[gDma3RequestCursor].dest += 0x1000;
gDma3Requests[gDma3RequestCursor].size -= 0x1000;
}
DmaCopy16(3, gDma3Requests[gDma3RequestCursor].src, gDma3Requests[gDma3RequestCursor].dest, gDma3Requests[gDma3RequestCursor].size);
break;
case 4: // repeat a single 16-bit value across RAM
// _08000D88
while (gDma3Requests[gDma3RequestCursor].size > 0x1000)
{
DmaFill16(3, gDma3Requests[gDma3RequestCursor].value, gDma3Requests[gDma3RequestCursor].dest, 0x1000);
gDma3Requests[gDma3RequestCursor].dest += 0x1000;
gDma3Requests[gDma3RequestCursor].size -= 0x1000;
}
DmaFill16(3, gDma3Requests[gDma3RequestCursor].value, gDma3Requests[gDma3RequestCursor].dest, gDma3Requests[gDma3RequestCursor].size);
break;
}
gDma3Requests[gDma3RequestCursor].src = 0;
gDma3Requests[gDma3RequestCursor].dest = 0;
gDma3Requests[gDma3RequestCursor].size = 0;
gDma3Requests[gDma3RequestCursor].mode = 0;
gDma3Requests[gDma3RequestCursor].value = 0;
gDma3RequestCursor++;
if (gDma3RequestCursor >= 128) // loop back to the first DMA request
gDma3RequestCursor = 0;
}
}
#else
__attribute__((naked))
void ProcessDma3Requests(void)
{
asm(".syntax unified\n\
push {r4-r7,lr}\n\
mov r7, r10\n\
mov r6, r9\n\
mov r5, r8\n\
push {r5-r7}\n\
sub sp, 0xC\n\
ldr r0, =gDma3ManagerLocked\n\
ldrb r0, [r0]\n\
cmp r0, 0\n\
beq _08000C06\n\
b _08000E46\n\
_08000C06:\n\
movs r0, 0\n\
str r0, [sp, 0x8]\n\
ldr r1, =gDma3Requests\n\
ldr r2, =gDma3RequestCursor\n\
ldrb r0, [r2]\n\
lsls r0, 4\n\
adds r0, r1\n\
ldrh r0, [r0, 0x8]\n\
mov r12, r2\n\
cmp r0, 0\n\
bne _08000C1E\n\
b _08000E46\n\
_08000C1E:\n\
mov r8, r1\n\
adds r1, 0x4\n\
mov r10, r1\n\
movs r6, 0x80\n\
lsls r6, 5\n\
ldr r7, =0x040000D4 @REG_DMA3\n\
movs r2, 0\n\
mov r9, r2\n\
_08000C2E:\n\
mov r3, r12 @ gDma3RequestCursor\n\
ldrb r0, [r3]\n\
lsls r5, r0, 4\n\
mov r0, r8 @ gDma3Requests\n\
adds r1, r5, r0 @ gDma3Requests[gDma3RequestCursor]\n\
ldrh r0, [r1, 0x8] @ gDma3Requests[gDma3RequestCursor].size\n\
ldr r2, [sp, 0x8]\n\
adds r0, r2, r0\n\
lsls r0, 16\n\
lsrs r0, 16\n\
str r0, [sp, 0x8]\n\
movs r0, 0xA0\n\
lsls r0, 8\n\
ldr r3, [sp, 0x8]\n\
cmp r3, r0\n\
bls _08000C50\n\
b _08000E46\n\
_08000C50:\n\
ldr r0, =0x04000006 @REG_VCOUNT\n\
ldrb r0, [r0]\n\
cmp r0, 0xE0\n\
bls _08000C5A\n\
b _08000E46\n\
_08000C5A:\n\
ldrh r0, [r1, 0xA]\n\
cmp r0, 0x2\n\
beq _08000CD0\n\
cmp r0, 0x2\n\
bgt _08000C80\n\
cmp r0, 0x1\n\
beq _08000C8C\n\
b _08000DF0\n\
.pool\n\
_08000C80:\n\
cmp r0, 0x3\n\
beq _08000D3C\n\
cmp r0, 0x4\n\
bne _08000C8A\n\
b _08000D88\n\
_08000C8A:\n\
b _08000DF0\n\
_08000C8C:\n\
ldr r3, [r1]\n\
mov r2, r10\n\
adds r0, r5, r2\n\
ldr r2, [r0]\n\
ldrh r1, [r1, 0x8]\n\
cmp r1, r6\n\
bhi _08000CA6\n\
str r3, [r7]\n\
str r2, [r7, 0x4]\n\
lsrs r0, r1, 2\n\
movs r1, 0x84\n\
lsls r1, 24\n\
b _08000DAA\n\
_08000CA6:\n\
ldr r4, =0x040000D4 @REG_DMA3\n\
str r3, [r4]\n\
str r2, [r4, 0x4]\n\
ldr r0, =0x84000400\n\
str r0, [r4, 0x8]\n\
ldr r0, [r4, 0x8]\n\
adds r3, r6\n\
adds r2, r6\n\
subs r1, r6\n\
cmp r1, r6\n\
bhi _08000CA6\n\
str r3, [r4]\n\
str r2, [r4, 0x4]\n\
lsrs r0, r1, 2\n\
movs r1, 0x84\n\
lsls r1, 24\n\
b _08000D76\n\
.pool\n\
_08000CD0:\n\
mov r3, r10\n\
adds r0, r5, r3\n\
ldr r4, [r0]\n\
ldrh r1, [r1, 0x8]\n\
cmp r1, r6\n\
bhi _08000CF4\n\
mov r0, r8\n\
adds r0, 0xC\n\
adds r0, r5, r0\n\
ldr r0, [r0]\n\
str r0, [sp]\n\
mov r5, sp\n\
str r5, [r7]\n\
str r4, [r7, 0x4]\n\
lsrs r0, r1, 2\n\
movs r1, 0x85\n\
lsls r1, 24\n\
b _08000DAA\n\
_08000CF4:\n\
mov r2, r12\n\
ldrb r0, [r2]\n\
lsls r0, 4\n\
mov r5, r8\n\
adds r5, 0xC\n\
adds r0, r5\n\
ldr r0, [r0]\n\
str r0, [sp]\n\
ldr r3, =0x040000D4 @REG_DMA3\n\
mov r0, sp\n\
str r0, [r3]\n\
str r4, [r3, 0x4]\n\
ldr r0, =0x85000400\n\
str r0, [r3, 0x8]\n\
ldr r0, [r3, 0x8]\n\
adds r4, r6\n\
subs r1, r6\n\
cmp r1, r6\n\
bhi _08000CF4\n\
ldrb r0, [r2]\n\
lsls r0, 4\n\
adds r0, r5\n\
ldr r0, [r0]\n\
str r0, [sp]\n\
mov r2, sp\n\
str r2, [r3]\n\
str r4, [r3, 0x4]\n\
lsrs r0, r1, 2\n\
movs r1, 0x85\n\
lsls r1, 24\n\
b _08000DEA\n\
.pool\n\
_08000D3C:\n\
ldr r3, [r1]\n\
mov r2, r10\n\
adds r0, r5, r2\n\
ldr r2, [r0]\n\
ldrh r1, [r1, 0x8]\n\
cmp r1, r6\n\
bhi _08000D56\n\
str r3, [r7]\n\
str r2, [r7, 0x4]\n\
lsrs r0, r1, 1\n\
movs r1, 0x80\n\
lsls r1, 24\n\
b _08000DAA\n\
_08000D56:\n\
ldr r4, =0x040000D4 @REG_DMA3\n\
str r3, [r4]\n\
str r2, [r4, 0x4]\n\
ldr r0, =0x80000800\n\
str r0, [r4, 0x8]\n\
ldr r0, [r4, 0x8]\n\
adds r3, r6\n\
adds r2, r6\n\
subs r1, r6\n\
cmp r1, r6\n\
bhi _08000D56\n\
str r3, [r4]\n\
str r2, [r4, 0x4]\n\
lsrs r0, r1, 1\n\
movs r1, 0x80\n\
lsls r1, 24\n\
_08000D76:\n\
orrs r0, r1\n\
str r0, [r4, 0x8]\n\
ldr r0, [r4, 0x8]\n\
b _08000DF0\n\
.pool\n\
_08000D88:\n\
mov r3, r10\n\
adds r0, r5, r3\n\
ldr r2, [r0]\n\
ldrh r4, [r1, 0x8]\n\
add r1, sp, 0x4\n\
cmp r4, r6\n\
bhi _08000DB2\n\
mov r0, r8\n\
adds r0, 0xC\n\
adds r0, r5, r0\n\
ldr r0, [r0]\n\
strh r0, [r1]\n\
str r1, [r7]\n\
str r2, [r7, 0x4]\n\
lsrs r0, r4, 1\n\
movs r1, 0x81\n\
lsls r1, 24\n\
_08000DAA:\n\
orrs r0, r1\n\
str r0, [r7, 0x8]\n\
ldr r0, [r7, 0x8]\n\
b _08000DF0\n\
_08000DB2:\n\
mov r5, r12\n\
ldrb r0, [r5]\n\
lsls r0, 4\n\
ldr r3, =gUnknown_0300001C\n\
adds r0, r3\n\
ldr r0, [r0]\n\
strh r0, [r1]\n\
ldr r3, =0x040000D4 @REG_DMA3\n\
str r1, [r3]\n\
str r2, [r3, 0x4]\n\
ldr r0, =0x81000800\n\
str r0, [r3, 0x8]\n\
ldr r0, [r3, 0x8]\n\
adds r2, r6\n\
subs r4, r6\n\
cmp r4, r6\n\
bhi _08000DB2\n\
ldrb r0, [r5]\n\
lsls r0, 4\n\
ldr r5, =gUnknown_0300001C\n\
adds r0, r5\n\
ldr r0, [r0]\n\
strh r0, [r1]\n\
str r1, [r3]\n\
str r2, [r3, 0x4]\n\
lsrs r0, r4, 1\n\
movs r1, 0x81\n\
lsls r1, 24\n\
_08000DEA:\n\
orrs r0, r1\n\
str r0, [r3, 0x8]\n\
ldr r0, [r3, 0x8]\n\
_08000DF0:\n\
ldr r1, =gDma3Requests\n\
mov r3, r12\n\
ldrb r0, [r3]\n\
lsls r0, 4\n\
adds r0, r1\n\
mov r2, r9\n\
str r2, [r0]\n\
ldrb r0, [r3]\n\
lsls r0, 4\n\
add r0, r10\n\
str r2, [r0]\n\
ldrb r0, [r3]\n\
lsls r0, 4\n\
adds r0, r1\n\
movs r4, 0\n\
strh r2, [r0, 0x8]\n\
ldrb r0, [r3]\n\
lsls r0, 4\n\
adds r0, r1\n\
mov r5, r9\n\
strh r5, [r0, 0xA]\n\
ldrb r0, [r3]\n\
lsls r0, 4\n\
adds r1, 0xC\n\
adds r0, r1\n\
mov r1, r9\n\
str r1, [r0]\n\
ldrb r0, [r3]\n\
adds r0, 0x1\n\
strb r0, [r3]\n\
lsls r0, 24\n\
cmp r0, 0\n\
bge _08000E34\n\
strb r4, [r3]\n\
_08000E34:\n\
mov r2, r12\n\
ldrb r0, [r2]\n\
lsls r0, 4\n\
ldr r3, =gDma3Requests\n\
adds r0, r3\n\
ldrh r0, [r0, 0x8]\n\
cmp r0, 0\n\
beq _08000E46\n\
b _08000C2E\n\
_08000E46:\n\
add sp, 0xC\n\
pop {r3-r5}\n\
mov r8, r3\n\
mov r9, r4\n\
mov r10, r5\n\
pop {r4-r7}\n\
pop {r0}\n\
bx r0\n\
.pool\n\
.syntax divided");
}
#endif
int RequestDma3Copy(void *src, void *dest, u16 size, u8 mode)
{
int cursor;
int var = 0;
gDma3ManagerLocked = 1;
cursor = gDma3RequestCursor;
while(1)
{
if(!gDma3Requests[cursor].size) // an empty copy was found and the current cursor will be returned.
{
gDma3Requests[cursor].src = src;
gDma3Requests[cursor].dest = dest;
gDma3Requests[cursor].size = size;
if(mode == 1)
gDma3Requests[cursor].mode = mode;
else
gDma3Requests[cursor].mode = 3;
gDma3ManagerLocked = FALSE;
return (s16)cursor;
}
if(++cursor >= 0x80) // loop back to start.
{
cursor = 0;
}
if(++var >= 0x80) // max checks were made. all resulted in failure.
{
break;
}
}
gDma3ManagerLocked = FALSE;
return -1;
}
int RequestDma3Fill(s32 value, void *dest, u16 size, u8 mode)
{
int cursor;
int var = 0;
cursor = gDma3RequestCursor;
gDma3ManagerLocked = 1;
while(1)
{
if(!gDma3Requests[cursor].size)
{
gDma3Requests[cursor].dest = dest;
gDma3Requests[cursor].size = size;
gDma3Requests[cursor].mode = mode;
gDma3Requests[cursor].value = value;
if(mode == 1)
gDma3Requests[cursor].mode = 2;
else
gDma3Requests[cursor].mode = 4;
gDma3ManagerLocked = FALSE;
return (s16)cursor;
}
if(++cursor >= 0x80) // loop back to start.
{
cursor = 0;
}
if(++var >= 0x80) // max checks were made. all resulted in failure.
{
break;
}
}
gDma3ManagerLocked = FALSE;
return -1;
}
int CheckForSpaceForDma3Request(s16 index)
{
int current = 0;
if (index == -1)
{
for (; current < 0x80; current ++)
if (gDma3Requests[current].size)
return -1;
return 0;
}
if (gDma3Requests[index].size)
return -1;
return 0;
}

418
src/main.c Normal file
View File

@@ -0,0 +1,418 @@
#include "global.h"
#include "main.h"
#include "gba/flash_internal.h"
#include "gba/m4a_internal.h"
extern u16 GetGpuReg(u8);
extern void SetGpuReg(u8, u16);
extern void LinkVSync(void);
extern void sub_800E174(void);
extern void sub_800B9B8(void);
extern struct SoundInfo gSoundInfo;
extern u32 gFlashMemoryPresent;
extern u32 IntrMain[];
extern u8 gHeap[];
extern struct SaveBlock2 gUnknown_02024A54;
extern char *gUnknown_03005D94;
extern char gUnknown_02029808[];
extern u32 gBattleTypeFlags;
extern u8 gUnknown_03002748;
extern u32 *gUnknown_0203CF5C;
void Timer3Intr(void);
bool8 HandleLinkConnection(void);
void c2_copyright_1(void);
static void VBlankIntr(void);
static void HBlankIntr(void);
static void VCountIntr(void);
static void SerialIntr(void);
static void IntrDummy(void);
const u8 gGameVersion = VERSION_EMERALD;
const u8 gGameLanguage = GAME_LANGUAGE; // English
const char BuildDateTime[] = "2005 02 21 11:10";
const IntrFunc gIntrTableTemplate[] =
{
VCountIntr, // V-count interrupt
SerialIntr, // Serial interrupt
Timer3Intr, // Timer 3 interrupt
HBlankIntr, // H-blank interrupt
VBlankIntr, // V-blank interrupt
IntrDummy, // Timer 0 interrupt
IntrDummy, // Timer 1 interrupt
IntrDummy, // Timer 2 interrupt
IntrDummy, // DMA 0 interrupt
IntrDummy, // DMA 1 interrupt
IntrDummy, // DMA 2 interrupt
IntrDummy, // DMA 3 interrupt
IntrDummy, // Key interrupt
IntrDummy, // Game Pak interrupt
};
#define INTR_COUNT ((int)(sizeof(gIntrTableTemplate)/sizeof(IntrFunc)))
extern u16 gUnknown_03000000;
extern u16 gKeyRepeatStartDelay;
extern u8 gUnknown_030022B4;
extern struct Main gMain;
extern u16 gKeyRepeatContinueDelay;
extern u8 gSoftResetDisabled;
extern IntrFunc gIntrTable[INTR_COUNT];
extern bool8 gLinkVSyncDisabled;
extern u32 IntrMain_Buffer[0x200];
extern u8 gPcmDmaCounter;
extern u16 gTrainerId;
EWRAM_DATA void (**gFlashTimerIntrFunc)(void) = NULL;
static void UpdateLinkAndCallCallbacks(void);
static void InitMainCallbacks(void);
static void CallCallbacks(void);
static void SeedRngWithRtc(void);
static void ReadKeys(void);
void InitIntrHandlers(void);
static void WaitForVBlank(void);
#define B_START_SELECT (B_BUTTON | START_BUTTON | SELECT_BUTTON)
void AgbMain()
{
RegisterRamReset(RESET_ALL);
*(vu16 *)BG_PLTT = 0x7FFF;
InitGpuRegManager();
REG_WAITCNT = WAITCNT_PREFETCH_ENABLE | WAITCNT_WS0_S_1 | WAITCNT_WS0_N_3;
InitKeys();
InitIntrHandlers();
m4aSoundInit();
EnableVCountIntrAtLine150();
sub_800E6D0();
RtcInit();
CheckForFlashMemory();
InitMainCallbacks();
InitMapMusic();
ClearDma3Requests();
ResetBgs();
SetDefaultFontsPointer();
InitHeap(gHeap, 0x1C000);
gSoftResetDisabled = FALSE;
if (gFlashMemoryPresent != TRUE)
SetMainCallback2(NULL);
gUnknown_030022B4 = 0;
gUnknown_03000000 = 0xFC0;
for (;;)
{
ReadKeys();
if (gSoftResetDisabled == FALSE
&& (gMain.heldKeysRaw & A_BUTTON)
&& (gMain.heldKeysRaw & B_START_SELECT) == B_START_SELECT)
{
rfu_REQ_stopMode();
rfu_waitREQComplete();
DoSoftReset();
}
if (sub_8087634() == 1)
{
gUnknown_030022B4 = 1;
UpdateLinkAndCallCallbacks();
gUnknown_030022B4 = 0;
}
else
{
gUnknown_030022B4 = 0;
UpdateLinkAndCallCallbacks();
if (sub_80875C8() == 1)
{
gMain.newKeys = 0;
ClearObjectCopyRequests();
gUnknown_030022B4 = 1;
UpdateLinkAndCallCallbacks();
gUnknown_030022B4 = 0;
}
}
PlayTimeCounter_Update();
MapMusicMain();
WaitForVBlank();
}
}
static void UpdateLinkAndCallCallbacks(void)
{
if (!HandleLinkConnection())
CallCallbacks();
}
static void InitMainCallbacks(void)
{
gMain.vblankCounter1 = 0;
gUnknown_0203CF5C = NULL;
gMain.vblankCounter2 = 0;
gMain.callback1 = NULL;
SetMainCallback2(c2_copyright_1);
gSaveBlock2Ptr = &gUnknown_02024A54;
gUnknown_03005D94 = gUnknown_02029808;
}
static void CallCallbacks(void)
{
if (gMain.callback1)
gMain.callback1();
if (gMain.callback2)
gMain.callback2();
}
void SetMainCallback2(MainCallback callback)
{
gMain.callback2 = callback;
gMain.state = 0;
}
void StartTimer1(void)
{
REG_TM1CNT_H = 0x80;
}
void SeedRngAndSetTrainerId(void)
{
u16 val = REG_TM1CNT_L;
SeedRng(val);
REG_TM1CNT_H = 0;
gTrainerId = val;
}
u16 GetTrainerId(void)
{
return gTrainerId;
}
void EnableVCountIntrAtLine150(void)
{
u16 gpuReg = (GetGpuReg(REG_OFFSET_DISPSTAT) & 0xFF) | (150 << 8);
SetGpuReg(REG_OFFSET_DISPSTAT, gpuReg | DISPSTAT_VCOUNT_INTR);
EnableInterrupts(INTR_FLAG_VCOUNT);
}
void InitKeys(void)
{
gKeyRepeatContinueDelay = 5;
gKeyRepeatStartDelay = 40;
gMain.heldKeys = 0;
gMain.newKeys = 0;
gMain.newAndRepeatedKeys = 0;
gMain.heldKeysRaw = 0;
gMain.newKeysRaw = 0;
}
static void ReadKeys(void)
{
u16 keyInput = REG_KEYINPUT ^ KEYS_MASK;
gMain.newKeysRaw = keyInput & ~gMain.heldKeysRaw;
gMain.newKeys = gMain.newKeysRaw;
gMain.newAndRepeatedKeys = gMain.newKeysRaw;
// BUG: Key repeat won't work when pressing L using L=A button mode
// because it compares the raw key input with the remapped held keys.
// Note that newAndRepeatedKeys is never remapped either.
if (keyInput != 0 && gMain.heldKeys == keyInput)
{
gMain.keyRepeatCounter--;
if (gMain.keyRepeatCounter == 0)
{
gMain.newAndRepeatedKeys = keyInput;
gMain.keyRepeatCounter = gKeyRepeatContinueDelay;
}
}
else
{
// If there is no input or the input has changed, reset the counter.
gMain.keyRepeatCounter = gKeyRepeatStartDelay;
}
gMain.heldKeysRaw = keyInput;
gMain.heldKeys = gMain.heldKeysRaw;
// Remap L to A if the L=A option is enabled.
if (gSaveBlock2Ptr->optionsButtonMode == 2)
{
if (gMain.newKeys & L_BUTTON)
gMain.newKeys |= A_BUTTON;
if (gMain.heldKeys & L_BUTTON)
gMain.heldKeys |= A_BUTTON;
}
if (gMain.newKeys & gMain.watchedKeysMask)
gMain.watchedKeysPressed = TRUE;
}
void InitIntrHandlers(void)
{
int i;
for (i = 0; i < INTR_COUNT; i++)
gIntrTable[i] = gIntrTableTemplate[i];
DmaCopy32(3, IntrMain, IntrMain_Buffer, sizeof(IntrMain_Buffer));
INTR_VECTOR = IntrMain_Buffer;
SetVBlankCallback(NULL);
SetHBlankCallback(NULL);
SetSerialCallback(NULL);
REG_IME = 1;
EnableInterrupts(0x1);
}
void SetVBlankCallback(IntrCallback callback)
{
gMain.vblankCallback = callback;
}
void SetHBlankCallback(IntrCallback callback)
{
gMain.hblankCallback = callback;
}
void SetVCountCallback(IntrCallback callback)
{
gMain.vcountCallback = callback;
}
void RestoreSerialTimer3IntrHandlers(void)
{
gIntrTable[1] = SerialIntr;
gIntrTable[2] = Timer3Intr;
}
void SetSerialCallback(IntrCallback callback)
{
gMain.serialCallback = callback;
}
extern void CopyBufferedValuesToGpuRegs(void);
extern void ProcessDma3Requests(void);
static void VBlankIntr(void)
{
if (gLinkVSyncDisabled != FALSE)
LinkVSync();
else if (gUnknown_03002748 == FALSE)
sub_800B9B8();
gMain.vblankCounter1++;
if (gUnknown_0203CF5C && *gUnknown_0203CF5C < 0xFFFFFFFF)
(*gUnknown_0203CF5C)++;
if (gMain.vblankCallback)
gMain.vblankCallback();
gMain.vblankCounter2++;
CopyBufferedValuesToGpuRegs();
ProcessDma3Requests();
gPcmDmaCounter = gSoundInfo.pcmDmaCounter;
m4aSoundMain();
sub_8033648();
if (!gMain.inBattle || (gBattleTypeFlags & 0x013F0102) == 0)
Random();
sub_800E174();
INTR_CHECK |= INTR_FLAG_VBLANK;
gMain.intrCheck |= INTR_FLAG_VBLANK;
}
void StartFlashMemoryTimer(void)
{
SetFlashTimerIntr(2, gIntrTable + 0x7);
}
static void HBlankIntr(void)
{
if (gMain.hblankCallback)
gMain.hblankCallback();
INTR_CHECK |= INTR_FLAG_HBLANK;
gMain.intrCheck |= INTR_FLAG_HBLANK;
}
static void VCountIntr(void)
{
if (gMain.vcountCallback)
gMain.vcountCallback();
m4aSoundVSync();
INTR_CHECK |= INTR_FLAG_VCOUNT;
gMain.intrCheck |= INTR_FLAG_VCOUNT;
}
static void SerialIntr(void)
{
if (gMain.serialCallback)
gMain.serialCallback();
INTR_CHECK |= INTR_FLAG_SERIAL;
gMain.intrCheck |= INTR_FLAG_SERIAL;
}
static void IntrDummy(void)
{}
static void WaitForVBlank(void)
{
gMain.intrCheck &= ~INTR_FLAG_VBLANK;
while (!(gMain.intrCheck & INTR_FLAG_VBLANK))
;
}
void sub_80008DC(u32 *var)
{
gUnknown_0203CF5C = var;
}
void sub_80008E8(void)
{
gUnknown_0203CF5C = NULL;
}
void DoSoftReset(void)
{
REG_IME = 0;
m4aSoundVSyncOff();
remove_some_task();
DmaStop(1);
DmaStop(2);
DmaStop(3);
SiiRtcProtect();
SoftReset(RESET_ALL);
}
void ClearPokemonCrySongs(void)
{
CpuFill16(0, gPokemonCrySongs, MAX_POKEMON_CRIES * sizeof(struct PokemonCrySong));
}

470
src/multiboot.c Normal file
View File

@@ -0,0 +1,470 @@
#include "gba/gba.h"
#include "multiboot.h"
static u16 MultiBoot_required_data[MULTIBOOT_NCHILD];
static int MultiBootSend(struct MultiBootParam *mp, u16 data);
static int MultiBootHandShake(struct MultiBootParam *mp);
static void MultiBootWaitCycles(u32 cycles);
static void MultiBootWaitSendDone(void);
void MultiBootInit(struct MultiBootParam *mp)
{
mp->client_bit = 0;
mp->probe_count = 0;
mp->response_bit = 0;
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT;
mp->sendflag = 0;
mp->handshake_timeout = 0;
REG_RCNT = 0;
REG_SIOCNT = SIO_MULTI_MODE | SIO_115200_BPS;
REG_SIODATA8 = 0;
}
int MultiBootMain(struct MultiBootParam *mp)
{
int i;
int j;
int k;
if (MultiBootCheckComplete(mp))
{
return 0;
}
if (mp->check_wait > MULTIBOOT_CONNECTION_CHECK_WAIT)
{
mp->check_wait--;
return 0;
}
output_burst:
if (mp->sendflag)
{
mp->sendflag = 0;
i = REG_SIOCNT & (SIO_MULTI_BUSY | SIO_ERROR | SIO_ID | SIO_MULTI_SD | SIO_MULTI_SI);
if (i != SIO_MULTI_SD)
{
MultiBootInit(mp);
return i ^ SIO_MULTI_SD;
}
}
if (mp->probe_count >= 0xe0)
{
i = MultiBootHandShake(mp);
if (i)
{
return i;
}
if (mp->server_type == MULTIBOOT_SERVER_TYPE_QUICK
&& mp->probe_count > 0xe1
&& MultiBootCheckComplete(mp) == 0)
{
MultiBootWaitSendDone();
goto output_burst;
}
if (MultiBootCheckComplete(mp) == 0)
{
if (mp->handshake_timeout == 0)
{
MultiBootInit(mp);
return MULTIBOOT_ERROR_HANDSHAKE_FAILURE;
}
mp->handshake_timeout--;
}
return 0;
}
switch (mp->probe_count)
{
case 0:
k = 0x0e;
for (i = MULTIBOOT_NCHILD; i != 0; i--)
{
if (*(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2) != 0xffff)
{
break;
}
k >>= 1;
}
k &= 0x0e;
mp->response_bit = k;
for (i = MULTIBOOT_NCHILD; i != 0; i--)
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
if (mp->client_bit & (1 << i))
{
if (j != ((MULTIBOOT_CLIENT_INFO << 8) | (1 << i)))
{
k = 0;
break;
}
}
}
mp->client_bit &= k;
if (k == 0)
{
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT;
}
if (mp->check_wait)
{
mp->check_wait--;
}
else
{
if (mp->response_bit != mp->client_bit)
{
MultiBootStartProbe(mp);
goto case_1;
}
}
output_master_info:
return MultiBootSend(mp, (MULTIBOOT_MASTER_INFO << 8) | mp->client_bit);
case_1:
case 1:
mp->probe_target_bit = 0;
for (i = MULTIBOOT_NCHILD; i != 0; i--)
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
if ((j >> 8) == MULTIBOOT_CLIENT_INFO)
{
MultiBoot_required_data[i - 1] = j;
j &= 0xff;
if (j == (1 << i))
{
mp->probe_target_bit |= j;
}
}
}
if (mp->response_bit != mp->probe_target_bit)
{
goto output_master_info;
}
mp->probe_count = 2;
return MultiBootSend(mp, (MULTIBOOT_MASTER_START_PROBE << 8) | mp->probe_target_bit);
case 2:
for (i = MULTIBOOT_NCHILD; i != 0; i--)
{
if (mp->probe_target_bit & (1 << i))
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
if (j != MultiBoot_required_data[i - 1])
{
mp->probe_target_bit ^= 1 << i;
}
}
}
goto output_header;
case 0xd0:
k = 1;
for (i = MULTIBOOT_NCHILD; i != 0; i--)
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
mp->client_data[i - 1] = j;
if (mp->probe_target_bit & (1 << i))
{
if ((j >> 8) != MULTIBOOT_CLIENT_INFO
&& (j >> 8) != MULTIBOOT_CLIENT_DLREADY)
{
MultiBootInit(mp);
return MULTIBOOT_ERROR_NO_DLREADY;
}
if (j == MultiBoot_required_data[i - 1])
{
k = 0;
}
}
}
if (k == 0)
{
return MultiBootSend(mp, (MULTIBOOT_MASTER_REQUEST_DLREADY << 8) | mp->palette_data);
}
mp->probe_count = 0xd1;
k = 0x11;
for (i = MULTIBOOT_NCHILD; i != 0; i--)
{
k += mp->client_data[i - 1];
}
mp->handshake_data = k;
return MultiBootSend(mp, (MULTIBOOT_MASTER_START_DL << 8) | (k & 0xff));
case 0xd1:
for (i = MULTIBOOT_NCHILD; i != 0; i--)
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
if (mp->probe_target_bit & (1 << i))
{
if ((j >> 8) != MULTIBOOT_CLIENT_DLREADY)
{
MultiBootInit(mp);
return MULTIBOOT_ERROR_NO_DLREADY;
}
}
}
i = MultiBoot(mp);
if (i == 0)
{
mp->probe_count = 0xe0;
mp->handshake_timeout = MULTIBOOT_HANDSHAKE_TIMEOUT;
return 0;
}
MultiBootInit(mp);
mp->check_wait = MULTIBOOT_CONNECTION_CHECK_WAIT * 2;
return MULTIBOOT_ERROR_BOOT_FAILURE;
default:
for (i = MULTIBOOT_NCHILD; i != 0; i--)
{
if (mp->probe_target_bit & (1 << i))
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
if ((j >> 8) != (MULTIBOOT_MASTER_START_PROBE + 1 - (mp->probe_count >> 1))
|| ((j & 0xff) != (1 << i)))
{
mp->probe_target_bit ^= 1 << i;
}
}
}
if (mp->probe_count == 0xc4)
{
mp->client_bit = mp->probe_target_bit & 0x0e;
mp->probe_count = 0;
goto output_master_info;
}
output_header:
if (mp->probe_target_bit == 0)
{
MultiBootInit(mp);
return MULTIBOOT_ERROR_NO_PROBE_TARGET;
}
mp->probe_count += 2;
if (mp->probe_count == 0xc4)
{
goto output_master_info;
}
i = MultiBootSend(mp,
(mp->masterp[mp->probe_count - 4 + 1] << 8)
| mp->masterp[mp->probe_count - 4]);
if (i)
{
return i;
}
if (mp->server_type == MULTIBOOT_SERVER_TYPE_QUICK)
{
MultiBootWaitSendDone();
goto output_burst;
}
return 0;
}
}
static int MultiBootSend(struct MultiBootParam *mp, u16 data)
{
int i;
i = REG_SIOCNT & (SIO_MULTI_BUSY | SIO_MULTI_SD | SIO_MULTI_SI);
if (i != SIO_MULTI_SD)
{
MultiBootInit(mp);
return i ^ SIO_MULTI_SD;
}
REG_SIODATA8 = data;
REG_SIOCNT = SIO_MULTI_MODE | SIO_START | SIO_115200_BPS;
mp->sendflag = 1;
return 0;
}
void MultiBootStartProbe(struct MultiBootParam *mp)
{
if (mp->probe_count != 0)
{
MultiBootInit(mp);
return;
}
mp->check_wait = 0;
mp->client_bit = 0;
mp->probe_count = 1;
}
void MultiBootStartMaster(struct MultiBootParam *mp, u8 *srcp, int length, u8 palette_color, s8 palette_speed)
{
int i = 0;
if (mp->probe_count != 0
|| mp->client_bit == 0
|| mp->check_wait != 0)
{
MultiBootInit(mp);
return;
}
mp->boot_srcp = srcp;
length = (length + 15) & ~15;
if (length < MULTIBOOT_SEND_SIZE_MIN || length > MULTIBOOT_SEND_SIZE_MAX)
{
MultiBootInit(mp);
return;
}
mp->boot_endp = srcp + length;
switch (palette_speed)
{
case -4:
case -3:
case -2:
case -1:
i = (palette_color << 3) | (3 - palette_speed);
break;
case 0:
i = 0x38 | palette_color;
break;
case 1:
case 2:
case 3:
case 4:
i = (palette_color << 3) | (palette_speed - 1);
break;
}
mp->palette_data = ((i & 0x3f) << 1) | 0x81;
mp->probe_count = 0xd0;
}
int MultiBootCheckComplete(struct MultiBootParam *mp)
{
if (mp->probe_count == 0xe9)
{
return 1;
}
return 0;
}
static int MultiBootHandShake(struct MultiBootParam *mp)
{
int i, j;
#define send_data (mp->system_work[0])
#define must_data (mp->system_work[1])
switch (mp->probe_count)
{
case_0xe0:
case 0xe0:
mp->probe_count = 0xe1;
must_data = 0x0000;
send_data = 0x100000;
return MultiBootSend(mp, 0x0000);
default:
for (i = MULTIBOOT_NCHILD; i != 0; i--)
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
if ((mp->client_bit & (1 << i))
&& j != must_data)
{
goto case_0xe0;
}
}
mp->probe_count++;
must_data = send_data & 0xffff;
if (send_data == 0x0000)
{
must_data = mp->masterp[0xac] | (mp->masterp[0xad] << 8);
send_data = must_data << 5;
}
send_data >>= 5;
output_common:
return MultiBootSend(mp, send_data);
case 0xe7:
case 0xe8:
for (i = MULTIBOOT_NCHILD; i != 0; i--)
{
j = *(vu16 *)(REG_ADDR_SIOMULTI0 + i * 2);
if ((mp->client_bit & (1 << i)) && j != must_data)
{
MultiBootInit(mp);
return MULTIBOOT_ERROR_HANDSHAKE_FAILURE;
}
}
mp->probe_count++;
if (mp->probe_count == 0xe9)
{
return 0;
}
send_data = mp->masterp[0xae] | (mp->masterp[0xaf] << 8);
must_data = send_data;
goto output_common;
}
#undef send_data
#undef must_data
}
static void MultiBootWaitCycles(u32 cycles)
{
asm("mov r2, pc");
asm("lsr r2, #24");
asm("mov r1, #12");
asm("cmp r2, #0x02");
asm("beq MultiBootWaitCyclesLoop");
asm("mov r1, #13");
asm("cmp r2, #0x08");
asm("beq MultiBootWaitCyclesLoop");
asm("mov r1, #4");
asm("MultiBootWaitCyclesLoop:");
asm("sub r0, r1");
asm("bgt MultiBootWaitCyclesLoop");
}
static void MultiBootWaitSendDone(void)
{
int i;
for (i = 0; i < 31069; i++)
{
if ((REG_SIOCNT & SIO_START) == 0)
{
break;
}
}
MultiBootWaitCycles(600);
}

35
src/rng.c Normal file
View File

@@ -0,0 +1,35 @@
#include "global.h"
#include "rng.h"
// The number 1103515245 comes from the example implementation of rand and srand
// in the ISO C standard.
extern u32 gRngValue;
extern u32 gRng2Value;
EWRAM_DATA static u8 sUnknown = 0;
EWRAM_DATA static u32 sRandCount = 0;
u16 Random()
{
gRngValue = 1103515245 * gRngValue + 24691;
sRandCount++;
return gRngValue >> 16;
}
void SeedRng(u16 seed)
{
gRngValue = seed;
sUnknown = 0;
}
void SeedRng2(u16 seed)
{
gRng2Value = seed;
}
u16 Random2(void)
{
gRng2Value = 1103515245 * gRng2Value + 24691;
return gRng2Value >> 16;
}

432
src/siirtc.c Normal file
View File

@@ -0,0 +1,432 @@
// Ruby/Sapphire/Emerald cartridges contain a Seiko Instruments Inc. (SII)
// S-3511A real-time clock (RTC). This library ("SIIRTC_V001") is for
// communicating with the RTC.
#include "gba/gba.h"
#include "siirtc.h"
#define STATUS_INTFE 0x02 // frequency interrupt enable
#define STATUS_INTME 0x08 // per-minute interrupt enable
#define STATUS_INTAE 0x20 // alarm interrupt enable
#define STATUS_24HOUR 0x40 // 0: 12-hour mode, 1: 24-hour mode
#define STATUS_POWER 0x80 // power on or power failure occurred
#define TEST_MODE 0x80 // flag in the "second" byte
#define ALARM_AM 0x00
#define ALARM_PM 0x80
#define OFFSET_YEAR offsetof(struct SiiRtcInfo, year)
#define OFFSET_MONTH offsetof(struct SiiRtcInfo, month)
#define OFFSET_DAY offsetof(struct SiiRtcInfo, day)
#define OFFSET_DAY_OF_WEEK offsetof(struct SiiRtcInfo, dayOfWeek)
#define OFFSET_HOUR offsetof(struct SiiRtcInfo, hour)
#define OFFSET_MINUTE offsetof(struct SiiRtcInfo, minute)
#define OFFSET_SECOND offsetof(struct SiiRtcInfo, second)
#define OFFSET_STATUS offsetof(struct SiiRtcInfo, status)
#define OFFSET_ALARM_HOUR offsetof(struct SiiRtcInfo, alarmHour)
#define OFFSET_ALARM_MINUTE offsetof(struct SiiRtcInfo, alarmMinute)
#define INFO_BUF(info, index) (*((u8 *)(info) + (index)))
#define DATETIME_BUF(info, index) INFO_BUF(info, OFFSET_YEAR + index)
#define DATETIME_BUF_LEN (OFFSET_SECOND - OFFSET_YEAR + 1)
#define TIME_BUF(info, index) INFO_BUF(info, OFFSET_HOUR + index)
#define TIME_BUF_LEN (OFFSET_SECOND - OFFSET_HOUR + 1)
#define WR 0 // command for writing data
#define RD 1 // command for reading data
#define CMD(n) (0x60 | (n << 1))
#define CMD_RESET CMD(0)
#define CMD_STATUS CMD(1)
#define CMD_DATETIME CMD(2)
#define CMD_TIME CMD(3)
#define CMD_ALARM CMD(4)
#define GPIO_PORT_DATA (*(vu16 *)0x80000C4)
#define GPIO_PORT_DIRECTION (*(vu16 *)0x80000C6)
#define GPIO_PORT_READ_ENABLE (*(vu16 *)0x80000C8)
extern vu16 GPIOPortDirection;
static u16 sDummy; // unused variable
static bool8 sLocked;
static int WriteCommand(u8 value);
static int WriteData(u8 value);
static u8 ReadData();
static void EnableGpioPortRead();
static void DisableGpioPortRead();
static const char AgbLibRtcVersion[] = "SIIRTC_V001";
void SiiRtcUnprotect()
{
EnableGpioPortRead();
sLocked = FALSE;
}
void SiiRtcProtect()
{
DisableGpioPortRead();
sLocked = TRUE;
}
u8 SiiRtcProbe()
{
u8 errorCode;
struct SiiRtcInfo rtc;
if (!SiiRtcGetStatus(&rtc))
return 0;
errorCode = 0;
if ((rtc.status & (SIIRTCINFO_POWER | SIIRTCINFO_24HOUR)) == SIIRTCINFO_POWER
|| (rtc.status & (SIIRTCINFO_POWER | SIIRTCINFO_24HOUR)) == 0)
{
// The RTC is in 12-hour mode. Reset it and switch to 24-hour mode.
// Note that the conditions are redundant and equivalent to simply
// "(rtc.status & SIIRTCINFO_24HOUR) == 0". It's possible that this
// was also intended to handle resetting the clock after power failure
// but a mistake was made.
if (!SiiRtcReset())
return 0;
errorCode++;
}
SiiRtcGetTime(&rtc);
if (rtc.second & TEST_MODE)
{
// The RTC is in test mode. Reset it to leave test mode.
if (!SiiRtcReset())
return (errorCode << 4) & 0xF0;
errorCode++;
}
return (errorCode << 4) | 1;
}
bool8 SiiRtcReset()
{
u8 result;
struct SiiRtcInfo rtc;
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 5;
GPIO_PORT_DIRECTION = 7;
WriteCommand(CMD_RESET | WR);
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 1;
sLocked = FALSE;
rtc.status = SIIRTCINFO_24HOUR;
result = SiiRtcSetStatus(&rtc);
return result;
}
bool8 SiiRtcGetStatus(struct SiiRtcInfo *rtc)
{
u8 statusData;
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 5;
GPIO_PORT_DIRECTION = 7;
WriteCommand(CMD_STATUS | RD);
GPIO_PORT_DIRECTION = 5;
statusData = ReadData();
rtc->status = (statusData & (STATUS_POWER | STATUS_24HOUR))
| ((statusData & STATUS_INTAE) >> 3)
| ((statusData & STATUS_INTME) >> 2)
| ((statusData & STATUS_INTFE) >> 1);
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 1;
sLocked = FALSE;
return TRUE;
}
bool8 SiiRtcSetStatus(struct SiiRtcInfo *rtc)
{
u8 statusData;
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 5;
statusData = STATUS_24HOUR
| ((rtc->status & SIIRTCINFO_INTAE) << 3)
| ((rtc->status & SIIRTCINFO_INTME) << 2)
| ((rtc->status & SIIRTCINFO_INTFE) << 1);
GPIO_PORT_DIRECTION = 7;
WriteCommand(CMD_STATUS | WR);
WriteData(statusData);
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 1;
sLocked = FALSE;
return TRUE;
}
bool8 SiiRtcGetDateTime(struct SiiRtcInfo *rtc)
{
u8 i;
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 5;
GPIO_PORT_DIRECTION = 7;
WriteCommand(CMD_DATETIME | RD);
GPIO_PORT_DIRECTION = 5;
for (i = 0; i < DATETIME_BUF_LEN; i++)
DATETIME_BUF(rtc, i) = ReadData();
INFO_BUF(rtc, OFFSET_HOUR) &= 0x7F;
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 1;
sLocked = FALSE;
return TRUE;
}
bool8 SiiRtcSetDateTime(struct SiiRtcInfo *rtc)
{
u8 i;
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 5;
GPIO_PORT_DIRECTION = 7;
WriteCommand(CMD_DATETIME | WR);
for (i = 0; i < DATETIME_BUF_LEN; i++)
WriteData(DATETIME_BUF(rtc, i));
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 1;
sLocked = FALSE;
return TRUE;
}
bool8 SiiRtcGetTime(struct SiiRtcInfo *rtc)
{
u8 i;
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 5;
GPIO_PORT_DIRECTION = 7;
WriteCommand(CMD_TIME | RD);
GPIO_PORT_DIRECTION = 5;
for (i = 0; i < TIME_BUF_LEN; i++)
TIME_BUF(rtc, i) = ReadData();
INFO_BUF(rtc, OFFSET_HOUR) &= 0x7F;
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 1;
sLocked = FALSE;
return TRUE;
}
bool8 SiiRtcSetTime(struct SiiRtcInfo *rtc)
{
u8 i;
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 5;
GPIO_PORT_DIRECTION = 7;
WriteCommand(CMD_TIME | WR);
for (i = 0; i < TIME_BUF_LEN; i++)
WriteData(TIME_BUF(rtc, i));
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 1;
sLocked = FALSE;
return TRUE;
}
bool8 SiiRtcSetAlarm(struct SiiRtcInfo *rtc)
{
u8 i;
u8 alarmData[2];
if (sLocked == TRUE)
return FALSE;
sLocked = TRUE;
// Decode BCD.
alarmData[0] = (rtc->alarmHour & 0xF) + 10 * ((rtc->alarmHour >> 4) & 0xF);
// The AM/PM flag must be set correctly even in 24-hour mode.
if (alarmData[0] < 12)
alarmData[0] = rtc->alarmHour | ALARM_AM;
else
alarmData[0] = rtc->alarmHour | ALARM_PM;
alarmData[1] = rtc->alarmMinute;
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 5;
GPIOPortDirection = 7; // Why is this the only instance that uses a symbol?
WriteCommand(CMD_ALARM | WR);
for (i = 0; i < 2; i++)
WriteData(alarmData[i]);
GPIO_PORT_DATA = 1;
GPIO_PORT_DATA = 1;
sLocked = FALSE;
return TRUE;
}
static int WriteCommand(u8 value)
{
u8 i;
u8 temp;
for (i = 0; i < 8; i++)
{
temp = ((value >> (7 - i)) & 1);
GPIO_PORT_DATA = (temp << 1) | 4;
GPIO_PORT_DATA = (temp << 1) | 4;
GPIO_PORT_DATA = (temp << 1) | 4;
GPIO_PORT_DATA = (temp << 1) | 5;
}
// control reaches end of non-void function
}
static int WriteData(u8 value)
{
u8 i;
u8 temp;
for (i = 0; i < 8; i++)
{
temp = ((value >> i) & 1);
GPIO_PORT_DATA = (temp << 1) | 4;
GPIO_PORT_DATA = (temp << 1) | 4;
GPIO_PORT_DATA = (temp << 1) | 4;
GPIO_PORT_DATA = (temp << 1) | 5;
}
// control reaches end of non-void function
}
static u8 ReadData()
{
u8 i;
u8 temp;
u8 value;
for (i = 0; i < 8; i++)
{
GPIO_PORT_DATA = 4;
GPIO_PORT_DATA = 4;
GPIO_PORT_DATA = 4;
GPIO_PORT_DATA = 4;
GPIO_PORT_DATA = 4;
GPIO_PORT_DATA = 5;
temp = ((GPIO_PORT_DATA & 2) >> 1);
value = (value >> 1) | (temp << 7); // UB: accessing uninitialized var
}
return value;
}
static void EnableGpioPortRead()
{
GPIO_PORT_READ_ENABLE = 1;
}
static void DisableGpioPortRead()
{
GPIO_PORT_READ_ENABLE = 0;
}

780
src/string_util.c Normal file
View File

@@ -0,0 +1,780 @@
#include "global.h"
#include "string_util.h"
#include "text.h"
EWRAM_DATA u8 gUnknownStringVar[16] = {0};
static const u8 sDigits[] = __("0123456789ABCDEF");
static const s32 sPowersOfTen[] =
{
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
};
extern u8 gExpandedPlaceholder_Empty[];
extern u8 gExpandedPlaceholder_Kun[];
extern u8 gExpandedPlaceholder_Chan[];
extern u8 gExpandedPlaceholder_Sapphire[];
extern u8 gExpandedPlaceholder_Ruby[];
extern u8 gExpandedPlaceholder_Emerald[];
extern u8 gExpandedPlaceholder_Aqua[];
extern u8 gExpandedPlaceholder_Magma[];
extern u8 gExpandedPlaceholder_Archie[];
extern u8 gExpandedPlaceholder_Maxie[];
extern u8 gExpandedPlaceholder_Kyogre[];
extern u8 gExpandedPlaceholder_Groudon[];
extern u8 gExpandedPlaceholder_Brendan[];
extern u8 gExpandedPlaceholder_May[];
u8 *StringCopy10(u8 *dest, const u8 *src)
{
u8 i;
u32 limit = 10;
for (i = 0; i < limit; i++)
{
dest[i] = src[i];
if (dest[i] == EOS)
return &dest[i];
}
dest[i] = EOS;
return &dest[i];
}
u8 *StringGetEnd10(u8 *str)
{
u8 i;
u32 limit = 10;
for (i = 0; i < limit; i++)
if (str[i] == EOS)
return &str[i];
str[i] = EOS;
return &str[i];
}
u8 *StringCopy7(u8 *dest, const u8 *src)
{
s32 i;
s32 limit = 7;
for (i = 0; i < limit; i++)
{
dest[i] = src[i];
if (dest[i] == EOS)
return &dest[i];
}
dest[i] = EOS;
return &dest[i];
}
u8 *StringCopy(u8 *dest, const u8 *src)
{
while (*src != EOS)
{
*dest = *src;
dest++;
src++;
}
*dest = EOS;
return dest;
}
u8 *StringAppend(u8 *dest, const u8 *src)
{
while (*dest != EOS)
dest++;
return StringCopy(dest, src);
}
u8 *StringCopyN(u8 *dest, const u8 *src, u8 n)
{
u16 i;
for (i = 0; i < n; i++)
dest[i] = src[i];
return &dest[n];
}
u8 *StringAppendN(u8 *dest, const u8 *src, u8 n)
{
while (*dest != EOS)
dest++;
return StringCopyN(dest, src, n);
}
u16 StringLength(const u8 *str)
{
u16 length = 0;
while (str[length] != EOS)
length++;
return length;
}
s32 StringCompare(const u8 *str1, const u8 *str2)
{
while (*str1 == *str2)
{
if (*str1 == EOS)
return 0;
str1++;
str2++;
}
return *str1 - *str2;
}
s32 StringCompareN(const u8 *str1, const u8 *str2, u32 n)
{
while (*str1 == *str2)
{
if (*str1 == EOS)
return 0;
str1++;
str2++;
if (--n == 0)
return 0;
}
return *str1 - *str2;
}
bool8 IsStringLengthAtLeast(const u8 *str, s32 n)
{
u8 i;
for (i = 0; i < n; i++)
if (str[i] && str[i] != EOS)
return TRUE;
return FALSE;
}
u8 *ConvertIntToDecimalStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n)
{
enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state;
s32 powerOfTen;
s32 largestPowerOfTen = sPowersOfTen[n - 1];
state = WAITING_FOR_NONZERO_DIGIT;
if (mode == STR_CONV_MODE_RIGHT_ALIGN)
state = WRITING_SPACES;
if (mode == STR_CONV_MODE_LEADING_ZEROS)
state = WRITING_DIGITS;
for (powerOfTen = largestPowerOfTen; powerOfTen > 0; powerOfTen /= 10)
{
u8 c;
u16 digit = value / powerOfTen;
s32 temp = value - (powerOfTen * digit);
if (state == WRITING_DIGITS)
{
u8 *out = dest++;
if (digit <= 9)
c = sDigits[digit];
else
c = CHAR_QUESTION_MARK;
*out = c;
}
else if (digit != 0 || powerOfTen == 1)
{
u8 *out;
state = WRITING_DIGITS;
out = dest++;
if (digit <= 9)
c = sDigits[digit];
else
c = CHAR_QUESTION_MARK;
*out = c;
}
else if (state == WRITING_SPACES)
{
*dest++ = 0x77;
}
value = temp;
}
*dest = EOS;
return dest;
}
u8 *ConvertUIntToDecimalStringN(u8 *dest, u32 value, enum StringConvertMode mode, u8 n)
{
enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state;
s32 powerOfTen;
s32 largestPowerOfTen = sPowersOfTen[n - 1];
state = WAITING_FOR_NONZERO_DIGIT;
if (mode == STR_CONV_MODE_RIGHT_ALIGN)
state = WRITING_SPACES;
if (mode == STR_CONV_MODE_LEADING_ZEROS)
state = WRITING_DIGITS;
for (powerOfTen = largestPowerOfTen; powerOfTen > 0; powerOfTen /= 10)
{
u8 c;
u16 digit = value / powerOfTen;
u32 temp = value - (powerOfTen * digit);
if (state == WRITING_DIGITS)
{
u8 *out = dest++;
if (digit <= 9)
c = sDigits[digit];
else
c = CHAR_QUESTION_MARK;
*out = c;
}
else if (digit != 0 || powerOfTen == 1)
{
u8 *out;
state = WRITING_DIGITS;
out = dest++;
if (digit <= 9)
c = sDigits[digit];
else
c = CHAR_QUESTION_MARK;
*out = c;
}
else if (state == WRITING_SPACES)
{
*dest++ = 0x77;
}
value = temp;
}
*dest = EOS;
return dest;
}
u8 *ConvertIntToHexStringN(u8 *dest, s32 value, enum StringConvertMode mode, u8 n)
{
enum { WAITING_FOR_NONZERO_DIGIT, WRITING_DIGITS, WRITING_SPACES } state;
u8 i;
s32 powerOfSixteen;
s32 largestPowerOfSixteen = 1;
for (i = 1; i < n; i++)
largestPowerOfSixteen *= 16;
state = WAITING_FOR_NONZERO_DIGIT;
if (mode == STR_CONV_MODE_RIGHT_ALIGN)
state = WRITING_SPACES;
if (mode == STR_CONV_MODE_LEADING_ZEROS)
state = WRITING_DIGITS;
for (powerOfSixteen = largestPowerOfSixteen; powerOfSixteen > 0; powerOfSixteen /= 16)
{
u8 c;
u32 digit = value / powerOfSixteen;
s32 temp = value % powerOfSixteen;
if (state == WRITING_DIGITS)
{
char *out = dest++;
if (digit <= 0xF)
c = sDigits[digit];
else
c = CHAR_QUESTION_MARK;
*out = c;
}
else if (digit != 0 || powerOfSixteen == 1)
{
char *out;
state = WRITING_DIGITS;
out = dest++;
if (digit <= 0xF)
c = sDigits[digit];
else
c = CHAR_QUESTION_MARK;
*out = c;
}
else if (state == WRITING_SPACES)
{
*dest++ = 0x77;
}
value = temp;
}
*dest = EOS;
return dest;
}
u8 *StringExpandPlaceholders(u8 *dest, const u8 *src)
{
for (;;)
{
u8 c = *src++;
u8 placeholderId;
u8 *expandedString;
switch (c)
{
case PLACEHOLDER_BEGIN:
placeholderId = *src++;
expandedString = GetExpandedPlaceholder(placeholderId);
dest = StringExpandPlaceholders(dest, expandedString);
break;
case EXT_CTRL_CODE_BEGIN:
*dest++ = c;
c = *src++;
*dest++ = c;
switch (c)
{
case 0x07:
case 0x09:
case 0x0F:
case 0x15:
case 0x16:
case 0x17:
case 0x18:
break;
case 0x04:
*dest++ = *src++;
case 0x0B:
*dest++ = *src++;
default:
*dest++ = *src++;
}
break;
case EOS:
*dest = EOS;
return dest;
case 0xFA:
case 0xFB:
case 0xFE:
default:
*dest++ = c;
}
}
}
u8 *StringBraille(u8 *dest, const u8 *src)
{
u8 setBrailleFont[] = { 0xFC, 0x06, 0x06, 0xFF };
u8 gotoLine2[] = { 0xFE, 0xFC, 0x0E, 0x02, 0xFF };
dest = StringCopy(dest, setBrailleFont);
for (;;)
{
u8 c = *src++;
switch (c)
{
case EOS:
*dest = c;
return dest;
case 0xFE:
dest = StringCopy(dest, gotoLine2);
break;
default:
*dest++ = c;
*dest++ = c + 0x40;
break;
}
}
}
static u8 *ExpandPlaceholder_UnknownStringVar(void)
{
return gUnknownStringVar;
}
static u8 *ExpandPlaceholder_PlayerName(void)
{
return gSaveBlock2Ptr->playerName;
}
static u8 *ExpandPlaceholder_StringVar1(void)
{
return gStringVar1;
}
static u8 *ExpandPlaceholder_StringVar2(void)
{
return gStringVar2;
}
static u8 *ExpandPlaceholder_StringVar3(void)
{
return gStringVar3;
}
static u8 *ExpandPlaceholder_KunChan(void)
{
if (gSaveBlock2Ptr->playerGender == MALE)
return gExpandedPlaceholder_Kun;
else
return gExpandedPlaceholder_Chan;
}
static u8 *ExpandPlaceholder_RivalName(void)
{
if (gSaveBlock2Ptr->playerGender == MALE)
return gExpandedPlaceholder_May;
else
return gExpandedPlaceholder_Brendan;
}
static u8 *ExpandPlaceholder_Version(void)
{
return gExpandedPlaceholder_Emerald;
}
static u8 *ExpandPlaceholder_Aqua(void)
{
return gExpandedPlaceholder_Aqua;
}
static u8 *ExpandPlaceholder_Magma(void)
{
return gExpandedPlaceholder_Magma;
}
static u8 *ExpandPlaceholder_Archie(void)
{
return gExpandedPlaceholder_Archie;
}
static u8 *ExpandPlaceholder_Maxie(void)
{
return gExpandedPlaceholder_Maxie;
}
static u8 *ExpandPlaceholder_Kyogre(void)
{
return gExpandedPlaceholder_Kyogre;
}
static u8 *ExpandPlaceholder_Groudon(void)
{
return gExpandedPlaceholder_Groudon;
}
u8 *GetExpandedPlaceholder(u32 id)
{
typedef u8 *(*ExpandPlaceholderFunc)(void);
static const ExpandPlaceholderFunc funcs[] =
{
ExpandPlaceholder_UnknownStringVar,
ExpandPlaceholder_PlayerName,
ExpandPlaceholder_StringVar1,
ExpandPlaceholder_StringVar2,
ExpandPlaceholder_StringVar3,
ExpandPlaceholder_KunChan,
ExpandPlaceholder_RivalName,
ExpandPlaceholder_Version,
ExpandPlaceholder_Aqua,
ExpandPlaceholder_Magma,
ExpandPlaceholder_Archie,
ExpandPlaceholder_Maxie,
ExpandPlaceholder_Kyogre,
ExpandPlaceholder_Groudon,
};
if (id >= ARRAY_COUNT(funcs))
return gExpandedPlaceholder_Empty;
else
return funcs[id]();
}
u8 *StringFill(u8 *dest, u8 c, u16 n)
{
u16 i;
for (i = 0; i < n; i++)
*dest++ = c;
*dest = EOS;
return dest;
}
u8 *StringCopyPadded(u8 *dest, const u8 *src, u8 c, u16 n)
{
while (*src != EOS)
{
*dest++ = *src++;
if (n)
n--;
}
n--;
while (n != (u16)-1)
{
*dest++ = c;
n--;
}
*dest = EOS;
return dest;
}
u8 *StringFillWithTerminator(u8 *dest, u16 n)
{
return StringFill(dest, EOS, n);
}
u8 *StringCopyN_Multibyte(u8 *dest, u8 *src, u32 n)
{
u32 i;
for (i = n - 1; i != (u32)-1; i--)
{
if (*src == EOS)
{
break;
}
else
{
*dest++ = *src++;
if (*(src - 1) == 0xF9)
*dest++ = *src++;
}
}
*dest = EOS;
return dest;
}
u32 StringLength_Multibyte(u8 *str)
{
u32 length = 0;
while (*str != EOS)
{
if (*str == 0xF9)
str++;
str++;
length++;
}
return length;
}
u8 *WriteColorChangeControlCode(u8 *dest, u32 colorType, u8 color)
{
*dest = 0xFC;
dest++;
switch (colorType)
{
case 0:
*dest = 1;
dest++;
break;
case 1:
*dest = 3;
dest++;
break;
case 2:
*dest = 2;
dest++;
break;
}
*dest = color;
dest++;
*dest = EOS;
return dest;
}
bool32 sub_8009228(u8 *str)
{
while (*str != EOS)
{
if (*str <= 0xA0)
if (*str != 0)
return TRUE;
str++;
}
return FALSE;
}
bool32 sub_800924C(u8 *str, s32 n)
{
s32 i;
for (i = 0; *str != EOS && i < n; i++)
{
if (*str <= 0xA0)
if (*str != 0)
return TRUE;
str++;
}
return FALSE;
}
u8 GetExtCtrlCodeLength(u8 code)
{
static const u8 lengths[] =
{
1,
2,
2,
2,
4,
2,
2,
1,
2,
1,
1,
3,
2,
2,
2,
1,
3,
2,
2,
2,
2,
1,
1,
1,
1,
};
u8 length = 0;
if (code < ARRAY_COUNT(lengths))
length = lengths[code];
return length;
}
static const u8 *SkipExtCtrlCode(const u8 *s)
{
while (*s == 0xFC)
{
s++;
s += GetExtCtrlCodeLength(*s);
}
return s;
}
s32 StringCompareWithoutExtCtrlCodes(const u8 *str1, const u8 *str2)
{
s32 retVal = 0;
while (1)
{
str1 = SkipExtCtrlCode(str1);
str2 = SkipExtCtrlCode(str2);
if (*str1 > *str2)
break;
if (*str1 < *str2)
{
retVal = -1;
if (*str2 == 0xFF)
retVal = 1;
}
if (*str1 == 0xFF)
return retVal;
str1++;
str2++;
}
retVal = 1;
if (*str1 == 0xFF)
retVal = -1;
return retVal;
}
void ConvertInternationalString(u8 *s, u8 language)
{
if (language == LANGUAGE_JAPANESE)
{
u8 i;
StripExtCtrlCodes(s);
i = StringLength(s);
s[i++] = 0xFC;
s[i++] = 22;
s[i++] = 0xFF;
i--;
while (i != (u8)-1)
{
s[i + 2] = s[i];
i--;
}
s[0] = 0xFC;
s[1] = 21;
}
}
void StripExtCtrlCodes(u8 *str)
{
u16 srcIndex = 0;
u16 destIndex = 0;
while (str[srcIndex] != 0xFF)
{
if (str[srcIndex] == 0xFC)
{
srcIndex++;
srcIndex += GetExtCtrlCodeLength(str[srcIndex]);
}
else
{
str[destIndex++] = str[srcIndex++];
}
}
str[destIndex] = 0xFF;
}

View File

@@ -49,7 +49,6 @@ u8 CreateTask(TaskFunc func, u8 priority)
return 0;
}
#ifdef NONMATCHING
static void InsertTask(u8 newTaskId)
{
u8 taskId = FindFirstActiveTask();
@@ -62,7 +61,7 @@ static void InsertTask(u8 newTaskId)
return;
}
for (;;)
while (1)
{
if (gTasks[newTaskId].priority < gTasks[taskId].priority)
{
@@ -70,112 +69,22 @@ static void InsertTask(u8 newTaskId)
// so we insert the new task before it.
gTasks[newTaskId].prev = gTasks[taskId].prev;
gTasks[newTaskId].next = taskId;
if (gTasks[taskId].prev != HEAD_SENTINEL)
gTasks[gTasks[taskId].prev].next = newTaskId;
gTasks[taskId].prev = newTaskId;
return;
}
if (gTasks[taskId].next != TAIL_SENTINEL)
taskId = gTasks[taskId].next;
else
break;
if (gTasks[taskId].next == TAIL_SENTINEL)
{
// We've reached the end.
gTasks[newTaskId].prev = taskId;
gTasks[newTaskId].next = gTasks[taskId].next;
gTasks[taskId].next = newTaskId;
return;
}
taskId = gTasks[taskId].next;
}
// We've reached the end.
gTasks[newTaskId].prev = taskId;
gTasks[newTaskId].next = gTasks[taskId].next;
gTasks[taskId].next = newTaskId;
}
#else
__attribute__((naked))
static void InsertTask(u8 newTaskId)
{
asm("push {r4, r5, r6, r7, lr}\n\
mov r7, r8\n\
push {r7}\n\
lsl r0, r0, #24\n\
lsr r4, r0, #24\n\
bl FindFirstActiveTask\n\
lsl r0, r0, #24\n\
lsr r1, r0, #24\n\
cmp r1, #16\n\
bne .LInsertTask_foundActiveTask\n\
ldr r1, .LInsertTask_gTasks1\n\
lsl r0, r4, #2\n\
add r0, r0, r4\n\
lsl r0, r0, #3\n\
add r0, r0, r1\n\
mov r1, #254\n\
strb r1, [r0, #5]\n\
mov r1, #255\n\
strb r1, [r0, #6]\n\
b .LInsertTask_done\n\
.align 2, 0\n\
.LInsertTask_gTasks1:\n\
.word gTasks\n\
.LInsertTask_foundActiveTask:\n\
ldr r6, .LInsertTask_gTasks2\n\
lsl r0, r4, #2\n\
mov r12, r0\n\
mov r8, r6\n\
add r0, r0, r4\n\
lsl r0, r0, #3\n\
add r2, r0, r6\n\
.LInsertTask_loop:\n\
lsl r0, r1, #2\n\
add r0, r0, r1\n\
lsl r5, r0, #3\n\
mov r7, r8\n\
add r3, r5, r7\n\
ldrb r0, [r2, #7]\n\
ldrb r7, [r3, #7]\n\
cmp r0, r7\n\
bcs .LInsertTask_next\n\
ldrb r0, [r3, #5]\n\
strb r0, [r2, #5]\n\
strb r1, [r2, #6]\n\
ldrb r0, [r3, #5]\n\
cmp r0, #254\n\
beq .LInsertTask_insertAtHead\n\
add r1, r0, #0\n\
lsl r0, r1, #2\n\
add r0, r0, r1\n\
lsl r0, r0, #3\n\
add r0, r0, r8\n\
strb r4, [r0, #6]\n\
.LInsertTask_insertAtHead:\n\
strb r4, [r3, #5]\n\
b .LInsertTask_done\n\
.align 2, 0\n\
.LInsertTask_gTasks2:\n\
.word gTasks\n\
.LInsertTask_next:\n\
ldrb r0, [r3, #6]\n\
cmp r0, #255\n\
beq .LInsertTask_insertAtTail\n\
add r1, r0, #0\n\
b .LInsertTask_loop\n\
.LInsertTask_insertAtTail:\n\
mov r2, r12\n\
add r0, r2, r4\n\
lsl r0, r0, #3\n\
add r0, r0, r6\n\
strb r1, [r0, #5]\n\
add r2, r5, r6\n\
ldrb r1, [r2, #6]\n\
strb r1, [r0, #6]\n\
strb r4, [r2, #6]\n\
.LInsertTask_done:\n\
pop {r3}\n\
mov r8, r3\n\
pop {r4, r5, r6, r7}\n\
pop {r0}\n\
bx r0\n");
}
#endif // NONMATCHING
void DestroyTask(u8 taskId)
{