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; +} | 
