added missing assembly files, extended .gitignore
This commit is contained in:
parent
e3ff5106cf
commit
3c6c119254
10 changed files with 15811 additions and 2924 deletions
11
.gitignore
vendored
11
.gitignore
vendored
|
|
@ -1,4 +1,7 @@
|
||||||
*.s
|
pcomp/*.s
|
||||||
|
progs/*.s
|
||||||
|
tests/*.s
|
||||||
|
examples/*.s
|
||||||
*.o
|
*.o
|
||||||
*.exe
|
*.exe
|
||||||
*.bin
|
*.bin
|
||||||
|
|
@ -20,8 +23,10 @@ graph2.pas
|
||||||
chase.pas
|
chase.pas
|
||||||
!runtime.s
|
!runtime.s
|
||||||
**/tridoracpu.*/
|
**/tridoracpu.*/
|
||||||
rtl/arty-a7/mig_dram_0/_tmp
|
rtl/arty-a7/mig_dram_0/_tmp/*
|
||||||
rtl/arty-a7/mig_dram_0/mig_dram_0
|
rtl/arty-a7/mig_dram_0/doc/*
|
||||||
|
rtl/arty-a7/mig_dram_0/mig_dram_0*
|
||||||
rtl/arty-a7/mig_dram_0/xil_txt.*
|
rtl/arty-a7/mig_dram_0/xil_txt.*
|
||||||
rtl/arty-a7/mig_dram_0/*.veo
|
rtl/arty-a7/mig_dram_0/*.veo
|
||||||
rtl/arty-a7/mig_dram_0/*.tcl
|
rtl/arty-a7/mig_dram_0/*.tcl
|
||||||
|
rtl/arty-a7/mig_dram_0/*.xml
|
||||||
|
|
|
||||||
1501
lib/corelib.s
Normal file
1501
lib/corelib.s
Normal file
File diff suppressed because it is too large
Load diff
279
lib/coreloader.s
Normal file
279
lib/coreloader.s
Normal file
|
|
@ -0,0 +1,279 @@
|
||||||
|
; Copyright 2021-2024 Sebastian Lederer. See the file LICENSE.md for details
|
||||||
|
.ORG 4096
|
||||||
|
|
||||||
|
CORELOADER:
|
||||||
|
; initialize program stack and
|
||||||
|
; return stack pointers
|
||||||
|
LOADCP 24060
|
||||||
|
STOREREG FP
|
||||||
|
LOADCP 24064
|
||||||
|
STOREREG RP
|
||||||
|
|
||||||
|
LOADCP SYSBOOTTICKS
|
||||||
|
LOADCP GETTICKS
|
||||||
|
CALL
|
||||||
|
STOREI
|
||||||
|
DROP
|
||||||
|
|
||||||
|
LOADCP INITSDCARD
|
||||||
|
CALL
|
||||||
|
|
||||||
|
;LOADCP FIND_SYSPART ; no need to call, it never
|
||||||
|
;CALL ; returns, so just fall through
|
||||||
|
|
||||||
|
.EQU PART_START 0
|
||||||
|
.EQU EXTENT_SIZE 4
|
||||||
|
.EQU DIR_SIZE 8
|
||||||
|
.EQU SLOT_NO 12
|
||||||
|
.EQU SIZE_BYTES 16
|
||||||
|
.EQU PRG_START_BLK 20
|
||||||
|
.EQU FIND_FS 24
|
||||||
|
|
||||||
|
.EQU PARTENTRY_SIZE 64
|
||||||
|
.EQU DIRENTRY_SIZE 64
|
||||||
|
FIND_SYSPART:
|
||||||
|
FPADJ -FIND_FS
|
||||||
|
; load block 0
|
||||||
|
LOADC 0
|
||||||
|
LOADCP CARDREADBLK
|
||||||
|
CALL
|
||||||
|
|
||||||
|
DUP ; non-zero return code means error
|
||||||
|
CBRANCH.Z FIND_1
|
||||||
|
|
||||||
|
LOADCP PRINTHEXW
|
||||||
|
CALL
|
||||||
|
LOADCP NEWLINE
|
||||||
|
CALL
|
||||||
|
LOADC 0
|
||||||
|
JUMP
|
||||||
|
|
||||||
|
FIND_1:
|
||||||
|
DROP ; remove return code
|
||||||
|
|
||||||
|
;LOADC 512
|
||||||
|
;LOADCP CARD_BUF
|
||||||
|
;LOADCP HEXDUMP
|
||||||
|
;CALL
|
||||||
|
|
||||||
|
; address of the first partition entry
|
||||||
|
LOADCP CARD_BUF
|
||||||
|
FIND_L:
|
||||||
|
DUP ; dup addr for comparison
|
||||||
|
LOADCP SYSPART_NAME
|
||||||
|
LOADC SYSNAME_WORDS
|
||||||
|
LOADCP _CMPWORDS
|
||||||
|
CALL
|
||||||
|
CBRANCH.NZ FIND_FOUND
|
||||||
|
; go to next entry
|
||||||
|
LOADC PARTENTRY_SIZE
|
||||||
|
ADD
|
||||||
|
|
||||||
|
; check if address is still
|
||||||
|
; within the data block
|
||||||
|
DUP
|
||||||
|
LOADCP CARD_BUF,512
|
||||||
|
CMP LT
|
||||||
|
CBRANCH FIND_L
|
||||||
|
|
||||||
|
; remove address
|
||||||
|
DROP
|
||||||
|
|
||||||
|
; not found, complain and
|
||||||
|
; go back to ROM monitor
|
||||||
|
LOADCP SYSPART_ERR
|
||||||
|
LOADCP PRINTLINE
|
||||||
|
CALL
|
||||||
|
|
||||||
|
LOADC 0
|
||||||
|
JUMP
|
||||||
|
|
||||||
|
FIND_FOUND:
|
||||||
|
; address of the part entry is on stack
|
||||||
|
|
||||||
|
; check if partition is enabled
|
||||||
|
DUP ; duplicate address
|
||||||
|
LOADC 40 ; add PartFlags field offset
|
||||||
|
ADD
|
||||||
|
LOADI
|
||||||
|
LOADC 1
|
||||||
|
AND ; check bit 0 (PartEnabled)
|
||||||
|
CBRANCH.Z FIND_L ; if not set, continue loop
|
||||||
|
|
||||||
|
|
||||||
|
; address of part entry is still on stack
|
||||||
|
DUP
|
||||||
|
LOADC 44 ; add startBlock field offset
|
||||||
|
ADD
|
||||||
|
LOADI ; get start block number
|
||||||
|
STORE PART_START
|
||||||
|
|
||||||
|
; address of part entry is still on stack
|
||||||
|
DUP
|
||||||
|
LOADC 52 ; move to extentSize field
|
||||||
|
ADD
|
||||||
|
LOADI ; get value
|
||||||
|
STORE EXTENT_SIZE
|
||||||
|
|
||||||
|
; address of part entry is still on stack
|
||||||
|
LOADC 56 ; move to dirSize field
|
||||||
|
ADD
|
||||||
|
LOADI ; get value
|
||||||
|
STORE DIR_SIZE
|
||||||
|
|
||||||
|
LOADC 0
|
||||||
|
STORE SLOT_NO ; start with dirslot 0
|
||||||
|
|
||||||
|
LOAD PART_START ; start with first block of the partition
|
||||||
|
FIND_FILE:
|
||||||
|
DUP ; duplicate block number
|
||||||
|
LOADCP CARDREADBLK ; read that block
|
||||||
|
CALL
|
||||||
|
DROP ; ignore error
|
||||||
|
|
||||||
|
; scan directory entries for shell file name
|
||||||
|
LOADCP CARD_BUF
|
||||||
|
FIND_FILE_L:
|
||||||
|
DUP
|
||||||
|
LOADCP SHELL_NAME
|
||||||
|
LOADC SHELLNAME_WORDS
|
||||||
|
LOADCP _CMPWORDS ; compare names
|
||||||
|
CALL
|
||||||
|
CBRANCH.NZ FIND_F_FOUND ; exit loop if names match
|
||||||
|
|
||||||
|
; check if current dirslot no
|
||||||
|
; is below maximum number of slots
|
||||||
|
LOAD SLOT_NO
|
||||||
|
LOAD DIR_SIZE
|
||||||
|
CMP GE
|
||||||
|
CBRANCH FIND_F_NOTFOUND ; max slots reached, exit
|
||||||
|
|
||||||
|
; add 1 to SLOT_NO
|
||||||
|
LOAD SLOT_NO
|
||||||
|
INC 1
|
||||||
|
STORE SLOT_NO
|
||||||
|
|
||||||
|
; address is still on stack
|
||||||
|
LOADC DIRENTRY_SIZE
|
||||||
|
ADD ; go to next dir entry
|
||||||
|
|
||||||
|
; check if address is still
|
||||||
|
; below end of data block
|
||||||
|
DUP
|
||||||
|
LOADCP CARD_BUF,512
|
||||||
|
CMP LT
|
||||||
|
CBRANCH FIND_FILE_L ; if it is below, loop
|
||||||
|
|
||||||
|
DROP ; remove dir entry addr
|
||||||
|
|
||||||
|
; block no is still on stack
|
||||||
|
INC 1
|
||||||
|
BRANCH FIND_FILE ; read next block
|
||||||
|
|
||||||
|
FIND_F_NOTFOUND:
|
||||||
|
LOADCP SHELL_ERR
|
||||||
|
LOADCP PRINTLINE
|
||||||
|
CALL
|
||||||
|
|
||||||
|
; remove entry addr and block number
|
||||||
|
DROP
|
||||||
|
DROP
|
||||||
|
LOADC 0
|
||||||
|
JUMP
|
||||||
|
|
||||||
|
FIND_F_FOUND:
|
||||||
|
; found the file name, now check if it has the right flags
|
||||||
|
|
||||||
|
; address of dir entry is still on stack
|
||||||
|
DUP
|
||||||
|
LOADC 40 ; add flags field offset
|
||||||
|
ADD
|
||||||
|
LOADI ; load flags
|
||||||
|
LOADC 16 ; test for SlotFirst flag
|
||||||
|
AND
|
||||||
|
CBRANCH.Z FIND_FILE_L ; if not set, continue loop
|
||||||
|
|
||||||
|
;LOADCP FOUND_MSG
|
||||||
|
;LOADCP PRINTLINE
|
||||||
|
;CALL
|
||||||
|
|
||||||
|
; we got the right file, now calculate start block
|
||||||
|
; and get file size from dir entry
|
||||||
|
|
||||||
|
; address of dir entry is still on stack
|
||||||
|
; phys start block = part start + slot_no * (extent_size/512)
|
||||||
|
LOAD EXTENT_SIZE
|
||||||
|
LOADC 9
|
||||||
|
LOADCP _SHRM
|
||||||
|
CALL
|
||||||
|
LOAD SLOT_NO
|
||||||
|
LOADCP _MUL
|
||||||
|
CALL
|
||||||
|
LOAD PART_START
|
||||||
|
ADD
|
||||||
|
|
||||||
|
;DUP
|
||||||
|
;LOADCP PRINTHEXW
|
||||||
|
;CALL
|
||||||
|
;LOADC ' '
|
||||||
|
;LOADCP CONOUT
|
||||||
|
;CALL
|
||||||
|
|
||||||
|
STORE PRG_START_BLK
|
||||||
|
|
||||||
|
; address of dir entry is still on stack
|
||||||
|
LOADC 44
|
||||||
|
ADD ; add sizeBytes field offset
|
||||||
|
LOADI ; get size in bytes
|
||||||
|
|
||||||
|
;DUP
|
||||||
|
;LOADCP PRINTHEXW
|
||||||
|
;CALL
|
||||||
|
;LOADCP NEWLINE
|
||||||
|
;CALL
|
||||||
|
|
||||||
|
STORE SIZE_BYTES
|
||||||
|
|
||||||
|
; remove block number
|
||||||
|
DROP
|
||||||
|
|
||||||
|
; set argument count to 0
|
||||||
|
; in case this gets called
|
||||||
|
; by a terminating program
|
||||||
|
LOADCP PARGCOUNT
|
||||||
|
LOADC 0
|
||||||
|
STOREI
|
||||||
|
DROP
|
||||||
|
|
||||||
|
LOADC 0 ; device id is always 0
|
||||||
|
LOAD PRG_START_BLK
|
||||||
|
LOAD SIZE_BYTES
|
||||||
|
; release our stack frame
|
||||||
|
FPADJ FIND_FS
|
||||||
|
|
||||||
|
; load program
|
||||||
|
LOADCP CORELOAD
|
||||||
|
CALL
|
||||||
|
|
||||||
|
LOADC 0
|
||||||
|
JUMP
|
||||||
|
|
||||||
|
.CPOOL
|
||||||
|
|
||||||
|
.EQU SYSNAME_WORDS 4
|
||||||
|
SYSPART_NAME:
|
||||||
|
.WORD 6, 32
|
||||||
|
.BYTE "SYSTEM"
|
||||||
|
SYSPART_ERR:
|
||||||
|
.BYTE "No ""SYSTEM"" partition.",13,10,10,0
|
||||||
|
.EQU SHELLNAME_WORDS 5
|
||||||
|
SHELL_NAME:
|
||||||
|
.WORD 10,32
|
||||||
|
.BYTE "shell.prog"
|
||||||
|
SHELL_ERR:
|
||||||
|
.BYTE "No shell on ""SYSTEM"" partition.",13,10,10,0
|
||||||
|
|
||||||
|
FOUND_MSG:
|
||||||
|
.BYTE " shell.prog ",0
|
||||||
|
|
||||||
|
%include corelib.s
|
||||||
1053
lib/float32.s
Normal file
1053
lib/float32.s
Normal file
File diff suppressed because it is too large
Load diff
805
lib/rommon.s
Normal file
805
lib/rommon.s
Normal file
|
|
@ -0,0 +1,805 @@
|
||||||
|
.EQU CR 13
|
||||||
|
.EQU LF 10
|
||||||
|
.EQU EOT 4
|
||||||
|
.EQU ACK 6
|
||||||
|
.EQU NAK 21
|
||||||
|
.EQU STX 2
|
||||||
|
.EQU UART_REG 2048
|
||||||
|
.EQU MON_ADDR 64512
|
||||||
|
|
||||||
|
BRANCH 2 ; the very first instruction is not
|
||||||
|
; executed correctly
|
||||||
|
LOADCP 65020 ; initialise FP and RP registers
|
||||||
|
STOREREG FP
|
||||||
|
LOADCP 65024
|
||||||
|
STOREREG RP
|
||||||
|
|
||||||
|
LOADCP MON_ADDR
|
||||||
|
LOADCP 4096
|
||||||
|
STOREI
|
||||||
|
DROP
|
||||||
|
CMDLOOP0:
|
||||||
|
LOADC MESSAGE
|
||||||
|
LOADC PRINTLINE
|
||||||
|
CALL
|
||||||
|
|
||||||
|
CMDLOOP:
|
||||||
|
LOADC NEWLINE
|
||||||
|
CALL
|
||||||
|
LOADC PROMPT
|
||||||
|
CALL
|
||||||
|
CMDLOOP1:
|
||||||
|
LOADC CONIN
|
||||||
|
CALL
|
||||||
|
LOADC TOUPPER
|
||||||
|
CALL
|
||||||
|
|
||||||
|
DUP
|
||||||
|
LOADC CONOUT
|
||||||
|
CALL
|
||||||
|
|
||||||
|
LOADC 'A'
|
||||||
|
CMP.S0 EQ
|
||||||
|
CBRANCH.Z CMD1
|
||||||
|
LOADC CMD_A
|
||||||
|
CALL
|
||||||
|
BRANCH CMDLOOP2
|
||||||
|
CMD1:
|
||||||
|
LOADC 'X'
|
||||||
|
CMP.S0 EQ
|
||||||
|
CBRANCH.Z CMD2
|
||||||
|
LOADC CMD_X
|
||||||
|
CALL
|
||||||
|
BRANCH CMDLOOP2
|
||||||
|
CMD2:
|
||||||
|
LOADC 'D'
|
||||||
|
CMP.S0 EQ
|
||||||
|
CBRANCH.Z CMD3
|
||||||
|
LOADC CMD_D
|
||||||
|
CALL
|
||||||
|
BRANCH CMDLOOP2
|
||||||
|
CMD3:
|
||||||
|
LOADC 'G'
|
||||||
|
CMP.S0 EQ
|
||||||
|
CBRANCH.Z CMD4
|
||||||
|
LOADC CMD_G
|
||||||
|
CALL
|
||||||
|
BRANCH CMDLOOP2
|
||||||
|
CMD4:
|
||||||
|
LOADC 'L'
|
||||||
|
CMP.S0 EQ
|
||||||
|
CBRANCH.Z CMD5
|
||||||
|
LOADC CMD_L
|
||||||
|
CALL
|
||||||
|
BRANCH CMDLOOP2
|
||||||
|
CMD5:
|
||||||
|
LOADC 'B'
|
||||||
|
CMP.S0 EQ
|
||||||
|
CBRANCH.Z CMD6
|
||||||
|
LOADC CMD_B
|
||||||
|
CALL
|
||||||
|
BRANCH CMDLOOP2
|
||||||
|
CMD6:
|
||||||
|
DROP
|
||||||
|
BRANCH CMDLOOP0
|
||||||
|
CMDLOOP2:
|
||||||
|
DROP
|
||||||
|
BRANCH CMDLOOP
|
||||||
|
|
||||||
|
; ---- Command 'A': set current address
|
||||||
|
CMD_A:
|
||||||
|
LOADC 32
|
||||||
|
LOADC CONOUT
|
||||||
|
CALL
|
||||||
|
LOADC READHEX
|
||||||
|
CALL
|
||||||
|
CBRANCH.Z CMD_A_INVALID ; 0 if not valid input
|
||||||
|
LOADCP MON_ADDR
|
||||||
|
SWAP
|
||||||
|
STOREI
|
||||||
|
DROP ; drop STOREI address
|
||||||
|
RET
|
||||||
|
CMD_A_INVALID:
|
||||||
|
DROP
|
||||||
|
LOADC '.'
|
||||||
|
LOADC CONOUT
|
||||||
|
CALL
|
||||||
|
RET
|
||||||
|
|
||||||
|
; ---- Command 'X': examine current address
|
||||||
|
CMD_X:
|
||||||
|
FPADJ -8 ; reserve space for 4 bytes of local variables
|
||||||
|
LOADCP MON_ADDR
|
||||||
|
LOADI
|
||||||
|
STORE 0 ; current memory address
|
||||||
|
LOADC 4 ; print 8 words
|
||||||
|
STORE 4 ; Loop counter
|
||||||
|
CMD_X_LOOP:
|
||||||
|
LOADC 32 ; print a a space
|
||||||
|
LOADC CONOUT
|
||||||
|
CALL
|
||||||
|
LOAD 0 ; load word via current address
|
||||||
|
LOADI
|
||||||
|
LOADC PRINTHEXW ; print it
|
||||||
|
CALL
|
||||||
|
LOAD 0
|
||||||
|
INC 4 ; increment current address
|
||||||
|
STORE 0
|
||||||
|
LOAD 4
|
||||||
|
DEC 1
|
||||||
|
DUP
|
||||||
|
STORE 4
|
||||||
|
CBRANCH.NZ CMD_X_LOOP
|
||||||
|
LOADCP MON_ADDR
|
||||||
|
LOAD 0
|
||||||
|
STOREI
|
||||||
|
DROP
|
||||||
|
FPADJ 8
|
||||||
|
RET
|
||||||
|
|
||||||
|
; ---- Command 'D': deposit words at current address
|
||||||
|
CMD_D:
|
||||||
|
FPADJ -4
|
||||||
|
LOADC 4 ; max number of words
|
||||||
|
STORE 0
|
||||||
|
CMD_D_LOOP:
|
||||||
|
LOADC 32 ; print a space
|
||||||
|
LOADC CONOUT
|
||||||
|
CALL
|
||||||
|
LOADC READHEX
|
||||||
|
CALL
|
||||||
|
DUP
|
||||||
|
CBRANCH.Z CMD_D_EXIT ; check for invalid input
|
||||||
|
SWAP ; swap return code and value
|
||||||
|
LOADCP MON_ADDR
|
||||||
|
LOADI ; get current address
|
||||||
|
SWAP ; swap address and value for STOREI
|
||||||
|
STOREI 4 ; store the value with post-increment of address
|
||||||
|
LOADCP MON_ADDR
|
||||||
|
SWAP ; swap destination address and value for STOREI
|
||||||
|
STOREI ; store the new address
|
||||||
|
DROP
|
||||||
|
LOADC 2 ; compare return code (swapped above) to 2
|
||||||
|
CMP EQ ; check for valid input and return key
|
||||||
|
CBRANCH CMD_D_EXIT
|
||||||
|
LOAD 0
|
||||||
|
DEC 1
|
||||||
|
DUP
|
||||||
|
STORE 0
|
||||||
|
CBRANCH.NZ CMD_D_LOOP
|
||||||
|
CMD_D_EXIT:
|
||||||
|
FPADJ 4
|
||||||
|
RET
|
||||||
|
|
||||||
|
CMD_G:
|
||||||
|
DROP ; remove input char
|
||||||
|
LOADCP NEWLINE
|
||||||
|
CALL
|
||||||
|
LOADCP MON_ADDR
|
||||||
|
LOADI
|
||||||
|
JUMP
|
||||||
|
|
||||||
|
CMD_L:
|
||||||
|
LOADCP NEWLINE
|
||||||
|
CALL
|
||||||
|
LOADCP RCVBLOCKS
|
||||||
|
CALL
|
||||||
|
LOADCP NEWLINE
|
||||||
|
CALL
|
||||||
|
RET
|
||||||
|
|
||||||
|
PROMPT:
|
||||||
|
LOADC '['
|
||||||
|
LOADC CONOUT
|
||||||
|
CALL
|
||||||
|
LOADCP MON_ADDR
|
||||||
|
LOADI
|
||||||
|
LOADC PRINTHEXW
|
||||||
|
CALL
|
||||||
|
LOADC PROMPT2
|
||||||
|
LOADC PRINTLINE
|
||||||
|
CALL
|
||||||
|
RET
|
||||||
|
|
||||||
|
NEWLINE:
|
||||||
|
LOADC CR
|
||||||
|
LOADC CONOUT
|
||||||
|
CALL
|
||||||
|
LOADC LF
|
||||||
|
LOADC CONOUT
|
||||||
|
CALL
|
||||||
|
RET
|
||||||
|
|
||||||
|
; print string of byte characters
|
||||||
|
; takes pointer to string on eval stack
|
||||||
|
PRINTLINE:
|
||||||
|
DUP ; duplicate address as arg to printchar
|
||||||
|
LOADC PRINTCHAR
|
||||||
|
CALL
|
||||||
|
CBRANCH.Z PRINTLINE_EXIT ; if char is zero, exit
|
||||||
|
INC 1 ; increment address
|
||||||
|
BRANCH PRINTLINE
|
||||||
|
PRINTLINE_EXIT:
|
||||||
|
DROP ; remove address from stack
|
||||||
|
RET
|
||||||
|
|
||||||
|
; print a single character
|
||||||
|
; takes a byte pointer on eval stack
|
||||||
|
; returns character on eval stack
|
||||||
|
PRINTCHAR:
|
||||||
|
LOADI.S1.X2Y ; load word, keep address on stack
|
||||||
|
BSEL ; select byte of a word via address
|
||||||
|
DUP ; check for null byte
|
||||||
|
CBRANCH.Z PRINTCHAR_XT
|
||||||
|
DUP
|
||||||
|
LOADC CONOUT
|
||||||
|
CALL
|
||||||
|
PRINTCHAR_XT:
|
||||||
|
RET
|
||||||
|
|
||||||
|
; print a 32-bit hexadecimal number
|
||||||
|
; takes the value on the stack
|
||||||
|
|
||||||
|
PRINTHEXW:
|
||||||
|
BROT
|
||||||
|
DUP
|
||||||
|
LOADC PRINTHEXB
|
||||||
|
CALL
|
||||||
|
BROT
|
||||||
|
DUP
|
||||||
|
LOADC PRINTHEXB
|
||||||
|
CALL
|
||||||
|
BROT
|
||||||
|
DUP
|
||||||
|
LOADC PRINTHEXB
|
||||||
|
CALL
|
||||||
|
BROT
|
||||||
|
LOADC PRINTHEXB
|
||||||
|
CALL
|
||||||
|
RET
|
||||||
|
|
||||||
|
PRINTHEXB:
|
||||||
|
DUP
|
||||||
|
SHR
|
||||||
|
SHR
|
||||||
|
SHR
|
||||||
|
SHR
|
||||||
|
LOADC PRINTNIBBLE
|
||||||
|
CALL
|
||||||
|
LOADC PRINTNIBBLE
|
||||||
|
CALL
|
||||||
|
RET
|
||||||
|
|
||||||
|
PRINTNIBBLE:
|
||||||
|
LOADC 15
|
||||||
|
AND ; isolate nibble
|
||||||
|
LOADC 10
|
||||||
|
CMPU.S0 GE ; nibble >= 10 ?
|
||||||
|
CBRANCH.NZ PRINTNIBBLE_1 ; then print a-f
|
||||||
|
LOADC '0' ; else print 0-9
|
||||||
|
BRANCH PRINTNIBBLE_2
|
||||||
|
PRINTNIBBLE_1:
|
||||||
|
LOADC 55 ; 55 + 10 == 'A'
|
||||||
|
PRINTNIBBLE_2:
|
||||||
|
ADD
|
||||||
|
LOADC CONOUT
|
||||||
|
CALL
|
||||||
|
RET
|
||||||
|
|
||||||
|
; ------ read a 8-digit hexadecimal number from the console
|
||||||
|
; stores variables on the user stack, so the FP register must be
|
||||||
|
; inizialized.
|
||||||
|
; returns two values on the eval stack:
|
||||||
|
; - return code (topmost)
|
||||||
|
; 0 - no valid number
|
||||||
|
; 1 - valid number
|
||||||
|
; 2 - valid number and enter was pressed
|
||||||
|
; - result value
|
||||||
|
|
||||||
|
READHEX:
|
||||||
|
FPADJ -8
|
||||||
|
LOADC 0 ; current value
|
||||||
|
STORE 0
|
||||||
|
LOADC 8 ; max number of digits
|
||||||
|
STORE 4 ; remaining digits counter
|
||||||
|
READHEX_1:
|
||||||
|
LOADC CONIN
|
||||||
|
CALL
|
||||||
|
LOADC CR ; RETURN pressed?
|
||||||
|
CMP.S0 EQ
|
||||||
|
CBRANCH READHEX_RT
|
||||||
|
DUP
|
||||||
|
LOADC CONOUT ; echo character
|
||||||
|
CALL
|
||||||
|
LOADC CONVHEXDIGIT
|
||||||
|
CALL
|
||||||
|
LOADC -1
|
||||||
|
CMP.S0 EQ ; invalid character?
|
||||||
|
CBRANCH.NZ READHEX_XT
|
||||||
|
LOAD 0
|
||||||
|
SHL 2 ; shift previous nibble
|
||||||
|
SHL 2
|
||||||
|
OR ; combine with last digit
|
||||||
|
STORE 0
|
||||||
|
LOAD 4
|
||||||
|
DEC 1
|
||||||
|
DUP
|
||||||
|
STORE 4
|
||||||
|
CBRANCH.NZ READHEX_1
|
||||||
|
BRANCH READHEX_XT1
|
||||||
|
READHEX_RT: ; if no digits were entered, set return code
|
||||||
|
DROP ; drop read character
|
||||||
|
LOAD 4 ;remaining digits counter
|
||||||
|
LOADC 8
|
||||||
|
CMP NE
|
||||||
|
CBRANCH READHEX_RT2
|
||||||
|
LOADC 0 ; no valid input
|
||||||
|
BRANCH READHEX_XT3
|
||||||
|
READHEX_RT2:
|
||||||
|
LOADC 2 ; valid input and return pressed
|
||||||
|
BRANCH READHEX_XT3
|
||||||
|
READHEX_XT:
|
||||||
|
DROP
|
||||||
|
LOAD 4
|
||||||
|
LOADC 8
|
||||||
|
CMP EQ ; if no digits were entered
|
||||||
|
CBRANCH READHEX_XT0
|
||||||
|
READHEX_XT1:
|
||||||
|
LOADC 1 ; valid input flag
|
||||||
|
BRANCH READHEX_XT3
|
||||||
|
READHEX_XT0:
|
||||||
|
LOADC 0
|
||||||
|
READHEX_XT3:
|
||||||
|
LOAD 0
|
||||||
|
SWAP
|
||||||
|
FPADJ 8
|
||||||
|
RET
|
||||||
|
|
||||||
|
; ------ convert character on the eval stack to upper case
|
||||||
|
TOUPPER:
|
||||||
|
LOADC 'a'
|
||||||
|
CMP.S0 LT
|
||||||
|
CBRANCH TOUPPER_XT
|
||||||
|
LOADC 'z'
|
||||||
|
CMP.S0 GT
|
||||||
|
CBRANCH TOUPPER_XT
|
||||||
|
LOADC 32
|
||||||
|
SUB
|
||||||
|
TOUPPER_XT:
|
||||||
|
RET
|
||||||
|
|
||||||
|
; ------ convert hexadecimal digit to integer
|
||||||
|
; ------ takes an ascii character as parameter on the eval stack
|
||||||
|
; ------ returns an integer value from 0-15 on the eval stack,
|
||||||
|
; ------ or -1 if the character was not a valid hexadecimal digit
|
||||||
|
|
||||||
|
CONVHEXDIGIT:
|
||||||
|
LOADC TOUPPER
|
||||||
|
CALL
|
||||||
|
LOADC '0'
|
||||||
|
CMP.S0 LT ; character < '0'?
|
||||||
|
CBRANCH.NZ CONVHEXDIGIT_ERR
|
||||||
|
LOADC '9'
|
||||||
|
CMP.S0 GT ; character > '9'?
|
||||||
|
CBRANCH.NZ CONVHEXDIGIT_ISALPHA
|
||||||
|
LOADC '0' ; character is between '0' and '9', subtract '0'
|
||||||
|
SUB
|
||||||
|
BRANCH CONVHEXDIGIT_NBL
|
||||||
|
CONVHEXDIGIT_ISALPHA:
|
||||||
|
LOADC 'A'
|
||||||
|
CMP.S0 LT ; character < 'A'?
|
||||||
|
CBRANCH.NZ CONVHEXDIGIT_ERR
|
||||||
|
LOADC 'F'
|
||||||
|
CMP.S0 GT ; character > 'F'?
|
||||||
|
CBRANCH.NZ CONVHEXDIGIT_ERR
|
||||||
|
LOADC 55 ; character is between 'A' and 'F', subtract ('A' - 10)
|
||||||
|
SUB
|
||||||
|
CONVHEXDIGIT_NBL:
|
||||||
|
RET
|
||||||
|
CONVHEXDIGIT_ERR:
|
||||||
|
DROP ; remove character from stack
|
||||||
|
LOADC -1 ; error
|
||||||
|
RET
|
||||||
|
|
||||||
|
; --------- output a character on serial console
|
||||||
|
; --------- takes a character (padded to a word) on the eval stack
|
||||||
|
CONOUT:
|
||||||
|
LOADC UART_REG ; address of UART register
|
||||||
|
LOADI ; load status
|
||||||
|
LOADC 256 ; check bit 8 (tx_busy)
|
||||||
|
AND
|
||||||
|
CBRANCH.NZ CONOUT ; loop if bit 8 is not zero
|
||||||
|
|
||||||
|
; transmitter is idle now, write character
|
||||||
|
LOADC UART_REG ; address of UART register
|
||||||
|
SWAP ; swap character and address for STOREI
|
||||||
|
LOADC 1024 ; TX enable bit
|
||||||
|
OR ; OR in the character
|
||||||
|
STOREI
|
||||||
|
DROP
|
||||||
|
RET
|
||||||
|
|
||||||
|
; ---- wait until a character is received and return it on eval stack
|
||||||
|
CONIN:
|
||||||
|
LOADC WAITFORBYTE
|
||||||
|
CALL
|
||||||
|
LOADC -1 ; -1 means timeout
|
||||||
|
CMP.S0 NE
|
||||||
|
CBRANCH CONIN_XT ; exit if no timeout
|
||||||
|
DROP ; remove last result
|
||||||
|
BRANCH CONIN
|
||||||
|
CONIN_XT:
|
||||||
|
RET
|
||||||
|
|
||||||
|
|
||||||
|
.EQU L_BLOCKSIZE 32
|
||||||
|
.EQU L_WORDSIZE 4
|
||||||
|
.EQU CKSUM_PATTERN $AFFECAFE
|
||||||
|
RCVBLOCKS:
|
||||||
|
LOADCP MON_ADDR ; pointer to current write position,
|
||||||
|
LOADI ; kept on stack
|
||||||
|
RCVBLOCKS_L:
|
||||||
|
LOADC WAITFORBYTE ; read header byte
|
||||||
|
CALL
|
||||||
|
LOADC -1
|
||||||
|
CMP.S0 EQ
|
||||||
|
CBRANCH RCVBLOCKS_XT ; exit on timeout
|
||||||
|
|
||||||
|
; check for EOT -> end
|
||||||
|
LOADC EOT
|
||||||
|
CMP.S0 EQ
|
||||||
|
CBRANCH RCVBLOCKS_XT
|
||||||
|
|
||||||
|
; check for STX -> read block
|
||||||
|
LOADC STX
|
||||||
|
CMP.S0 EQ
|
||||||
|
CBRANCH RCVBLOCKS_CONT
|
||||||
|
|
||||||
|
; anything else -> send NAK
|
||||||
|
BRANCH RCVBLOCKS_RETRY
|
||||||
|
|
||||||
|
RCVBLOCKS_CONT:
|
||||||
|
DROP ; remove header byte
|
||||||
|
DUP ; duplicate pointer
|
||||||
|
LOADC READBLOCK
|
||||||
|
CALL
|
||||||
|
LOADC -1
|
||||||
|
CMP.S0 EQ ; check for timeout
|
||||||
|
CBRANCH RCVBLOCKS_XT ; exit on timeout
|
||||||
|
|
||||||
|
LOADC -2
|
||||||
|
CMP.S0 EQ ; check for checksum error
|
||||||
|
CBRANCH RCVBLOCKS_RETRY
|
||||||
|
|
||||||
|
DROP ; remove return code
|
||||||
|
LOADC L_BLOCKSIZE ; advance pointer
|
||||||
|
ADD
|
||||||
|
|
||||||
|
LOADC ACK ; send ACK
|
||||||
|
LOADC CONOUT
|
||||||
|
CALL
|
||||||
|
|
||||||
|
; next block
|
||||||
|
BRANCH RCVBLOCKS_L
|
||||||
|
|
||||||
|
RCVBLOCKS_RETRY:
|
||||||
|
DROP ; remove read byte
|
||||||
|
; send NAK
|
||||||
|
LOADC NAK
|
||||||
|
LOADC CONOUT
|
||||||
|
CALL
|
||||||
|
|
||||||
|
; next block
|
||||||
|
BRANCH RCVBLOCKS_L
|
||||||
|
|
||||||
|
RCVBLOCKS_XT:
|
||||||
|
DROP ; remove pointer
|
||||||
|
DROP ; remove read byte
|
||||||
|
RET
|
||||||
|
|
||||||
|
|
||||||
|
; ---- read a sequence of binary words and store into memory
|
||||||
|
; - arguments: pointer to memory area
|
||||||
|
READBLOCK:
|
||||||
|
FPADJ -12
|
||||||
|
STORE 0 ; buffer pointer
|
||||||
|
LOADCP L_BLOCKSIZE
|
||||||
|
STORE 4 ; remaining bytes
|
||||||
|
LOADC 0
|
||||||
|
STORE 8 ; checksum
|
||||||
|
READBLOCK_L:
|
||||||
|
LOADCP READWORD ; read a word
|
||||||
|
CALL
|
||||||
|
LOADC -1 ; check for timeout
|
||||||
|
CMP EQ
|
||||||
|
CBRANCH.NZ READBLOCK_ERR
|
||||||
|
|
||||||
|
; DUP ; debug
|
||||||
|
; LOADC PRINTHEXW
|
||||||
|
; CALL
|
||||||
|
|
||||||
|
|
||||||
|
DUP ; duplicate read word
|
||||||
|
LOAD 8 ; load checksum
|
||||||
|
ADD ; checksum = ((checksum + data) ^ pattern) << 1
|
||||||
|
LOADCP CKSUM_PATTERN
|
||||||
|
XOR
|
||||||
|
SHL
|
||||||
|
STORE 8 ; store new checkcsum
|
||||||
|
|
||||||
|
LOAD 0 ; load buffer pointer
|
||||||
|
SWAP ; swap value and pointer for STOREI
|
||||||
|
STOREI 4 ; store word and increment pointer
|
||||||
|
STORE 0 ; store pointer
|
||||||
|
|
||||||
|
LOAD 4 ; load remaining bytes
|
||||||
|
DEC L_WORDSIZE ; decrement by word size
|
||||||
|
DUP
|
||||||
|
STORE 4 ; store
|
||||||
|
CBRANCH.NZ READBLOCK_L ; loop if remaining words not zero
|
||||||
|
|
||||||
|
|
||||||
|
LOADCP READWORD ; read checksum
|
||||||
|
CALL
|
||||||
|
LOADC -1 ; check for timeout
|
||||||
|
CMP EQ
|
||||||
|
CBRANCH READBLOCK_ERR
|
||||||
|
|
||||||
|
LOAD 8 ; load checksum
|
||||||
|
CMP EQ
|
||||||
|
CBRANCH READBLOCK_OK
|
||||||
|
LOADC -2 ; return code for checksum error
|
||||||
|
BRANCH READBLOCK_XT
|
||||||
|
READBLOCK_OK:
|
||||||
|
LOADC 0 ; return 0
|
||||||
|
READBLOCK_XT:
|
||||||
|
FPADJ 12
|
||||||
|
RET
|
||||||
|
|
||||||
|
READBLOCK_ERR:
|
||||||
|
DROP ; remove result
|
||||||
|
LOAD 4 ; return number of missing bytes
|
||||||
|
FPADJ 8
|
||||||
|
RET
|
||||||
|
|
||||||
|
; --- read four bytes (msb to lsb) and return as word
|
||||||
|
; returns: word, error code (-1 for error, 0 otherwise)
|
||||||
|
|
||||||
|
READWORD:
|
||||||
|
LOADCP WAITFORBYTE
|
||||||
|
CALL
|
||||||
|
DUP
|
||||||
|
LOADC -1 ; check for error
|
||||||
|
CMP EQ
|
||||||
|
CBRANCH.NZ READWORD_ERR
|
||||||
|
; first byte is now on stack
|
||||||
|
BROT ; rotate byte left
|
||||||
|
|
||||||
|
LOADCP WAITFORBYTE
|
||||||
|
CALL
|
||||||
|
DUP
|
||||||
|
LOADC -1 ; check for error
|
||||||
|
CMP EQ
|
||||||
|
CBRANCH.NZ READWORD_ERR
|
||||||
|
; second byte is now on stack
|
||||||
|
OR ; OR last byte with this byte
|
||||||
|
BROT ; rotate bytes left
|
||||||
|
|
||||||
|
LOADCP WAITFORBYTE
|
||||||
|
CALL
|
||||||
|
DUP
|
||||||
|
LOADC -1 ; check for error
|
||||||
|
CMP EQ
|
||||||
|
CBRANCH.NZ READWORD_ERR
|
||||||
|
; third byte is now on stack
|
||||||
|
OR ; OR last byte with this byte
|
||||||
|
BROT
|
||||||
|
|
||||||
|
LOADCP WAITFORBYTE
|
||||||
|
CALL
|
||||||
|
DUP
|
||||||
|
LOADC -1 ; check for error
|
||||||
|
CMP EQ
|
||||||
|
CBRANCH.NZ READWORD_ERR
|
||||||
|
; fourth byte is now on stack
|
||||||
|
OR ; OR last byte with this byte
|
||||||
|
|
||||||
|
LOADC 0 ; error code (0: no error)
|
||||||
|
RET
|
||||||
|
|
||||||
|
READWORD_ERR:
|
||||||
|
LOADC -1 ; error code
|
||||||
|
RET
|
||||||
|
|
||||||
|
;---- wait a fixed amount of cycles for a character to be
|
||||||
|
; received on the UART.
|
||||||
|
; returns character or -1 on timeout
|
||||||
|
|
||||||
|
.EQU MAX_WAIT 20000000
|
||||||
|
WAITFORBYTE:
|
||||||
|
LOADCP MAX_WAIT ; maximum wait loops
|
||||||
|
WAITFORBYTE_L:
|
||||||
|
LOADC UART_REG ; address of UART register
|
||||||
|
LOADI ; load status
|
||||||
|
LOADC 512 ; check bit 9 (rx_avail)
|
||||||
|
AND
|
||||||
|
CBRANCH WAITFORBYTE_RX ; if bit 9 is one, a character is available
|
||||||
|
DEC 1
|
||||||
|
DUP
|
||||||
|
CBRANCH.NZ WAITFORBYTE_L
|
||||||
|
DROP ; remove wait counter from stack
|
||||||
|
LOADC -1 ; error code
|
||||||
|
RET
|
||||||
|
WAITFORBYTE_RX:
|
||||||
|
DROP ; remove wait counter from stack
|
||||||
|
LOADC UART_REG
|
||||||
|
LOADI ; read register again
|
||||||
|
LOADC 255 ; mask status bits
|
||||||
|
AND
|
||||||
|
LOADC UART_REG ; I/O address
|
||||||
|
LOADC 512 ; set bit 9 (rx_clear)
|
||||||
|
STOREI ; write register
|
||||||
|
DROP ; remove address left by STOREI
|
||||||
|
RET
|
||||||
|
|
||||||
|
.CPOOL
|
||||||
|
|
||||||
|
;---- boot from SD-card
|
||||||
|
|
||||||
|
; declare buffer addresses used by sdcardlib.s
|
||||||
|
.EQU CSD_BUF 63984
|
||||||
|
.EQU CARD_BUF 64000
|
||||||
|
CMD_B:
|
||||||
|
DROP ; remove input char
|
||||||
|
LOADCP NEWLINE
|
||||||
|
CALL
|
||||||
|
|
||||||
|
FPADJ -4
|
||||||
|
; initialize card
|
||||||
|
LOADC INITSDCARD
|
||||||
|
CALL
|
||||||
|
|
||||||
|
; read partition block
|
||||||
|
LOADC 0
|
||||||
|
LOADC CARDREADBLK
|
||||||
|
CALL
|
||||||
|
|
||||||
|
DUP ; non-zero return code means error
|
||||||
|
CBRANCH.Z CMD_B_1
|
||||||
|
CMD_B_ERR:
|
||||||
|
LOADC PRINTHEXW ; print error code
|
||||||
|
CALL
|
||||||
|
LOADC NEWLINE
|
||||||
|
CALL
|
||||||
|
LOADC 0 ; if we return, we need to
|
||||||
|
; put a fake input char back on the
|
||||||
|
; stack because the main loop will
|
||||||
|
; try to remove it
|
||||||
|
FPADJ 4
|
||||||
|
RET
|
||||||
|
|
||||||
|
CMD_B_1:
|
||||||
|
DROP ; remove error code
|
||||||
|
; check boot partition slot (boot flag)
|
||||||
|
LOADCP CARD_BUF,104 ; offset partition flags second part slot
|
||||||
|
LOADI
|
||||||
|
LOADC 2 ; PartFlags [PartBoot]
|
||||||
|
CMP EQ
|
||||||
|
CBRANCH CMD_B_C
|
||||||
|
|
||||||
|
; no boot partition
|
||||||
|
LOADC $B0
|
||||||
|
BRANCH CMD_B_ERR
|
||||||
|
|
||||||
|
CMD_B_C:
|
||||||
|
; get start block
|
||||||
|
LOADCP CARD_BUF,108 ; offset startBlock
|
||||||
|
LOADI
|
||||||
|
; get block count
|
||||||
|
LOADCP CARD_BUF,124 ; offset bootBlocks
|
||||||
|
LOADI
|
||||||
|
|
||||||
|
FPADJ -4 ; allocate space for address var
|
||||||
|
LOADCP MON_ADDR
|
||||||
|
LOADI
|
||||||
|
STORE 0 ; initialize dest addr
|
||||||
|
CMD_B_L:
|
||||||
|
; read block
|
||||||
|
OVER ; duplicate block no
|
||||||
|
LOADC CARDREADBLK
|
||||||
|
CALL
|
||||||
|
|
||||||
|
DUP ; check for error
|
||||||
|
CBRANCH.Z CMD_B_C2 ; continue if zero (no error)
|
||||||
|
|
||||||
|
NIP ; remove start and count, keep error code
|
||||||
|
NIP
|
||||||
|
BRANCH CMD_B_ERR
|
||||||
|
CMD_B_C2: DROP ; remove error code
|
||||||
|
CMD_B_2:
|
||||||
|
; copy to destination
|
||||||
|
LOAD 0 ; dest addr
|
||||||
|
LOADC COPY_BLK
|
||||||
|
CALL
|
||||||
|
|
||||||
|
; decrement count and loop
|
||||||
|
LOAD 0 ; increment dest addr
|
||||||
|
LOADC 512
|
||||||
|
ADD
|
||||||
|
STORE 0
|
||||||
|
|
||||||
|
SWAP ; swap block no/count, blockno is now ToS
|
||||||
|
INC 1
|
||||||
|
SWAP ; count is now ToS
|
||||||
|
DEC 1
|
||||||
|
DUP
|
||||||
|
CBRANCH.NZ CMD_B_L ; if not zero, loop
|
||||||
|
|
||||||
|
; jump to coreloader
|
||||||
|
DROP
|
||||||
|
DROP
|
||||||
|
FPADJ 4
|
||||||
|
LOADCP MON_ADDR
|
||||||
|
LOADI
|
||||||
|
JUMP
|
||||||
|
|
||||||
|
CMD_B_XT:
|
||||||
|
FPADJ 4
|
||||||
|
RET
|
||||||
|
|
||||||
|
; copy a sdcard block to destination address
|
||||||
|
; block size is always 512 byte, source
|
||||||
|
; is always CARD_BUF
|
||||||
|
; parameters: dest addr
|
||||||
|
COPY_BLK:
|
||||||
|
FPADJ -4
|
||||||
|
LOADC 128 ; word count
|
||||||
|
STORE 0
|
||||||
|
|
||||||
|
LOADCP CARD_BUF ; src addr
|
||||||
|
COPY_BLK1:
|
||||||
|
SWAP
|
||||||
|
; [ src addr, dest addr ]
|
||||||
|
OVER ; [ saddr, daddr, saddr ]
|
||||||
|
LOADI ; [ saddr, daddr, sword ]
|
||||||
|
STOREI 4 ; [ saddr, daddr + 4 ]
|
||||||
|
SWAP ; [ daddr + 4, saddr ]
|
||||||
|
INC 4 ; [ daddr + 4, saddr + 4]
|
||||||
|
|
||||||
|
LOAD 0 ; load and decrement counter
|
||||||
|
DEC 1
|
||||||
|
DUP
|
||||||
|
STORE 0 ; store it again
|
||||||
|
CBRANCH.NZ COPY_BLK1 ; if not zero, loop
|
||||||
|
|
||||||
|
DROP ; remove saddr and daddr
|
||||||
|
DROP
|
||||||
|
|
||||||
|
FPADJ 4
|
||||||
|
RET
|
||||||
|
|
||||||
|
.CPOOL
|
||||||
|
|
||||||
|
; wait approx. 1 millisecond
|
||||||
|
;
|
||||||
|
; 83.333 MHz Clock, three instructions a 4 cycles
|
||||||
|
; 83333 / 12 = 6944.4166
|
||||||
|
; works only if executed without wait states (i.e.
|
||||||
|
; from BRAM/SRAM)
|
||||||
|
WAIT1MSEC:
|
||||||
|
LOADCP 6944
|
||||||
|
WAIT1LOOP:
|
||||||
|
DEC 1
|
||||||
|
DUP
|
||||||
|
CBRANCH.NZ WAIT1LOOP
|
||||||
|
DROP
|
||||||
|
RET
|
||||||
|
|
||||||
|
%include "sdcardboot.s"
|
||||||
|
.CPOOL
|
||||||
|
MESSAGE:
|
||||||
|
.BYTE 13,10,"ROM Monitor v3.0.3", 13, 10,
|
||||||
|
"Set A)ddress D)eposit eX)amine L)oad G)o B)oot",13,10,0
|
||||||
|
PROMPT2:
|
||||||
|
.BYTE "]> ",0
|
||||||
|
END:
|
||||||
613
lib/sdcardboot.s
Normal file
613
lib/sdcardboot.s
Normal file
|
|
@ -0,0 +1,613 @@
|
||||||
|
.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:
|
||||||
|
LOADC WAIT1MSEC
|
||||||
|
CALL
|
||||||
|
DEC 1
|
||||||
|
DUP
|
||||||
|
CBRANCH.NZ _WAITL
|
||||||
|
DROP
|
||||||
|
RET
|
||||||
|
|
||||||
|
INITSDCARD:
|
||||||
|
LOADC WAIT1MSEC
|
||||||
|
CALL
|
||||||
|
|
||||||
|
LOADC _SPIINIT1
|
||||||
|
CALL
|
||||||
|
|
||||||
|
;LOADC 'I'
|
||||||
|
;LOADCP CONOUT
|
||||||
|
;CALL
|
||||||
|
|
||||||
|
LOADC _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
|
||||||
|
LOADC SENDCMD_R1
|
||||||
|
CALL
|
||||||
|
|
||||||
|
DROP ; TODO: handle errors
|
||||||
|
;LOADCP PRINTHEXW ; print status returned by the card
|
||||||
|
;CALL
|
||||||
|
;LOADCP NEWLINE
|
||||||
|
;CALL
|
||||||
|
|
||||||
|
;LOADC '9'
|
||||||
|
;LOADCP CONOUT
|
||||||
|
;CALL
|
||||||
|
|
||||||
|
LOADC _WAITSPITXRDY
|
||||||
|
CALL
|
||||||
|
|
||||||
|
LOADC _WAIT
|
||||||
|
CALL
|
||||||
|
|
||||||
|
;LOADC '1'
|
||||||
|
;LOADCP CONOUT
|
||||||
|
;CALL
|
||||||
|
|
||||||
|
LOADC $87
|
||||||
|
LOADC $01AA
|
||||||
|
LOADC $8
|
||||||
|
LOADC SENDCMD_R7
|
||||||
|
CALL
|
||||||
|
|
||||||
|
DROP
|
||||||
|
|
||||||
|
LOADC _WAITSPITXRDY
|
||||||
|
CALL
|
||||||
|
|
||||||
|
;LOADC '2'
|
||||||
|
;LOADCP CONOUT
|
||||||
|
;CALL
|
||||||
|
|
||||||
|
;LOADCP _WAIT
|
||||||
|
;CALL
|
||||||
|
|
||||||
|
;LOADC '.'
|
||||||
|
;LOADCP CONOUT
|
||||||
|
;CALL
|
||||||
|
|
||||||
|
LOADC CARDINITV2
|
||||||
|
CALL
|
||||||
|
|
||||||
|
;LOADC '+'
|
||||||
|
;LOADCP CONOUT
|
||||||
|
;CALL
|
||||||
|
|
||||||
|
|
||||||
|
LOADC 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
|
||||||
|
LOADC SENDCMD_PKT
|
||||||
|
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:
|
||||||
|
LOADC WAIT1MSEC
|
||||||
|
CALL
|
||||||
|
DEC 1
|
||||||
|
DUP
|
||||||
|
CBRANCH.NZ CARD_LOOP2
|
||||||
|
DROP ; remove loop count value
|
||||||
|
|
||||||
|
LOADC $0
|
||||||
|
LOADC $0
|
||||||
|
LOADC 58
|
||||||
|
LOADC SENDCMD_R7 ; send CMD58
|
||||||
|
CALL
|
||||||
|
DROP ; ignore result (why?)
|
||||||
|
|
||||||
|
LOADC $0
|
||||||
|
LOADCP $40000000
|
||||||
|
LOADC 41
|
||||||
|
LOADC 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
|
||||||
|
LOADC SENDCMD_R1
|
||||||
|
CALL
|
||||||
|
DROP ; ignore return value
|
||||||
|
|
||||||
|
RET
|
||||||
|
|
||||||
|
; set fast transfer rate
|
||||||
|
CARDFASTCLK:
|
||||||
|
LOADC SPIREG
|
||||||
|
; set clock divider to ~2,6MHz
|
||||||
|
LOADC SPI_CLK_DIV_WR+10
|
||||||
|
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
|
||||||
|
LOADC SPI_CLK_DIV_WR+64
|
||||||
|
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:
|
||||||
|
LOADC 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:
|
||||||
|
LOADC $FF
|
||||||
|
LOADC _SENDBYTE
|
||||||
|
CALL
|
||||||
|
LOADC $FF
|
||||||
|
LOADC _SENDBYTE
|
||||||
|
CALL
|
||||||
|
|
||||||
|
;LOADC 'E'
|
||||||
|
;LOADCP CONOUT
|
||||||
|
;CALL
|
||||||
|
|
||||||
|
LOADC _SPIWAITTX
|
||||||
|
CALL
|
||||||
|
|
||||||
|
;LOADC 'w'
|
||||||
|
;LOADCP CONOUT
|
||||||
|
;CALL
|
||||||
|
LOADC _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
|
||||||
|
LOADC SENDCMD_0
|
||||||
|
CALL
|
||||||
|
|
||||||
|
LOADC _RCVBYTE ; receive R1 response
|
||||||
|
CALL
|
||||||
|
|
||||||
|
CBRANCH.NZ SENDCMD_PKT_E ; on success we get 0
|
||||||
|
|
||||||
|
; now wait for data token
|
||||||
|
SENDCMD_PKT_L:
|
||||||
|
LOADC _RCVBYTE
|
||||||
|
CALL
|
||||||
|
LOADC $FF
|
||||||
|
CMP EQ
|
||||||
|
CBRANCH SENDCMD_PKT_L
|
||||||
|
|
||||||
|
; parameters for _RCVWORDS are on the stack now
|
||||||
|
LOADC _RCVWORDS
|
||||||
|
CALL
|
||||||
|
|
||||||
|
; receive 2 crc bytes
|
||||||
|
LOADC _RCVBYTE
|
||||||
|
CALL
|
||||||
|
BROT
|
||||||
|
LOADC _RCVBYTE
|
||||||
|
CALL
|
||||||
|
OR
|
||||||
|
|
||||||
|
; terminate command
|
||||||
|
LOADC _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 receive a 1-byte-response (R1)
|
||||||
|
; args: checksum byte, 32-bit cmd arg, cmd number
|
||||||
|
; returns: received byte
|
||||||
|
SENDCMD_R1:
|
||||||
|
LOADC SENDCMD_0
|
||||||
|
CALL
|
||||||
|
|
||||||
|
LOADC _RCVBYTE
|
||||||
|
CALL
|
||||||
|
|
||||||
|
;LOADC 'R'
|
||||||
|
;LOADCP CONOUT
|
||||||
|
;CALL
|
||||||
|
|
||||||
|
;terminate command (/cs high, disable clock)
|
||||||
|
LOADC _SPIENDCMD
|
||||||
|
CALL
|
||||||
|
|
||||||
|
RET
|
||||||
|
|
||||||
|
; send a command
|
||||||
|
; args: checksum byte, 32-bit cmd arg, cmd number
|
||||||
|
SENDCMD_0:
|
||||||
|
; clear RX FIFO first
|
||||||
|
LOADC 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
|
||||||
|
LOADC _SENDBYTE
|
||||||
|
CALL
|
||||||
|
; cmd arg is at TOS now
|
||||||
|
LOADC _SENDWORD
|
||||||
|
CALL
|
||||||
|
; checksum byte is at TOS now
|
||||||
|
LOADC _SENDBYTE
|
||||||
|
CALL
|
||||||
|
|
||||||
|
LOADC _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
|
||||||
|
LOADC SENDCMD_R1
|
||||||
|
CALL
|
||||||
|
|
||||||
|
LOADC 1 ; 1 = idle state, no errors
|
||||||
|
CMP NE
|
||||||
|
CBRANCH.NZ SENDACMD_ERR
|
||||||
|
|
||||||
|
; pass our args to SENDCMD_R1
|
||||||
|
LOADC 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
|
||||||
|
LOADC SENDCMD_0
|
||||||
|
CALL
|
||||||
|
|
||||||
|
;LOADC '7'
|
||||||
|
;LOADCP CONOUT
|
||||||
|
;CALL
|
||||||
|
|
||||||
|
LOADC _RCVBYTE
|
||||||
|
CALL
|
||||||
|
|
||||||
|
LOADC _RCVWORD
|
||||||
|
CALL
|
||||||
|
|
||||||
|
;terminate command (/cs high, disable clock)
|
||||||
|
LOADC _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
|
||||||
|
LOADC _SENDBYTE
|
||||||
|
CALL
|
||||||
|
|
||||||
|
BROT ; byte 1
|
||||||
|
LOADC 255
|
||||||
|
AND.S0
|
||||||
|
LOADC _SENDBYTE
|
||||||
|
CALL
|
||||||
|
|
||||||
|
BROT ; byte 2
|
||||||
|
LOADC 255
|
||||||
|
AND
|
||||||
|
LOADC _SENDBYTE
|
||||||
|
CALL
|
||||||
|
|
||||||
|
; byte 3 is already on the stack
|
||||||
|
LOADC 255
|
||||||
|
AND
|
||||||
|
LOADC _SENDBYTE
|
||||||
|
CALL
|
||||||
|
|
||||||
|
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
|
||||||
|
LOADC _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:
|
||||||
|
LOADC _RCVBYTE ; receive first byte
|
||||||
|
CALL
|
||||||
|
BROT ; rotate byte to left
|
||||||
|
|
||||||
|
LOADC _RCVBYTE ; receive second byte
|
||||||
|
CALL
|
||||||
|
OR ; or first and second byte together
|
||||||
|
BROT ; rotate 1st + 2nd to left
|
||||||
|
|
||||||
|
LOADC _RCVBYTE ; receive third byte
|
||||||
|
CALL
|
||||||
|
OR
|
||||||
|
BROT
|
||||||
|
|
||||||
|
LOADCP _RCVBYTE ; receive fourth byte
|
||||||
|
CALL
|
||||||
|
OR
|
||||||
|
RET
|
||||||
|
|
||||||
|
_XCVR_ENABLE:
|
||||||
|
LOADC SPIREG
|
||||||
|
LOADC 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 RECVGOTIT
|
||||||
|
DROP ; rx_avail not set, remove register value and loop
|
||||||
|
BRANCH _RCVBYTE
|
||||||
|
RECVGOTIT:
|
||||||
|
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
|
||||||
795
lib/sdcardlib.s
Normal file
795
lib/sdcardlib.s
Normal file
|
|
@ -0,0 +1,795 @@
|
||||||
|
; 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
|
||||||
|
|
||||||
9181
lib/stdlib.s
Normal file
9181
lib/stdlib.s
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -15,56 +15,15 @@
|
||||||
# run results please launch the synthesis/implementation runs as needed.
|
# run results please launch the synthesis/implementation runs as needed.
|
||||||
#
|
#
|
||||||
#*****************************************************************************************
|
#*****************************************************************************************
|
||||||
# NOTE: In order to use this script for source control purposes, please make sure that the
|
|
||||||
# following files are added to the source control system:-
|
|
||||||
#
|
|
||||||
# 1. This project restoration tcl script (tridoracpu.tcl) that was generated.
|
|
||||||
#
|
|
||||||
# 2. The following source(s) files that were local or imported into the original project.
|
|
||||||
# (Please see the '$orig_proj_dir' and '$origin_dir' variable setting below at the start of the script)
|
|
||||||
#
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/cpuclk.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/display_clock.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/mem.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/stack.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/stackcpu.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/vgafb.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/top.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/testbench.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/rom.mem"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/ip/mig_dram_0/mig_a.prj"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/ip/mig_dram_0/mig_b.prj"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/dram_bridge.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/sdspi.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/bram_tdp.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/palette.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/irqctrl.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo_testbench.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/sdspi_testbench.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/ip/mig_dram_0/mig_dram_0.xci"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sim_1/new/uart_tb.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/testbench_behav1.wcfg"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo_testbench.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/sdspi_testbench_behav.wcfg"
|
|
||||||
#
|
|
||||||
# 3. The following remote source files that were added to the original project:-
|
|
||||||
#
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/imports/verilog/uart.v"
|
|
||||||
# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/constrs_1/imports/fpga/Arty-A7-35-Master.xdc"
|
|
||||||
#
|
|
||||||
#*****************************************************************************************
|
|
||||||
|
|
||||||
#xhub::refresh_catalog [xhub::get_xstores xilinx_board_store]
|
# uncomment next two statements if you have never initialized the Xilinx Board Store
|
||||||
# this will take quite some time
|
# this will take quite some time
|
||||||
|
#xhub::refresh_catalog [xhub::get_xstores xilinx_board_store]
|
||||||
#xhub::install [xhub::get_xitems]
|
#xhub::install [xhub::get_xitems]
|
||||||
|
|
||||||
# Set the reference directory for source file relative paths (by default the value is script directory path)
|
# Set the reference directory for source file relative paths
|
||||||
set origin_dir "C:/Users/sebastian/develop/Tridora/rtl"
|
set origin_dir "change_this_to_your_rtl_directory"
|
||||||
|
|
||||||
# Oh come on, Xilinx, why?
|
|
||||||
#set xilinx_board_store_dir "../../../../AppData/Roaming/Xilinx/Vivado/2020.1/xhub/board_store/xilinx_board_store"
|
|
||||||
set xilinx_board_store_dir [get_property LOCAL_ROOT_DIR [xhub::get_xstores xilinx_board_store]]
|
set xilinx_board_store_dir [get_property LOCAL_ROOT_DIR [xhub::get_xstores xilinx_board_store]]
|
||||||
set_param board.repoPaths [get_property LOCAL_ROOT_DIR [xhub::get_xstores xilinx_board_store]]
|
set_param board.repoPaths [get_property LOCAL_ROOT_DIR [xhub::get_xstores xilinx_board_store]]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue