diff options
Diffstat (limited to 'src')
-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 |
3 files changed, 518 insertions, 0 deletions
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; +} |