diff --git a/blk/001 b/blk/001 index 4bf5f69..ba7b225 100644 --- a/blk/001 +++ b/blk/001 @@ -4,7 +4,7 @@ MASTER INDEX 70 Implementation notes 100 Block editor 200 Z80 assembler 260 Cross compilation 280 Z80 boot code 350 ACIA driver - +370 SD Card driver diff --git a/blk/370 b/blk/370 new file mode 100644 index 0000000..9418293 --- /dev/null +++ b/blk/370 @@ -0,0 +1,4 @@ +SD Card driver + +Load the z80 part with "372 LOAD", the Forth part with +"374 LOAD". diff --git a/drv/sdc.z80 b/blk/372 similarity index 64% rename from drv/sdc.z80 rename to blk/372 index 2e48f66..c4ce3fd 100644 --- a/drv/sdc.z80 +++ b/blk/372 @@ -1,7 +1,6 @@ -( n -- n ) ( Initiate SPI exchange with the SD card. n is the data to send. ) -CODE _sdcSR +CODE _sdcSR ( n -- n ) HL POPqq, chkPS, A L LDrr, @@ -12,10 +11,4 @@ CODE _sdcSR HL PUSHqq, ;CODE -CODE _sdcSel - SDC_CSLOW OUTnA, -;CODE - -CODE _sdcDesel - SDC_CSHIGH OUTnA, -;CODE +373 LOAD diff --git a/blk/373 b/blk/373 new file mode 100644 index 0000000..4d81491 --- /dev/null +++ b/blk/373 @@ -0,0 +1,9 @@ +CODE _sdcSel + SDC_CSLOW OUTnA, +;CODE + +CODE _sdcDesel + SDC_CSHIGH OUTnA, +;CODE + + diff --git a/blk/374 b/blk/374 new file mode 100644 index 0000000..573dafc --- /dev/null +++ b/blk/374 @@ -0,0 +1,16 @@ +( -- n ) +: _idle 0xff _sdcSR ; + +( -- n ) +( _sdcSR 0xff until the response is something else than 0xff + for a maximum of 20 times. Returns 0xff if no response. ) +: _wait + 0 ( cnt ) + BEGIN + _idle + DUP 0xff = IF DROP ELSE SWAP DROP EXIT THEN + 1+ + DUP 20 = UNTIL + DROP 0xff +; +375 386 LOADR diff --git a/blk/375 b/blk/375 new file mode 100644 index 0000000..e3b2953 --- /dev/null +++ b/blk/375 @@ -0,0 +1,10 @@ +( -- ) +( The opposite of sdcWaitResp: we wait until response is 0xff. + After a successful read or write operation, the card will be + busy for a while. We need to give it time before interacting + with it again. Technically, we could continue processing on + our side while the card it busy, and maybe we will one day, + but at the moment, I'm having random write errors if I don't + do this right after a write, so I prefer to stay cautious + for now. ) +: _ready BEGIN _idle 0xff = UNTIL ; diff --git a/blk/376 b/blk/376 new file mode 100644 index 0000000..3ae7a8c --- /dev/null +++ b/blk/376 @@ -0,0 +1,16 @@ +( c n -- c ) +( Computes n into crc c with polynomial 0x09 + Note that the result is "left aligned", that is, that 8th + bit to the "right" is insignificant (will be stop bit). ) +: _crc7 + XOR ( c ) + 8 0 DO + 2 * ( <<1 ) + DUP 255 > IF + ( MSB was set, apply polynomial ) + 0xff AND + 0x12 XOR ( 0x09 << 1, we apply CRC on high bits ) + THEN + LOOP +; + diff --git a/blk/377 b/blk/377 new file mode 100644 index 0000000..18facb2 --- /dev/null +++ b/blk/377 @@ -0,0 +1,16 @@ +( c n -- c ) +( Computes n into crc c with polynomial 0x1021 ) +: _crc16 + SWAP DUP 256 / ( n c c>>8 ) + ROT XOR ( c x ) + DUP 16 / XOR ( c x^x>>4 ) + SWAP 256 * ( x c<<8 ) + OVER 4096 * XOR ( x c^x<<12 ) + OVER 32 * XOR ( x c^x<<5 ) + XOR ( c ) +; + +( send-and-crc7 ) +( n c -- c ) +: _s+crc SWAP DUP _sdcSR DROP _crc7 ; + diff --git a/blk/378 b/blk/378 new file mode 100644 index 0000000..3b252b3 --- /dev/null +++ b/blk/378 @@ -0,0 +1,16 @@ +( cmd arg1 arg2 -- resp ) +( Sends a command to the SD card, along with arguments and + specified CRC fields. (CRC is only needed in initial commands + though). This does *not* handle CS. You have to + select/deselect the card outside this routine. ) +: _cmd + _wait DROP ROT ( a1 a2 cmd ) + 0 _s+crc ( a1 a2 crc ) + ROT 256 /MOD ROT ( a2 h l crc ) + _s+crc _s+crc ( a2 crc ) + SWAP 256 /MOD ROT ( h l crc ) + _s+crc _s+crc ( crc ) + 0x01 OR ( ensure stop bit ) + _sdcSR DROP ( send CRC ) + _wait ( wait for a valid response... ) +; diff --git a/blk/379 b/blk/379 new file mode 100644 index 0000000..5d3edca --- /dev/null +++ b/blk/379 @@ -0,0 +1,16 @@ +( cmd arg1 arg2 -- r ) +( Send a command that expects a R1 response, handling CS. ) +: SDCMDR1 _sdcSel _cmd _sdcDesel ; + +( cmd arg1 arg2 -- r arg1 arg2 ) +( Send a command that expects a R7 response, handling CS. A R7 + is a R1 followed by 4 bytes. arg1 contains bytes 0:1, arg2 + has 2:3 ) +: SDCMDR7 + _sdcSel + _cmd ( r ) + _idle 256 * _idle + ( r arg1 ) + _idle 256 * _idle + ( r arg1 arg2 ) + _sdcDesel +; + diff --git a/blk/380 b/blk/380 new file mode 100644 index 0000000..0884215 --- /dev/null +++ b/blk/380 @@ -0,0 +1,16 @@ +: _err _sdcDesel ABORT" SDerr" ; + +( Initialize a SD card. This should be called at least 1ms + after the powering up of the card. ) +: SDC$ +( Wake the SD card up. After power up, a SD card has to receive + at least 74 dummy clocks with CS and DI high. We send 80. ) + 10 0 DO _idle DROP LOOP + ( call cmd0 and expect a 0x01 response (card idle) + this should be called multiple times. we're actually + expected to. let's call this for a maximum of 10 times. ) + 0 ( dummy ) + 10 0 DO ( r ) + DROP 0x40 0 0 SDCMDR1 ( CMD0 ) + DUP 0x01 = IF LEAVE THEN + LOOP 0x01 = NOT IF _err THEN ( cont. ) diff --git a/blk/381 b/blk/381 new file mode 100644 index 0000000..35528cf --- /dev/null +++ b/blk/381 @@ -0,0 +1,10 @@ +( Then comes the CMD8. We send it with a 0x01aa argument and + expect a 0x01aa argument back, along with a 0x01 R1 + response. ) + 0x48 0 0x1aa ( CMD8 ) + SDCMDR7 ( r arg1 arg2 ) + 0x1aa = NOT IF _err THEN ( arg2 check ) + 0 = NOT IF _err THEN ( arg1 check ) + 0x01 = NOT IF _err THEN ( r check ) + + ( cont. ) diff --git a/blk/382 b/blk/382 new file mode 100644 index 0000000..ac24ea7 --- /dev/null +++ b/blk/382 @@ -0,0 +1,13 @@ +( Now we need to repeatedly run CMD55+CMD41 (0x40000000) + until the card goes out of idle mode, that is, when it stops + sending us 0x01 response and send us 0x00 instead. Any other + response means that initialization failed. ) + BEGIN + 0x77 0 0 SDCMDR1 ( CMD55 ) + 0x01 = NOT IF _err THEN + 0x69 0x4000 0x0000 SDCMDR1 ( CMD41 ) + DUP 0x01 > IF _err THEN + NOT UNTIL + ( Out of idle mode! Success! ) +; + diff --git a/blk/383 b/blk/383 new file mode 100644 index 0000000..2058089 --- /dev/null +++ b/blk/383 @@ -0,0 +1,15 @@ +: _sdc@ ( dstaddr blkno -- ) + _sdcSel 0x51 ( CMD17 ) 0 ROT ( a cmd 0 blkno ) _cmd + IF _err THEN + _wait 0xfe = NOT IF _err THEN + 0 SWAP ( crc a ) + 512 0 DO ( crc a ) + DUP _idle ( crc a a n ) + DUP ROT C! ( crc a n ) + ROT SWAP _crc16 ( a crc ) + SWAP 1+ ( crc a+1 ) + LOOP + DROP ( crc1 ) + _idle 256 * _idle + ( crc2 ) + _wait DROP _sdcDesel + = NOT IF _err THEN ; diff --git a/blk/384 b/blk/384 new file mode 100644 index 0000000..23c80a9 --- /dev/null +++ b/blk/384 @@ -0,0 +1,7 @@ +: SDC@ + 2 * DUP BLK( SWAP ( b a b ) + _sdc@ + 1+ BLK( 512 + SWAP + _sdc@ +; + diff --git a/blk/385 b/blk/385 new file mode 100644 index 0000000..9123593 --- /dev/null +++ b/blk/385 @@ -0,0 +1,16 @@ +: _sdc! ( srcaddr blkno -- ) + _sdcSel 0x58 ( CMD24 ) 0 ROT ( a cmd 0 blkno ) _cmd + IF _err THEN + _idle DROP 0xfe _sdcSR DROP + 0 SWAP ( crc a ) + 512 0 DO ( crc a ) + C@+ ( crc a+1 n ) + ROT OVER ( a n crc n ) + _crc16 ( a n crc ) + SWAP ( a crc n ) + _sdcSR DROP ( a crc ) + SWAP ( crc a ) + LOOP + DROP ( crc ) 256 /MOD ( lsb msb ) + _sdcSR DROP _sdcSR DROP + _wait DROP _sdcDesel ; diff --git a/blk/386 b/blk/386 new file mode 100644 index 0000000..f443dc2 --- /dev/null +++ b/blk/386 @@ -0,0 +1,7 @@ +: SDC! + 2 * DUP BLK( SWAP ( b a b ) + _sdc! + 1+ BLK( 512 + SWAP + _sdc! +; + diff --git a/recipes/rc2014/Makefile b/recipes/rc2014/Makefile index 0c6bd0a..0b05b6f 100644 --- a/recipes/rc2014/Makefile +++ b/recipes/rc2014/Makefile @@ -7,7 +7,6 @@ EMUL = $(BASEDIR)/emul/hw/rc2014/classic BOOTSRCS = conf.fs \ $(EDIR)/xcomp.fs \ drvz80.fs \ - $(BASEDIR)/drv/sdc.z80 \ $(FDIR)/icore.fs \ $(EDIR)/stop.fs diff --git a/recipes/rc2014/drvz80.fs b/recipes/rc2014/drvz80.fs index 59aeb62..1738e44 100644 --- a/recipes/rc2014/drvz80.fs +++ b/recipes/rc2014/drvz80.fs @@ -1 +1,2 @@ 352 LOAD ( acia.z80 ) +372 LOAD ( sdc.z80 )