Compare commits

...

4 Commits

Author SHA1 Message Date
Virgil Dupras
052c744000 drv/sdc: implement "SDC@"
I can read a block from blkfs in RC2014 emulator. It even checks
CRC16 successfully!
2020-04-18 14:22:26 -04:00
Virgil Dupras
c64a8a2e2b drv/sdc: new unit to drive SD card through SPI relay
Goes through initialization in RC2014 emulator.
2020-04-18 11:11:11 -04:00
Virgil Dupras
b062a9092a parse: use "0<" instead of "0 <"
As I wrote in my "Clarify signed-ness" commit, "0 <" is broken.

Also, made this unit a bit more compact. The RC2014 stage1 can
really use some breathing room...
2020-04-18 09:18:09 -04:00
Virgil Dupras
66f65daa08 Add word LEAVE 2020-04-18 08:37:57 -04:00
10 changed files with 210 additions and 25 deletions

View File

@ -5,7 +5,7 @@ unsigned. For convenience, decimal parsing and formatting
support the "-" prefix, but under the hood, it's all unsigned.
This leads to some oddities. For example, "-1 0 <" is false.
To compare whether something is negative, use the "<0" word
To compare whether something is negative, use the "0<" word
which is the equivalent to "0x7fff >".

View File

@ -11,6 +11,6 @@ ABORT" x" -- *I* Compiles a ." followed by a ABORT.
EXECUTE a -- Execute wordref at addr a
INTERPRET -- Get a line from stdin, compile it in tmp memory,
then execute the compiled contents.
LEAVE -- In a DO..LOOP, exit at the next LOOP call.
QUIT -- Return to interpreter prompt immediately
EXIT! -- Exit current INTERPRET loop.

184
drv/sdc.fs Normal file
View File

