From 145b48efb74bc42bfb4d9d578e8b7e0fb91b2b22 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Mon, 10 Jun 2019 15:13:46 -0400 Subject: [PATCH] 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 :) --- apps/sdct/README.md | 4 +++ apps/sdct/glue.asm | 27 +++++++++++++++ apps/sdct/main.asm | 64 ++++++++++++++++++++++++++++++++++++ kernel/sdc.asm | 52 +++++++++++++++++------------ recipes/rc2014/zasm/Makefile | 5 ++- recipes/rc2014/zasm/glue.asm | 3 ++ recipes/rc2014/zasm/user.h | 3 ++ 7 files changed, 136 insertions(+), 22 deletions(-) create mode 100644 apps/sdct/README.md create mode 100644 apps/sdct/glue.asm create mode 100644 apps/sdct/main.asm diff --git a/apps/sdct/README.md b/apps/sdct/README.md new file mode 100644 index 0000000..22d221b --- /dev/null +++ b/apps/sdct/README.md @@ -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. diff --git a/apps/sdct/glue.asm b/apps/sdct/glue.asm new file mode 100644 index 0000000..dda3cf7 --- /dev/null +++ b/apps/sdct/glue.asm @@ -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" diff --git a/apps/sdct/main.asm b/apps/sdct/main.asm new file mode 100644 index 0000000..b68d13a --- /dev/null +++ b/apps/sdct/main.asm @@ -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 diff --git a/kernel/sdc.asm b/kernel/sdc.asm index 39066f1..db5b920 100644 --- a/kernel/sdc.asm +++ b/kernel/sdc.asm @@ -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 diff --git a/recipes/rc2014/zasm/Makefile b/recipes/rc2014/zasm/Makefile index c3f964f..e7f8d17 100644 --- a/recipes/rc2014/zasm/Makefile +++ b/recipes/rc2014/zasm/Makefile @@ -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 $< $@ diff --git a/recipes/rc2014/zasm/glue.asm b/recipes/rc2014/zasm/glue.asm index 18cb7fa..441fc62 100644 --- a/recipes/rc2014/zasm/glue.asm +++ b/recipes/rc2014/zasm/glue.asm @@ -41,6 +41,9 @@ jp aciaInt jp _blkPutC jp _blkSeek jp _blkTell + jp printHexPair + jp sdcGetC + jp sdcPutC #include "err.h" #include "core.asm" diff --git a/recipes/rc2014/zasm/user.h b/recipes/rc2014/zasm/user.h index e55b387..b5b7826 100644 --- a/recipes/rc2014/zasm/user.h +++ b/recipes/rc2014/zasm/user.h @@ -28,3 +28,6 @@ .equ _blkPutC 0x44 .equ _blkSeek 0x47 .equ _blkTell 0x4a +.equ printHexPair 0x4d +.equ sdcGetC 0x50 +.equ sdcPutC 0x53