diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | asm/rom.s | 10 | ||||
-rw-r--r-- | data/data2.s | 2 | ||||
-rw-r--r-- | include/gba/flash_internal.h | 65 | ||||
-rw-r--r-- | include/gba/io_reg.h | 51 | ||||
-rw-r--r-- | include/gba/macro.h | 4 | ||||
-rw-r--r-- | include/gba/syscall.h | 4 | ||||
-rw-r--r-- | iwram_syms.txt | 16 | ||||
-rw-r--r-- | src/agb_flash.c | 295 | ||||
-rw-r--r-- | src/agb_flash_1m.c | 80 | ||||
-rw-r--r-- | src/agb_flash_mx.c | 143 |
11 files changed, 666 insertions, 8 deletions
@@ -64,6 +64,10 @@ $(OBJS): $(CSRCS:src/%.c=genasm/%.s) genasm/siirtc.s: CFLAGS := -mthumb-interwork -Iinclude +genasm/agb_flash.s: CFLAGS := -O -mthumb-interwork -Iinclude +genasm/agb_flash_1m.s: CFLAGS := -O -mthumb-interwork -Iinclude +genasm/agb_flash_mx.s: CFLAGS := -O -mthumb-interwork -Iinclude + # TODO: fix this .syntax hack genasm/prefix.tmp: @@ -600023,7 +600023,7 @@ sub_8125440: ; 8125440 lsls r0, 24 lsrs r4, r0, 24 adds r0, r4, 0 - bl ProgramFlashSectorsAndVerify + bl ProgramFlashSectorAndVerify cmp r0, 0 bne _0812545C movs r0, 0x1 @@ -601555,7 +601555,7 @@ _08126030: movs r2, 0x80 lsls r2, 5 adds r1, r4, 0 - bl ProgramFlashSectorsVerifyFirstNBytes + bl ProgramFlashSectorAndVerifyNBytes ldr r1, _0812605C str r0, [r1] cmp r0, 0 @@ -601582,7 +601582,7 @@ sub_8126068: ; 8126068 push {lr} lsls r0, 24 lsrs r0, 24 - bl ProgramFlashSectorsAndVerify + bl ProgramFlashSectorAndVerify cmp r0, 0 bne _0812607A movs r0, 0x1 @@ -676820,7 +676820,9 @@ _0814AE2C: .4byte gUnknown_0842F6C0 .include "data/data1.s" .include "asm/libgcnmultiboot.s" .include "asm/libmks4agb.s" - .include "asm/libagbbackup.s" + .include "genasm/agb_flash.s" + .include "genasm/agb_flash_1m.s" + .include "genasm/agb_flash_mx.s" .include "genasm/siirtc.s" .include "asm/libagbsyscall.s" .include "asm/libgcc.s" diff --git a/data/data2.s b/data/data2.s index a3c66a58a..e165ab50e 100644 --- a/data/data2.s +++ b/data/data2.s @@ -7984,7 +7984,7 @@ gUnknown_0845545C: ; 845545C gUnknown_0845548C: ; 845548C .incbin "baserom.gba", 0x0045548c, 0x25b31c -gUnknown_086B07A8: ; 86B07A8 +sSetupInfos: ; 86B07A8 .incbin "baserom.gba", 0x006b07a8, 0x150 gUnknown_086B08F8: ; 86B08F8 diff --git a/include/gba/flash_internal.h b/include/gba/flash_internal.h new file mode 100644 index 000000000..ca357d196 --- /dev/null +++ b/include/gba/flash_internal.h @@ -0,0 +1,65 @@ +#ifndef GUARD_GBA_FLASH_INTERNAL_H +#define GUARD_GBA_FLASH_INTERNAL_H + +#define FLASH_BASE ((u8 *)0xE000000) + +#define FLASH_WRITE(addr, data) ((*(vu8 *)(FLASH_BASE + (addr))) = (data)) + +#define FLASH_ROM_SIZE_1M 131072 // 1 megabit ROM + +#define SECTORS_PER_BANK 16 + +struct FlashSector +{ + u32 size; + u8 shift; + u16 count; + u16 top; +}; + +struct FlashType { + u32 romSize; + struct FlashSector sector; + u16 wait[2]; // game pak bus read/write wait + + // TODO: add support for anonymous unions/structs if possible + union { + struct { + u8 makerId; + u8 deviceId; + } separate; + u16 joined; + } ids; +}; + +struct FlashSetupInfo +{ + u16 (*programFlashByte)(u16, u32, u8); + u16 (*programFlashSector)(u16, u8 *); + u16 (*eraseFlashChip)(void); + u16 (*eraseFlashSector)(u16); + u16 (*WaitForFlashWrite)(u8, u8 *, u8); + const u16 *maxTime; + struct FlashType type; +}; + +extern u16 gFlashNumRemainingBytes; + +extern u16 (*ProgramFlashByte)(u16, u32, u8); +extern u16 (*ProgramFlashSector)(u16, u8 *); +extern u16 (*EraseFlashChip)(void); +extern u16 (*EraseFlashSector)(u16); +extern u16 (*WaitForFlashWrite)(u8, u8 *, u8); +extern const u16 *gFlashMaxTime; +extern const struct FlashType *gFlash; + +extern u8 (*PollFlashStatus)(u8 *); +extern u8 gFlashTimeoutFlag; + +void SwitchFlashBank(u8 bankNum); +u16 ReadFlashId(void); +void StartFlashTimer(u8 phase); +void SetReadFlash1(u16 *dest); +void StopFlashTimer(void); + +#endif // GUARD_GBA_FLASH_INTERNAL_H diff --git a/include/gba/io_reg.h b/include/gba/io_reg.h index ed27f33b8..e8b3bde47 100644 --- a/include/gba/io_reg.h +++ b/include/gba/io_reg.h @@ -128,6 +128,7 @@ #define REG_OFFSET_DMA3CNT_L 0xdc #define REG_OFFSET_DMA3CNT_H 0xde +#define REG_OFFSET_TMCNT 0x100 #define REG_OFFSET_TM0CNT 0x100 #define REG_OFFSET_TM0CNT_L 0x100 #define REG_OFFSET_TM0CNT_H 0x102 @@ -280,6 +281,7 @@ #define REG_ADDR_DMA3CNT_L (REG_BASE + REG_OFFSET_DMA3CNT_L) #define REG_ADDR_DMA3CNT_H (REG_BASE + REG_OFFSET_DMA3CNT_H) +#define REG_ADDR_TMCNT (REG_BASE + REG_OFFSET_TMCNT) #define REG_ADDR_TM0CNT (REG_BASE + REG_OFFSET_TM0CNT) #define REG_ADDR_TM0CNT_L (REG_BASE + REG_OFFSET_TM0CNT_L) #define REG_ADDR_TM0CNT_H (REG_BASE + REG_OFFSET_TM0CNT_H) @@ -353,10 +355,14 @@ #define REG_DMA3CNT_L (*(vu16 *)REG_ADDR_DMA3CNT_L) #define REG_DMA3CNT_H (*(vu16 *)REG_ADDR_DMA3CNT_H) +#define REG_TMCNT(n) (*(vu16 *)(REG_ADDR_TMCNT + ((n) * 4))) + #define REG_IME (*(vu16 *)REG_ADDR_IME) #define REG_IE (*(vu16 *)REG_ADDR_IE) #define REG_IF (*(vu16 *)REG_ADDR_IF) +#define REG_WAITCNT (*(vu16 *)REG_ADDR_WAITCNT) + // I/O register fields // DISPCNT @@ -412,4 +418,49 @@ #define INTR_FLAG_KEYPAD (1 << 12) #define INTR_FLAG_GAMEPAK (1 << 13) +// WAITCNT +#define WAITCNT_SRAM_4 (0 << 0) +#define WAITCNT_SRAM_3 (1 << 0) +#define WAITCNT_SRAM_2 (2 << 0) +#define WAITCNT_SRAM_8 (3 << 0) +#define WAITCNT_SRAM_MASK (3 << 0) + +#define WAITCNT_WS0_N_4 (0 << 2) +#define WAITCNT_WS0_N_3 (1 << 2) +#define WAITCNT_WS0_N_2 (2 << 2) +#define WAITCNT_WS0_N_8 (3 << 2) +#define WAITCNT_WS0_N_MASK (3 << 2) + +#define WAITCNT_WS0_S_2 (0 << 4) +#define WAITCNT_WS0_S_1 (1 << 4) + +#define WAITCNT_WS1_N_4 (0 << 5) +#define WAITCNT_WS1_N_3 (1 << 5) +#define WAITCNT_WS1_N_2 (2 << 5) +#define WAITCNT_WS1_N_8 (3 << 5) +#define WAITCNT_WS1_N_MASK (3 << 5) + +#define WAITCNT_WS1_S_4 (0 << 7) +#define WAITCNT_WS1_S_1 (1 << 7) + +#define WAITCNT_WS2_N_4 (0 << 8) +#define WAITCNT_WS2_N_3 (1 << 8) +#define WAITCNT_WS2_N_2 (2 << 8) +#define WAITCNT_WS2_N_8 (3 << 8) +#define WAITCNT_WS2_N_MASK (3 << 8) + +#define WAITCNT_WS2_S_8 (0 << 10) +#define WAITCNT_WS2_S_1 (1 << 10) + +#define WAITCNT_PHI_OUT_NONE (0 << 11) +#define WAITCNT_PHI_OUT_4MHZ (1 << 11) +#define WAITCNT_PHI_OUT_8MHZ (2 << 11) +#define WAITCNT_PHI_OUT_16MHZ (3 << 11) +#define WAITCNT_PHI_OUT_MASK (3 << 11) + +#define WAITCNT_PREFETCH_ENABLE (1 << 14) + +#define WAITCNT_AGB (0 << 15) +#define WAITCNT_CGB (1 << 15) + #endif // GUARD_GBA_IO_REG_H diff --git a/include/gba/macro.h b/include/gba/macro.h index 42830d47c..7c56943b7 100644 --- a/include/gba/macro.h +++ b/include/gba/macro.h @@ -17,12 +17,12 @@ do { #define CpuCopy16(src, dest, size) CPU_COPY(src, dest, size, 16) #define CpuCopy32(src, dest, size) CPU_COPY(src, dest, size, 32) -#define DmaSet(dmaNum, src, dest, controlData) \ +#define DmaSet(dmaNum, src, dest, control) \ do { \ vu32 *dmaRegs = (vu32 *)REG_ADDR_DMA##dmaNum; \ dmaRegs[0] = (vu32)(src); \ dmaRegs[1] = (vu32)(dest); \ - dmaRegs[2] = (vu32)(controlData); \ + dmaRegs[2] = (vu32)(control); \ dmaRegs[2]; \ } while (0) diff --git a/include/gba/syscall.h b/include/gba/syscall.h index 0f4198b44..4d69907ee 100644 --- a/include/gba/syscall.h +++ b/include/gba/syscall.h @@ -5,6 +5,8 @@ #define CPU_SET_16BIT 0x00000000 #define CPU_SET_32BIT 0x04000000 -extern void CpuSet(void *src, void *dest, u32 controlData); +extern void CpuSet(void *src, void *dest, u32 control); + +extern void VBlankIntrWait(void); #endif // GUARD_GBA_SYSCALL_H diff --git a/iwram_syms.txt b/iwram_syms.txt index b3ad6eb06..308762876 100644 --- a/iwram_syms.txt +++ b/iwram_syms.txt @@ -5,6 +5,11 @@ gRtcSavedIme = 0x300046E; gPlayTimeCounterState = 0x300057C; +sTimerNum = 0x3000F28; +sTimerCount = 0x3000F2A; +sTimerReg = 0x3000F2C; +sSavedIme = 0x3000F30; + gSiiRtcLocked = 0x3000F36; gUnknownStringVar = 0x3002900; @@ -12,3 +17,14 @@ gUnknownStringVar = 0x3002900; gLocalTime = 0x3004038; gTasks = 0x3004B20; + +gFlashTimeoutFlag = 0x3007490; +PollFlashStatus = 0x3007494; +WaitForFlashWrite = 0x3007498; +ProgramFlashSector = 0x300749C; +gFlash = 0x30074A0; +ProgramFlashByte = 0x30074A4; +gFlashNumRemainingBytes = 0x30074A8; +EraseFlashChip = 0x30074AC; +EraseFlashSector = 0x30074B0; +gFlashMaxTime = 0x30074B4; diff --git a/src/agb_flash.c b/src/agb_flash.c new file mode 100644 index 000000000..834b80842 --- /dev/null +++ b/src/agb_flash.c @@ -0,0 +1,295 @@ +#include "gba/gba.h" +#include "gba/flash_internal.h" + +extern u8 sTimerNum; +extern u16 sTimerCount; +extern vu16 *sTimerReg; +extern u16 sSavedIme; + +extern u8 gFlashTimeoutFlag; +extern u8 (*PollFlashStatus)(u8 *); +extern u16 (*WaitForFlashWrite)(u8 phase, u8 *addr, u8 lastData); +extern u16 (*ProgramFlashSector)(u16 sectorNum, u8 *src); +extern const struct FlashType *gFlash; +extern u16 (*ProgramFlashByte)(u16 sectorNum, u32 offset, u8 data); +extern u16 gFlashNumRemainingBytes; +extern u16 (*EraseFlashChip)(); +extern u16 (*EraseFlashSector)(u16 sectorNum); +extern const u16 *gFlashMaxTime; + +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, 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 000000000..397b3d229 --- /dev/null +++ b/src/agb_flash_1m.c @@ -0,0 +1,80 @@ +#include "gba/gba.h" +#include "gba/flash_internal.h" + +static const char AgbLibFlashVersion[] = "FLASH1M_V103"; +extern const struct FlashSetupInfo *sSetupInfos[]; + +u16 IdentifyFlash(void) +{ + u16 result; + u16 flashId; + const struct FlashSetupInfo **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; +} diff --git a/src/agb_flash_mx.c b/src/agb_flash_mx.c new file mode 100644 index 000000000..90e51926e --- /dev/null +++ b/src/agb_flash_mx.c @@ -0,0 +1,143 @@ +#include "gba/gba.h" +#include "gba/flash_internal.h" + +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, 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; +} |