From 7dad2846f83f892cdb4ffd7a757d0858b02fc96e Mon Sep 17 00:00:00 2001 From: Diegoisawesome Date: Tue, 1 Nov 2016 14:15:48 -0500 Subject: [PATCH] Port agb_flash from pokeruby --- asm/libagbbackup.s | 1079 -------------------------------------------- asm/save.s | 4 +- ld_script.txt | 9 +- src/agb_flash.c | 295 ++++++++++++ src/agb_flash_1m.c | 86 ++++ src/agb_flash_le.c | 31 ++ src/agb_flash_mx.c | 193 ++++++++ 7 files changed, 614 insertions(+), 1083 deletions(-) delete mode 100644 asm/libagbbackup.s create mode 100644 src/agb_flash.c create mode 100644 src/agb_flash_1m.c create mode 100644 src/agb_flash_le.c create mode 100644 src/agb_flash_mx.c diff --git a/asm/libagbbackup.s b/asm/libagbbackup.s deleted file mode 100644 index 35180530c..000000000 --- a/asm/libagbbackup.s +++ /dev/null @@ -1,1079 +0,0 @@ - .include "asm/macros.inc" - - .syntax unified - - .text - - thumb_func_start SwitchFlashBank -SwitchFlashBank: @ 82E185C - lsls r0, 24 - lsrs r0, 24 - ldr r3, =0x0e005555 - movs r1, 0xAA - strb r1, [r3] - ldr r2, =0x0e002aaa - movs r1, 0x55 - strb r1, [r2] - movs r1, 0xB0 - strb r1, [r3] - movs r1, 0xE0 - lsls r1, 20 - strb r0, [r1] - bx lr - .pool - thumb_func_end SwitchFlashBank - - thumb_func_start ReadFlashID -@ u16 ReadFlashID() -ReadFlashID: @ 82E1880 - push {r4,r5,lr} - sub sp, 0x44 - mov r0, sp - bl SetReadFlash1 - mov r5, sp - adds r5, 0x1 - ldr r2, =0x0e005555 - movs r0, 0xAA - strb r0, [r2] - ldr r1, =0x0e002aaa - movs r0, 0x55 - strb r0, [r1] - movs r0, 0x90 - strb r0, [r2] - add r1, sp, 0x40 - ldr r2, =0x00004e20 - adds r0, r2, 0 - b _082E18B8 - .pool -_082E18B4: - ldrh r0, [r1] - subs r0, 0x1 -_082E18B8: - strh r0, [r1] - ldrh r0, [r1] - cmp r0, 0 - bne _082E18B4 - ldr r0, =0x0e000001 - bl _call_via_r5 - lsls r0, 24 - lsrs r4, r0, 16 - movs r0, 0xE0 - lsls r0, 20 - bl _call_via_r5 - lsls r0, 24 - lsrs r0, 24 - orrs r4, r0 - ldr r1, =0x0e005555 - movs r0, 0xAA - strb r0, [r1] - ldr r2, =0x0e002aaa - movs r0, 0x55 - strb r0, [r2] - movs r0, 0xF0 - strb r0, [r1] - strb r0, [r1] - add r1, sp, 0x40 - ldr r2, =0x00004e20 - adds r0, r2, 0 - b _082E1908 - .pool -_082E1904: - ldrh r0, [r1] - subs r0, 0x1 -_082E1908: - strh r0, [r1] - ldrh r0, [r1] - cmp r0, 0 - bne _082E1904 - adds r0, r4, 0 - add sp, 0x44 - pop {r4,r5} - pop {r1} - bx r1 - thumb_func_end ReadFlashID - - thumb_func_start FlashTimerIntr -@ void FlashTimerIntr() -FlashTimerIntr: @ 82E191C - push {lr} - ldr r1, =0x03001a72 - ldrh r0, [r1] - cmp r0, 0 - beq _082E1938 - ldrh r0, [r1] - subs r0, 0x1 - strh r0, [r1] - lsls r0, 16 - cmp r0, 0 - bne _082E1938 - ldr r1, =0x03007840 - movs r0, 0x1 - strb r0, [r1] -_082E1938: - pop {r0} - bx r0 - .pool - thumb_func_end FlashTimerIntr - - thumb_func_start SetFlashTimerIntr -@ void SetFlashTimerIntr(u8 timer_id, void ( **irq_timer_func)()) -SetFlashTimerIntr: @ 82E1944 - push {lr} - adds r2, r1, 0 - lsls r0, 24 - lsrs r1, r0, 24 - cmp r1, 0x3 - bhi _082E1978 - ldr r0, =0x03001a70 - strb r1, [r0] - ldr r1, =0x03001a74 - ldrb r0, [r0] - lsls r0, 2 - ldr r3, =0x04000100 - adds r0, r3 - str r0, [r1] - ldr r0, =FlashTimerIntr - str r0, [r2] - movs r0, 0 - b _082E197A - .pool -_082E1978: - movs r0, 0x1 -_082E197A: - pop {r1} - bx r1 - thumb_func_end SetFlashTimerIntr - - thumb_func_start StartFlashTimer -StartFlashTimer: @ 82E1980 - push {r4-r6,lr} - mov r6, r10 - mov r5, r9 - mov r4, r8 - push {r4-r6} - lsls r0, 24 - lsrs r0, 24 - ldr r1, =0x03007864 - lsls r2, r0, 1 - adds r2, r0 - lsls r2, 1 - ldr r0, [r1] - adds r2, r0 - ldr r1, =0x03001a78 - ldr r0, =0x04000208 - mov r9, r0 - ldrh r0, [r0] - strh r0, [r1] - movs r3, 0 - mov r1, r9 - strh r3, [r1] - ldr r0, =0x03001a74 - mov r8, r0 - ldr r4, [r0] - strh r3, [r4, 0x2] - ldr r6, =0x04000200 - ldr r1, =0x03001a70 - mov r10, r1 - ldrb r1, [r1] - movs r5, 0x8 - adds r0, r5, 0 - lsls r0, r1 - adds r1, r0, 0 - ldrh r0, [r6] - orrs r0, r1 - strh r0, [r6] - ldr r0, =0x03007840 - strb r3, [r0] - ldr r1, =0x03001a72 - ldrh r0, [r2] - strh r0, [r1] - adds r2, 0x2 - ldrh r0, [r2] - strh r0, [r4] - adds r0, r4, 0x2 - mov r1, r8 - str r0, [r1] - ldrh r0, [r2, 0x2] - strh r0, [r4, 0x2] - str r4, [r1] - ldr r1, =0x04000202 - mov r2, r10 - ldrb r0, [r2] - lsls r5, r0 - strh r5, [r1] - movs r0, 0x1 - mov r3, r9 - strh r0, [r3] - pop {r3-r5} - mov r8, r3 - mov r9, r4 - mov r10, r5 - pop {r4-r6} - pop {r0} - bx r0 - .pool - thumb_func_end StartFlashTimer - - thumb_func_start StopFlashTimer -StopFlashTimer: @ 82E1A28 - ldr r3, =0x04000208 - movs r1, 0 - strh r1, [r3] - ldr r2, =0x03001a74 - ldr r0, [r2] - strh r1, [r0] - adds r0, 0x2 - str r0, [r2] - strh r1, [r0] - subs r0, 0x2 - str r0, [r2] - ldr r2, =0x04000200 - ldr r0, =0x03001a70 - ldrb r0, [r0] - movs r1, 0x8 - lsls r1, r0 - ldrh r0, [r2] - bics r0, r1 - strh r0, [r2] - ldr r0, =0x03001a78 - ldrh r0, [r0] - strh r0, [r3] - bx lr - .pool - thumb_func_end StopFlashTimer - - thumb_func_start ReadFlash1 -@ u8 ReadFlash1(int address) -ReadFlash1: @ 82E1A6C - ldrb r0, [r0] - bx lr - thumb_func_end ReadFlash1 - - thumb_func_start SetReadFlash1 -@ void SetReadFlash1(u8 ( *target_func)(int address)) -SetReadFlash1: @ 82E1A70 - push {lr} - adds r2, r0, 0 - ldr r1, =0x03007844 - adds r0, r2, 0x1 - str r0, [r1] - ldr r3, =ReadFlash1 - movs r0, 0x1 - eors r3, r0 - ldr r0, =SetReadFlash1 - ldr r1, =ReadFlash1 - subs r0, r1 - lsls r0, 15 - b _082E1AA4 - .pool -_082E1A98: - ldrh r0, [r3] - strh r0, [r2] - adds r3, 0x2 - adds r2, 0x2 - subs r0, r1, 0x1 - lsls r0, 16 -_082E1AA4: - lsrs r1, r0, 16 - cmp r1, 0 - bne _082E1A98 - pop {r0} - bx r0 - thumb_func_end SetReadFlash1 - - thumb_func_start ReadFlash_Core -ReadFlash_Core: @ 82E1AB0 - push {r4,lr} - adds r4, r0, 0 - subs r3, r2, 0x1 - cmp r2, 0 - beq _082E1ACC - movs r2, 0x1 - negs r2, r2 -_082E1ABE: - ldrb r0, [r4] - strb r0, [r1] - adds r4, 0x1 - adds r1, 0x1 - subs r3, 0x1 - cmp r3, r2 - bne _082E1ABE -_082E1ACC: - pop {r4} - pop {r0} - bx r0 - thumb_func_end ReadFlash_Core - - thumb_func_start ReadFlash -ReadFlash: @ 82E1AD4 - push {r4-r7,lr} - sub sp, 0x80 - adds r5, r1, 0 - adds r6, r2, 0 - adds r7, r3, 0 - lsls r3, r0, 16 - lsrs r4, r3, 16 - ldr r2, =0x04000204 - ldrh r0, [r2] - ldr r1, =0x0000fffc - ands r0, r1 - movs r1, 0x3 - orrs r0, r1 - strh r0, [r2] - ldr r0, =0x03007850 - ldr r0, [r0] - ldr r1, [r0] - movs r0, 0x80 - lsls r0, 10 - cmp r1, r0 - bne _082E1B0C - lsrs r0, r3, 20 - lsls r0, 24 - lsrs r0, 24 - bl SwitchFlashBank - movs r0, 0xF - ands r4, r0 -_082E1B0C: - ldr r3, =ReadFlash_Core - movs r0, 0x1 - eors r3, r0 - mov r2, sp - ldr r0, =ReadFlash - ldr r1, =ReadFlash_Core - subs r0, r1 - lsls r0, 15 - b _082E1B40 - .pool -_082E1B34: - ldrh r0, [r3] - strh r0, [r2] - adds r3, 0x2 - adds r2, 0x2 - subs r0, r1, 0x1 - lsls r0, 16 -_082E1B40: - lsrs r1, r0, 16 - cmp r1, 0 - bne _082E1B34 - mov r3, sp - adds r3, 0x1 - ldr r0, =0x03007850 - ldr r0, [r0] - ldrb r0, [r0, 0x8] - lsls r4, r0 - adds r0, r4, 0 - movs r2, 0xE0 - lsls r2, 20 - adds r1, r5, r2 - adds r0, r1 - adds r1, r6, 0 - adds r2, r7, 0 - bl _call_via_r3 - add sp, 0x80 - pop {r4-r7} - pop {r0} - bx r0 - .pool - thumb_func_end ReadFlash - - thumb_func_start VerifyFlashSector_Core -VerifyFlashSector_Core: @ 82E1B70 - push {r4,r5,lr} - adds r5, r0, 0 - adds r3, r1, 0 - subs r4, r2, 0x1 - cmp r2, 0 - beq _082E1B96 - movs r2, 0x1 - negs r2, r2 -_082E1B80: - ldrb r1, [r3] - ldrb r0, [r5] - adds r5, 0x1 - adds r3, 0x1 - cmp r1, r0 - beq _082E1B90 - subs r0, r3, 0x1 - b _082E1B98 -_082E1B90: - subs r4, 0x1 - cmp r4, r2 - bne _082E1B80 -_082E1B96: - movs r0, 0 -_082E1B98: - pop {r4,r5} - pop {r1} - bx r1 - thumb_func_end VerifyFlashSector_Core - - thumb_func_start VerifyFlashSector -VerifyFlashSector: @ 82E1BA0 - push {r4,r5,lr} - sub sp, 0x100 - adds r5, r1, 0 - lsls r3, r0, 16 - lsrs r4, r3, 16 - ldr r2, =0x04000204 - ldrh r0, [r2] - ldr r1, =0x0000fffc - ands r0, r1 - movs r1, 0x3 - orrs r0, r1 - strh r0, [r2] - ldr r0, =0x03007850 - ldr r0, [r0] - ldr r1, [r0] - movs r0, 0x80 - lsls r0, 10 - cmp r1, r0 - bne _082E1BD4 - lsrs r0, r3, 20 - lsls r0, 24 - lsrs r0, 24 - bl SwitchFlashBank - movs r0, 0xF - ands r4, r0 -_082E1BD4: - ldr r3, =VerifyFlashSector_Core - movs r0, 0x1 - eors r3, r0 - mov r2, sp - ldr r0, =VerifyFlashSector - ldr r1, =VerifyFlashSector_Core - subs r0, r1 - lsls r0, 15 - b _082E1C08 - .pool -_082E1BFC: - ldrh r0, [r3] - strh r0, [r2] - adds r3, 0x2 - adds r2, 0x2 - subs r0, r1, 0x1 - lsls r0, 16 -_082E1C08: - lsrs r1, r0, 16 - cmp r1, 0 - bne _082E1BFC - mov r3, sp - adds r3, 0x1 - ldr r0, =0x03007850 - ldr r0, [r0] - ldrb r1, [r0, 0x8] - lsls r4, r1 - adds r1, r4, 0 - movs r2, 0xE0 - lsls r2, 20 - adds r1, r2 - ldrh r2, [r0, 0x4] - adds r0, r5, 0 - bl _call_via_r3 - add sp, 0x100 - pop {r4,r5} - pop {r1} - bx r1 - .pool - thumb_func_end VerifyFlashSector - - thumb_func_start VerifyFlashSectorFirstNBytes -VerifyFlashSectorFirstNBytes: @ 82E1C38 - push {r4-r6,lr} - sub sp, 0x100 - adds r5, r1, 0 - adds r6, r2, 0 - lsls r2, r0, 16 - lsrs r4, r2, 16 - ldr r0, =0x03007850 - ldr r0, [r0] - ldr r1, [r0] - movs r0, 0x80 - lsls r0, 10 - cmp r1, r0 - bne _082E1C60 - lsrs r0, r2, 20 - lsls r0, 24 - lsrs r0, 24 - bl SwitchFlashBank - movs r0, 0xF - ands r4, r0 -_082E1C60: - ldr r2, =0x04000204 - ldrh r0, [r2] - ldr r1, =0x0000fffc - ands r0, r1 - movs r1, 0x3 - orrs r0, r1 - strh r0, [r2] - ldr r3, =VerifyFlashSector_Core - movs r0, 0x1 - eors r3, r0 - mov r2, sp - ldr r0, =VerifyFlashSector - ldr r1, =VerifyFlashSector_Core - subs r0, r1 - lsls r0, 15 - b _082E1CA0 - .pool -_082E1C94: - ldrh r0, [r3] - strh r0, [r2] - adds r3, 0x2 - adds r2, 0x2 - subs r0, r1, 0x1 - lsls r0, 16 -_082E1CA0: - lsrs r1, r0, 16 - cmp r1, 0 - bne _082E1C94 - mov r3, sp - adds r3, 0x1 - ldr r0, =0x03007850 - ldr r0, [r0] - ldrb r1, [r0, 0x8] - lsls r4, r1 - adds r1, r4, 0 - movs r0, 0xE0 - lsls r0, 20 - adds r1, r0 - adds r0, r5, 0 - adds r2, r6, 0 - bl _call_via_r3 - add sp, 0x100 - pop {r4-r6} - pop {r1} - bx r1 - .pool - thumb_func_end VerifyFlashSectorFirstNBytes - - thumb_func_start ProgramFlashSectorsAndVerify -ProgramFlashSectorsAndVerify: @ 82E1CD0 - push {r4-r6,lr} - adds r5, r1, 0 - lsls r0, 16 - lsrs r4, r0, 16 - movs r6, 0 - b _082E1CE2 -_082E1CDC: - adds r0, r6, 0x1 - lsls r0, 24 - lsrs r6, r0, 24 -_082E1CE2: - cmp r6, 0x2 - bhi _082E1D08 - ldr r0, =0x0300784c - ldr r2, [r0] - adds r0, r4, 0 - adds r1, r5, 0 - bl _call_via_r2 - lsls r0, 16 - lsrs r2, r0, 16 - cmp r2, 0 - bne _082E1CDC - adds r0, r4, 0 - adds r1, r5, 0 - bl VerifyFlashSector - adds r2, r0, 0 - cmp r2, 0 - bne _082E1CDC -_082E1D08: - adds r0, r2, 0 - pop {r4-r6} - pop {r1} - bx r1 - .pool - thumb_func_end ProgramFlashSectorsAndVerify - - thumb_func_start ProgramFlashSectorsVerifyFirstNBytes -ProgramFlashSectorsVerifyFirstNBytes: @ 82E1D14 - push {r4-r7,lr} - adds r5, r1, 0 - adds r7, r2, 0 - lsls r0, 16 - lsrs r4, r0, 16 - movs r6, 0 - b _082E1D28 -_082E1D22: - adds r0, r6, 0x1 - lsls r0, 24 - lsrs r6, r0, 24 -_082E1D28: - cmp r6, 0x2 - bhi _082E1D50 - ldr r0, =0x0300784c - ldr r2, [r0] - adds r0, r4, 0 - adds r1, r5, 0 - bl _call_via_r2 - lsls r0, 16 - lsrs r3, r0, 16 - cmp r3, 0 - bne _082E1D22 - adds r0, r4, 0 - adds r1, r5, 0 - adds r2, r7, 0 - bl VerifyFlashSectorFirstNBytes - adds r3, r0, 0 - cmp r3, 0 - bne _082E1D22 -_082E1D50: - adds r0, r3, 0 - pop {r4-r7} - pop {r1} - bx r1 - .pool - thumb_func_end ProgramFlashSectorsVerifyFirstNBytes - - thumb_func_start IdentifyFlash -@ _BOOL2 IdentifyFlash() -IdentifyFlash: @ 82E1D5C - push {r4,lr} - ldr r2, =0x04000204 - ldrh r0, [r2] - ldr r1, =0x0000fffc - ands r0, r1 - movs r1, 0x3 - orrs r0, r1 - strh r0, [r2] - bl ReadFlashID - lsls r0, 16 - lsrs r3, r0, 16 - ldr r2, =gUnknown_089A30D0 - movs r4, 0x1 - b _082E1D8A - .pool -_082E1D88: - adds r2, 0x4 -_082E1D8A: - ldr r1, [r2] - adds r0, r1, 0 - adds r0, 0x2C - ldrb r0, [r0] - cmp r0, 0 - beq _082E1D9E - ldrh r0, [r1, 0x2C] - cmp r3, r0 - bne _082E1D88 - movs r4, 0 -_082E1D9E: - ldr r1, =0x03007854 - ldr r0, [r2] - ldr r0, [r0] - str r0, [r1] - ldr r1, =0x0300784c - ldr r0, [r2] - ldr r0, [r0, 0x4] - str r0, [r1] - ldr r1, =0x0300785c - ldr r0, [r2] - ldr r0, [r0, 0x8] - str r0, [r1] - ldr r1, =0x03007860 - ldr r0, [r2] - ldr r0, [r0, 0xC] - str r0, [r1] - ldr r1, =0x03007848 - ldr r0, [r2] - ldr r0, [r0, 0x10] - str r0, [r1] - ldr r1, =0x03007864 - ldr r0, [r2] - ldr r0, [r0, 0x14] - str r0, [r1] - ldr r1, =0x03007850 - ldr r0, [r2] - adds r0, 0x18 - str r0, [r1] - adds r0, r4, 0 - pop {r4} - pop {r1} - bx r1 - .pool - thumb_func_end IdentifyFlash - - thumb_func_start PollingSR_COMMON -PollingSR_COMMON: @ 82E1DFC - push {r4-r7,lr} - mov r7, r9 - mov r6, r8 - push {r6,r7} - adds r4, r1, 0 - lsls r0, 24 - lsrs r7, r0, 24 - lsls r2, 24 - lsrs r5, r2, 24 - movs r0, 0 - mov r8, r0 - adds r0, r7, 0 - bl StartFlashTimer - ldr r6, =0x03007844 - ldr r1, =0x0e005555 - mov r9, r1 - b _082E1E60 - .pool -_082E1E28: - movs r0, 0xF0 - mov r1, r9 - strb r0, [r1] - movs r0, 0xA0 - lsls r0, 8 - b _082E1E56 -_082E1E34: - ldr r0, =0x03007840 - ldrb r0, [r0] - cmp r0, 0 - beq _082E1E60 - ldr r1, [r6] - adds r0, r4, 0 - bl _call_via_r1 - lsls r0, 24 - lsrs r0, 24 - cmp r0, r5 - beq _082E1E88 - movs r0, 0xF0 - mov r1, r9 - strb r0, [r1] - movs r0, 0xC0 - lsls r0, 8 -_082E1E56: - orrs r7, r0 - mov r8, r7 - b _082E1E88 - .pool -_082E1E60: - ldr r1, [r6] - adds r0, r4, 0 - bl _call_via_r1 - lsls r0, 24 - lsrs r1, r0, 24 - cmp r1, r5 - beq _082E1E88 - movs r0, 0x20 - ands r0, r1 - cmp r0, 0 - beq _082E1E34 - ldr r1, [r6] - adds r0, r4, 0 - bl _call_via_r1 - lsls r0, 24 - lsrs r0, 24 - cmp r0, r5 - bne _082E1E28 -_082E1E88: - bl StopFlashTimer - mov r0, r8 - pop {r3,r4} - mov r8, r3 - mov r9, r4 - pop {r4-r7} - pop {r1} - bx r1 - thumb_func_end PollingSR_COMMON - - thumb_func_start EraseFlashChip -EraseFlashChip: @ 82E1E9C - push {r4-r6,lr} - sub sp, 0x40 - ldr r5, =0x04000204 - ldrh r1, [r5] - ldr r6, =0x0000fffc - ands r1, r6 - ldr r0, =0x03007850 - ldr r0, [r0] - ldrh r0, [r0, 0x10] - orrs r1, r0 - strh r1, [r5] - ldr r1, =0x0e005555 - movs r4, 0xAA - strb r4, [r1] - ldr r3, =0x0e002aaa - movs r2, 0x55 - strb r2, [r3] - movs r0, 0x80 - strb r0, [r1] - strb r4, [r1] - strb r2, [r3] - movs r0, 0x10 - strb r0, [r1] - mov r0, sp - bl SetReadFlash1 - ldr r0, =0x03007848 - movs r1, 0xE0 - lsls r1, 20 - ldr r3, [r0] - movs r0, 0x3 - movs r2, 0xFF - bl _call_via_r3 - lsls r0, 16 - lsrs r0, 16 - ldrh r1, [r5] - ands r1, r6 - movs r2, 0x3 - orrs r1, r2 - strh r1, [r5] - add sp, 0x40 - pop {r4-r6} - pop {r1} - bx r1 - .pool - thumb_func_end EraseFlashChip - - thumb_func_start EraseFlashSector -EraseFlashSector: @ 82E1F10 - push {r4-r7,lr} - sub sp, 0x40 - lsls r0, 16 - lsrs r6, r0, 16 - ldr r0, =0x03007850 - ldr r0, [r0] - ldrh r0, [r0, 0xA] - cmp r6, r0 - bcc _082E1F30 - ldr r0, =0x000080ff - b _082E1FD0 - .pool -_082E1F30: - lsrs r0, r6, 4 - lsls r0, 24 - lsrs r0, 24 - bl SwitchFlashBank - movs r0, 0xF - ands r6, r0 - movs r7, 0 -_082E1F40: - ldr r3, =0x04000204 - ldrh r1, [r3] - ldr r0, =0x0000fffc - ands r1, r0 - ldr r0, =0x03007850 - ldr r2, [r0] - ldrh r0, [r2, 0x10] - orrs r1, r0 - strh r1, [r3] - ldrb r4, [r2, 0x8] - adds r0, r6, 0 - lsls r0, r4 - adds r4, r0, 0 - movs r0, 0xE0 - lsls r0, 20 - adds r4, r0 - ldr r1, =0x0e005555 - movs r5, 0xAA - strb r5, [r1] - ldr r3, =0x0e002aaa - movs r2, 0x55 - strb r2, [r3] - movs r0, 0x80 - strb r0, [r1] - strb r5, [r1] - strb r2, [r3] - movs r0, 0x30 - strb r0, [r4] - mov r0, sp - bl SetReadFlash1 - ldr r0, =0x03007848 - ldr r3, [r0] - movs r0, 0x2 - adds r1, r4, 0 - movs r2, 0xFF - bl _call_via_r3 - lsls r0, 16 - lsrs r3, r0, 16 - movs r0, 0xA0 - lsls r0, 8 - ands r0, r3 - cmp r0, 0 - beq _082E1FC0 - cmp r7, 0x3 - bhi _082E1FC0 - adds r0, r7, 0x1 - lsls r0, 16 - lsrs r7, r0, 16 - b _082E1F40 - .pool -_082E1FC0: - ldr r2, =0x04000204 - ldrh r0, [r2] - ldr r1, =0x0000fffc - ands r0, r1 - movs r1, 0x3 - orrs r0, r1 - strh r0, [r2] - adds r0, r3, 0 -_082E1FD0: - add sp, 0x40 - pop {r4-r7} - pop {r1} - bx r1 - .pool - thumb_func_end EraseFlashSector - - thumb_func_start ProgramFlashByte -ProgramFlashByte: @ 82E1FE0 - push {r4-r7,lr} - sub sp, 0x40 - adds r6, r1, 0 - lsls r1, r0, 16 - lsrs r4, r1, 16 - lsls r2, 24 - lsrs r7, r2, 24 - ldr r5, =0x03007850 - ldr r0, [r5] - ldr r0, [r0, 0x4] - cmp r6, r0 - bcs _082E2068 - lsrs r0, r1, 20 - lsls r0, 24 - lsrs r0, 24 - bl SwitchFlashBank - movs r0, 0xF - ldr r1, [r5] - ands r4, r0 - ldrb r1, [r1, 0x8] - lsls r4, r1 - movs r1, 0xE0 - lsls r1, 20 - adds r0, r6, r1 - adds r4, r0 - mov r0, sp - bl SetReadFlash1 - ldr r2, =0x04000204 - ldrh r0, [r2] - ldr r1, =0x0000fffc - ands r0, r1 - ldr r1, [r5] - ldrh r1, [r1, 0x10] - orrs r0, r1 - strh r0, [r2] - ldr r2, =0x0e005555 - movs r0, 0xAA - strb r0, [r2] - ldr r1, =0x0e002aaa - movs r0, 0x55 - strb r0, [r1] - movs r0, 0xA0 - strb r0, [r2] - strb r7, [r4] - ldr r0, =0x03007848 - ldr r3, [r0] - movs r0, 0x1 - adds r1, r4, 0 - adds r2, r7, 0 - bl _call_via_r3 - lsls r0, 16 - lsrs r0, 16 - b _082E206C - .pool -_082E2068: - movs r0, 0x80 - lsls r0, 8 -_082E206C: - add sp, 0x40 - pop {r4-r7} - pop {r1} - bx r1 - thumb_func_end ProgramFlashByte - - thumb_func_start ProgramFlashByteInternal -ProgramFlashByteInternal: @ 82E2074 - push {r4,lr} - ldr r4, =0x0e005555 - movs r2, 0xAA - strb r2, [r4] - ldr r3, =0x0e002aaa - movs r2, 0x55 - strb r2, [r3] - movs r2, 0xA0 - strb r2, [r4] - ldrb r2, [r0] - strb r2, [r1] - ldr r3, =0x03007848 - ldrb r2, [r0] - ldr r3, [r3] - movs r0, 0x1 - bl _call_via_r3 - lsls r0, 16 - lsrs r0, 16 - pop {r4} - pop {r1} - bx r1 - .pool - thumb_func_end ProgramFlashByteInternal - - thumb_func_start ProgramFlashSector -ProgramFlashSector: @ 82E20AC - push {r4-r7,lr} - sub sp, 0x40 - adds r7, r1, 0 - lsls r0, 16 - lsrs r4, r0, 16 - ldr r0, =0x03007850 - ldr r0, [r0] - ldrh r0, [r0, 0xA] - cmp r4, r0 - bcc _082E20CC - ldr r0, =0x000080ff - b _082E2146 - .pool -_082E20CC: - adds r0, r4, 0 - bl EraseFlashSector - lsls r0, 16 - lsrs r5, r0, 16 - cmp r5, 0 - bne _082E2144 - lsrs r0, r4, 4 - lsls r0, 24 - lsrs r0, 24 - bl SwitchFlashBank - movs r0, 0xF - ands r4, r0 - mov r0, sp - bl SetReadFlash1 - ldr r3, =0x04000204 - ldrh r1, [r3] - ldr r0, =0x0000fffc - ands r1, r0 - ldr r0, =0x03007850 - ldr r2, [r0] - ldrh r0, [r2, 0x10] - orrs r1, r0 - strh r1, [r3] - ldr r1, =0x03007858 - ldr r0, [r2, 0x4] - strh r0, [r1] - ldrb r0, [r2, 0x8] - lsls r4, r0 - movs r0, 0xE0 - lsls r0, 20 - adds r4, r0 - adds r6, r1, 0 - b _082E212E - .pool -_082E2124: - ldrh r0, [r6] - subs r0, 0x1 - strh r0, [r6] - adds r7, 0x1 - adds r4, 0x1 -_082E212E: - ldrh r0, [r6] - cmp r0, 0 - beq _082E2144 - adds r0, r7, 0 - adds r1, r4, 0 - bl ProgramFlashByteInternal - lsls r0, 16 - lsrs r5, r0, 16 - cmp r5, 0 - beq _082E2124 -_082E2144: - adds r0, r5, 0 -_082E2146: - add sp, 0x40 - pop {r4-r7} - pop {r1} - bx r1 - thumb_func_end ProgramFlashSector - - .align 2, 0 @ Don't pad with nop. diff --git a/asm/save.s b/asm/save.s index 0cc13bad5..e20190db5 100644 --- a/asm/save.s +++ b/asm/save.s @@ -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 diff --git a/ld_script.txt b/ld_script.txt index 6ff1860ff..1c668bf83 100644 --- a/ld_script.txt +++ b/ld_script.txt @@ -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); diff --git a/src/agb_flash.c b/src/agb_flash.c new file mode 100644 index 000000000..34fb4e84a --- /dev/null +++ b/src/agb_flash.c @@ -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 = ®_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..e249fab9a --- /dev/null +++ b/src/agb_flash_1m.c @@ -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; +} diff --git a/src/agb_flash_le.c b/src/agb_flash_le.c new file mode 100644 index 000000000..39d956e27 --- /dev/null +++ b/src/agb_flash_le.c @@ -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 + } +}; diff --git a/src/agb_flash_mx.c b/src/agb_flash_mx.c new file mode 100644 index 000000000..01f848901 --- /dev/null +++ b/src/agb_flash_mx.c @@ -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; +}