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:
Edoardo Lolletti
2026-01-10 23:00:39 +01:00
committed by GitHub
parent eac8f7e734
commit 6a97b677a7
22 changed files with 945 additions and 3 deletions

View File

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