Payload is now independent of agbsdk
Are you happy now @luckytyphlosion? Kappa
This commit is contained in:
@@ -0,0 +1,296 @@
|
||||
#include <gba/gba.h>
|
||||
#include <gba/flash_internal.h>
|
||||
|
||||
static u8 sTimerNum;
|
||||
static u16 sTimerCount;
|
||||
static vu16 *sTimerReg;
|
||||
static u16 sSavedIme;
|
||||
|
||||
u8 gFlashTimeoutFlag;
|
||||
u8 (*PollFlashStatus)(u8 *);
|
||||
const struct FlashType *gFlash;
|
||||
u16 gFlashNumRemainingBytes;
|
||||
const u16 *gFlashMaxTime;
|
||||
|
||||
u16 (*ProgramFlashByte)(u16, u32, u8);
|
||||
u16 (*ProgramFlashSector)(u16, void *);
|
||||
u16 (*EraseFlashChip)(void);
|
||||
u16 (*EraseFlashSector)(u16);
|
||||
u16 (*WaitForFlashWrite)(u8, u8 *, u8);
|
||||
|
||||
void SetReadFlash1(u16 *dest);
|
||||
|
||||
void SwitchFlashBank(u8 bankNum)
|
||||
{
|
||||
FLASH_WRITE(0x5555, 0xAA);
|
||||
FLASH_WRITE(0x2AAA, 0x55);
|
||||
FLASH_WRITE(0x5555, 0xB0);
|
||||
FLASH_WRITE(0x0000, bankNum);
|
||||
}
|
||||
|
||||
#define DELAY() \
|
||||
do { \
|
||||
vu16 i; \
|
||||
for (i = 20000; i != 0; i--) \
|
||||
; \
|
||||
} while (0)
|
||||
|
||||
u16 ReadFlashId(void)
|
||||
{
|
||||
u16 flashId;
|
||||
u16 readFlash1Buffer[0x20];
|
||||
u8 (*readFlash1)(u8 *);
|
||||
|
||||
SetReadFlash1(readFlash1Buffer);
|
||||
readFlash1 = (u8 (*)(u8 *))((s32)readFlash1Buffer + 1);
|
||||
|
||||
// Enter ID mode.
|
||||
FLASH_WRITE(0x5555, 0xAA);
|
||||
FLASH_WRITE(0x2AAA, 0x55);
|
||||
FLASH_WRITE(0x5555, 0x90);
|
||||
DELAY();
|
||||
|
||||
flashId = readFlash1(FLASH_BASE + 1) << 8;
|
||||
flashId |= readFlash1(FLASH_BASE);
|
||||
|
||||
// Leave ID mode.
|
||||
FLASH_WRITE(0x5555, 0xAA);
|
||||
FLASH_WRITE(0x2AAA, 0x55);
|
||||
FLASH_WRITE(0x5555, 0xF0);
|
||||
FLASH_WRITE(0x5555, 0xF0);
|
||||
DELAY();
|
||||
|
||||
return flashId;
|
||||
}
|
||||
|
||||
void FlashTimerIntr(void)
|
||||
{
|
||||
if (sTimerCount != 0 && --sTimerCount == 0)
|
||||
gFlashTimeoutFlag = 1;
|
||||
}
|
||||
|
||||
u16 SetFlashTimerIntr(u8 timerNum, void (**intrFunc)(void))
|
||||
{
|
||||
if (timerNum >= 4)
|
||||
return 1;
|
||||
|
||||
sTimerNum = timerNum;
|
||||
sTimerReg = ®_TMCNT(sTimerNum);
|
||||
*intrFunc = FlashTimerIntr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void StartFlashTimer(u8 phase)
|
||||
{
|
||||
const u16 *maxTime = &gFlashMaxTime[phase * 3];
|
||||
sSavedIme = REG_IME;
|
||||
REG_IME = 0;
|
||||
sTimerReg[1] = 0;
|
||||
REG_IE |= (INTR_FLAG_TIMER0 << sTimerNum);
|
||||
gFlashTimeoutFlag = 0;
|
||||
sTimerCount = *maxTime++;
|
||||
*sTimerReg++ = *maxTime++;
|
||||
*sTimerReg-- = *maxTime++;
|
||||
REG_IF = (INTR_FLAG_TIMER0 << sTimerNum);
|
||||
REG_IME = 1;
|
||||
}
|
||||
|
||||
void StopFlashTimer(void)
|
||||
{
|
||||
REG_IME = 0;
|
||||
*sTimerReg++ = 0;
|
||||
*sTimerReg-- = 0;
|
||||
REG_IE &= ~(INTR_FLAG_TIMER0 << sTimerNum);
|
||||
REG_IME = sSavedIme;
|
||||
}
|
||||
|
||||
u8 ReadFlash1(u8 *addr)
|
||||
{
|
||||
return *addr;
|
||||
}
|
||||
|
||||
void SetReadFlash1(u16 *dest)
|
||||
{
|
||||
u16 *src;
|
||||
u16 i;
|
||||
|
||||
PollFlashStatus = (u8 (*)(u8 *))((s32)dest + 1);
|
||||
|
||||
src = (u16 *)ReadFlash1;
|
||||
src = (u16 *)((s32)src ^ 1);
|
||||
|
||||
i = ((s32)SetReadFlash1 - (s32)ReadFlash1) >> 1;
|
||||
|
||||
while (i != 0)
|
||||
{
|
||||
*dest++ = *src++;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
void ReadFlash_Core(u8 *src, u8 *dest, u32 size)
|
||||
{
|
||||
while (size-- != 0)
|
||||
{
|
||||
*dest++ = *src++;
|
||||
}
|
||||
}
|
||||
|
||||
void ReadFlash(u16 sectorNum, u32 offset, void *dest, u32 size)
|
||||
{
|
||||
u8 *src;
|
||||
u16 i;
|
||||
u16 readFlash_Core_Buffer[0x40];
|
||||
u16 *funcSrc;
|
||||
u16 *funcDest;
|
||||
void (*readFlash_Core)(u8 *, u8 *, u32);
|
||||
|
||||
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | WAITCNT_SRAM_8;
|
||||
|
||||
if (gFlash->romSize == FLASH_ROM_SIZE_1M)
|
||||
{
|
||||
SwitchFlashBank(sectorNum / SECTORS_PER_BANK);
|
||||
sectorNum %= SECTORS_PER_BANK;
|
||||
}
|
||||
|
||||
funcSrc = (u16 *)ReadFlash_Core;
|
||||
funcSrc = (u16 *)((s32)funcSrc ^ 1);
|
||||
funcDest = readFlash_Core_Buffer;
|
||||
|
||||
i = ((s32)ReadFlash - (s32)ReadFlash_Core) >> 1;
|
||||
|
||||
while (i != 0)
|
||||
{
|
||||
*funcDest++ = *funcSrc++;
|
||||
i--;
|
||||
}
|
||||
|
||||
readFlash_Core = (void (*)(u8 *, u8 *, u32))((s32)readFlash_Core_Buffer + 1);
|
||||
|
||||
src = FLASH_BASE + (sectorNum << gFlash->sector.shift) + offset;
|
||||
|
||||
readFlash_Core(src, dest, size);
|
||||
}
|
||||
|
||||
u32 VerifyFlashSector_Core(u8 *src, u8 *tgt, u32 size)
|
||||
{
|
||||
while (size-- != 0)
|
||||
{
|
||||
if (*tgt++ != *src++)
|
||||
return (u32)(tgt - 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 VerifyFlashSector(u16 sectorNum, u8 *src)
|
||||
{
|
||||
u16 i;
|
||||
u16 verifyFlashSector_Core_Buffer[0x80];
|
||||
u16 *funcSrc;
|
||||
u16 *funcDest;
|
||||
u8 *tgt;
|
||||
u16 size;
|
||||
u32 (*verifyFlashSector_Core)(u8 *, u8 *, u32);
|
||||
|
||||
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | WAITCNT_SRAM_8;
|
||||
|
||||
if (gFlash->romSize == FLASH_ROM_SIZE_1M)
|
||||
{
|
||||
SwitchFlashBank(sectorNum / SECTORS_PER_BANK);
|
||||
sectorNum %= SECTORS_PER_BANK;
|
||||
}
|
||||
|
||||
funcSrc = (u16 *)VerifyFlashSector_Core;
|
||||
funcSrc = (u16 *)((s32)funcSrc ^ 1);
|
||||
funcDest = verifyFlashSector_Core_Buffer;
|
||||
|
||||
i = ((s32)VerifyFlashSector - (s32)VerifyFlashSector_Core) >> 1;
|
||||
|
||||
while (i != 0)
|
||||
{
|
||||
*funcDest++ = *funcSrc++;
|
||||
i--;
|
||||
}
|
||||
|
||||
verifyFlashSector_Core = (u32 (*)(u8 *, u8 *, u32))((s32)verifyFlashSector_Core_Buffer + 1);
|
||||
|
||||
tgt = FLASH_BASE + (sectorNum << gFlash->sector.shift);
|
||||
size = gFlash->sector.size;
|
||||
|
||||
return verifyFlashSector_Core(src, tgt, size);
|
||||
}
|
||||
|
||||
u32 VerifyFlashSectorNBytes(u16 sectorNum, u8 *src, u32 n)
|
||||
{
|
||||
u16 i;
|
||||
u16 verifyFlashSector_Core_Buffer[0x80];
|
||||
u16 *funcSrc;
|
||||
u16 *funcDest;
|
||||
u8 *tgt;
|
||||
u32 (*verifyFlashSector_Core)(u8 *, u8 *, u32);
|
||||
|
||||
if (gFlash->romSize == FLASH_ROM_SIZE_1M)
|
||||
{
|
||||
SwitchFlashBank(sectorNum / SECTORS_PER_BANK);
|
||||
sectorNum %= SECTORS_PER_BANK;
|
||||
}
|
||||
|
||||
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | WAITCNT_SRAM_8;
|
||||
|
||||
funcSrc = (u16 *)VerifyFlashSector_Core;
|
||||
funcSrc = (u16 *)((s32)funcSrc ^ 1);
|
||||
funcDest = verifyFlashSector_Core_Buffer;
|
||||
|
||||
i = ((s32)VerifyFlashSector - (s32)VerifyFlashSector_Core) >> 1;
|
||||
|
||||
while (i != 0)
|
||||
{
|
||||
*funcDest++ = *funcSrc++;
|
||||
i--;
|
||||
}
|
||||
|
||||
verifyFlashSector_Core = (u32 (*)(u8 *, u8 *, u32))((s32)verifyFlashSector_Core_Buffer + 1);
|
||||
|
||||
tgt = FLASH_BASE + (sectorNum << gFlash->sector.shift);
|
||||
|
||||
return verifyFlashSector_Core(src, tgt, n);
|
||||
}
|
||||
|
||||
u32 ProgramFlashSectorAndVerify(u16 sectorNum, u8 *src)
|
||||
{
|
||||
u8 i;
|
||||
u32 result;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
result = ProgramFlashSector(sectorNum, src);
|
||||
if (result != 0)
|
||||
continue;
|
||||
|
||||
result = VerifyFlashSector(sectorNum, src);
|
||||
if (result == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 ProgramFlashSectorAndVerifyNBytes(u16 sectorNum, void *src, u32 n)
|
||||
{
|
||||
u8 i;
|
||||
u32 result;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
result = ProgramFlashSector(sectorNum, src);
|
||||
if (result != 0)
|
||||
continue;
|
||||
|
||||
result = VerifyFlashSectorNBytes(sectorNum, src, n);
|
||||
if (result == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
#include "gba/gba.h"
|
||||
#include "gba/flash_internal.h"
|
||||
|
||||
static const char AgbLibFlashVersion[] = "FLASH1M_V103";
|
||||
|
||||
const struct FlashSetupInfo * const sSetupInfos[] =
|
||||
{
|
||||
&MX29L010,
|
||||
&LE26FV10N1TS,
|
||||
&DefaultFlash
|
||||
};
|
||||
|
||||
u32 IdentifyFlash(void)
|
||||
{
|
||||
u16 result;
|
||||
u16 flashId;
|
||||
const struct FlashSetupInfo * const *setupInfo;
|
||||
|
||||
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | WAITCNT_SRAM_8;
|
||||
|
||||
flashId = ReadFlashId();
|
||||
|
||||
setupInfo = sSetupInfos;
|
||||
result = 1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if ((*setupInfo)->type.ids.separate.makerId == 0)
|
||||
break;
|
||||
|
||||
if (flashId == (*setupInfo)->type.ids.joined)
|
||||
{
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
setupInfo++;
|
||||
}
|
||||
|
||||
ProgramFlashByte = (*setupInfo)->programFlashByte;
|
||||
ProgramFlashSector = (*setupInfo)->programFlashSector;
|
||||
EraseFlashChip = (*setupInfo)->eraseFlashChip;
|
||||
EraseFlashSector = (*setupInfo)->eraseFlashSector;
|
||||
WaitForFlashWrite = (*setupInfo)->WaitForFlashWrite;
|
||||
gFlashMaxTime = (*setupInfo)->maxTime;
|
||||
gFlash = &(*setupInfo)->type;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
u16 WaitForFlashWrite_Common(u8 phase, u8 *addr, u8 lastData)
|
||||
{
|
||||
u16 result = 0;
|
||||
u8 status;
|
||||
|
||||
StartFlashTimer(phase);
|
||||
|
||||
while ((status = PollFlashStatus(addr)) != lastData)
|
||||
{
|
||||
if (status & 0x20)
|
||||
{
|
||||
// The write operation exceeded the flash chip's time limit.
|
||||
|
||||
if (PollFlashStatus(addr) == lastData)
|
||||
break;
|
||||
|
||||
FLASH_WRITE(0x5555, 0xF0);
|
||||
result = phase | 0xA000u;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gFlashTimeoutFlag)
|
||||
{
|
||||
if (PollFlashStatus(addr) == lastData)
|
||||
break;
|
||||
|
||||
FLASH_WRITE(0x5555, 0xF0);
|
||||
result = phase | 0xC000u;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
StopFlashTimer();
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "gba/gba.h"
|
||||
#include "gba/flash_internal.h"
|
||||
|
||||
const u16 leMaxTime[] =
|
||||
{
|
||||
10, 65469, TIMER_ENABLE | TIMER_INTR_ENABLE | TIMER_256CLK,
|
||||
10, 65469, TIMER_ENABLE | TIMER_INTR_ENABLE | TIMER_256CLK,
|
||||
2000, 65469, TIMER_ENABLE | TIMER_INTR_ENABLE | TIMER_256CLK,
|
||||
2000, 65469, TIMER_ENABLE | TIMER_INTR_ENABLE | TIMER_256CLK,
|
||||
};
|
||||
|
||||
const struct FlashSetupInfo LE26FV10N1TS =
|
||||
{
|
||||
ProgramFlashByte_MX,
|
||||
ProgramFlashSector_MX,
|
||||
EraseFlashChip_MX,
|
||||
EraseFlashSector_MX,
|
||||
WaitForFlashWrite_Common,
|
||||
leMaxTime,
|
||||
{
|
||||
131072, // ROM size
|
||||
{
|
||||
4096, // sector size
|
||||
12, // bit shift to multiply by sector size (4096 == 1 << 12)
|
||||
32, // number of sectors
|
||||
0 // appears to be unused
|
||||
},
|
||||
{ 3, 1 }, // wait state setup data
|
||||
{ { 0x62, 0x13 } } // ID
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,193 @@
|
||||
#include "gba/gba.h"
|
||||
#include "gba/flash_internal.h"
|
||||
|
||||
const u16 mxMaxTime[] =
|
||||
{
|
||||
10, 65469, TIMER_ENABLE | TIMER_INTR_ENABLE | TIMER_256CLK,
|
||||
10, 65469, TIMER_ENABLE | TIMER_INTR_ENABLE | TIMER_256CLK,
|
||||
2000, 65469, TIMER_ENABLE | TIMER_INTR_ENABLE | TIMER_256CLK,
|
||||
2000, 65469, TIMER_ENABLE | TIMER_INTR_ENABLE | TIMER_256CLK,
|
||||
};
|
||||
|
||||
const struct FlashSetupInfo MX29L010 =
|
||||
{
|
||||
ProgramFlashByte_MX,
|
||||
ProgramFlashSector_MX,
|
||||
EraseFlashChip_MX,
|
||||
EraseFlashSector_MX,
|
||||
WaitForFlashWrite_Common,
|
||||
mxMaxTime,
|
||||
{
|
||||
131072, // ROM size
|
||||
{
|
||||
4096, // sector size
|
||||
12, // bit shift to multiply by sector size (4096 == 1 << 12)
|
||||
32, // number of sectors
|
||||
0 // appears to be unused
|
||||
},
|
||||
{ 3, 1 }, // wait state setup data
|
||||
{ { 0xC2, 0x09 } } // ID
|
||||
}
|
||||
};
|
||||
|
||||
const struct FlashSetupInfo DefaultFlash =
|
||||
{
|
||||
ProgramFlashByte_MX,
|
||||
ProgramFlashSector_MX,
|
||||
EraseFlashChip_MX,
|
||||
EraseFlashSector_MX,
|
||||
WaitForFlashWrite_Common,
|
||||
mxMaxTime,
|
||||
{
|
||||
131072, // ROM size
|
||||
{
|
||||
4096, // sector size
|
||||
12, // bit shift to multiply by sector size (4096 == 1 << 12)
|
||||
32, // number of sectors
|
||||
0 // appears to be unused
|
||||
},
|
||||
{ 3, 1 }, // wait state setup data
|
||||
{ { 0x00, 0x00 } } // ID of 0
|
||||
}
|
||||
};
|
||||
|
||||
u16 EraseFlashChip_MX(void)
|
||||
{
|
||||
u16 result;
|
||||
u16 readFlash1Buffer[0x20];
|
||||
|
||||
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | gFlash->wait[0];
|
||||
|
||||
FLASH_WRITE(0x5555, 0xAA);
|
||||
FLASH_WRITE(0x2AAA, 0x55);
|
||||
FLASH_WRITE(0x5555, 0x80);
|
||||
FLASH_WRITE(0x5555, 0xAA);
|
||||
FLASH_WRITE(0x2AAA, 0x55);
|
||||
FLASH_WRITE(0x5555, 0x10);
|
||||
|
||||
SetReadFlash1(readFlash1Buffer);
|
||||
|
||||
result = WaitForFlashWrite(3, FLASH_BASE, 0xFF);
|
||||
|
||||
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | WAITCNT_SRAM_8;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
u16 EraseFlashSector_MX(u16 sectorNum)
|
||||
{
|
||||
u16 numTries;
|
||||
u16 result;
|
||||
u8 *addr;
|
||||
u16 readFlash1Buffer[0x20];
|
||||
|
||||
if (sectorNum >= gFlash->sector.count)
|
||||
return 0x80FF;
|
||||
|
||||
SwitchFlashBank(sectorNum / SECTORS_PER_BANK);
|
||||
sectorNum %= SECTORS_PER_BANK;
|
||||
|
||||
numTries = 0;
|
||||
|
||||
try_erase:
|
||||
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | gFlash->wait[0];
|
||||
|
||||
addr = FLASH_BASE + (sectorNum << gFlash->sector.shift);
|
||||
|
||||
FLASH_WRITE(0x5555, 0xAA);
|
||||
FLASH_WRITE(0x2AAA, 0x55);
|
||||
FLASH_WRITE(0x5555, 0x80);
|
||||
FLASH_WRITE(0x5555, 0xAA);
|
||||
FLASH_WRITE(0x2AAA, 0x55);
|
||||
*addr = 0x30;
|
||||
|
||||
SetReadFlash1(readFlash1Buffer);
|
||||
|
||||
result = WaitForFlashWrite(2, addr, 0xFF);
|
||||
|
||||
if (!(result & 0xA000) || numTries > 3)
|
||||
goto done;
|
||||
|
||||
numTries++;
|
||||
|
||||
goto try_erase;
|
||||
|
||||
done:
|
||||
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | WAITCNT_SRAM_8;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
u16 ProgramFlashByte_MX(u16 sectorNum, u32 offset, u8 data)
|
||||
{
|
||||
u8 *addr;
|
||||
u16 readFlash1Buffer[0x20];
|
||||
|
||||
if (offset >= gFlash->sector.size)
|
||||
return 0x8000;
|
||||
|
||||
SwitchFlashBank(sectorNum / SECTORS_PER_BANK);
|
||||
sectorNum %= SECTORS_PER_BANK;
|
||||
|
||||
addr = FLASH_BASE + (sectorNum << gFlash->sector.shift) + offset;
|
||||
|
||||
SetReadFlash1(readFlash1Buffer);
|
||||
|
||||
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | gFlash->wait[0];
|
||||
|
||||
FLASH_WRITE(0x5555, 0xAA);
|
||||
FLASH_WRITE(0x2AAA, 0x55);
|
||||
FLASH_WRITE(0x5555, 0xA0);
|
||||
*addr = data;
|
||||
|
||||
return WaitForFlashWrite(1, addr, data);
|
||||
}
|
||||
|
||||
static u16 ProgramByte(u8 *src, u8 *dest)
|
||||
{
|
||||
FLASH_WRITE(0x5555, 0xAA);
|
||||
FLASH_WRITE(0x2AAA, 0x55);
|
||||
FLASH_WRITE(0x5555, 0xA0);
|
||||
*dest = *src;
|
||||
|
||||
return WaitForFlashWrite(1, dest, *src);
|
||||
}
|
||||
|
||||
u16 ProgramFlashSector_MX(u16 sectorNum, void *src)
|
||||
{
|
||||
u16 result;
|
||||
u8 *dest;
|
||||
u16 readFlash1Buffer[0x20];
|
||||
|
||||
if (sectorNum >= gFlash->sector.count)
|
||||
return 0x80FF;
|
||||
|
||||
result = EraseFlashSector_MX(sectorNum);
|
||||
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
SwitchFlashBank(sectorNum / SECTORS_PER_BANK);
|
||||
sectorNum %= SECTORS_PER_BANK;
|
||||
|
||||
SetReadFlash1(readFlash1Buffer);
|
||||
|
||||
REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | gFlash->wait[0];
|
||||
|
||||
gFlashNumRemainingBytes = gFlash->sector.size;
|
||||
dest = FLASH_BASE + (sectorNum << gFlash->sector.shift);
|
||||
|
||||
while (gFlashNumRemainingBytes > 0)
|
||||
{
|
||||
result = ProgramByte(src, dest);
|
||||
|
||||
if (result != 0)
|
||||
break;
|
||||
|
||||
gFlashNumRemainingBytes--;
|
||||
src++;
|
||||
dest++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <gba/gba.h>
|
||||
#include <agb_flash.h>
|
||||
#include "gba/gba.h"
|
||||
#include "gba/flash_internal.h"
|
||||
#include "constants/vars.h"
|
||||
#include "global.h"
|
||||
#include "main.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <gba/gba.h>
|
||||
#include "gba/gba.h"
|
||||
#include "global.h"
|
||||
#include "main.h"
|
||||
#include "rtc.h"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <gba/gba.h>
|
||||
#include <siirtc.h>
|
||||
#include "gba/gba.h"
|
||||
#include "siirtc.h"
|
||||
#include "global.h"
|
||||
#include "main.h"
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user