tridoraemu: fix crash on invalid vmem addresses examples: removed 5cubes due to unclear licensing add stuff to gitignore, licenses, README import Vivado project added missing assembly files, extended .gitignore stdlib: use DEL instead of BS
795 lines
13 KiB
ArmAsm
795 lines
13 KiB
ArmAsm
; Copyright 2021-2024 Sebastian Lederer. See the file LICENSE.md for details
|
|
.EQU SPIREG $880
|
|
|
|
.EQU SPI_CTRL_WRITE %100000000000000
|
|
.EQU SPI_RX_FILTER_EN %010000000000000
|
|
.EQU SPI_TXRX_EN %001000000000000
|
|
.EQU SPI_CLK_F_EN %000100000000000
|
|
.EQU SPI_CLK_DIV_WR %000010000000000
|
|
.EQU SPI_RX_RD %000001000000000
|
|
.EQU SPI_TX_WR %000000100000000
|
|
|
|
.EQU SPI_C_D %100000000000000
|
|
.EQU SPI_C_CHG %010000000000000
|
|
.EQU SPDI_C_BUSY %001000000000000
|
|
.EQU SPI_TX_RDY %000100000000000
|
|
.EQU SPI_TX_EMPTY %000010000000000
|
|
.EQU SPI_RX_AVAIL %000001000000000
|
|
.EQU SPI_RX_OVR %000000100000000
|
|
|
|
.EQU SPI_TXRX_EN_MASK ~SPI_TXRX_EN
|
|
|
|
_WAIT:
|
|
LOADC 10
|
|
_WAITL:
|
|
LOADCP WAIT1MSEC
|
|
CALL
|
|
DEC 1
|
|
DUP
|
|
CBRANCH.NZ _WAITL
|
|
DROP
|
|
RET
|
|
|
|
INITSDCARD:
|
|
LOADCP WAIT1MSEC
|
|
CALL
|
|
|
|
LOADCP _SPIINIT1
|
|
CALL
|
|
|
|
;LOADC 'I'
|
|
;LOADCP CONOUT
|
|
;CALL
|
|
|
|
LOADCP _WAITSPITXRDY
|
|
CALL
|
|
|
|
;LOADC 'W'
|
|
;LOADCP CONOUT
|
|
;CALL
|
|
|
|
; send RESET CARD command
|
|
LOADC $95 ; send cmd0 with arg 0 and checksum $95
|
|
LOADC $0
|
|
LOADC $0
|
|
LOADCP SENDCMD_R1
|
|
CALL
|
|
|
|
DROP ; TODO: handle errors
|
|
;LOADCP PRINTHEXW ; print status returned by the card
|
|
;CALL
|
|
;LOADCP NEWLINE
|
|
;CALL
|
|
|
|
;LOADC '9'
|
|
;LOADCP CONOUT
|
|
;CALL
|
|
|
|
LOADCP _WAITSPITXRDY
|
|
CALL
|
|
|
|
LOADCP _WAIT
|
|
CALL
|
|
|
|
;LOADC '1'
|
|
;LOADCP CONOUT
|
|
;CALL
|
|
|
|
LOADC $87
|
|
LOADC $01AA
|
|
LOADC $8
|
|
LOADCP SENDCMD_R7
|
|
CALL
|
|
|
|
DROP
|
|
|
|
LOADCP _WAITSPITXRDY
|
|
CALL
|
|
|
|
;LOADC '2'
|
|
;LOADCP CONOUT
|
|
;CALL
|
|
|
|
;LOADCP _WAIT
|
|
;CALL
|
|
|
|
;LOADC '.'
|
|
;LOADCP CONOUT
|
|
;CALL
|
|
|
|
LOADCP CARDINITV2
|
|
CALL
|
|
|
|
;LOADC '+'
|
|
;LOADCP CONOUT
|
|
;CALL
|
|
|
|
|
|
LOADCP CARDFASTCLK
|
|
CALL
|
|
|
|
;LOADC '3'
|
|
;LOADCP CONOUT
|
|
;CALL
|
|
|
|
; CMD16: set block size to 512 byte
|
|
LOADC 0
|
|
LOADC 512
|
|
LOADC 16
|
|
LOADCP SENDCMD_R1
|
|
CALL
|
|
|
|
DROP
|
|
|
|
;LOADCP _WAIT
|
|
;CALL
|
|
|
|
;LOADC '4'
|
|
;LOADCP CONOUT
|
|
;CALL
|
|
|
|
RET
|
|
|
|
; read a 512-byte-block from the card
|
|
; args: block number
|
|
; returns: 0 on success
|
|
CARDREADBLK:
|
|
LOADC 128 ; number of words in a block
|
|
SWAP ; move block number up the stack
|
|
LOADCP CARD_BUF
|
|
SWAP
|
|
LOADC 0
|
|
SWAP
|
|
LOADC 17 ; CMD17: read block
|
|
LOADCP SENDCMD_PKT
|
|
CALL
|
|
RET
|
|
|
|
; determine number of blocks
|
|
; returns: number of blocks or -1 on error
|
|
CARDSIZE:
|
|
LOADC 4
|
|
LOADCP CSD_BUF
|
|
LOADC 0
|
|
LOADC 0
|
|
LOADC 9
|
|
LOADCP SENDCMD_PKT ; send CMD9
|
|
CALL
|
|
|
|
CBRANCH.NZ CARDSIZE_ERR ; if response is zero, an error occurred
|
|
|
|
; take bytes 7, 8 and 9 from CSD data
|
|
; and add 1 to get card size in ksectors
|
|
LOADCP CSD_BUF
|
|
INC 4
|
|
LOADI
|
|
LOADC $3F ; get byte 7 (bits 22-16)
|
|
AND
|
|
BROT
|
|
BROT
|
|
|
|
LOADCP CSD_BUF ; get bytes 8 and 9 (bits 15-0)
|
|
INC 8
|
|
LOADI
|
|
BROT
|
|
BROT
|
|
LOADCP $FFFF
|
|
AND
|
|
|
|
OR
|
|
|
|
INC 1
|
|
|
|
BROT
|
|
SHL 2; multiply by 1024 to get size in sectors
|
|
|
|
RET
|
|
|
|
CARDSIZE_ERR:
|
|
LOADC -1
|
|
RET
|
|
|
|
; returns 1 if the card was changed, 0 otherwise
|
|
CARDCHANGED:
|
|
LOADCP SPIREG
|
|
LOADI
|
|
LOADCP SPI_C_CHG
|
|
AND
|
|
LOADC 0
|
|
CMPU NE
|
|
RET
|
|
|
|
; write a 512-byte-block to the card
|
|
; args: block number
|
|
; returns: 0 on success
|
|
CARDWRITEBLK:
|
|
LOADC 128 ; number of words in a block
|
|
SWAP ; move block number up the stack
|
|
LOADCP CARD_BUF
|
|
SWAP
|
|
LOADC 0
|
|
SWAP
|
|
LOADC 24 ; CMD24: write block
|
|
LOADCP SENDCMD_TXPKT
|
|
CALL
|
|
RET
|
|
; send the card initialization command
|
|
; wait until the card responds
|
|
CARDINITV2:
|
|
LOADC 100 ; try up to 100 times
|
|
CARD_LOOP1:
|
|
LOADC 50 ; wait 50 msec
|
|
CARD_LOOP2:
|
|
LOADCP WAIT1MSEC
|
|
CALL
|
|
DEC 1
|
|
DUP
|
|
CBRANCH.NZ CARD_LOOP2
|
|
DROP ; remove loop count value
|
|
|
|
LOADC $0
|
|
LOADC $0
|
|
LOADC 58
|
|
LOADCP SENDCMD_R7 ; send CMD58
|
|
CALL
|
|
DROP ; ignore result (why?)
|
|
|
|
LOADC $0
|
|
LOADCP $40000000
|
|
LOADC 41
|
|
LOADCP SENDACMD_R1 ; send ACMD41
|
|
CALL
|
|
|
|
CBRANCH.Z CARD_OK ; if result is zero, the command succeded
|
|
; and the card initialization is finished
|
|
DEC 1
|
|
DUP
|
|
CBRANCH.NZ CARD_LOOP1
|
|
DROP ; remove outer loop count value
|
|
|
|
RET
|
|
CARD_OK:
|
|
DROP ; remove outer loop count value
|
|
|
|
; CMD16: set block size to 512 byte
|
|
LOADC 0
|
|
LOADC 512
|
|
LOADC 16
|
|
LOADCP SENDCMD_R1
|
|
CALL
|
|
DROP ; ignore return value
|
|
|
|
RET
|
|
|
|
; set fast transfer rate
|
|
CARDFASTCLK:
|
|
LOADC SPIREG
|
|
; set clock divider to ~2,6MHz
|
|
LOADCP SPI_CLK_DIV_WR,10 ; using the LOADCP with offset syntax here
|
|
STOREI
|
|
DROP
|
|
RET
|
|
|
|
; perform first phase of card initialization
|
|
; which is to enable clock and wait a bit
|
|
; leaves the clock running
|
|
_SPIINIT1:
|
|
LOADC SPIREG
|
|
; set clock divider to ~325KHz
|
|
LOADCP SPI_CLK_DIV_WR,64 ; LOADCP with offset
|
|
STOREI
|
|
DROP
|
|
|
|
; clear all flags + enable clock
|
|
; /CS and MOSI are default high
|
|
LOADC SPIREG
|
|
LOADCP SPI_CTRL_WRITE,SPI_CLK_F_EN
|
|
STOREI
|
|
DROP
|
|
|
|
; we should wait at least for 74 clock cycles now
|
|
LOADC 2 ; wait 2 msec, that should be ~300 cycles
|
|
_SPIINIT1L:
|
|
LOADCP WAIT1MSEC
|
|
CALL
|
|
DEC 1
|
|
DUP
|
|
CBRANCH.NZ _SPIINIT1L
|
|
DROP
|
|
|
|
LOADC SPIREG
|
|
LOADCP SPI_CTRL_WRITE ; disable clock
|
|
STOREI
|
|
DROP
|
|
|
|
LOADCP WAIT1MSEC
|
|
CALL
|
|
|
|
RET
|
|
|
|
; wait for transmission to finish
|
|
; (wait for TX_EMPTY bit)
|
|
_SPIWAITTX:
|
|
LOADC SPIREG
|
|
LOADI
|
|
LOADCP SPI_TX_EMPTY
|
|
AND
|
|
CBRANCH.Z _SPIWAITTX
|
|
RET
|
|
|
|
; finalize a command that has been sent:
|
|
; wait until the transmitter is idle
|
|
; then disable clock and set MOSI high
|
|
_SPIENDCMD:
|
|
LOADCP $FF
|
|
LOADCP _SENDBYTE
|
|
CALL
|
|
LOADCP $FF
|
|
LOADCP _SENDBYTE
|
|
CALL
|
|
|
|
;LOADC 'E'
|
|
;LOADCP CONOUT
|
|
;CALL
|
|
|
|
LOADCP _SPIWAITTX
|
|
CALL
|
|
|
|
;LOADC 'w'
|
|
;LOADCP CONOUT
|
|
;CALL
|
|
LOADCP _WAIT_S ; wait a short time
|
|
CALL
|
|
|
|
LOADC SPIREG
|
|
LOADCP SPI_IDLE_FLAGS ; turn off transceiver
|
|
LOADI
|
|
STOREI
|
|
DROP
|
|
|
|
; wait for a few instructions
|
|
LOADC 100
|
|
SPIEND_LP: DEC 1
|
|
DUP
|
|
CBRANCH.NZ SPIEND_LP
|
|
DROP
|
|
|
|
RET
|
|
|
|
_WAIT_S:
|
|
LOADC 100
|
|
_WAIT_S_L:
|
|
DEC 1
|
|
DUP
|
|
CBRANCH.NZ _WAIT_S_L
|
|
DROP
|
|
RET
|
|
|
|
; clear RX fifo
|
|
CLEAR_RX_FIFO:
|
|
CLEAR_RX_L1:
|
|
LOADC SPIREG
|
|
LOADI
|
|
|
|
;DUP
|
|
;LOADCP PRINTHEXW
|
|
;CALL
|
|
;LOADCP NEWLINE
|
|
;CALL
|
|
|
|
LOADC SPI_RX_AVAIL
|
|
AND
|
|
CBRANCH.Z CLEAR_RX_X
|
|
LOADC SPIREG
|
|
LOADC SPI_RX_RD
|
|
STOREI
|
|
DROP
|
|
|
|
; FIXME: it seems that this
|
|
; does not remove a byte from the fifo,
|
|
; rx_avail stays on, but only after the first
|
|
; byte has been received and read
|
|
|
|
;LOADC 'x'
|
|
;LOADCP CONOUT
|
|
;CALL
|
|
|
|
BRANCH CLEAR_RX_L1
|
|
CLEAR_RX_X:
|
|
RET
|
|
|
|
_WAITSPITXRDY:
|
|
LOADC SPIREG
|
|
LOADI
|
|
LOADCP SPI_TX_RDY
|
|
AND
|
|
CBRANCH.Z _WAITSPITXRDY
|
|
RET
|
|
|
|
; send a command and receive a data packet response
|
|
; args: packet size in words, buffer pointer
|
|
; checksum byte, 32-bit cmd arg, cmd number
|
|
; returns: 0 on success
|
|
SENDCMD_PKT:
|
|
; first send the command
|
|
LOADCP SENDCMD_0
|
|
CALL
|
|
|
|
LOADCP _RCVBYTE ; receive R1 response
|
|
CALL
|
|
|
|
CBRANCH.NZ SENDCMD_PKT_E ; on success we get 0
|
|
|
|
; now wait for data token
|
|
SENDCMD_PKT_L:
|
|
LOADCP _RCVBYTE
|
|
CALL
|
|
LOADC $FF
|
|
CMP EQ
|
|
CBRANCH SENDCMD_PKT_L
|
|
|
|
; parameters for _RCVWORDS are on the stack now
|
|
LOADCP _RCVWORDS
|
|
CALL
|
|
|
|
; receive 2 crc bytes
|
|
LOADCP _RCVBYTE
|
|
CALL
|
|
BROT
|
|
LOADCP _RCVBYTE
|
|
CALL
|
|
OR
|
|
|
|
; terminate command
|
|
LOADCP _SPIENDCMD
|
|
CALL
|
|
|
|
DROP ; we ignore the checksum for now
|
|
|
|
LOADC 0
|
|
RET
|
|
SENDCMD_PKT_E:
|
|
DROP ; remove remaining args
|
|
DROP
|
|
LOADC -1 ; return code for error
|
|
RET
|
|
|
|
; send a command and send a data packet
|
|
; args: packet size in words, buffer pointer
|
|
; checksum byte, 32-bit cmd arg, cmd number
|
|
; returns: 0 on success
|
|
SENDCMD_TXPKT:
|
|
; first send the command
|
|
LOADCP SENDCMD_0
|
|
CALL
|
|
|
|
;LOADCP _RCVBYTE
|
|
;CALL
|
|
;DROP ; remove byte received during transmit
|
|
|
|
LOADCP _RCVBYTE ; receive R1 response
|
|
CALL
|
|
|
|
CBRANCH.NZ SENDCMD_TXPKT_E ; on error we get nonzero
|
|
|
|
; send stuff byte
|
|
LOADC $FF
|
|
LOADCP _SENDBYTE
|
|
CALL
|
|
|
|
; now send data token
|
|
LOADCP %11111110
|
|
LOADCP _SENDBYTE
|
|
CALL
|
|
|
|
; send data block
|
|
; parameters for _SENDWORDS are on the stack now
|
|
LOADCP _SENDWORDS
|
|
CALL
|
|
|
|
; send 2 dummy crc bytes
|
|
LOADC 0
|
|
LOADCP _SENDBYTE
|
|
CALL
|
|
LOADC 0
|
|
LOADCP _SENDBYTE
|
|
CALL
|
|
|
|
;receive data response byte
|
|
SENDCMD_TXPKT_LR:
|
|
LOADCP _RCVBYTE
|
|
CALL
|
|
LOADC $FF ; discard $FF bytes
|
|
CMP.S0 NE
|
|
CBRANCH SENDCMD_TXPKT_CT
|
|
DROP
|
|
BRANCH SENDCMD_TXPKT_LR
|
|
|
|
SENDCMD_TXPKT_CT:
|
|
LOADC $1F
|
|
AND ; isolate status bits
|
|
LOADC $5 ; command accepted bit set?
|
|
CMP NE ; if not, exit with error
|
|
CBRANCH SENDCMD_TXPKT_E2
|
|
|
|
; wait until card is busy
|
|
SENDCMD_TXPKT_LB:
|
|
LOADCP _RCVBYTE ; receive byte
|
|
CALL
|
|
CBRANCH.NZ SENDCMD_TXPKT_LB ; loop until byte is 0
|
|
; wait until card is not busy
|
|
SENDCMD_TXPKT_L2:
|
|
LOADCP _RCVBYTE ;receive byte
|
|
CALL
|
|
CBRANCH.Z SENDCMD_TXPKT_L2 ; loop if byte is 0 (i.e. MISO is held low)
|
|
|
|
LOADC 0
|
|
BRANCH SENDCMD_TXPKT_X
|
|
|
|
SENDCMD_TXPKT_E:
|
|
DROP ; remove remaining args
|
|
DROP
|
|
SENDCMD_TXPKT_E2:
|
|
LOADC -1 ; return code for error
|
|
SENDCMD_TXPKT_X:
|
|
; terminate command
|
|
LOADCP _SPIENDCMD
|
|
CALL
|
|
|
|
RET
|
|
|
|
; send a command and receive a 1-byte-response (R1)
|
|
; args: checksum byte, 32-bit cmd arg, cmd number
|
|
; returns: received byte
|
|
SENDCMD_R1:
|
|
LOADCP SENDCMD_0
|
|
CALL
|
|
|
|
LOADCP _RCVBYTE
|
|
CALL
|
|
|
|
;LOADC 'R'
|
|
;LOADCP CONOUT
|
|
;CALL
|
|
|
|
;terminate command (/cs high, disable clock)
|
|
LOADCP _SPIENDCMD
|
|
CALL
|
|
|
|
RET
|
|
|
|
; send a command
|
|
; args: checksum byte, 32-bit cmd arg, cmd number
|
|
SENDCMD_0:
|
|
; clear RX FIFO first
|
|
LOADCP CLEAR_RX_FIFO
|
|
CALL
|
|
|
|
;LOADC '>'
|
|
;LOADCP CONOUT
|
|
;CALL
|
|
|
|
; cmd byte is at TOS at this point
|
|
LOADC $40 ; or in start of frame bit
|
|
OR
|
|
LOADCP _SENDBYTE
|
|
CALL
|
|
; cmd arg is at TOS now
|
|
LOADCP _SENDWORD
|
|
CALL
|
|
; checksum byte is at TOS now
|
|
LOADCP _SENDBYTE
|
|
CALL
|
|
|
|
LOADCP _XCVR_ENABLE ; enable transceiver last,
|
|
CALL ; a complete command should
|
|
RET ; fit into the tx fifo
|
|
|
|
; send ACMD and receive a 1-byte-response (R1)
|
|
; args: checksum byte, 32-bit cmd arg, ACMD number
|
|
; returns: received byte or -1 if first response byte
|
|
; indicated an error
|
|
SENDACMD_R1:
|
|
LOADC $0
|
|
LOADC $0
|
|
LOADC 55 ; send CMD55
|
|
LOADCP SENDCMD_R1
|
|
CALL
|
|
|
|
LOADC 1 ; 1 = idle state, no errors
|
|
CMP NE
|
|
CBRANCH.NZ SENDACMD_ERR
|
|
|
|
; pass our args to SENDCMD_R1
|
|
LOADCP SENDCMD_R1
|
|
CALL
|
|
RET
|
|
|
|
SENDACMD_ERR:
|
|
LOADCP -1
|
|
RET
|
|
|
|
; send a command and receive a 4+1-byte-response (R7)
|
|
; args: checksum byte, 32-bit cmd arg, cmd number
|
|
; returns: received word or -1 if first response byte
|
|
; indicated an error
|
|
|
|
SENDCMD_R7:
|
|
; send the command
|
|
LOADCP SENDCMD_0
|
|
CALL
|
|
|
|
;LOADC '7'
|
|
;LOADCP CONOUT
|
|
;CALL
|
|
|
|
LOADCP _RCVBYTE
|
|
CALL
|
|
|
|
LOADCP _RCVWORD
|
|
CALL
|
|
|
|
;terminate command (/cs high, disable clock)
|
|
LOADCP _SPIENDCMD
|
|
CALL
|
|
|
|
SWAP ; swap 1st response byte with received word
|
|
LOADC %011111110 ; check for any error flags
|
|
AND
|
|
CBRANCH.Z SENDCMD_R7_NOERR
|
|
DROP
|
|
LOADC -1
|
|
SENDCMD_R7_NOERR:
|
|
RET
|
|
|
|
; send a word as 4 bytes, msb first
|
|
_SENDWORD:
|
|
DUP ; remember original value for later
|
|
|
|
BROT ; rotate msb to lsb (byte 0)
|
|
LOADC 255
|
|
AND.S0 ; isolate byte, keep previous value
|
|
LOADCP _SENDBYTE
|
|
CALL
|
|
|
|
BROT ; byte 1
|
|
LOADC 255
|
|
AND.S0
|
|
LOADCP _SENDBYTE
|
|
CALL
|
|
|
|
BROT ; byte 2
|
|
LOADC 255
|
|
AND
|
|
LOADCP _SENDBYTE
|
|
CALL
|
|
|
|
; byte 3 is already on the stack
|
|
LOADC 255
|
|
AND
|
|
LOADCP _SENDBYTE
|
|
CALL
|
|
|
|
RET
|
|
|
|
; send multiple 4-byte-words
|
|
; args: number of words, pointer to buffer
|
|
_SENDWORDS:
|
|
FPADJ -4
|
|
STORE 0 ; store pointer arg into local variable
|
|
; keep counter on stack
|
|
_SENDWORDS_LP:
|
|
LOAD 0 ; load buf pointer
|
|
DUP ; duplicate it
|
|
INC 4 ; increment pointer
|
|
STORE 0 ; and store it back
|
|
LOADI ; load from previously duped pointer
|
|
LOADCP _SENDWORD
|
|
CALL ; send a word
|
|
|
|
DEC 1 ; decrement word counter
|
|
DUP
|
|
CBRANCH.NZ _SENDWORDS_LP ; if not null, loop
|
|
DROP ; remove counter value
|
|
|
|
FPADJ 4
|
|
RET
|
|
|
|
; receive multiple 4-byte-words and store into
|
|
; memory buffer
|
|
; args: number of words, pointer to buffer
|
|
_RCVWORDS:
|
|
FPADJ -4
|
|
STORE 0 ; store pointer arg into local variable
|
|
; keep counter on stack
|
|
_RCVWORDS_LP:
|
|
LOAD 0 ; load buf pointer for STOREI
|
|
LOADCP _RCVWORD
|
|
CALL ; receive a word
|
|
STOREI 4 ; store to buf with postincrement
|
|
STORE 0 ; store pointer variable
|
|
|
|
DEC 1 ; decrement word counter
|
|
DUP
|
|
CBRANCH.NZ _RCVWORDS_LP ; if not null, loop
|
|
DROP ; remove counter value
|
|
|
|
FPADJ 4
|
|
RET
|
|
|
|
; receive 4 bytes, return as word
|
|
_RCVWORD:
|
|
LOADCP _RCVBYTE ; receive first byte
|
|
CALL
|
|
BROT ; rotate byte to left
|
|
|
|
LOADCP _RCVBYTE ; receive second byte
|
|
CALL
|
|
OR ; or first and second byte together
|
|
BROT ; rotate 1st + 2nd to left
|
|
|
|
LOADCP _RCVBYTE ; receive third byte
|
|
CALL
|
|
OR
|
|
BROT
|
|
|
|
LOADCP _RCVBYTE ; receive fourth byte
|
|
CALL
|
|
OR
|
|
RET
|
|
|
|
_XCVR_ENABLE:
|
|
LOADC SPIREG
|
|
LOADCP SPI_TX_FLAGS
|
|
LOADI
|
|
STOREI
|
|
DROP
|
|
RET
|
|
|
|
; send a byte
|
|
; args: byte to be sent
|
|
_SENDBYTE:
|
|
LOADC SPIREG
|
|
LOADI ; load spi io register
|
|
LOADCP SPI_TX_RDY
|
|
AND ; check tx_rdy bit
|
|
CBRANCH.Z _SENDBYTE ; if not set, loop
|
|
|
|
LOADC SPI_TX_WR ; TX_WR bit
|
|
OR ; OR in byte to be send
|
|
|
|
LOADC SPIREG
|
|
SWAP ; swap value and addr for STOREI
|
|
STOREI ; store word (flags + data) to io register
|
|
DROP ; remove STOREI result
|
|
|
|
RET
|
|
|
|
; receive a byte. receiver must be enabled.
|
|
; returns: received byte
|
|
_RCVBYTE:
|
|
LOADC SPIREG
|
|
LOADI ; load spi io register
|
|
LOADC SPI_RX_AVAIL
|
|
AND.S0 ; check rx_avail bit, keep original value
|
|
CBRANCH.NZ RECV_GOTIT
|
|
DROP ; rx_avail not set, remove register value and loop
|
|
BRANCH _RCVBYTE
|
|
RECV_GOTIT:
|
|
LOADC SPIREG
|
|
LOADC SPI_RX_RD ; remove one byte from rx fifo
|
|
STOREI
|
|
DROP
|
|
|
|
LOADC 255
|
|
AND ; keep bits 7-0
|
|
RET
|
|
|
|
SPI_TX_FLAGS: .WORD SPI_CTRL_WRITE + SPI_TXRX_EN + SPI_RX_FILTER_EN
|
|
SPI_IDLE_FLAGS: .WORD SPI_CTRL_WRITE
|
|
|
|
.CPOOL
|
|
|
|
CSD_BUF: .BLOCK 4
|
|
CARD_BUF: .BLOCK 128
|
|
|