mirror of
https://github.com/LNH-team/pico-loader.git
synced 2026-06-02 09:16:49 +02:00
381 lines
8.9 KiB
ArmAsm
381 lines
8.9 KiB
ArmAsm
.cpu arm7tdmi
|
|
.syntax unified
|
|
|
|
#define LITE
|
|
#include "../asminc.h"
|
|
|
|
.macro LOAD_EXMEMCNT
|
|
@ loads EXMEMCNT register address
|
|
ldr r7,= 0x04000200
|
|
@ waitstate 4,2 and arm9 slot2 access
|
|
@ r7 holds the EXMEMCNT address, use lower 8 bits as 0
|
|
strb r7, [r7, #4]
|
|
.endm
|
|
|
|
.macro RESTORE_EXMEMCNT
|
|
@ waitstate 4,2 and arm7 slot2 access
|
|
movs r2, #0x80
|
|
strb r2, [r7, #4]
|
|
.endm
|
|
|
|
.macro SD_COMMAND_ARGUMENT value
|
|
movs r2, \value|0x40
|
|
.endm
|
|
|
|
.equ sd_dataadd, 0x9000000
|
|
.equ sd_resetaddr, 0x9440000
|
|
.equ reg_scsd_cmd, 0x9800000
|
|
.equ sd_crc_bit, 0x0100000
|
|
.equ sd_rw4, 0x0200000
|
|
.equ sd_rw1, 0x0000000
|
|
.equ sd_buff_bit, 0x0400000
|
|
.equ sd_command_bit, 0x0800000
|
|
.equ sd_st, 0x0040000 + sd_crc_bit
|
|
.equ sd_status_addr, sd_dataadd + sd_st
|
|
.equ sd_buff_bit_addr, sd_dataadd + sd_buff_bit
|
|
.equ sd_dataread_4, sd_dataadd + sd_rw4
|
|
.equ sd_dataread_1, sd_dataadd + sd_rw1
|
|
.equ sd_datawrite_4, sd_dataadd + sd_rw4
|
|
.equ sd_datawrite_1, sd_dataadd + sd_rw1
|
|
|
|
.section "sclite_sd_command_drop", "ax"
|
|
@ void sclite_sdCommandAndDropResponse6(uint32_t dummy, uint32_t argument, SD_COMMANDS command)
|
|
@ command is passed in r2
|
|
BEGIN_THUMB_FUNCTION sclite_sdCommandAndDropResponse6
|
|
@ among the pushed registers there are the command and
|
|
@ argument one, which are then used at the loop to
|
|
@ send the sd command
|
|
push {r1-r7,lr}
|
|
|
|
@ loads reg_scsd_cmd
|
|
movs r7, #0x98
|
|
lsls r7, r7, #20
|
|
|
|
@ while(*r7 & 0x01) == 0
|
|
SDCommand_loop:
|
|
ldrh r0, [r7]
|
|
lsrs r0, r0, #1
|
|
bcc SDCommand_loop
|
|
|
|
@ perform an extra read
|
|
ldrh r0, [r7]
|
|
|
|
@ loads sd_buff_bit_addr
|
|
movs r1, #0x94
|
|
lsls r1, r1, #20
|
|
@ lower halfword is 0
|
|
strh r1, [r1]
|
|
|
|
@ loads sd_dataadd + sd_command_bit + sd_rw4
|
|
movs r1, #0x9A
|
|
lsls r1, r1, #20
|
|
|
|
@ the command buffer starts at sp+4 (r1 and r2) since this loop starts with offset 5
|
|
@ decrement the value of the stack pointer address used by 1
|
|
mov r4,sp
|
|
movs r3, #4
|
|
write_SDCommand_loop:
|
|
ldrb r0, [r4, r3]
|
|
lsls r2, r0, #20
|
|
adds r2, r2, r0
|
|
str r2, [r1]
|
|
subs r3, r3, #1
|
|
bpl write_SDCommand_loop
|
|
|
|
@ loads sd_dataadd + sd_crc_bit + sd_rw4
|
|
movs r1, #0x9B
|
|
lsls r1, r1, #20
|
|
movs r2, #0
|
|
str r2, [r1]
|
|
|
|
@ while(*r7 & 0x01) != 0
|
|
SDCommand_loop_2nd:
|
|
ldrh r0, [r7]
|
|
lsrs r0, r0, #1
|
|
bcs SDCommand_loop_2nd
|
|
|
|
movs r6, #4
|
|
SDCommand_drop_resp:
|
|
ldmia r7!, {r0-r5}
|
|
subs r6, r6, #1
|
|
bne SDCommand_drop_resp
|
|
|
|
@ restore stack space
|
|
pop {r1-r7,pc}
|
|
.balign 4
|
|
.pool
|
|
|
|
.section "sclite_write_sector", "ax"
|
|
@ void sclite_writeSector(uint32_t sector, uint8_t* buff, uint32_t writenum)
|
|
BEGIN_THUMB_FUNCTION sclite_writeSector
|
|
push {r1,r2,r4-r7,lr}
|
|
|
|
@ load EXMEMCNT register
|
|
LOAD_EXMEMCNT
|
|
|
|
@ r1 for now holds the sector
|
|
.global sclite_writeSectorSdhcLabel
|
|
sclite_writeSectorSdhcLabel:
|
|
@ if not sdhc this needs to be shifted to the left by 9
|
|
lsls r1, r0, #9
|
|
@ movs r1, r0
|
|
|
|
@ enable sd access
|
|
@ this function won't touch r1
|
|
movs r0, #3
|
|
CALL sccmn_changeMode writeInterwork
|
|
|
|
@ WRITE_MULTIPLE_BLOCK
|
|
SD_COMMAND_ARGUMENT #25
|
|
@ 2nd parameter is in r1 from above
|
|
|
|
CALL sclite_sdCommandAndDropResponse6 writeInterwork
|
|
|
|
@ this function will trash r4 but leave r0 and r1 untouched
|
|
CALL sccmn_sdSendClock10 writeInterwork
|
|
|
|
@ loads the saved r0 and r2 (readnum)
|
|
@ into r0 and r1
|
|
pop {r0,r1}
|
|
write_sector_loop:
|
|
@ all the functions called in this loop don't change the value of r0 and r1
|
|
@ except sclite_writeData, which will increase r0 by 512
|
|
@ sccmn_sdio4BitCrc16 will write the checksum to r2-r3
|
|
CALL sccmn_sdio4BitCrc16 writeInterwork
|
|
|
|
@ first argument is buffer
|
|
@ regs r2 and r3 hold the crc
|
|
CALL sclite_writeData writeInterwork
|
|
|
|
@ this function will trash r4 but leave r0 and r1 untouched
|
|
CALL sccmn_sdSendClock10 writeInterwork
|
|
|
|
subs r1, #1
|
|
bne write_sector_loop
|
|
|
|
@ STOP_TRANSMISSION
|
|
SD_COMMAND_ARGUMENT #12
|
|
@ 2nd parameter is passed in r1
|
|
@ and from the loop above r1 is already 0
|
|
|
|
CALL sclite_sdCommandAndDropResponse6 writeInterwork
|
|
|
|
@ this function will trash r4 but leave r0 and r1 untouched
|
|
CALL sccmn_sdSendClock10 writeInterwork
|
|
|
|
@ loads sd_dataadd
|
|
movs r0, #0x90
|
|
lsls r0, r0, #20
|
|
|
|
@ while(*r1 &0x100) == 0
|
|
beginwhile_WriteSector:
|
|
ldrh r1, [r0]
|
|
lsrs r1, #9
|
|
bcc beginwhile_WriteSector
|
|
|
|
movs r0, #1
|
|
CALL sccmn_changeMode writeInterwork
|
|
|
|
@ restore EXMEMCNT register
|
|
RESTORE_EXMEMCNT
|
|
|
|
pop {r4-r7,pc}
|
|
INTERWORK writeInterwork
|
|
INTERWORK_FUNCTION sclite_writeData writeInterwork
|
|
INTERWORK_FUNCTION sccmn_sdio4BitCrc16 writeInterwork
|
|
INTERWORK_FUNCTION sccmn_sdSendClock10 writeInterwork
|
|
INTERWORK_FUNCTION sccmn_changeMode writeInterwork
|
|
INTERWORK_FUNCTION sclite_sdCommandAndDropResponse6 writeInterwork
|
|
|
|
.balign 4
|
|
.pool
|
|
|
|
.section "sclite_read_sector", "ax"
|
|
@ bool sclite_readSector(uint32_t sector, uint8_t *buff, uint32_t readnum)
|
|
BEGIN_THUMB_FUNCTION sclite_readSector
|
|
push {r1,r2-r7,lr}
|
|
LOAD_EXMEMCNT
|
|
|
|
@ r1 for now holds the sector
|
|
.global sclite_readSectorSdhcLabel
|
|
sclite_readSectorSdhcLabel:
|
|
@ if not sdhc this needs to be shifted to the left by 9
|
|
lsls r1, r0, #9
|
|
@ movs r1, r0
|
|
|
|
@ enable sd access
|
|
@ this function won't touch r1
|
|
movs r0, #3
|
|
CALL sccmn_changeMode readInterwork
|
|
|
|
@ READ_MULTIPLE_BLOCK
|
|
SD_COMMAND_ARGUMENT #18
|
|
@ 2nd parameter is in r1 from above
|
|
|
|
CALL sclite_sdCommandAndDropResponse6 readInterwork
|
|
|
|
@ loads the saved r0 and r2 (writenum)
|
|
@ into r0 and r1
|
|
pop {r0,r1}
|
|
read_sector_loop:
|
|
@ all the functions called in this loop don't change the value of r0 or r1
|
|
@ except sclite_readData, which will increase r0 by 512 automatically
|
|
CALL sclite_readData readInterwork
|
|
|
|
subs r1, #1
|
|
bne read_sector_loop
|
|
|
|
@ STOP_TRANSMISSION
|
|
SD_COMMAND_ARGUMENT #12
|
|
@ 2nd parameter is passed in r1
|
|
@ and from the loop above r1 is already 0
|
|
|
|
CALL sclite_sdCommandAndDropResponse6 readInterwork
|
|
|
|
@ this function will trash r4 but leave r0 and r1 untouched
|
|
CALL sccmn_sdSendClock10 readInterwork
|
|
|
|
|
|
movs r0, #1
|
|
CALL sccmn_changeMode readInterwork
|
|
|
|
RESTORE_EXMEMCNT
|
|
|
|
@ returns true
|
|
@ the change mode function above doesn't touch r0, so it's still 1
|
|
@ movs r0, #1
|
|
pop {r3-r7,pc}
|
|
INTERWORK readInterwork
|
|
INTERWORK_FUNCTION sccmn_changeMode readInterwork
|
|
INTERWORK_FUNCTION sclite_sdCommandAndDropResponse6 readInterwork
|
|
INTERWORK_FUNCTION sclite_readData readInterwork
|
|
INTERWORK_FUNCTION sccmn_sdSendClock10 readInterwork
|
|
|
|
.balign 4
|
|
.pool
|
|
|
|
.section "sclite_read_data", "ax"
|
|
@ void sclite_readData(void* buffer)
|
|
BEGIN_THUMB_FUNCTION sclite_readData
|
|
push {r1,r4-r7,lr}
|
|
|
|
@ dummy read SD_STATUS
|
|
ldr r1,= sd_status_addr
|
|
ldrh r1, [r1]
|
|
|
|
@ loads sd_buff_bit_addr
|
|
movs r1, #0x94
|
|
lsls r1, r1, #20
|
|
|
|
@ loops as long as sd_buff_bit is 1
|
|
sclite_readData_buff_bit_loop:
|
|
ldrh r3, [r1]
|
|
lsrs r3, #1
|
|
bcs sclite_readData_buff_bit_loop
|
|
|
|
@ loads sd_dataread_4
|
|
movs r1, #0x92
|
|
lsls r1, r1, #20
|
|
|
|
@ performs a dummy read of a short to initiate the transfer
|
|
ldrh r2, [r1]
|
|
|
|
@ lr holds buffer + 512
|
|
movs r2, #0x80
|
|
lsls r2, r2, #2
|
|
adds r2, r0, r2
|
|
mov lr, r2
|
|
|
|
ldmia r1!, {r2-r3}
|
|
stmia r0!, {r2-r3}
|
|
|
|
sclite_readData_loop:
|
|
@ load 6 ints at the time, for a total of 24 bytes
|
|
ldmia r1!, {r2-r7}
|
|
stmia r0!, {r2-r7}
|
|
cmp r0,lr
|
|
bne sclite_readData_loop
|
|
|
|
@ drop crc16
|
|
ldr r2, [r1]
|
|
ldrh r2, [r1]
|
|
|
|
@ loads sd_dataread_1
|
|
movs r1, #0x90
|
|
lsls r1, r1, #20
|
|
ldrh r2, [r1]
|
|
|
|
pop {r1,r4-r7,pc}
|
|
|
|
.balign 4
|
|
.pool
|
|
|
|
.section "sclite_write_data", "ax"
|
|
@ void sclite_writeData(void*& buffer, int value_to_keep, int crc_buff1, int crc_buff2)
|
|
@ this function updates r0, leaves r1 untouched and thrashes r4
|
|
BEGIN_THUMB_FUNCTION sclite_writeData
|
|
@ loads sd_dataadd
|
|
movs r4, #0x90
|
|
lsls r4, r4, #20
|
|
|
|
@ save sd_dataadd constant above for later
|
|
push {r1-r7,lr}
|
|
|
|
waitOnWriteFalse_WriteData:
|
|
ldrh r1, [r4]
|
|
lsrs r1, #9
|
|
bcc waitOnWriteFalse_WriteData
|
|
|
|
@ dummy read SD_DATAADD
|
|
ldrh r1, [r4]
|
|
|
|
@ transmission start bit (lower 16 bit of r4 are 0)
|
|
strh r4, [r4]
|
|
|
|
|
|
@ loads sd_datawrite_4
|
|
movs r7, #0x92
|
|
lsls r7, r7, #20
|
|
|
|
@ lr holds buffer + 512
|
|
movs r2, #0x80
|
|
lsls r2, r2, #2
|
|
adds r2, r0, r2
|
|
mov lr, r2
|
|
|
|
ldmia r0!, {r1-r2}
|
|
stmia r7!, {r1-r2}
|
|
|
|
sclite_writeData_loop:
|
|
@ load 6 ints at the time, for a total of 24 bytes
|
|
ldmia r0!, {r1-r6}
|
|
stmia r7!, {r1-r6}
|
|
cmp r0, lr
|
|
bne sclite_writeData_loop
|
|
|
|
|
|
@ r1 holds a value that has not to be changed
|
|
@ r2-r3 hold the crc value to be written
|
|
@ r4 holds the value sd_dataadd saved at the start
|
|
pop {r1-r4}
|
|
stmia r7!, {r2-r3}
|
|
|
|
@ write end bit
|
|
movs r3, #0xff
|
|
strh r3, [r4]
|
|
|
|
waitOnWriteTrue_WriteData:
|
|
ldrh r3, [r4]
|
|
lsrs r3, #9
|
|
bcs waitOnWriteTrue_WriteData
|
|
|
|
@ dummy writes to end the transfer
|
|
movs r3, #0
|
|
str r3, [r4]
|
|
str r3, [r4]
|
|
|
|
pop {r5-r7,pc}
|
|
|
|
.balign 4
|
|
.pool
|