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
|
||||
sdcWaitReady:
|
||||
push af
|
||||
push bc
|
||||
ld b, 20
|
||||
; for now, we have no timeout for waiting. It means that broken SD
|
||||
; cards can cause infinite loops.
|
||||
.loop:
|
||||
call sdcIdle
|
||||
inc a ; if 0xff, it's going to become zero
|
||||
jr z, .end ; zero? good, we're not busy any more
|
||||
djnz .loop
|
||||
.end:
|
||||
pop bc
|
||||
jr nz, .loop ; not zero? still busy. loop
|
||||
pop af
|
||||
ret
|
||||
|
||||
@ -169,6 +166,9 @@ sdcCmd:
|
||||
call sdcSendRecv
|
||||
; send CRC
|
||||
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
|
||||
|
||||
; And now we just have to wait for a valid response...
|
||||
@ -275,20 +275,6 @@ sdcInitialize:
|
||||
or a ; cp 0
|
||||
jr nz, .error
|
||||
; 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
|
||||
|
||||
.error:
|
||||
@ -322,6 +308,7 @@ sdcSetBlkSize:
|
||||
; Returns 0 in A if success, non-zero if error.
|
||||
sdcReadBlk:
|
||||
push bc
|
||||
push de
|
||||
push hl
|
||||
|
||||
out (SDC_PORT_CSLOW), a
|
||||
@ -371,6 +358,7 @@ sdcReadBlk:
|
||||
call sdcIdle
|
||||
; success! wait until card is ready
|
||||
call sdcWaitReady
|
||||
xor a ; success
|
||||
jr .end
|
||||
.error:
|
||||
; try to preserve error code
|
||||
@ -380,6 +368,7 @@ sdcReadBlk:
|
||||
.end:
|
||||
out (SDC_PORT_CSHIGH), a
|
||||
pop hl
|
||||
pop de
|
||||
pop bc
|
||||
ret
|
||||
|
||||
@ -451,6 +440,8 @@ sdcWriteBlk:
|
||||
|
||||
; Before returning, wait until card is ready
|
||||
call sdcWaitReady
|
||||
xor a
|
||||
; A is already 0
|
||||
jr .end
|
||||
.error:
|
||||
; try to preserve error code
|
||||
@ -538,7 +529,23 @@ sdcSync:
|
||||
sdcInitializeCmd:
|
||||
.db "sdci", 0, 0, 0
|
||||
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
|
||||
sdcFlushCmd:
|
||||
@ -615,7 +622,10 @@ sdcPutC:
|
||||
xor a ; ensure Z
|
||||
jr .end
|
||||
.error:
|
||||
; preserve error code
|
||||
ex af, af'
|
||||
pop af
|
||||
ex af, af'
|
||||
call unsetZ
|
||||
.end:
|
||||
pop hl
|
||||
|
@ -1,4 +1,4 @@
|
||||
CFSTARGETS = cfsin/zasm cfsin/user.h
|
||||
CFSTARGETS = cfsin/zasm cfsin/sdct cfsin/user.h
|
||||
BASE = ../../..
|
||||
TOOLS = $(BASE)/tools
|
||||
ZASM = $(TOOLS)/zasm.sh
|
||||
@ -21,5 +21,8 @@ sdcard.cfs: $(CFSTARGETS) $(CFSPACK)
|
||||
cfsin/zasm: $(ZASMBIN)
|
||||
$(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
|
||||
cp $< $@
|
||||
|
@ -41,6 +41,9 @@ jp aciaInt
|
||||
jp _blkPutC
|
||||
jp _blkSeek
|
||||
jp _blkTell
|
||||
jp printHexPair
|
||||
jp sdcGetC
|
||||
jp sdcPutC
|
||||
|
||||
#include "err.h"
|
||||
#include "core.asm"
|
||||
|
@ -28,3 +28,6 @@
|
||||
.equ _blkPutC 0x44
|
||||
.equ _blkSeek 0x47
|
||||
.equ _blkTell 0x4a
|
||||
.equ printHexPair 0x4d
|
||||
.equ sdcGetC 0x50
|
||||
.equ sdcPutC 0x53
|
||||
|
Loading…
Reference in New Issue
Block a user