mirror of
https://github.com/LNH-team/pico-loader.git
synced 2026-06-02 09:16:49 +02:00
Add support for Slot 2 flashcarts using Compact Flash (#84)
- Supercard CF (SUPERCARDCF) - GBA Media Player CF (MPCF) - M3 Adapter CF (M3CF) - Max Media Dock CF (MMCF)
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
.cpu arm7tdmi
|
||||
.syntax unified
|
||||
.thumb
|
||||
|
||||
.section "cf_perform_transfer", "ax"
|
||||
|
||||
.equ CF_CMD_LBA, 0xE0
|
||||
.equ CF_CMD_READ, 0x20
|
||||
.equ CF_CMD_WRITE, 0x30
|
||||
|
||||
@ bool cf_performTransferSectors(u32 numSectors, u32 sector, void* srcAddr, void* dstAddr, u8 command)
|
||||
.type cf_performTransferSectors, %function
|
||||
.global cf_performTransferSectors
|
||||
cf_performTransferSectors:
|
||||
push {r0,r1,r4-r7,lr}
|
||||
ldr r7, cf_performTransferSectors_waitCardAvailableForCommands
|
||||
@ calls waitCardAvailableForCommands
|
||||
@ this function doesn't alter r0, but sets the zero flag on failure and clears it on success
|
||||
bl cf_performTransferSectors_interwork
|
||||
beq cf_performTransferSectors_error
|
||||
|
||||
ldr r5, cf_performTransferSectors_reg_sector_count
|
||||
|
||||
@ load 0x20000
|
||||
movs r6, #0x01
|
||||
lsls r6, #17
|
||||
|
||||
@ store sector count
|
||||
strh r0, [r5]
|
||||
adds r5, r6
|
||||
|
||||
lsls r7, r1, #24
|
||||
lsrs r7, r7, #24
|
||||
@ store lba1
|
||||
strh r7, [r5]
|
||||
adds r5, r6
|
||||
|
||||
lsls r7, r1, #16
|
||||
lsrs r7, r7, #24
|
||||
@ store lba2
|
||||
strh r7, [r5]
|
||||
adds r5, r6
|
||||
|
||||
lsls r7, r1, #8
|
||||
lsrs r7, r7, #24
|
||||
@ store lba3
|
||||
strh r7, [r5]
|
||||
adds r5, r6
|
||||
|
||||
@ Only lower nibble is transferred
|
||||
lsls r7, r1, #4
|
||||
lsrs r7, r7, #28
|
||||
@ store lba4
|
||||
adds r7, CF_CMD_LBA
|
||||
strh r7, [r5]
|
||||
|
||||
@ store command
|
||||
strh r4, [r5, r6]
|
||||
|
||||
@ get total number of bytes to write
|
||||
lsls r0, #9
|
||||
|
||||
ldr r7, cf_performTransferSectors_waitNextBlockReady
|
||||
read_next_block:
|
||||
@ calls waitCardNextBlockReady
|
||||
@ this function doesn't alter r0, but sets the zero flag on failure and clears it on success
|
||||
bl cf_performTransferSectors_interwork
|
||||
beq cf_performTransferSectors_error
|
||||
|
||||
read_next_int:
|
||||
ldm r2!, {r1,r4,r5,r6}
|
||||
stm r3!, {r1,r4,r5,r6}
|
||||
|
||||
subs r0, #16
|
||||
beq done
|
||||
|
||||
@ Shifting left by 0x17 will set the Zero flag if the number that was shifted is a multiple
|
||||
@ of 0x200 (indicating a full sector has been written)
|
||||
lsls r1, r0, #0x17
|
||||
bne read_next_int
|
||||
|
||||
b read_next_block
|
||||
done:
|
||||
movs r0, #1
|
||||
cf_performTransferSectors_error:
|
||||
pop {r0,r1,r4-r7, pc}
|
||||
|
||||
cf_performTransferSectors_interwork:
|
||||
bx r7
|
||||
|
||||
.balign 4
|
||||
.pool
|
||||
.global cf_performTransferSectors_reg_sector_count
|
||||
cf_performTransferSectors_reg_sector_count:
|
||||
.word 0
|
||||
.global cf_performTransferSectors_waitCardAvailableForCommands
|
||||
cf_performTransferSectors_waitCardAvailableForCommands:
|
||||
.word 0
|
||||
.global cf_performTransferSectors_waitNextBlockReady
|
||||
cf_performTransferSectors_waitNextBlockReady:
|
||||
.word 0
|
||||
|
||||
.section "cf_read_write_functions", "ax"
|
||||
.global cf_performTransfer_unlock_label
|
||||
.global cf_performTransfer_lock_label
|
||||
@ r2 srcAddr
|
||||
@ r3 dstAddr
|
||||
@ r4 command
|
||||
@ top of stack startSector
|
||||
@ below it numSectors
|
||||
@ cf_performTransfer(dstAddr, srcAddr, command, startSector, numSectors)
|
||||
cf_performTransfer:
|
||||
@ loads EXMEMCNT register address
|
||||
ldr r6, =0x04000200
|
||||
@ waitstate 4,2 and arm9 slot2 access
|
||||
@ r6 + 4 is EXMEMCNT, use lower 8 bits as 0
|
||||
strb r6, [r6, #4]
|
||||
|
||||
ldr r7, cf_performTransfer_lockUnlockCard
|
||||
movs r0, #0
|
||||
|
||||
@ if the cart requires no lock/unlock sequence, this is replaced with a nop
|
||||
cf_performTransfer_unlock_label:
|
||||
@ calls lockUnlockCard
|
||||
bl cf_performTransfer_interwork
|
||||
|
||||
@ r2,r3,r4 hold variables not to be touched
|
||||
|
||||
ldr r7, cf_performTransfer_performTransferSectors
|
||||
|
||||
@ r1 holds startSector
|
||||
@ r5 holds remainingSectors
|
||||
pop {r1,r5}
|
||||
movs r0, #0xFF
|
||||
readNextSectorBlock:
|
||||
subs r5, r0
|
||||
ble lastRead
|
||||
|
||||
@ calls performTransferSectors
|
||||
@ this function doesn't alter r0, but sets the zero flag on failure and clears it on success
|
||||
bl cf_performTransfer_interwork
|
||||
beq error
|
||||
@ increment sector
|
||||
adds r1, r0
|
||||
b readNextSectorBlock
|
||||
|
||||
lastRead:
|
||||
adds r0, r5
|
||||
@ calls performTransferSectors
|
||||
@ this function doesn't alter r0, but sets the zero flag on failure and clears it on success
|
||||
bl cf_performTransfer_interwork
|
||||
|
||||
error:
|
||||
ldr r7, cf_performTransfer_lockUnlockCard
|
||||
movs r0, #1
|
||||
|
||||
@ if the cart requires no lock/unlock sequence, this is replaced with a nop
|
||||
cf_performTransfer_lock_label:
|
||||
@ calls lockUnlockCard
|
||||
bl cf_performTransfer_interwork
|
||||
|
||||
@ waitstate 4,2 and arm7 slot2 access
|
||||
movs r2, #0x80
|
||||
@ r6 + 4 is EXMEMCNT
|
||||
strb r2, [r6, #4]
|
||||
pop {r4-r7, pc}
|
||||
cf_performTransfer_interwork:
|
||||
bx r7
|
||||
|
||||
@ cf_readSectors(u32 sector, void* buffer, u32 numSectors)
|
||||
.type cf_readSectors, %function
|
||||
.global cf_readSectors
|
||||
cf_readSectors:
|
||||
push {r0,r2,r4-r7, lr}
|
||||
movs r4, CF_CMD_READ
|
||||
movs r3, r1
|
||||
ldr r2, cf_performTransfer_reg_data
|
||||
|
||||
b cf_performTransfer
|
||||
|
||||
@ cf_writeSectors(u32 sector, void* buffer, u32 numSectors)
|
||||
.type cf_writeSectors, %function
|
||||
.global cf_writeSectors
|
||||
cf_writeSectors:
|
||||
push {r0,r2,r4-r7, lr}
|
||||
movs r4, CF_CMD_WRITE
|
||||
ldr r3, cf_performTransfer_reg_data
|
||||
movs r2, r1
|
||||
|
||||
b cf_performTransfer
|
||||
|
||||
.balign 4
|
||||
.pool
|
||||
.global cf_performTransfer_reg_data
|
||||
cf_performTransfer_reg_data:
|
||||
.word 0
|
||||
.global cf_performTransfer_performTransferSectors
|
||||
cf_performTransfer_performTransferSectors:
|
||||
.word 0
|
||||
.global cf_performTransfer_lockUnlockCard
|
||||
cf_performTransfer_lockUnlockCard:
|
||||
.word 0
|
||||
Reference in New Issue
Block a user