Forth source code for 1802 MMC / SD interface

for testing/experimenting purposes i found it useful to include a constant, 'xfrlen', which limits the number of bytes which will be read into or out of cpu memory by the card read/write routines

this value would normally be 200h for the default card block length size, but it can be reduced for testing purposes

re-instate the commented-out line beginning '
( 200 xfrlen -' in the definitions for 'mrd' & 'mwr' if you wish to vary xfrlen:

 -  a full block of data must always be written to the card when using the card Block Write command, so if xfrlen is set to less than the current card block size then the write routine must supply 'fill' bytes to make up the correct length data transfer

 - similarly, the read routine would need to issue sufficient dummy read byte calls to consume any remaining data sent by the card

(the MMC standard includes the ability to change the default block length used in card data read/write transfers - however, some card manufacturers use a fixed block size so i have not included the Set Block Length command in this software)


i have included below an optional definition which issues an MMC command to read the card specific data (including max. storage size of card, default block length, etc) and also an alternative method for defining the three Forth low-level code definitions, if a Forth assembler is not available

if you have a Forth system running on your 1802 and you want to try out the  MMC / SD card interface described on this site, the source code below can be cut-and-pasted from this HTML page into a text file to customise the code and edit out the notes before producing the input format required for your system

documentation is provided on the main MMC card interface page

PLEASE NOTE:
since Forth is something of a 'write-only' language, ahead even of 'C' (but light-years behind 'APL'!) i have tried to keep the obscurity to a minimum for general consumption - these listings are given as a guide only

feel free to improve the 'Forth factor' to your own satisfaction


hex
200 constant xfrlen           ( card default block size )

0 variable cmd  here 2- dp !  ( command buffer )       
40 c, 00 c, 00 c, 00 c, 00 c, 95 c,

code spi  ( tx_byte -> rx_byte )
 rb pop,          ( pop top of stack into rb )
 00 ldi  rd phi  rd plo
 08 ldi  rc plo
 here
  rb glo  shl  rb plo
  here 04 + bdf  req  skp  seq
  rd glo  shl
  here 04 + b3  01 ori  rd plo
  s dec  03 out   ( stack 's' is 'X' reg, set to r3 on HHC )
  rc dec  rc glo
 bnz
 rd push,         ( push rd onto top of stack )
 next
end-code

code N6  ( -> )
 s dec  6 out  next
end-code

code N7  ( -> )
 s dec  7 out  next
end-code

: ccs0 ( -> )
  N7  0FF spi drop ;

: ccs1 ( -> )
  N6  0FF spi drop ;

: mmc ( command madr_lo madr_hi -> response )
  cmd  swap over 1+ !  swap over 3 + !
  swap 40 or swap c!  cmd 6 + cmd
  do  i c@ spi drop  loop  8 0
  do  spi dup 0FF = not
   if  leave  then
  loop ;

: mini ( -> )
  ccs1  0A 0 do  0FF spi drop  loop
  ccs0  0 0 0 mmc  dup 01 =
  if  8 0
   do  drop  1 0 0 mmc  dup 00 =
    if  leave  then
   loop  ?dup if  ." mmc init err:" . abort  then
  else  ." mmc reset err:" . abort
  then  ccs1 ;

: mrd ( madr_lo  madr_hi  adr  -> ) ;
  ccs0  rot rot  11 rot rot mmc  dup
  if  ." mrd err:" . abort
  else  ( 0 )  8 0
   do  0FF spi 0FE =
    if  drop 1 leave  then
   loop
   if  xfrlen over + swap
    do  0FF spi i c!  loop
    ( 200 xfrlen - 0 do  0FF spi drop  loop )
    0FF spi drop  0FF spi drop
   else ." mrd timeout" abort
   then
  then  ccs1 ;

: mwr ( adr  madr_lo  madr_hi  -> )
  ccs0  18 rot rot mmc  dup
  if  ." mwr err:" . abort
  else  drop  0FF spi drop  0FE spi drop
   xfrlen over + swap
   do  i c@ spi drop  loop
   ( 200 xfrlen - 0 do  0FF spi drop  loop )
   0FF spi drop  0FF spi drop
   0  4 0
   do  0FF spi 0F and 5 =
    if  drop 1 leave  then
   loop
   if  80 0 do  0FF spi if  leave  then  loop
   else  ." mwr failed" abort
   then
  then  ccs1 ;

: b>ad ( blk  ->  madr_lo  madr_hi )
  400 u* ;

: brd ( mblk  bfr  -> )
  buffer >r b>ad 
  over over r@ mrd
  200 0 d+ r> 200 + mrd ;

: bwr ( bfr  mblk  -> )
  >r buffer dup 200 + 
  r@ b>ad 200 0 d+ mwr
  r> b>ad mwr ;

\ ==========================================

\ optional command to read card specific data
\  - after initialising card using 'mini' above,
\  use 'cd csd' to read csd from card into buffer

\ variable cd  0e allot
\ (16 byte buffer for csd info from card)

\: csd ( bfr_adr -> )
\  ccs0  9 0 0 mmc  dup
\  if  ." csd err:" . abort
\  else  ( 0 )  8 0
\   do  0FF spi 0FE =
\    if  drop 1 leave  then
\   loop
\   if  10 over + swap
\    do  0FF spi i c!  loop
\    0FF spi drop  0FF spi drop
\   else  ." csd timeout" abort
\   then
\  then ccs1 ;

\ ==========================================

\ if you don't have a Forth 1802 assembler,
\ you can customise the definitions below

\ you will need to check which registers
\ are free to use, swap in your preferred
\ parameter passing method and the code that
\ is required to return to the Forth
\ inner interpreter; then replace the 
\ relevant bytes below with your
\ hand-compiled code values 

\ variable spi  here 2- dp !      ( reset dp to PFA of spi )
\  72 c, 0BB c, 72 c, 0AB c,      ( rb pop, )
\  0F8 c, 00 c, 0BD c, 0AD c,     (
00 ldi  rd phi  rd plo )
\  0F8 c, 08 c, 0AC c,            ( 08 ldi  rc plo )
\  here                           ( here )
\   8B c, 0FE c, 0AB c,           ( rb glo  shl  rb plo )
\   here 4 + 33 c, c,             ( here 04 + bdf )
\    7A c, 38 c, 7B c,            ( req  skp  seq )
\   8D c, 0FE c,                  ( rd glo  shl )
\   here 4 + 36 c, c,             ( here 04 + b3 )
\    0F9 c, 01 c, 0AD c,          ( 01 ori  rd plo )
\   23 c, 63 c, 2c c, 8C c,       ( s dec  03 out  rc dec  rc glo )
\  3A c, c,                       ( bnz )
\  23 c, 8D c, 73 c, 9D c, 53 c,  ( rd push, )
\  0D8 c,                         ( next is 'sep r8' on HHC )
\ spi spi 2- !                    ( point CFA of spi to code start ) 

\ variable N6  here 2- dp !
\  23 c, 66 c, 0D8 c,             ( s dec  6 out  next )
\ N6 N6 2- !

\ variable N7  here 2- dp !
\  23 c, 67 c, 0D8 c,             ( s dec  7 out  next )
\ N7 N7 2- !