@ -0,0 +1,184 @@
: SDC_CSHIGH 6 ;
: SDC_CSLOW 5 ;
: SDC_SPI 4 ;
: _sdcSR SDC_SPI PC! SDC_SPI PC@ ;
: _sel 0 SDC_CSLOW PC! ;
: _desel 0 SDC_CSHIGH PC! ;
( -- 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
;
( -- )
( 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 ;
( 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
;
( 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 ;
( 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 ( a2 crc h l )
ROT ( a2 h l crc )
_s+crc ( a2 h crc )
_s+crc ( a2 crc )
SWAP 256 /MOD ( crc h l )
ROT ( h l crc )
_s+crc ( h crc )
_s+crc ( crc )
( send CRC )
0x01 OR ( ensure stop bit )
_sdcSR DROP
( And now we just have to wait for a valid response... )
_wait
;
( cmd arg1 arg2 -- r )
( Send a command that expects a R1 response, handling CS. )
: SDCMDR1 _sel _cmd _desel ;
( 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
_sel
_cmd ( r )
_idle 256 * ( r h )
_idle + ( r arg1 )
_idle 256 * ( r arg1 h )
_idle + ( r arg1 arg2 )
_desel
;
( Initialize a SD card. This should be called at least 1ms
after the powering up of the card. r is result.
Zero means success, non-zero means error. )
: 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 0xff SDC_SPI PC! 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
0b01000000 0 0 ( CMD0 )
SDCMDR1
DUP 0x01 = IF LEAVE THEN
LOOP
0x01 = NOT IF 1 EXIT THEN
( Then comes the CMD8. We send it with a 0x01aa argument
and expect a 0x01aa argument back, along with a 0x01 R1
response. )
0b01001000 0 0x1aa ( CMD8 )
SDCMDR7 ( r arg1 arg2 )
0x1aa = NOT IF 2 EXIT THEN ( arg2 check )
0 = NOT IF 3 EXIT THEN ( arg1 check )
0x01 = NOT IF 4 EXIT THEN ( r check )
( 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
0b01110111 0 0 ( CMD55 )
SDCMDR1
0x01 = NOT IF 5 EXIT THEN
0b01101001 0x4000 0x0000 ( CMD41 )
SDCMDR1
DUP 0x01 > IF DROP 6 EXIT THEN
NOT UNTIL
( Out of idle mode! Success! )
0
;
( dstaddr blkno -- f )
: SDC@
_sel
0x51 ( CMD17 )
0 ROT ( a cmd 0 blkno )
_cmd
IF _desel 0 EXIT THEN
_wait
0xfe = NOT IF _desel 0 EXIT THEN
0 SWAP ( crc a )
512 0 DO ( crc a )
DUP ( crc a a )
_idle ( crc a a n )
DUP ROT ( crc a n n a )
C! ( crc a n )
ROT SWAP ( a crc n )
_crc16 ( a crc )
SWAP 1+ ( crc a+1 )
LOOP
DROP ( crc1 )
_idle 256 *
_idle + ( crc2 )
_wait DROP
_desel
= ( success if crc1 == crc2 )
;

Binary file not shown.

View File

@ -122,6 +122,7 @@ void sdc_spi_wr(SDC *sdc, uint8_t val)
uint8_t cmd = b[0] & 0x3f;
uint16_t arg1 = (b[1] << 8) | b[2];
uint16_t arg2 = (b[3] << 8) | b[4];
// printf("cmd %02x %04x %04x\n", cmd, arg1, arg2);
if (sdc->initstat == 8) {
// At this stage, we're expecting CMD0
if (cmd == 0) {

View File

@ -2,8 +2,7 @@
: >= < NOT ;
: <= > NOT ;
: <0 32767 > ;
: >=0 <0 NOT ;
: 0>= 0< NOT ;
( n1 -- n1 true )
: <>{ 1 ;

View File

@ -133,6 +133,8 @@
COMPILE R> COMPILE DROP COMPILE R> COMPILE DROP
; IMMEDIATE
: LEAVE R> R> DROP I 1- >R >R ;
( a1 a2 u -- )
: MOVE
( u ) 0 DO

View File

@ -12,7 +12,7 @@
: . ( n -- )
( handle negative )
DUP <0 IF '-' EMIT -1 * THEN
DUP 0< IF '-' EMIT -1 * THEN
_
BEGIN
DUP '9' > IF DROP EXIT THEN ( stop indicator, we're done )

View File

@ -51,6 +51,7 @@
: = CMP NOT ;
: < CMP -1 = ;
: > CMP 1 = ;
: 0< 32767 > ;
( r c -- r f )
( Parse digit c and accumulate into result r.
@ -61,7 +62,7 @@
( parse char )
'0' -
( if bad, return "r -1" )
DUP 0 < IF DROP -1 EXIT THEN ( bad )
DUP 0< IF DROP -1 EXIT THEN ( bad )
DUP 9 > IF DROP -1 EXIT THEN ( bad )
( good, add to running result )
SWAP 10 * + ( r*10+n )

View File

@ -11,14 +11,14 @@
;
( returns negative value on error )
: hexdig ( c -- n )
: _ ( c -- n )
( '0' is ASCII 48 )
48 -
DUP 0 < IF EXIT THEN ( bad )
DUP 0< IF EXIT THEN ( bad )
DUP 10 < IF EXIT THEN ( good )
( 'a' is ASCII 97. 59 = 97 - 48 )
49 -
DUP 0 < IF EXIT THEN ( bad )
DUP 0< IF EXIT THEN ( bad )
DUP 6 < IF 10 + EXIT THEN ( good )
( bad )
255 -
@ -31,24 +31,23 @@
2+
( validate slen )
DUP SLEN ( a l )
DUP 0 = IF DROP 0 EXIT THEN ( a 0 )
DUP NOT IF DROP 0 EXIT THEN ( a 0 )
4 > IF DROP 0 EXIT THEN ( a 0 )
0 ( a r )
0 ( a r )
BEGIN
OVER C@
DUP 0 = IF DROP SWAP DROP 1 EXIT THEN ( r, 1 )
hexdig ( a r n )
DUP 0 < IF DROP DROP 1 EXIT THEN ( a 0 )
SWAP 16 * + ( a r*16+n )
SWAP 1+ SWAP ( a+1 r )
SWAP C@+ ( r a+1 c )
DUP NOT IF 2DROP 1 EXIT THEN ( r, 1 )
_ ( r a n )
DUP 0< IF ROT 2DROP 0 EXIT THEN ( a 0 )
ROT 16 * + ( a r*16+n )
AGAIN
;
( returns negative value on error )
: bindig ( c -- n )
: _ ( c -- n )
( '0' is ASCII 48 )
48 -
DUP 0 < IF EXIT THEN ( bad )
DUP 0< IF EXIT THEN ( bad )
DUP 2 < IF EXIT THEN ( good )
( bad )
255 -
@ -65,12 +64,11 @@
16 > IF DROP 0 EXIT THEN ( a 0 )
0 ( a r )
BEGIN
OVER C@
DUP 0 = IF DROP SWAP DROP 1 EXIT THEN ( r, 1 )
bindig ( a r n )
DUP 0 < IF DROP DROP 1 EXIT THEN ( a 0 )
SWAP 2 * + ( a r*2+n )
SWAP 1+ SWAP ( a+1 r )
SWAP C@+ ( r a+1 c )
DUP NOT IF 2DROP 1 EXIT THEN ( r 1 )
_ ( r a n )
DUP 0< IF ROT 2DROP 0 EXIT THEN ( a 0 )
ROT 2 * + ( a r*2+n )
AGAIN
;