Add apps/sdct
A new app to stress test the SD card driver. Also, accompanying this commit, changes solidifying the SD card driver so that stress tests actually pass :)
This commit is contained in:
parent
8b638f6899
commit
145b48efb7
4
apps/sdct/README.md
Normal file
4
apps/sdct/README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# sdct - test SD Card
|
||||||
|
|
||||||
|
This program stress-tests a SD card by repeatedly reading and writing to it and
|
||||||
|
verify that data stays the same.
|
27
apps/sdct/glue.asm
Normal file
27
apps/sdct/glue.asm
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
; sdct
|
||||||
|
;
|
||||||
|
; We want to test reading and writing random data in random sequences of
|
||||||
|
; sectors. Collapse OS doesn't have a random number generator, so we'll simply
|
||||||
|
; rely on initial SRAM value, which tend is random enough for our purpose.
|
||||||
|
;
|
||||||
|
; How it works is simple. From its designated RAMSTART, it calls PutC until it
|
||||||
|
; reaches the end of RAM (0xffff). Then, it starts over and this time it reads
|
||||||
|
; every byte and compares.
|
||||||
|
;
|
||||||
|
; If there's an error, prints out where.
|
||||||
|
;
|
||||||
|
; *** Requirements ***
|
||||||
|
; sdcPutC
|
||||||
|
; sdcGetC
|
||||||
|
; printstr
|
||||||
|
; printHexPair
|
||||||
|
;
|
||||||
|
; *** Includes ***
|
||||||
|
|
||||||
|
#include "user.h"
|
||||||
|
.org USER_CODE
|
||||||
|
.equ SDCT_RAMSTART USER_RAMSTART
|
||||||
|
|
||||||
|
jp sdctMain
|
||||||
|
|
||||||
|
#include "sdct/main.asm"
|
64
apps/sdct/main.asm
Normal file
64
apps/sdct/main.asm
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
sdctMain:
|
||||||
|
ld hl, .sWriting
|
||||||
|
call printstr
|
||||||
|
ld hl, 0
|
||||||
|
ld de, SDCT_RAMSTART
|
||||||
|
.wLoop:
|
||||||
|
ld a, (de)
|
||||||
|
call sdcPutC
|
||||||
|
jr nz, .error
|
||||||
|
inc hl
|
||||||
|
inc de
|
||||||
|
; Stop looping if DE == 0
|
||||||
|
xor a
|
||||||
|
cp e
|
||||||
|
jr nz, .wLoop
|
||||||
|
; print some kind of progress
|
||||||
|
call printHexPair
|
||||||
|
cp d
|
||||||
|
jr nz, .wLoop
|
||||||
|
; Finished writing
|
||||||
|
ld hl, .sReading
|
||||||
|
call printstr
|
||||||
|
ld hl, 0
|
||||||
|
ld de, SDCT_RAMSTART
|
||||||
|
.rLoop:
|
||||||
|
call sdcGetC
|
||||||
|
jr nz, .error
|
||||||
|
ex de, hl
|
||||||
|
cp (hl)
|
||||||
|
ex de, hl
|
||||||
|
jr nz, .notMatching
|
||||||
|
inc hl
|
||||||
|
inc de
|
||||||
|
; Stop looping if DE == 0
|
||||||
|
xor a
|
||||||
|
cp d
|
||||||
|
jr nz, .rLoop
|
||||||
|
cp e
|
||||||
|
jr nz, .rLoop
|
||||||
|
; Finished checking
|
||||||
|
xor a
|
||||||
|
ld hl, .sOk
|
||||||
|
jp printstr ; returns
|
||||||
|
.notMatching:
|
||||||
|
; error position is in HL, let's preserve it
|
||||||
|
ex de, hl
|
||||||
|
ld hl, .sNotMatching
|
||||||
|
call printstr
|
||||||
|
ex de, hl
|
||||||
|
jp printHexPair ; returns
|
||||||
|
.error:
|
||||||
|
ld hl, .sErr
|
||||||
|
jp printstr ; returns
|
||||||
|
|
||||||
|
.sWriting:
|
||||||
|
.db "Writing", 0xd, 0xa, 0
|
||||||
|
.sReading:
|
||||||
|
.db "Reading", 0xd, 0xa, 0
|
||||||
|
.sNotMatching:
|
||||||
|
.db "Not matching at pos ", 0xd, 0xa, 0
|
||||||
|
.sErr:
|
||||||
|
.db "Error", 0xd, 0xa, 0
|
||||||
|
.sOk:
|
||||||
|
.db "OK", 0xd, 0xa, 0
|
@ -126,15 +126,12 @@ sdcWaitResp:
|
|||||||
; This has no error condition and preserves A
|
; This has no error condition and preserves A
|
||||||
sdcWaitReady:
|
sdcWaitReady:
|
||||||
push af
|
push af
|
||||||
push bc
|
; for now, we have no timeout for waiting. It means that broken SD
|
||||||
ld b, 20
|
; cards can cause infinite loops.
|
||||||
.loop:
|
.loop:
|
||||||
call sdcIdle
|
call sdcIdle
|
||||||
inc a ; if 0xff, it's going to become zero
|
inc a ; if 0xff, it's going to become zero
|
||||||
jr z, .end ; zero? good, we're not busy any more
|
jr nz, .loop ; not zero? still busy. loop
|
||||||
djnz .loop
|
|
||||||
.end:
|
|
||||||
pop bc
|
|
||||||
pop af
|
pop af
|
||||||
ret
|
ret
|
||||||
|
|
||||||
@ -169,6 +166,9 @@ sdcCmd:
|
|||||||
call sdcSendRecv
|
call sdcSendRecv
|
||||||
; send CRC
|
; send CRC
|
||||||
ld a, c
|
ld a, c
|
||||||
|
; Most of the time, we don't care about C, but in all cases, we want
|
||||||
|
; the last bit to be high. It's the stop bit.
|
||||||
|
or 0x01
|
||||||
call sdcSendRecv
|
call sdcSendRecv
|
||||||
|
|
||||||
; And now we just have to wait for a valid response...
|
; And now we just have to wait for a valid response...
|
||||||
@ -275,20 +275,6 @@ sdcInitialize:
|
|||||||
or a ; cp 0
|
or a ; cp 0
|
||||||
jr nz, .error
|
jr nz, .error
|
||||||
; Success! out of idle mode!
|
; Success! out of idle mode!
|
||||||
; At this point, our buffers are innitialized. We could have some logic
|
|
||||||
; that determines whether a buffer is initialized in appropriate SDC
|
|
||||||
; routines and act appropriately, but why bother when we could, instead,
|
|
||||||
; just buffer the first two sectors of the card on initialization? This
|
|
||||||
; way, no need for special conditions.
|
|
||||||
; initialize variables
|
|
||||||
ld hl, SDC_BUFSEC1
|
|
||||||
xor a
|
|
||||||
ld (SDC_BUFPTR), hl
|
|
||||||
call sdcReadBlk ; read sector 0 in buf1
|
|
||||||
ld hl, SDC_BUFSEC2
|
|
||||||
inc a
|
|
||||||
ld (SDC_BUFPTR), hl
|
|
||||||
call sdcReadBlk ; read sector 1 in buf2
|
|
||||||
jr .end
|
jr .end
|
||||||
|
|
||||||
.error:
|
.error:
|
||||||
@ -322,6 +308,7 @@ sdcSetBlkSize:
|
|||||||
; Returns 0 in A if success, non-zero if error.
|
; Returns 0 in A if success, non-zero if error.
|
||||||
sdcReadBlk:
|
sdcReadBlk:
|
||||||
push bc
|
push bc
|
||||||
|
push de
|
||||||
push hl
|
push hl
|
||||||
|
|
||||||
out (SDC_PORT_CSLOW), a
|
out (SDC_PORT_CSLOW), a
|
||||||
@ -371,6 +358,7 @@ sdcReadBlk:
|
|||||||
call sdcIdle
|
call sdcIdle
|
||||||
; success! wait until card is ready
|
; success! wait until card is ready
|
||||||
call sdcWaitReady
|
call sdcWaitReady
|
||||||
|
xor a ; success
|
||||||
jr .end
|
jr .end
|
||||||
.error:
|
.error:
|
||||||
; try to preserve error code
|
; try to preserve error code
|
||||||
@ -380,6 +368,7 @@ sdcReadBlk:
|
|||||||
.end:
|
.end:
|
||||||
out (SDC_PORT_CSHIGH), a
|
out (SDC_PORT_CSHIGH), a
|
||||||
pop hl
|
pop hl
|
||||||
|
pop de
|
||||||
pop bc
|
pop bc
|
||||||
ret
|
ret
|
||||||
|
|
||||||
@ -451,6 +440,8 @@ sdcWriteBlk:
|
|||||||
|
|
||||||
; Before returning, wait until card is ready
|
; Before returning, wait until card is ready
|
||||||
call sdcWaitReady
|
call sdcWaitReady
|
||||||
|
xor a
|
||||||
|
; A is already 0
|
||||||
jr .end
|
jr .end
|
||||||
.error:
|
.error:
|
||||||
; try to preserve error code
|
; try to preserve error code
|
||||||
@ -538,7 +529,23 @@ sdcSync:
|
|||||||
sdcInitializeCmd:
|
sdcInitializeCmd:
|
||||||
.db "sdci", 0, 0, 0
|
.db "sdci", 0, 0, 0
|
||||||
call sdcInitialize
|
call sdcInitialize
|
||||||
jp sdcSetBlkSize ; returns
|
ret nz
|
||||||
|
call sdcSetBlkSize
|
||||||
|
ret nz
|
||||||
|
; At this point, our buffers are unnitialized. We could have some logic
|
||||||
|
; that determines whether a buffer is initialized in appropriate SDC
|
||||||
|
; routines and act appropriately, but why bother when we could, instead,
|
||||||
|
; just buffer the first two sectors of the card on initialization? This
|
||||||
|
; way, no need for special conditions.
|
||||||
|
; initialize variables
|
||||||
|
ld hl, SDC_BUFSEC1
|
||||||
|
xor a
|
||||||
|
ld (SDC_BUFPTR), hl
|
||||||
|
call sdcReadBlk ; read sector 0 in buf1
|
||||||
|
ld hl, SDC_BUFSEC2
|
||||||
|
inc a
|
||||||
|
ld (SDC_BUFPTR), hl
|
||||||
|
jp sdcReadBlk ; read sector 1 in buf2, returns
|
||||||
|
|
||||||
; Flush the current SDC buffer if dirty
|
; Flush the current SDC buffer if dirty
|
||||||
sdcFlushCmd:
|
sdcFlushCmd:
|
||||||
@ -615,7 +622,10 @@ sdcPutC:
|
|||||||
xor a ; ensure Z
|
xor a ; ensure Z
|
||||||
jr .end
|
jr .end
|
||||||
.error:
|
.error:
|
||||||
|
; preserve error code
|
||||||
|
ex af, af'
|
||||||
pop af
|
pop af
|
||||||
|
ex af, af'
|
||||||
call unsetZ
|
call unsetZ
|
||||||
.end:
|
.end:
|
||||||
pop hl
|
pop hl
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
CFSTARGETS = cfsin/zasm cfsin/user.h
|
CFSTARGETS = cfsin/zasm cfsin/sdct cfsin/user.h
|
||||||
BASE = ../../..
|
BASE = ../../..
|
||||||
TOOLS = $(BASE)/tools
|
TOOLS = $(BASE)/tools
|
||||||
ZASM = $(TOOLS)/zasm.sh
|
ZASM = $(TOOLS)/zasm.sh
|
||||||
@ -21,5 +21,8 @@ sdcard.cfs: $(CFSTARGETS) $(CFSPACK)
|
|||||||
cfsin/zasm: $(ZASMBIN)
|
cfsin/zasm: $(ZASMBIN)
|
||||||
$(ZASM) $(KERNEL) $(APPS) user.h < $(APPS)/zasm/glue.asm > $@
|
$(ZASM) $(KERNEL) $(APPS) user.h < $(APPS)/zasm/glue.asm > $@
|
||||||
|
|
||||||
|
cfsin/sdct: $(ZASMBIN)
|
||||||
|
$(ZASM) $(APPS) user.h < $(APPS)/sdct/glue.asm > $@
|
||||||
|
|
||||||
cfsin/user.h: user.h
|
cfsin/user.h: user.h
|
||||||
cp $< $@
|
cp $< $@
|
||||||
|
@ -41,6 +41,9 @@ jp aciaInt
|
|||||||
jp _blkPutC
|
jp _blkPutC
|
||||||
jp _blkSeek
|
jp _blkSeek
|
||||||
jp _blkTell
|
jp _blkTell
|
||||||
|
jp printHexPair
|
||||||
|
jp sdcGetC
|
||||||
|
jp sdcPutC
|
||||||
|
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "core.asm"
|
#include "core.asm"
|
||||||
|
@ -28,3 +28,6 @@
|
|||||||
.equ _blkPutC 0x44
|
.equ _blkPutC 0x44
|
||||||
.equ _blkSeek 0x47
|
.equ _blkSeek 0x47
|
||||||
.equ _blkTell 0x4a
|
.equ _blkTell 0x4a
|
||||||
|
.equ printHexPair 0x4d
|
||||||
|
.equ sdcGetC 0x50
|
||||||
|
.equ sdcPutC 0x53
|
||||||
|
Loading…
Reference in New Issue
Block a user