Port agb_flash from pokeruby

This commit is contained in:
Diegoisawesome 2016-11-01 14:15:48 -05:00
parent b4a39100c0
commit 7dad2846f8
7 changed files with 614 additions and 1083 deletions

File diff suppressed because it is too large Load Diff

View File

@ -333,7 +333,7 @@ sub_8152908: @ 8152908
lsls r0, 24
lsrs r4, r0, 24
adds r0, r4, 0
bl ProgramFlashSectorsAndVerify
bl ProgramFlashSectorAndVerify
cmp r0, 0
bne _08152924
movs r0, 0x1
@ -1876,7 +1876,7 @@ _08153654:
ble _08153654
adds r0, r6, 0
adds r1, r7, 0
bl ProgramFlashSectorsAndVerify
bl ProgramFlashSectorAndVerify
cmp r0, 0
bne _08153680
movs r0, 0x1

View File

@ -197,7 +197,9 @@ SECTIONS {
{
asm/libgcnmultiboot.o(.text);
asm/libmks4agb.o(.text);
asm/libagbbackup.o(.text);
src/agb_flash.o(.text);
src/agb_flash_1m.o(.text);
src/agb_flash_mx.o(.text);
asm/librtc.o(.text);
asm/librfu.o(.text);
asm/libagbsyscall.o(.text);
@ -230,7 +232,10 @@ SECTIONS {
lib_rodata :
ALIGN(4)
{
data/libagbbackup_rodata.o(.rodata);
src/agb_flash.o(.rodata);
src/agb_flash_1m.o(.rodata);
src/agb_flash_mx.o(.rodata);
src/agb_flash_le.o(.rodata);
data/librtc_rodata.o(.rodata);
data/librfu_rodata.o(.rodata);
tools/agbcc/lib/libgcc.a:_divdi3.o(.rodata);

295
src/agb_flash.c Normal file
View File

@ -0,0 +1,295 @@
#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 *);
u16 (*WaitForFlashWrite)(u8 phase, u8 *addr, u8 lastData);
u16 (*ProgramFlashSector)(u16 sectorNum, u8 *src);
const struct FlashType *gFlash;
u16 (*ProgramFlashByte)(u16 sectorNum, u32 offset, u8 data);
u16 gFlashNumRemainingBytes;
u16 (*EraseFlashChip)();
u16 (*EraseFlashSector)(u16 sectorNum);
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 = &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;
}

86
src/agb_flash_1m.c Normal file
View File

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

31
src/agb_flash_le.c Normal file
View File

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

193
src/agb_flash_mx.c Normal file
View File

@ -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, 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;
}