掌機 - TRIMUI - Assembly - SDMMC



參考資料:
http://nano.lichee.pro/
https://mangopi.org/mangopi_r
http://www.zeroplus.com.tw/E-paper/200907/image/SD_command%20and%20register%20list.pdf

暫存器


腳位


main.s

    .global _start

    .equiv SDC0_BASE,             0x01c0f000
    .equiv CCU_BASE,              0x01c20000
    .equiv PIO_BASE,              0x01c20800
    .equiv UART1_BASE,            0x01c25400

    .equiv PA,                    (0 * 0x24)
    .equiv PF,                    (5 * 0x24)
    .equiv PIO_CFG0,              0x00
    .equiv PIO_DATA,              0x10

    .equiv PLL_PERIPH_CTRL_REG,   0x0028
    .equiv AHB_APB_HCLKC_CFG_REG, 0x0054
    .equiv BUS_CLK_GATING_REG0,   0x0060
    .equiv BUS_CLK_GATING_REG2,   0x0068
    .equiv SDMMC0_CLK_REG,        0x0088
    .equiv BUS_SOFT_RST_REG0,     0x02c0
    .equiv BUS_SOFT_RST_REG2,     0x02d0

    .equiv UART_RBR,              0x0000
    .equiv UART_DLL,              0x0000
    .equiv UART_DLH,              0x0004
    .equiv UART_IER,              0x0004
    .equiv UART_IIR,              0x0008
    .equiv UART_LCR,              0x000c
    .equiv UART_MCR,              0x0010
    .equiv UART_USR,              0x007c

    .equiv SD_GCTL_REG,           0x0000
    .equiv SD_CKCR_REG,           0x0004
    .equiv SD_TMOR_REG,           0x0008
    .equiv SD_BWDR_REG,           0x000c
    .equiv SD_BKSR_REG,           0x0010
    .equiv SD_BYCR_REG,           0x0014
    .equiv SD_CMDR_REG,           0x0018
    .equiv SD_CAGR_REG,           0x001c
    .equiv SD_RESP0_REG,          0x0020
    .equiv SD_RESP1_REG,          0x0024
    .equiv SD_RESP2_REG,          0x0028
    .equiv SD_RESP3_REG,          0x002c
    .equiv SD_IMKR_REG,           0x0030
    .equiv SD_MISR_REG,           0x0034
    .equiv SD_RISR_REG,           0x0038
    .equiv SD_STAR_REG,           0x003c
    .equiv SD_FWLR_REG,           0x0040
    .equiv SD_FUNS_REG,           0x0044
    .equiv SD_CBCR_REG,           0x0048
    .equiv SD_BBCR_REG,           0x004c
    .equiv SD_DBGC_REG,           0x0050
    .equiv SD_A12A_REG,           0x0058
    .equiv SD_HWRST_REG,          0x0078
    .equiv SD_DMAC_REG,           0x0080
    .equiv SD_DLBA_REG,           0x0084
    .equiv SD_IDST_REG,           0x0088
    .equiv SD_IDIE_REG,           0x008c
    .equiv SD_CHDA_REG,           0x0090
    .equiv SD_CBDA_REG,           0x0094
    .equiv CARD_THLDC_REG,        0x0100
    .equiv EMMC_DSBD_REG,         0x010c
    .equiv SD_FIFO_REG,           0x0200

    .equiv MMC_RSP_NONE,                 (0)
    .equiv MMC_RSP_R1,                   (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
    .equiv MMC_RSP_R1b,                  (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | MMC_RSP_BUSY)
    .equiv MMC_RSP_R2,                   (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC)
    .equiv MMC_RSP_R3,                   (MMC_RSP_PRESENT)
    .equiv MMC_RSP_R4,                   (MMC_RSP_PRESENT)
    .equiv MMC_RSP_R5,                   (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
    .equiv MMC_RSP_R6,                   (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
    .equiv MMC_RSP_R7,                   (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)

    .equiv MMC_RSP_PRESENT,              (1 << 0)
    .equiv MMC_RSP_136,                  (1 << 1)
    .equiv MMC_RSP_CRC,                  (1 << 2)
    .equiv MMC_RSP_BUSY,                 (1 << 3)
    .equiv MMC_RSP_OPCODE,               (1 << 4)

    .equiv MMC_CMD_GO_IDLE_STATE,        0
    .equiv MMC_CMD_SEND_OP_COND,         1
    .equiv MMC_CMD_ALL_SEND_CID,         2
    .equiv MMC_CMD_SET_RELATIVE_ADDR,    3
    .equiv MMC_CMD_SET_DSR,              4
    .equiv MMC_CMD_SWITCH,               6
    .equiv MMC_CMD_SELECT_CARD,          7
    .equiv MMC_CMD_SEND_EXT_CSD,         8
    .equiv MMC_CMD_SEND_CSD,             9
    .equiv MMC_CMD_SEND_CID,             10
    .equiv MMC_CMD_STOP_TRANSMISSION,    12
    .equiv MMC_CMD_SEND_STATUS,          13
    .equiv MMC_CMD_SET_BLOCKLEN,         16
    .equiv MMC_CMD_READ_SINGLE_BLOCK,    17
    .equiv MMC_CMD_READ_MULTIPLE_BLOCK,  18
    .equiv MMC_CMD_SET_BLOCK_COUNT,      23
    .equiv MMC_CMD_WRITE_SINGLE_BLOCK,   24
    .equiv MMC_CMD_WRITE_MULTIPLE_BLOCK, 25
    .equiv MMC_CMD_ERASE_GROUP_START,    35
    .equiv MMC_CMD_ERASE_GROUP_END,      36
    .equiv MMC_CMD_ERASE,                38
    .equiv MMC_CMD_APP_CMD,              55
    .equiv MMC_CMD_SPI_READ_OCR,         58
    .equiv MMC_CMD_SPI_CRC_ON_OFF,       59
    .equiv MMC_CMD_RES_MAN,              62
    .equiv MMC_VDD_32_33,                0x00100000
    .equiv MMC_VDD_33_34,                0x00200000

    .equiv SD_CMD_SEND_RELATIVE_ADDR,    3
    .equiv SD_CMD_SWITCH_FUNC,           6
    .equiv SD_CMD_SEND_IF_COND,          8
    .equiv SD_CMD_SWITCH_UHS18V,         11
    .equiv SD_CMD_APP_SET_BUS_WIDTH,     6
    .equiv SD_CMD_APP_SD_STATUS,         13
    .equiv SD_CMD_ERASE_WR_BLK_START,    32
    .equiv SD_CMD_ERASE_WR_BLK_END,      33
    .equiv SD_CMD_APP_SEND_OP_COND,      41
    .equiv SD_CMD_APP_SEND_SCR,          51

    .equiv OCR_BUSY,                     0x80000000
    .equiv OCR_HCS,                      0x40000000
    .equiv OCR_VOLTAGE_MASK,             0x007fff80
    .equiv OCR_ACCESS_MODE,              0x60000000

    .equiv MMC_STATUS_SWITCH_ERROR,      (0x01 << 7)
    .equiv MMC_STATUS_RDY_FOR_DATA,      (0x01 << 8)
    .equiv MMC_STATUS_CURR_STATE,        (0x0f << 9)
    .equiv MMC_STATUS_ERROR,             (0x01 << 19)
    .equiv MMC_STATE_PRG,                (0x07 << 9)

    .equiv SUNXI_MMC_CMD_RESP_EXPIRE,          (1 << 6)
    .equiv SUNXI_MMC_CMD_LONG_RESPONSE,        (1 << 7)
    .equiv SUNXI_MMC_CMD_CHK_RESPONSE_CRC,     (1 << 8)
    .equiv SUNXI_MMC_CMD_DATA_EXPIRE,          (1 << 9)
    .equiv SUNXI_MMC_CMD_WRITE,                (1 << 10)
    .equiv SUNXI_MMC_CMD_AUTO_STOP,            (1 << 12)
    .equiv SUNXI_MMC_CMD_WAIT_PRE_OVER,        (1 << 13)
    .equiv SUNXI_MMC_CMD_SEND_INIT_SEQ,        (1 << 15)
    .equiv SUNXI_MMC_CMD_UPCLK_ONLY,           (1 << 21)
    .equiv SUNXI_MMC_CMD_START,                (1 << 31)
    .equiv SUNXI_MMC_RINT_RESP_ERROR,          (1 << 1)
    .equiv SUNXI_MMC_RINT_COMMAND_DONE,        (1 << 2)
    .equiv SUNXI_MMC_RINT_DATA_OVER,           (1 << 3)
    .equiv SUNXI_MMC_RINT_TX_DATA_REQUEST,     (1 << 4)
    .equiv SUNXI_MMC_RINT_RX_DATA_REQUEST,     (1 << 5)
    .equiv SUNXI_MMC_RINT_RESP_CRC_ERROR,      (1 << 6)
    .equiv SUNXI_MMC_RINT_DATA_CRC_ERROR,      (1 << 7)
    .equiv SUNXI_MMC_RINT_RESP_TIMEOUT,        (1 << 8)
    .equiv SUNXI_MMC_RINT_DATA_TIMEOUT,        (1 << 9)
    .equiv SUNXI_MMC_RINT_VOLTAGE_CHANGE_DONE, (1 << 10)
    .equiv SUNXI_MMC_RINT_FIFO_RUN_ERROR,      (1 << 11)
    .equiv SUNXI_MMC_RINT_HARD_WARE_LOCKED,    (1 << 12)
    .equiv SUNXI_MMC_RINT_START_BIT_ERROR,     (1 << 13)
    .equiv SUNXI_MMC_RINT_AUTO_COMMAND_DONE,   (1 << 14)
    .equiv SUNXI_MMC_RINT_END_BIT_ERROR,       (1 << 15)
    .equiv SUNXI_MMC_RINT_SDIO_INTERRUPT,      (1 << 16)
    .equiv SUNXI_MMC_RINT_CARD_INSERT,         (1 << 30)
    .equiv SUNXI_MMC_RINT_CARD_REMOVE,         (1 << 31)
    .equiv SUNXI_MMC_GCTRL_SOFT_RESET,         (1 << 0)
    .equiv SUNXI_MMC_GCTRL_FIFO_RESET,         (1 << 1)
    .equiv SUNXI_MMC_GCTRL_DMA_RESET,          (1 << 2)
    .equiv SUNXI_MMC_GCTRL_RESET,              (SUNXI_MMC_GCTRL_SOFT_RESET | SUNXI_MMC_GCTRL_FIFO_RESET | SUNXI_MMC_GCTRL_DMA_RESET)
    .equiv SUNXI_MMC_GCTRL_DMA_ENABLE,         (1 << 5)
    .equiv SUNXI_MMC_GCTRL_ACCESS_BY_AHB,      (1 << 31)
    .equiv SUNXI_MMC_CLK_ENABLE,               (1 << 16)

    .equiv SUNXI_MMC_STATUS_RXWL_FLAG,         (1 << 0)
    .equiv SUNXI_MMC_STATUS_TXWL_FLAG,         (1 << 1)
    .equiv SUNXI_MMC_STATUS_FIFO_EMPTY,        (1 << 2)
    .equiv SUNXI_MMC_STATUS_FIFO_FULL,         (1 << 3)
    .equiv SUNXI_MMC_STATUS_CARD_PRESENT,      (1 << 8)
    .equiv SUNXI_MMC_STATUS_CARD_DATA_BUSY,    (1 << 9)
    .equiv SUNXI_MMC_STATUS_DATA_FSM_BUSY,     (1 << 10)

    .arm
    .text
_start:
    .long 0xea000016
    .byte 'e', 'G', 'O', 'N', '.', 'B', 'T', '0'
    .long 0, __spl_size
    .byte 'S', 'P', 'L', 2
    .long 0, 0
    .long 0, 0, 0, 0, 0, 0, 0, 0
    .long 0, 0, 0, 0, 0, 0, 0, 0

_vector:
    b reset
    b .
    b .
    b .
    b .
    b .
    b .
    b .

reset:
    bl ccu_init
    bl uart_init
    bl sdcard_init

    ldr r0, =MMC_CMD_GO_IDLE_STATE
    mov r1, #0
    ldr r2, =MMC_RSP_NONE
    mov r3, #0
    bl sdcard_cmd

    ldr r0, =SD_CMD_SEND_IF_COND
    ldr r1, =0x1aa
    ldr r2, =MMC_RSP_R7
    mov r3, #0
    bl sdcard_cmd

0:
    ldr r0, =MMC_CMD_APP_CMD
    mov r1, #0
    ldr r2, =MMC_RSP_R1
    mov r3, #0
    bl sdcard_cmd

    ldr r0, =SD_CMD_APP_SEND_OP_COND
    ldr r1, =OCR_HCS | MMC_VDD_32_33 | MMC_VDD_33_34
    ldr r2, =MMC_RSP_R3
    mov r3, #0
    bl sdcard_cmd

    tst r0, #OCR_BUSY
    beq 0b

    ldr r0, =MMC_CMD_ALL_SEND_CID
    mov r1, #0
    ldr r2, =MMC_RSP_R2
    mov r3, #0
    bl sdcard_cmd

    ldr r0, =SD_CMD_SEND_RELATIVE_ADDR
    mov r1, #0
    ldr r2, =MMC_RSP_R6
    mov r3, #0
    bl sdcard_cmd

    mov r1, r0, lsr #8
    lsl r1, #8
    ldr r2, =mmc_rca
    str r1, [r2]

    ldr r0, =MMC_CMD_SEND_CSD
    ldr r2, =MMC_RSP_R2
    mov r3, #0
    bl sdcard_cmd

    ldr r0, =MMC_CMD_SELECT_CARD
    ldr r1, =mmc_rca
    ldr r1, [r1]
    ldr r2, =MMC_RSP_R1
    mov r3, #0
    bl sdcard_cmd

    ldr r0, =MMC_CMD_APP_CMD
    ldr r1, =mmc_rca
    ldr r1, [r1]
    ldr r2, =MMC_RSP_R1
    mov r3, #0
    bl sdcard_cmd

    ldr r0, =MMC_CMD_SWITCH
    mov r1, #2
    ldr r2, =MMC_RSP_R1b
    mov r3, #0
    bl sdcard_cmd
    bl sdcard_wait

    ldr r4, =SDC0_BASE
    mov r1, #1
    str r1, [r4, #SD_BWDR_REG]

    ldr r0, =MMC_CMD_SET_BLOCKLEN
    mov r1, #512
    ldr r2, =MMC_RSP_R1
    mov r3, #0
    bl sdcard_cmd

    ldr r0, =SD_CMD_ERASE_WR_BLK_START
    ldr r1, =0x2000
    ldr r2, =MMC_RSP_R1
    mov r3, #0
    bl sdcard_cmd

    ldr r0, =SD_CMD_ERASE_WR_BLK_END
    ldr r1, =0x2000 + 512
    ldr r2, =MMC_RSP_R1
    mov r3, #0
    bl sdcard_cmd

    ldr r0, =MMC_CMD_ERASE
    mov r1, #0
    ldr r2, =MMC_RSP_R1b
    mov r3, #0
    bl sdcard_cmd
    bl sdcard_wait

    ldr r1, =mmc_wr
    mov r2, #512
    mov r3, #0
0:
    str r3, [r1]
    add r3, #1
    add r1, #4
    subs r2, #4
    bne 0b

    ldr r0, =MMC_CMD_WRITE_SINGLE_BLOCK
    ldr r1, =0x2000
    ldr r2, =MMC_RSP_R1
    ldr r3, =512
    bl sdcard_cmd
    bl sdcard_wait

    ldr r1, =mmc_rd
    mov r2, #512
    mov r3, #0
0:
    str r3, [r1]
    add r1, #4
    subs r2, #4
    bne 0b

    ldr r0, =MMC_CMD_READ_SINGLE_BLOCK
    ldr r1, =0x2000
    ldr r2, =MMC_RSP_R1
    ldr r3, =512
    bl sdcard_cmd

    ldr r4, =mmc_rd
    mov r5, #512
0:
    ldr r0, [r4]
    bl uart_4byte
    add r4, #4
    subs r5, #4
    bne 0b
    b .

sdcard_wait:
    push {lr}
0:
    ldr r0, =MMC_CMD_SEND_STATUS
    ldr r1, =mmc_rca
    ldr r1, [r1]
    ldr r2, =MMC_RSP_R1
    mov r3, #0
    bl sdcard_cmd
    tst r0, #MMC_STATUS_RDY_FOR_DATA
    beq 0b
    tst r0, #MMC_STATE_PRG
    beq 0b
    pop {pc}

sdcard_wr:
    push {r4, lr}
    ldr r4, =SDC0_BASE
    ldr r1, =mmc_wr
0:
    ldr r2, [r4, #SD_STAR_REG]
    tst r2, #SUNXI_MMC_STATUS_FIFO_FULL
    bne 0b

    ldr r2, [r1]
    str r2, [r4, #SD_FIFO_REG]
    add r1, #4
    subs r0, #4
    bne 0b
    pop {r4, pc}

sdcard_rd:
    push {r4, lr}
    ldr r4, =SDC0_BASE
    ldr r1, =mmc_rd
0:
    ldr r2, [r4, #SD_STAR_REG]
    tst r2, #SUNXI_MMC_STATUS_FIFO_EMPTY
    bne 0b

    ldr r2, [r4, #SD_FIFO_REG]
    str r2, [r1]
    add r1, #4
    subs r0, #4
    bne 0b
    pop {r4, pc}

sdcard_cmd:
    push {r4, r5, r6, r7, lr}
    ldr r4, =SDC0_BASE

    mov r5, r2
    mov r6, #SUNXI_MMC_RINT_COMMAND_DONE
    mov r7, r0

    cmp r7, #MMC_CMD_GO_IDLE_STATE
    orreq r0, #SUNXI_MMC_CMD_SEND_INIT_SEQ
    orr r0, #SUNXI_MMC_CMD_START
    tst r2, #MMC_RSP_PRESENT
    orrne r0, #SUNXI_MMC_CMD_RESP_EXPIRE
    tst r2, #MMC_RSP_136
    orrne r0, #SUNXI_MMC_CMD_LONG_RESPONSE
    tst r2, #MMC_RSP_CRC
    orrne r0, #SUNXI_MMC_CMD_CHK_RESPONSE_CRC

    cmp r7, #MMC_CMD_WRITE_SINGLE_BLOCK
    orreq r0, #SUNXI_MMC_CMD_WRITE

    cmp r3, #0
    orrne r6, #SUNXI_MMC_RINT_DATA_OVER
    strne r3, [r4, #SD_BKSR_REG]
    strne r3, [r4, #SD_BYCR_REG]
    orrne r0, #SUNXI_MMC_CMD_DATA_EXPIRE
    orrne r0, #SUNXI_MMC_CMD_WAIT_PRE_OVER
    str r1, [r4, #SD_CAGR_REG]
    str r0, [r4, #SD_CMDR_REG]
    beq 0f

    ldr r1, [r4, #SD_GCTL_REG]
    orr r1, #SUNXI_MMC_GCTRL_ACCESS_BY_AHB
    str r1, [r4, #SD_GCTL_REG]

    mov r0, r3
    cmp r7, #MMC_CMD_WRITE_SINGLE_BLOCK
    bleq sdcard_wr
    blne sdcard_rd

0:
    ldr r1, [r4, #SD_RISR_REG]
    tst r1, r6
    beq 0b

    ldr r1, =0xffffffff
    str r1, [r4, #SD_RISR_REG]

    ldr r1, [r4, #SD_GCTL_REG]
    orr r1, #SUNXI_MMC_GCTRL_FIFO_RESET
    str r1, [r4, #SD_GCTL_REG]

    tst r5, #MMC_RSP_136
    ldrne r3, [r4, #SD_RESP0_REG]
    ldrne r2, [r4, #SD_RESP1_REG]
    ldrne r1, [r4, #SD_RESP2_REG]
    ldrne r0, [r4, #SD_RESP3_REG]
    ldreq r0, [r4, #SD_RESP0_REG]
    ldreq r1, [r4, #SD_RESP1_REG]
    ldreq r2, [r4, #SD_RESP2_REG]
    ldreq r3, [r4, #SD_RESP3_REG]
    pop {r4, r5, r6, r7, pc}

ccu_init:
    push {r4, lr}
    ldr r4, =CCU_BASE
    ldr r1, =0x80041800
    str r1, [r4, #PLL_PERIPH_CTRL_REG]
0:
    ldr r1, [r4, #PLL_PERIPH_CTRL_REG]
    tst r1, #(1 << 28)
    beq 0b

    ldr r1, =0x00003180
    str r1, [r4, #AHB_APB_HCLKC_CFG_REG]
    pop {r4, pc}

sdcard_init:
    push {r4, lr}
    ldr r4, =PIO_BASE
    ldr r1, =0x222222
    str r1, [r4, #(PF + PIO_CFG0)]

    ldr r4, =CCU_BASE
    ldr r1, [r4, #BUS_CLK_GATING_REG0]
    orr r1, #(1 << 8)
    str r1, [r4, #BUS_CLK_GATING_REG0]

    ldr r1, [r4, #BUS_SOFT_RST_REG0]
    orr r1, #(1 << 8)
    str r1, [r4, #BUS_SOFT_RST_REG0]

    ldr r1, =(1 << 31) | (1 << 24) | (3 << 0)
    str r1, [r4, #SDMMC0_CLK_REG]

    ldr r4, =SDC0_BASE
    ldr r1, =SUNXI_MMC_GCTRL_RESET
    str r1, [r4, #SD_GCTL_REG]

    ldr r1, =SUNXI_MMC_CLK_ENABLE
    str r1, [r4, #SD_CKCR_REG]

    ldr r1, =SUNXI_MMC_CMD_START | SUNXI_MMC_CMD_UPCLK_ONLY | SUNXI_MMC_CMD_WAIT_PRE_OVER
    str r1, [r4, #SD_CMDR_REG]
0:
    ldr r1, [r4, #SD_CMDR_REG]
    tst r1, #SUNXI_MMC_CMD_START
    bne 0b
    ldr r1, =0xffffffff
    str r1, [r4, #SD_RISR_REG]

    ldr r1, =0
    str r1, [r4, #SD_BWDR_REG]
    pop {r4, pc}

uart_init:
    push {r4, lr}
    ldr r4, =PIO_BASE
    ldr r1, [r4, #(PA + PIO_CFG0)]
    bic r1, #0xff00
    orr r1, #0x5500
    str r1, [r4, #(PA + PIO_CFG0)]

    ldr r4, =CCU_BASE
    ldr r1, [r4, #BUS_CLK_GATING_REG2]
    orr r1, #(1 << 21)
    str r1, [r4, #BUS_CLK_GATING_REG2]

    ldr r1, [r4, #BUS_SOFT_RST_REG2]
    orr r1, #(1 << 21)
    str r1, [r4, #BUS_SOFT_RST_REG2]

    ldr r4, =UART1_BASE
    ldr r1, =0x00
    str r1, [r4, #UART_IER]
    ldr r1, =0xf7
    str r1, [r4, #UART_IIR]
    ldr r1, =0x00
    str r1, [r4, #UART_MCR]
    ldr r1, [r4, #UART_LCR]
    orr r1, #(1 << 7)
    str r1, [r4, #UART_LCR]
    ldr r1, =54
    str r1, [r4, #UART_DLL]
    ldr r1, =0x00
    str r1, [r4, #UART_DLH]
    ldr r1, [r4, #UART_LCR]
    bic r1, #(1 << 7)
    str r1, [r4, #UART_LCR]
    ldr r1, [r4, #UART_LCR]
    bic r1, #0x1f
    orr r1, #0x03
    str r1, [r4, #UART_LCR]
    pop {r4, pc}

uart_byte:
    push {r4, lr}
    ldr r4, =UART1_BASE
0:
    ldr r1, [r4, #UART_USR]
    tst r1, #(1 << 1)
    beq 0b
    strb r0, [r4, #UART_RBR]
    pop {r4, pc}

uart_4byte:
    push {r4, lr}
    mov r4, r0
    lsr r0, #24
    bl uart_byte

    mov r0, r4
    lsr r0, #16
    bl uart_byte

    mov r0, r4
    lsr r0, #8
    bl uart_byte

    mov r0, r4
    bl uart_byte
    pop {r4, pc}

uart_resp:
    push {r4, r5, r6, r7, lr}
    mov r4, r0
    mov r5, r1
    mov r6, r2
    mov r7, r3

    mov r0, r4
    bl uart_4byte

    mov r0, r5
    bl uart_4byte

    mov r0, r6
    bl uart_4byte

    mov r0, r7
    bl uart_4byte
    pop {r4, r5, r6, r7, pc}

.data
    mmc_rca: .word 0
    mmc_rd: .skip 512
    mmc_wr: .skip 512
    .end

完成