Files
super6502/sw/test_code/sd_controller_test/main.s
2024-07-31 21:56:50 -07:00

335 lines
8.0 KiB
ArmAsm

.export _init, _nmi_int, _irq_int
.include "zeropage.inc"
.autoimport
.segment "VECTORS"
.addr _nmi_int ; NMI vector
.addr _init ; Reset vector
.addr _irq_int ; IRQ/BRK vector
SD_CONTROLLER = $e000
SD_CMD = SD_CONTROLLER
SD_ARG = SD_CONTROLLER + $4
SD_DATA = SD_ARG
SD_FIFO_0 = SD_CONTROLLER + $8
SD_FIFO_1 = SD_CONTROLLER + $C
SD_PHY = SD_CONTROLLER + $10
SD_PHY_CLKDIV = SD_PHY
SD_PHY_CLKCTRL = SD_PHY + $1
SD_PHY_SAMP_VOLT = SD_PHY + $2
SD_PHY_BLKSIZ = SD_PHY + $3
SD_DMA_BASE = SD_CONTROLLER + $14
SD_DMA_BASE2 = SD_CONTROLLER + $18
SD_DMA_LEN = SD_CONTROLLER + $1C
SDIOCLK_100KHZ = $FC
SDIOCLK_25MHZ = $03
SPEED_512B = $09
.zeropage
rca: .res 4
.code
_nmi_int:
_irq_int:
_init:
ldx #$ff
txs
cld
lda #<(__STACKSTART__ + __STACKSIZE__)
sta sp
lda #>(__STACKSTART__ + __STACKSIZE__)
sta sp+1
stz SD_PHY_CLKCTRL
stz SD_PHY_SAMP_VOLT
lda #SPEED_512B
sta SD_PHY_BLKSIZ
lda #SDIOCLK_100KHZ
sta SD_PHY_CLKDIV
@wait_clk: lda SD_PHY_CLKDIV
cmp #SDIOCLK_100KHZ
bne @wait_clk
; send_goidle();
jsr send_goidle
; send_r1(8, 0x1aa);
lda #$0
sta sreg+1
lda #$0
sta sreg
ldx #$01
lda #$aa
jsr pusheax
lda #$08
jsr send_r1
@acmd41:
; send_r1(55, 0x00);
lda #$0
sta sreg+1
lda #$0
sta sreg
ldx #$00
lda #$00
jsr pusheax
lda #55
jsr send_r1
; send_r1(41, 0x4000ff80);
lda #$40
sta sreg+1
lda #$0
sta sreg
ldx #$ff
lda #$80
jsr pusheax
lda #41
jsr send_r1
lda sreg+1
bpl @acmd41
; send_r2(2, 0x00);
stz sreg+1
stz sreg
ldx #$00
lda #$00
jsr pusheax
lda #2
jsr send_r2
lda SD_FIFO_0
lda SD_FIFO_0
lda SD_FIFO_0
lda SD_FIFO_0
; send_r1(3, 0x00);
stz sreg+1
stz sreg
ldx #$00
lda #$00
jsr pusheax
lda #3
jsr send_r1
lda #$30
sta SD_PHY_CLKCTRL
stz SD_PHY_SAMP_VOLT
lda #SPEED_512B
sta SD_PHY_BLKSIZ
lda #SDIOCLK_25MHZ
sta SD_PHY_CLKDIV
@wait_clk2: lda SD_PHY_CLKDIV
cmp #SDIOCLK_25MHZ
bne @wait_clk2
; The upper 16 bits are the RCA, but they are already in sreg
; The lower 16 are don't cares, so we can leave them.
jsr pusheax
lda #7
jsr send_r1b
; Now we need to DMA the first sector into memory, say at $1000
; The example code reads multiple, but we can probably just read 1 (cmd17)
; write to address $1000
; dma length is 1
stz SD_DMA_BASE+$3
stz SD_DMA_BASE+$2
lda #$10
sta SD_DMA_BASE+$1
stz SD_DMA_BASE
stz SD_DMA_LEN + $3
stz SD_DMA_LEN + $2
stz SD_DMA_LEN + $1
lda #$01
sta SD_DMA_LEN
; address 0
stz sreg+1
stz sreg
ldx #$00
lda #$00
jsr pusheax
lda #18
jsr send_dma
; dumb sleep to wait for DMA to be done.
lda #$3a
@sleep: dec
bne @sleep
; Try reading again just to make sure it works.
stz SD_DMA_BASE+$3
stz SD_DMA_BASE+$2
lda #$12
sta SD_DMA_BASE+$1
stz SD_DMA_BASE
stz SD_DMA_LEN + $3
stz SD_DMA_LEN + $2
stz SD_DMA_LEN + $1
lda #$01
sta SD_DMA_LEN
; address 2
stz sreg+1
stz sreg
ldx #$00
lda #$02
jsr pusheax
lda #18
jsr send_dma
; dumb sleep to wait for DMA to be done.
lda #$3a
@sleep2:dec
bne @sleep2
; Write the first sector into the second sector
stz SD_DMA_BASE+$3
stz SD_DMA_BASE+$2
lda #$10
sta SD_DMA_BASE+$1
stz SD_DMA_BASE
stz SD_DMA_LEN + $3
stz SD_DMA_LEN + $2
stz SD_DMA_LEN + $1
lda #$2
sta SD_DMA_LEN
; address 2
stz sreg+1
stz sreg
ldx #$00
lda #$02
jsr pusheax
lda #25
jsr write_dma
@end:
bra @end
wait_busy: lda SD_CMD+$1
bit #$40
bne wait_busy
rts
; No arguments, no response
; sends cmd0
; also clears removed and error flags?
send_goidle:
stz SD_ARG+$3
stz SD_ARG+$2
stz SD_ARG+$1
stz SD_ARG
stz SD_CMD+$3
lda #$04
sta SD_CMD+$2
lda #$80
sta SD_CMD+$1
lda #$40
sta SD_CMD
jsr wait_busy
rts
; Command in A
; Arg on stack as 32 bits
; returns the response in eax
; (How can we signal a failure then?)
send_r1: stz tmp1
inc tmp1
bra send
send_r1b: stz tmp1
inc tmp1
inc tmp1
inc tmp1
bra send
send_dma: pha
lda #$20
sta tmp1
pla
bra send
write_dma: pha
lda #$a4
sta tmp1
pla
bra send
send: pha ; push command to stack
jsr popeax
PHA
stx SD_ARG+$1
lda sreg
sta SD_ARG+$2
lda sreg+1
sta SD_ARG+$3
pla
sta SD_ARG ; lsb has to be the last written.
lda #$80 ; This also clears error flag (only for acmd41?)
ora tmp1
sta SD_CMD+$1
pla
ora #$40
sta SD_CMD
jsr wait_busy
lda SD_DATA + $3
sta sreg+1
lda SD_DATA + $2
sta sreg
ldx SD_DATA + $1
lda SD_DATA
rts
; Command in A
; Arg on stack as 32 bits
; returns the response in eax
; (How can we signal a failure then?)
send_r2:
pha ; push command to stack
jsr popeax
PHA
stx SD_ARG+$1
lda sreg
sta SD_ARG+$2
lda sreg+1
sta SD_ARG+$3
pla
sta SD_ARG ; lsb has to be the last written.
lda #$82 ; This also clears error flag (only for acmd41?)
sta SD_CMD+$1
pla
ora #$40
sta SD_CMD
jsr wait_busy
rts