summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/agb_flash.c284
-rw-r--r--src/agb_flash_1m.c85
-rw-r--r--src/agb_flash_le.c30
-rw-r--r--src/agb_flash_mx.c166
-rw-r--r--src/main.c108
5 files changed, 673 insertions, 0 deletions
diff --git a/src/agb_flash.c b/src/agb_flash.c
new file mode 100644
index 0000000..11e2085
--- /dev/null
+++ b/src/agb_flash.c
@@ -0,0 +1,284 @@
+#include "gba/gba.h"
+#include "gba/flash_internal.h"
+
+static u8 sTimerNum;
+static u16 sTimerCount;
+static vu16 *sTimerReg;
+static u16 sSavedIme;
+
+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 = &REG_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, u8 *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, u8 *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;
+}
diff --git a/src/agb_flash_1m.c b/src/agb_flash_1m.c
new file mode 100644
index 0000000..85ee0a2
--- /dev/null
+++ b/src/agb_flash_1m.c
@@ -0,0 +1,85 @@
+#include "gba/gba.h"
+#include "gba/flash_internal.h"
+
+static const char AgbLibFlashVersion[] = "FLASH1M_V102";
+
+const struct FlashSetupInfo * const sSetupInfos[] =
+{
+ &MX29L010,
+ &LE26FV10N1TS,
+ &DefaultFlash
+};
+
+u16 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++;
+ }
+
+ 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;
+}
diff --git a/src/agb_flash_le.c b/src/agb_flash_le.c
new file mode 100644
index 0000000..f05b343
--- /dev/null
+++ b/src/agb_flash_le.c
@@ -0,0 +1,30 @@
+#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 =
+{
+ 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
+ }
+};
diff --git a/src/agb_flash_mx.c b/src/agb_flash_mx.c
new file mode 100644
index 0000000..50df609
--- /dev/null
+++ b/src/agb_flash_mx.c
@@ -0,0 +1,166 @@
+#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 =
+{
+ 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 =
+{
+ 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 != 0)
+ goto done;
+
+ numTries = 1;
+
+ goto try_erase;
+
+done:
+ REG_WAITCNT = (REG_WAITCNT & ~WAITCNT_SRAM_MASK) | WAITCNT_SRAM_8;
+
+ return result;
+}
+
+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, u8 *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;
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..212822e
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,108 @@
+#include "global.h"
+
+extern char ewram_start[];
+
+extern u16 gUnknown_202D7FC;
+extern u8 gUnknown_202D7FE;
+
+extern char alt_203B038[];
+
+extern char gUnknown_203B038[];
+extern char gUnknown_203BC04[];
+
+extern char iwram_start[];
+
+extern char alt_3001B58[];
+
+extern char unk_code_ram[];
+extern char unk_code_ram_end[];
+
+extern u8 gUnknown_80B9BF1[];
+
+extern char gUnknown_8270000[];
+
+extern char unk_code[];
+
+extern void sub_800CDA8(int);
+extern void sub_800B540(void);
+extern void sub_800CF0C(void);
+extern void SeedRng(u8 *);
+extern void sub_8004D78(void);
+extern void nullsub_9(void);
+extern void nullsub_6(void);
+extern void sub_80047E8(void);
+extern void InitBGPaletteBuffer(void);
+extern void sub_80057E8(void);
+extern void sub_800A8C4(void);
+extern void sub_8006218(void);
+extern void sub_80098A0(void);
+extern void sub_80096E0(void);
+extern void sub_800B6F4(int, void *);
+extern void GameLoop(void);
+extern void Hang(void);
+extern void sub_800CE54(void);
+
+void AgbMain(void)
+{
+ u8 value[4];
+ u8 seed[6];
+
+ REG_WAITCNT = WAITCNT_PREFETCH_ENABLE | WAITCNT_WS0_S_1 | WAITCNT_WS0_N_3;
+
+ DmaStop(0);
+ DmaStop(1);
+ DmaStop(2);
+ DmaStop(3);
+
+ if (gUnknown_203BC04 - gUnknown_203B038 > 0)
+ CpuCopy32(gUnknown_8270000, gUnknown_203B038, gUnknown_203BC04 - gUnknown_203B038);
+
+ if (alt_203B038 - ewram_start > 0)
+ {
+ memset(value, 0, 4);
+ CpuSet(&value, ewram_start, CPU_SET_SRC_FIXED | CPU_SET_32BIT | (((alt_203B038 - ewram_start) / 4) & 0x1FFFFF));
+ }
+
+ if (unk_code_ram_end - unk_code_ram > 0)
+ CpuCopy32(unk_code, unk_code_ram, unk_code_ram_end - unk_code_ram);
+
+ if (alt_3001B58 - iwram_start > 0)
+ {
+ memset(value, 0, 4);
+ CpuSet(&value, iwram_start, CPU_SET_SRC_FIXED | CPU_SET_32BIT | (((alt_3001B58 - iwram_start) / 4) & 0x1FFFFF));
+ }
+
+ REG_WIN0H = 0;
+ REG_WIN1H = 0;
+ REG_WIN0V = 0;
+ REG_WIN1V = 0;
+ REG_WININ = 16191;
+ REG_WINOUT = 61;
+ gUnknown_202D7FC = REG_BLDCNT = 15426;
+ REG_BLDALPHA = 1546;
+ gUnknown_202D7FE = 0;
+ REG_BG0CNT = 11264;
+ REG_BG1CNT = 11521;
+ REG_BG2CNT = 11786;
+ REG_BG3CNT = 12043;
+ REG_DISPCNT = 32704;
+ sub_800CDA8(1);
+ sub_800B540();
+ sub_800CF0C();
+ memcpy(seed, gUnknown_80B9BF1, 6);
+ SeedRng(seed);
+ sub_8004D78();
+ nullsub_9();
+ nullsub_6();
+ sub_80047E8();
+ InitBGPaletteBuffer();
+ sub_80057E8();
+ sub_800A8C4();
+ sub_8006218();
+ sub_80098A0();
+ sub_80096E0();
+ sub_800B6F4(1, sub_800CE54);
+ REG_DISPCNT = 32576;
+ GameLoop();
+ Hang();
+}