; ;============================================================================= ; SD DISK DRIVER ;============================================================================= ; ; - CATER FOR THE VARIOUS SDCARD HARDWARE VERSIONS ; CSIO IS FOR N8-2312 PRODUCTION BOARDS AND MODIFIED N8-2511 PROTOTYPE BOARDS ; RTC IS FOR UNMODIFIED N8-2511 BOARDS AND N8VEM/ZETA USING JUHA MINI-BOARDS ; PPISD IS FOR A PPISD MINI-BOARD CONNECTED TO 26-PIN PPI HEADER ; - MAKE RTC A PSEUDO-REGISTER FOR NON-CSIO ; - PERFORM BOOT INITIALIZATION OF RTC SOMEWHERE ELSE??? ; - PUT RELEVANT RTC BITS TO A KNOWN STATE AT ALL I/O ENTRY POINTS ; ; CONTROL BITS ; #IF (PLATFORM==PLT_N8) SD_CS .EQU $04 ; RTC BIT 2, SD CARD SELECT (ACTIVE HI) #IF (!SDCSIO) SD_CLK .EQU $02 ; RTC BIT 1, SD CLOCK SD_DOUT .EQU $01 ; RTC BIT 0, SD DATA OUT SD_DIN .EQU $40 ; RTC BIT 6, SD DATA IN #ENDIF #ELSE #IF (PPISD) SD_CS .EQU $10 ; PC4, SD CARD SELECT (ACTIVE LO) SD_CLK .EQU $02 ; PC1, SD CLOCK SD_DOUT .EQU $01 ; PC0, SD DATA OUT SD_DIN .EQU $80 ; PB7, SD DATA IN #ELSE SD_CS .EQU $04 ; RTC BIT 2, SD CARD SELECT (ACTIVE HI) SD_CLK .EQU $40 ; RTC BIT 6, SD CLOCK SD_DOUT .EQU $80 ; RTC BIT 7, DATA OUT TO SD-CARD SD_DIN .EQU $40 ; RTC BIT 6, DATA IN FROM SD-CARD #ENDIF #ENDIF ;#IF (!SDCSIO) ;#IF (PLATFORM = PLT_N8) ;SD_CS .EQU $04 ; RTC BIT 2, SD CARD SELECT ;SD_CLK .EQU $02 ; RTC BIT 1, SD CLOCK ;SD_DOUT .EQU $01 ; RTC BIT 0, SD DATA OUT ;SD_DIN .EQU $40 ; RTC BIT 6, SD DATA IN ;#ELSE ; Zeta or Z80-SBC MK II ;SD_CS .EQU $04 ; RTC BIT 2, SD CARD SELECT ;SD_CLK .EQU $40 ; RTC BIT 6, SD CLOCK ;SD_DOUT .EQU $80 ; RTC BIT 7, DATA OUT TO SD-CARD ;SD_DIN .EQU $40 ; RTC BIT 6, DATA IN FROM SD-CARD ;#ENDIF ;#ENDIF ; ; SD CARD COMMANDS ; SD_CMD0 .EQU $40 | 0 ; GO_IDLE_STATE SD_CMD1 .EQU $40 | 1 ; SEND_OP_COND SD_CMD8 .EQU $40 | 8 ; SEND_IF_COND SD_CMD9 .EQU $40 | 9 ; SEND_CSD SD_CMD10 .EQU $40 | 10 ; SEND_CID SD_CMD16 .EQU $40 | 16 ; SET_BLOCKLEN SD_CMD17 .EQU $40 | 17 ; READ_SINGLE_BLOCK SD_CMD24 .EQU $40 | 24 ; WRITE_BLOCK SD_CMD55 .EQU $40 | 55 ; APP_CMD SD_CMD58 .EQU $40 | 58 ; READ_OCR ; SD APPLICATION SPECIFIC COMMANDS SD_ACMD41 .EQU $40 | 41 ; SD_APP_OP_COND ; ; SD CARD TYPE ; SD_TYPEUNK .EQU 0 SD_TYPEMMC .EQU 1 SD_TYPESDSC .EQU 2 SD_TYPESDHC .EQU 3 ; ; ; SD_DISPATCH: LD A,B ; GET REQUESTED FUNCTION AND $0F JR Z,SD_READ DEC A JR Z,SD_WRITE DEC A JR Z,SD_STATUS DEC A JR Z,SD_MEDIA CALL PANIC ; ; ; SD_MEDIA: ; INITIALIZE THE SD CARD TO ACCOMMODATE HOT SWAPPING CALL SD_INITCARD LD A,MID_NONE ; ASSUME FAILURE RET NZ ; INIT FAILED, RETURN WITH HL=0 ; SET READY AND RETURN XOR A LD (SD_STAT),A ; SD_STAT = 0 = OK LD A,MID_HD RET ; SD_INIT: PRTS("SD:$") LD A,20H ; PUT RTC LATCH TO IDLE OUT (RTC),A #IF (PPISD) LD A,82H ; PPI PORT A=OUT, B=IN, C=OUT OUT (PPIX),A LD A,30H ; PC4,5 /CS HIGH OUT (PPIC),A #ENDIF XOR A DEC A LD (SD_STAT),A RET ; SD_STATUS: LD A,(SD_STAT) OR A RET ; SD_READ: JP SD_RDSEC ; SD_WRITE: JP SD_WRSEC ; ;============================================================================= ; SD INTERFACE ROUTINES ;============================================================================= ; ; SD_SENDCLKS: A=RTC MASK, B=# OF CLK TRANSITIONS ; For bit bang versions B is number of transitions ; For PPISD B is number of bits ; For CSIO B is number of bytes SD_SENDCLKS: #IF (!SDCSIO) #IF (PPISD) LD A,03 ;PC1=1, TOGGLE CLOCK OUT (PPIX),A NOP LD A,02 ;PC1=0, RESET CLOCK OUT (PPIX),A #ELSE OUT (RTC),A XOR SD_CLK ; TOGGLE CLOCK BIT #ENDIF DJNZ SD_SENDCLKS RET #ELSE SD_SENDCLKS1: CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING LD A,0FFH OUT0 (CPU_TRDR),A ; put byte in buffer IN0 A,(CPU_CNTR) SET 4,A ; set transmit enable OUT0 (CPU_CNTR),A DJNZ SD_SENDCLKS RET SD_WAITTX: ; WAIT FOR TX EMPTY IN0 A,(CPU_CNTR) ; get CSIO status BIT 4,A ; Tx empty? JR NZ,SD_WAITTX RET SD_WAITRX: IN0 A,(CPU_CNTR) ; wait for receiver to finish BIT 5,A JR NZ,SD_WAITRX RET #ENDIF ; ; COMPLETE A TRANSACTION - PRESERVE AF ; SD_DONE: PUSH AF #IF (!SDCSIO) #IF (PPISD) LD A,30H OUT (PPIC),A ;PC4=1 /CS INACTIVE LD B,16 #ELSE XOR A LD B,17 #ENDIF CALL SD_SENDCLKS #ELSE CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING IN A,(RTC) AND ~SD_CS ; CLEAR CS OUT (RTC),A LD B,2 CALL SD_SENDCLKS #ENDIF POP AF RET ; ; SEND ONE BYTE ; SD_PUT: #IF (PPISD) ; CALL PRTHEXBYTE ; *DEBUG* LD C,A ; C=BYTE TO SEND LD B,8 ; SEND 8 BITS (LOOP 8 TIMES) LD A,08H ;PC4=0, /CS ACTIVE OUT (PPIX),A SD_PUT1: RL C ;ROTATE NEXT BIT FROM C INTO CF LD A,01 ;PC0=1, DATA OUT=1 JR C,SD_PUT2 LD A,00 ;PC0=0, DATA OUT =0 SD_PUT2: OUT (PPIX),A ;SEND DATA OUT LD A,03 ;PC1=1, TOGGLE CLOCK OUT (PPIX),A LD A,02 ;PC1=0, RESET CLOCK OUT (PPIX),A DJNZ SD_PUT1 ;REPEAT FOR ALL 8 BITS RET #ELSE #IF (!SDCSIO) ; CALL PRTHEXBYTE ; *DEBUG* LD C,A ; C=BYTE TO SEND LD B,8 ; SEND 8 BITS (LOOP 8 TIMES) SD_PUT1: #IF (PLATFORM=PLT_N8) LD A,2 ; SD_CS >> 1 (SD_CS WILL BE SET AFTER ROTATE) RL C ; ROTATE NEXT BIT FROM C INTO CF RLA ; ROTATE CF INTO A:0, SD_DOUT is RTC:0 #ELSE LD A,8 ; SD_CS WILL BE IN BIT2 AFTER ROTATE RL C ; ROTATE NEXT BIT FROM C INTO CF RRA ; ROTATE CARRY INTO A:7, SD_DOUT is RTC:7 #ENDIF OUT (RTC),A ; CLOCK LOW (ABOUT TO SEND BIT) OR SD_CLK ; SET CLOCK BIT OUT (RTC),A ; CLOCK HIGH (SEND BIT) DJNZ SD_PUT1 ; REPEAT FOR ALL 8 BITS AND ~SD_CLK ; RESET CLOCK OUT (RTC),A ; LEAVE WITH CLOCK LOW RET #ELSE CALL MIRROR ; MSB<-->LSB mirror bits, result in C CALL SD_WAITRX ; MAKE SURE WE ARE DONE SENDING OUT0 (CPU_TRDR),C ; put byte in buffer IN0 A,(CPU_CNTR) SET 4,A ; set transmit enable OUT0 (CPU_CNTR),A RET ; let it do the rest #ENDIF #ENDIF ; ; RECEIVE ONE BYTE ; SD_GET: #IF (PPISD) LD B,8 ; RECEIVE 8 BITS (LOOP 8 TIMES) SD_GET1: IN A,(PPIB) ; GET BIT FROM SD-CARD RLA ; ROTATE PB7 INTO CARRY RL C ; ROTATE CARRY INTO C LD A,03 ; PC1=1, TOGGLE CLOCK OUT (PPIX),A LD A,02 ; PC1=0, RESET CLOCK OUT (PPIX),A DJNZ SD_GET1 ; REPEAT FOR ALL 8 BITS LD A,C ; GET BYTE RECEIVED INTO A ; CALL PRTHEXBYTE ; *DEBUG* RET #ELSE #IF (!SDCSIO) LD B,8 ; RECEIVE 8 BITS (LOOP 8 TIMES) SD_GET1: IN A,(RTC) ; GET RTC BITS RLA ; ROTATE RTC:6 (SD_IN) INTO CF RLA RL C ; ROTATE CF INTO C:0 LD A,SD_CS | SD_DOUT | SD_CLK OUT (RTC),A ; CLOCK HIGH (ACK BIT RECEIVED) AND ~SD_CLK ; RESET CLOCK BIT OUT (RTC),A ; CLOCK LOW (READY FOR NEXT BIT) DJNZ SD_GET1 ; REPEAT FOR ALL 8 BITS LD A,C ; GET BYTE RECEIVED INTO A ; CALL PRTHEXBYTE ; *DEBUG* RET #ELSE CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING IN0 A,(CPU_CNTR) ; get CSIO status SET 5,A ; start receiver OUT0 (CPU_CNTR),A CALL SD_WAITRX IN0 A,(CPU_TRDR) ; get received byte CALL MIRROR ; MSB<-->LSB mirror bits LD A,C ; keep result RET #ENDIF #ENDIF #IF (SDCSIO) MIRROR: ; MSB<-->LSB mirror bits in A, result in C #IF (!SDCSIOFAST) ; slow speed, least code space LD B,8 ; bit counter MIRROR1: RLA ; rotate bit 7 into carry RR C ; rotate carry into result DJNZ MIRROR1 ; do all 8 bits RET #ELSE ; fastest but uses most code space LD BC,MIRTAB ; 256 byte mirror table ADD A,C ; add offset LD C,A JR NC,MIRROR2 INC B MIRROR2: LD A,(BC) ; get result LD C,A ; return result in C RET #ENDIF #ENDIF ; ; SELECT CARD AND WAIT FOR IT TO BE READY ($FF) ; SD_WAITRDY: #IF (PPISD) LD A,21H ;/CS ACTIVE (PC4), DOUT=1 (PC0) OUT (PPIC),A #ELSE IN A,(RTC) #IF (!SDCSIO) OR SD_CS | SD_DOUT ; SET SD_CS (CHIP SELECT) #ELSE CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING OR SD_CS ; SET SD_CS (CHIP SELECT) #ENDIF OUT (RTC),A #ENDIF LD DE,0 ; LOOP MAX (TIMEOUT) SD_WAITRDY1: ; CALL PC_SPACE ; *DEBUG* CALL SD_GET ; CALL PRTHEXBYTE ; *DEBUG* ; XOR A ; *DEBUG* TO SIMULATE READY TIMEOUT INC A ; $FF -> $00 RET Z ; IF READY, RETURN DEC DE LD A,D OR E JR NZ,SD_WAITRDY1 ; KEEP TRYING UNTIL TIMEOUT LD A,$FF ; SIGNAL TIMEOUT ERROR OR A ; SET FLAGS RET ; TIMEOUT ; ; SD_GETDATA ; SD_GETDATA: PUSH BC ; SAVE LENGTH TO RECEIVE LD DE,$7FFF ; LOOP MAX (TIMEOUT) SD_GETDATA1: CALL SD_GET CP $FF ; WANT BYTE != $FF JR NZ,SD_GETDATA2 ; NOT $FF, MOVE ON DEC DE BIT 7,D JR Z,SD_GETDATA1 ; KEEP TRYING UNTIL TIMEOUT SD_GETDATA2: LD (SD_TOK),A POP DE ; RESTORE LENGTH TO RECEIVE CP $FE ; PACKET START? JR NZ,SD_GETDATA4 ; NOPE, ABORT, A HAS ERROR CODE LD HL,(DIOBUF) ; RECEIVE BUFFER SD_GETDATA3: CALL SD_GET ; GET NEXT BYTE LD (HL),A ; SAVE IT INC HL DEC DE LD A,D OR E JR NZ,SD_GETDATA3 ; LOOP FOR ALL BYTES CALL SD_GET ; DISCARD CRC BYTE 1 CALL SD_GET ; DISCARD CRC BYTE 2 XOR A ; RESULT IS ZERO SD_GETDATA4: RET ; ; SD_PUTDATA ; SD_PUTDATA: PUSH BC ; SAVE LENGTH TO SEND LD A,$FE ; PACKET START CALL SD_PUT ; SEND IT POP DE ; RESTORE LENGTH TO SEND LD HL,(DIOBUF) ; RECEIVE BUFFER SD_PUTDATA1: LD A,(HL) ; GET NEXT BYTE TO SEND CALL SD_PUT ; SEND IF INC HL DEC DE LD A,D OR E JR NZ,SD_PUTDATA1 ; LOOP FOR ALL BYTES LD A,$FF ; DUMMY CRC BYTE CALL SD_PUT LD A,$FF ; DUMMY CRC BYTE CALL SD_PUT LD DE,$7FFF ; LOOP MAX (TIMEOUT) SD_PUTDATA2: CALL SD_GET CP $FF ; WANT BYTE != $FF JR NZ,SD_PUTDATA3 ; NOT $FF, MOVE ON DEC DE BIT 7,D JR Z,SD_PUTDATA2 ; KEEP TRYING UNTIL TIMEOUT SD_PUTDATA3: AND $1F LD (SD_TOK),A CP $05 RET NZ XOR A RET ; ; SETUP COMMAND BUFFER ; SD_SETCMD0: ; NO PARMS LD HL,SD_CMDBUF LD (HL),A INC HL XOR A LD (HL),A INC HL LD (HL),A INC HL LD (HL),A INC HL LD (HL),A INC HL LD A,$FF LD (HL),A RET ; SD_SETCMDP: ; W/ PARMS IN BC & DE CALL SD_SETCMD0 LD HL,SD_CMDP0 LD (HL),B INC HL LD (HL),C INC HL LD (HL),D INC HL LD (HL),E RET ; ; EXECUTE A SD CARD COMMAND ; SD_EXEC: XOR A LD (SD_RC),A LD (SD_TOK),A LD HL,SD_CMDBUF LD E,6 ; COMMANDS ARE 6 BYTES SD_EXEC1: #IF (SDCSIO) CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING IN A,(RTC) OR SD_CS ; SET CS OUT (RTC),A #ENDIF LD A,(HL) CALL SD_PUT INC HL DEC E JR NZ,SD_EXEC1 LD DE,$100 ; LOOP MAX (TIMEOUT) SD_EXEC2: CALL SD_GET OR A ; SET FLAGS JP P,SD_EXEC3 ; IF HIGH BIT IS 0, WE HAVE RESULT DEC DE BIT 7,D JR Z,SD_EXEC2 SD_EXEC3: LD (SD_RC),A #IF (SDTRACE >= 2) CALL SD_PRTTRN #ENDIF #IF (DSKYENABLE) CALL SD_DSKY #ENDIF RET ; SD_EXECCMD0: ; EXEC COMMAND, NO PARMS CALL SD_SETCMD0 JR SD_EXEC ; SD_EXECCMDP: ; EXEC CMD W/ PARMS IN BC/DE CALL SD_SETCMDP JR SD_EXEC ; ; PUT CARD IN IDLE STATE ; SD_GOIDLE: ; SMALL DELAY HERE HELPS SOME CARDS LD DE,200 ; 5 MILISECONDS CALL VDELAY ; PUT CARD IN IDLE STATE LD A,SD_CMD0 ; CMD0 = ENTER IDLE STATE CALL SD_SETCMD0 LD A,$95 LD (SD_CMDBUF+5),A ; SET CRC=$95 CALL SD_EXEC ; EXEC CMD CP $01 ; IN IDLE STATE? CALL SD_DONE RET ; ; INIT CARD ; SD_INITCARD: #IF (PPISD) LD A,82H ; PPI PORT A=OUT, B=IN, C=OUT OUT (PPIX),A LD A,30H ; PC4,5 /CS HIGH OUT (PPIC),A #ENDIF LD A,20H ; PUT RTC LATCH TO IDLE OUT (RTC),A #IF (SDCSIO) ; CSIO SETUP ; LD A,02 ; 18MHz/20 <= 400kHz LD A,06 ; ??? OUT0 (CPU_CNTR),A #ENDIF CALL SD_DONE ; SEEMS TO HELP SOME CARDS... #IF (!SDCSIO) #IF (PPISD) LD A,21H ; /CS=0, DOUT=1, CLK=0 OUT (PPIC),A LD B,07FH ; 127 CLOCKS (255 TRANSITIONS STARTING WITH LO) #ELSE LD A,SD_CS | SD_DOUT ; CS=HI, DOUT=HI LD B,0FFH ; 127 CLOCKS (255 TRANSITIONS STARTING WITH LO) #ENDIF #ELSE CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING IN A,(RTC) OR SD_CS ; SET CS OUT (RTC),A LD B,16 #ENDIF CALL SD_SENDCLKS ; INIT DELAY + GO SPI MODE ; WAIT FOR CARD TO BE READY FOR A COMMAND CALL SD_WAITRDY JP NZ,SD_ERRRDYTO ; PUT CARD IN IDLE STATE CALL SD_GOIDLE CALL NZ,SD_GOIDLE ; SOME CARDS REQUIRE A SECOND ATTEMPT JP NZ,SD_ERRCMD ; GIVE UP SD_INITCARD00: LD A,SD_TYPESDSC ; ASSUME SDSC CARD TYPE LD (SD_TYPE),A ; SAVE IT ; CMD8 IS REQUIRED FOR V2 CARDS. FAILURE HERE IS OK AND ; JUST MEANS THAT IT IS A V1.X CARD LD A,SD_CMD8 LD BC,0 LD D,1 ; VHS=1, 2.7-3.6V LD E,$AA ; CHECK PATTERN CALL SD_SETCMDP LD A,$87 LD (SD_CMDBUF+5),A ; SET CRC=$87 CALL SD_EXEC ; EXEC CMD AND ~$01 JR NZ,SD_INITCARD0 ; CMD8 WORKED, SO THIS IS V2 CARD ; NEED TO CONSUME EXTRA CMD8 RESPONSE BYTES (4) CALL SD_GET CALL SD_GET CALL SD_GET CALL SD_GET SD_INITCARD0: CALL SD_DONE LD B,0 ; LOOP LIMIT (TIMEOUT) SD_INITCARD1: ; CALL SD_APP_OP_COND UNTIL CARD IS READY (NOT IDLE) LD DE,200 ; 5 MILLISECONDS CALL VDELAY LD A,SD_CMD55 ; APP CMD IS NEXT PUSH BC CALL SD_EXECCMD0 POP BC AND ~$01 ; ONLY 0 (OK) OR 1 (IDLE) ARE OK CALL SD_DONE JP NZ,SD_ERRCMD LD A,SD_ACMD41 ; SD_APP_OP_COND PUSH BC LD BC,$4000 ; INDICATE WE SUPPORT HC LD DE,$0000 CALL SD_EXECCMDP POP BC PUSH AF AND ~$01 CALL SD_DONE POP AF ; LD A,$01 ; *DEBUG* TO SIMULATE INIT TIMEOUT ERROR CP $00 ; INIT DONE? JR Z,SD_INITCARD2 ; YUP, MOVE ON CP $01 ; IDLE? JP NZ,SD_ERRCMD ; NOPE, MUST BE CMD ERROR, ABORT DJNZ SD_INITCARD1 ; KEEP CHECKING LD A,$FF ; SIGNAL TIMEOUT OR A JP SD_ERRINITTO SD_INITCARD2: ; CMD58 RETURNS THE 32 BIT OCR REGISTER, WE WANT TO CHECK ; BIT 30, IF SET THIS IS SDHC/XC CARD LD A,SD_CMD58 CALL SD_EXECCMD0 CALL NZ,SD_DONE JP NZ,SD_ERRCMD ; CMD58 WORKED, GET OCR DATA AND SET CARD TYPE CALL SD_GET ; BITS 31-24 AND $40 ; ISOLATE BIT 30 (CCS) JR Z,SD_INITCARD21 ; NOT HC/XC, BYPASS LD A,SD_TYPESDHC ; CARD TYPE = SDHC LD (SD_TYPE),A ; SAVE IT SD_INITCARD21: CALL SD_GET ; BITS 23-16, DISCARD CALL SD_GET ; BITS 15-8, DISCARD CALL SD_GET ; BITS 7-0, DISCARD CALL SD_DONE ; SET OUR DESIRED BLOCK LENGTH (512 BYTES) LD A,SD_CMD16 ; SET_BLOCK_LEN LD BC,0 LD DE,512 CALL SD_EXECCMDP CALL SD_DONE JP NZ,SD_ERRCMD #IF (SDTRACE >= 2) CALL NEWLINE LD DE,SDSTR_SDTYPE CALL WRITESTR LD A,(SD_TYPE) CALL PRTHEXBYTE #ENDIF ; RET NZ ; IF ERROR, ABORT NOW WITH A SET CORRECTLY #IF (SDCSIO) CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING XOR A ; NOW SET CSIO PORT TO FULL SPEED OUT (CPU_CNTR),A #ENDIF XOR A ; A = 0 (STATUS = OK) LD (SD_STAT),A ; SAVE IT RET ; RETURN WITH A=0, AND Z SET ;; ;; GET AND PRINT CSD, CID ;; ;SD_CARDINFO: ; LD A,SD_CMD9 ; SEND_CSD ; CALL SD_EXECCMD0 ; CALL SD_DONE ; JP NZ,SD_ERRCMD ; ABORT IF PROBLEM ; LD BC,16 ; 16 BYTES OF CSD ; CALL SD_GETDATA ; CALL SD_DONE ; ; LD DE,SDSTR_CSD ; CALL WRITESTR ; LD DE,SECBUF ; LD A,16 ; CALL PRTHEXBUF ; ; LD A,SD_CMD10 ; SEND_CID ; CALL SD_EXECCMD0 ; CALL SD_DONE ; JP NZ,SD_ERRCMD ; ABORT IF PROBLEM ; LD BC,16 ; 16 BYTES OF CID ; CALL SD_GETDATA ; CALL SD_DONE ; ; LD DE,SDSTR_CID ; CALL WRITESTR ; LD DE,SECBUF ; LD A,16 ; CALL PRTHEXBUF ; ; RET ; ; READ ONE SECTOR ; ; ; CHECK THE SD CARD, ATTEMPT TO REINITIALIZE IF NEEDED ; SD_CHKCARD: LD A,(SD_STAT) ; GET STATUS OR A ; SET FLAGS CALL NZ,SD_INITCARD ; INIT CARD IF NOT READY RET ; RETURN WITH STATUS IN A SD_RDSEC: CALL SD_CHKCARD ; CHECK / REINIT CARD AS NEEDED RET NZ CALL SD_WAITRDY ; WAIT FOR CARD TO BE READY FOR A COMMAND JP NZ,SD_ERRRDYTO ; HANDLE NOT READY TIMEOUT ERROR CALL SD_SETADDR ; SETUP BLOCK ADDRESS LD A,SD_CMD17 ; READ_SINGLE_BLOCK CALL SD_EXECCMDP ; EXEC CMD WITH BLOCK ADDRESS AS PARM CALL NZ,SD_DONE ; TRANSACTION DONE IF ERROR OCCURRED JP NZ,SD_ERRCMD ; ABORT ON ERROR LD BC,512 ; LENGTH TO READ CALL SD_GETDATA ; GET THE BLOCK CALL SD_DONE JP NZ,SD_ERRDATA ; DATA XFER ERROR RET ; ; WRITE ONE SECTOR ; SD_WRSEC: CALL SD_CHKCARD ; CHECK / REINIT CARD AS NEEDED RET NZ CALL SD_WAITRDY ; WAIT FOR CARD TO BE READY FOR A COMMAND JP NZ,SD_ERRRDYTO ; HANDLE NOT READY TIMEOUT ERROR CALL SD_SETADDR ; SETUP BLOCK ADDRESS LD A,SD_CMD24 ; WRITE_BLOCK CALL SD_EXECCMDP ; EXEC CMD WITH BLOCK ADDRESS AS PARM CALL NZ,SD_DONE ; TRANSACTION DONE IF ERROR OCCURRED JP NZ,SD_ERRCMD ; ABORT ON ERROR LD BC,512 ; LENGTH TO WRITE CALL SD_PUTDATA ; PUT THE BLOCK CALL SD_DONE JP NZ,SD_ERRDATA ; DATA XFER ERROR RET ; ; ; SD_SETADDR: LD A,(SD_TYPE) CP SD_TYPESDSC JR Z,SD_SETADDRSDSC CP SD_TYPESDHC JR Z,SD_SETADDRSDHC CALL PANIC SD_SETADDRSDSC: LD HL,(HSTSEC) LD E,0 LD D,L LD HL,(HSTTRK) LD C,L LD B,H XOR A RL D RL C RL B RET SD_SETADDRSDHC: LD A,(HSTSEC) ; GET SECTOR (LSB ONLY) LD E,A ; PUT IN E LD HL,(HSTTRK) ; GET TRACK LD D,L ; TRACK LSB -> D LD C,H ; TRACK MSB -> C LD B,0 ; B ALWAYS ZERO RET ; ; HANDLE READY TIMEOUT ERROR ; SD_ERRRDYTO: #IF (SDTRACE >= 1) CALL SD_PRTPREFIX LD DE,SDSTR_ERRRDYTO #ENDIF JR SD_CARDERR ; ; HANDLE INIT TIMEOUT ERROR ; SD_ERRINITTO: #IF (SDTRACE >= 1) CALL SD_PRTPREFIX LD DE,SDSTR_ERRINITTO #ENDIF JR SD_CARDERR ; ; HANDLE COMMAND ERROR ; SD_ERRCMD: #IF (SDTRACE == 1) CALL SD_PRTTRN #ENDIF #IF (SDTRACE >= 1) LD DE,SDSTR_ERRCMD #ENDIF JR SD_CARDERR ; ; HANDLE COMMAND ERROR ; SD_ERRDATA: #IF (SDTRACE == 1) CALL SD_PRTTRN #ENDIF #IF (SDTRACE >= 1) LD DE,SDSTR_ERRDATA #ENDIF JR SD_CARDERR ; ; GENERIC ERROR HANDLER, DE POINTS TO ERROR STRING ; SD_CARDERR: PUSH AF XOR A DEC A LD A,FALSE LD (SD_STAT),A #IF (SDTRACE >= 1) CALL PC_SPACE CALL PC_LBKT CALL WRITESTR CALL PC_RBKT #ENDIF POP AF LD (SD_STAT),A RET ; ; PRINT DIAGNONSTIC PREFIX ; SD_PRTPREFIX: CALL NEWLINE LD DE,SDSTR_PREFIX CALL WRITESTR RET ; ; PRT COMMAND TRACE ; SD_PRTTRN: PUSH AF CALL SD_PRTPREFIX LD DE,SD_CMDBUF LD A,6 CALL PRTHEXBUF CALL PC_SPACE LD DE,SDSTR_ARROW CALL WRITESTR CALL PC_SPACE LD DE,SDSTR_RC CALL WRITESTR LD A,(SD_RC) CALL PRTHEXBYTE CALL PC_SPACE LD DE,SDSTR_TOK CALL WRITESTR LD A,(SD_TOK) CALL PRTHEXBYTE POP AF RET ; ; DISPLAY COMMAND, LOW ORDER WORD OF PARMS, AND RC ; #IF (DSKYENABLE) SD_DSKY: PUSH AF LD HL,DSKY_HEXBUF LD A,(SD_CMD) LD (HL),A INC HL LD A,(SD_CMDP2) LD (HL),A INC HL LD A,(SD_CMDP3) LD (HL),A INC HL LD A,(SD_RC) CALL DSKY_HEXOUT POP AF RET #ENDIF ; ; ; #IF (SDCSIOFAST) MIRTAB: .DB 00H, 80H, 40H, 0C0H, 20H, 0A0H, 60H, 0E0H, 10H, 90H, 50H, 0D0H, 30H, 0B0H, 70H, 0F0H .DB 08H, 88H, 48H, 0C8H, 28H, 0A8H, 68H, 0E8H, 18H, 98H, 58H, 0D8H, 38H, 0B8H, 78H, 0F8H .DB 04H, 84H, 44H, 0C4H, 24H, 0A4H, 64H, 0E4H, 14H, 94H, 54H, 0D4H, 34H, 0B4H, 74H, 0F4H .DB 0CH, 8CH, 4CH, 0CCH, 2CH, 0ACH, 6CH, 0ECH, 1CH, 9CH, 5CH, 0DCH, 3CH, 0BCH, 7CH, 0FCH .DB 02H, 82H, 42H, 0C2H, 22H, 0A2H, 62H, 0E2H, 12H, 92H, 52H, 0D2H, 32H, 0B2H, 72H, 0F2H .DB 0AH, 8AH, 4AH, 0CAH, 2AH, 0AAH, 6AH, 0EAH, 1AH, 9AH, 5AH, 0DAH, 3AH, 0BAH, 7AH, 0FAH .DB 06H, 86H, 46H, 0C6H, 26H, 0A6H, 66H, 0E6H, 16H, 96H, 56H, 0D6H, 36H, 0B6H, 76H, 0F6H .DB 0EH, 8EH, 4EH, 0CEH, 2EH, 0AEH, 6EH, 0EEH, 1EH, 9EH, 5EH, 0DEH, 3EH, 0BEH, 7EH, 0FEH .DB 01H, 81H, 41H, 0C1H, 21H, 0A1H, 61H, 0E1H, 11H, 91H, 51H, 0D1H, 31H, 0B1H, 71H, 0F1H .DB 09H, 89H, 49H, 0C9H, 29H, 0A9H, 69H, 0E9H, 19H, 99H, 59H, 0D9H, 39H, 0B9H, 79H, 0F9H .DB 05H, 85H, 45H, 0C5H, 25H, 0A5H, 65H, 0E5H, 15H, 95H, 55H, 0D5H, 35H, 0B5H, 75H, 0F5H .DB 0DH, 8DH, 4DH, 0CDH, 2DH, 0ADH, 6DH, 0EDH, 1DH, 9DH, 5DH, 0DDH, 3DH, 0BDH, 7DH, 0FDH .DB 03H, 83H, 43H, 0C3H, 23H, 0A3H, 63H, 0E3H, 13H, 93H, 53H, 0D3H, 33H, 0B3H, 73H, 0F3H .DB 0BH, 8BH, 4BH, 0CBH, 2BH, 0ABH, 6BH, 0EBH, 1BH, 9BH, 5BH, 0DBH, 3BH, 0BBH, 7BH, 0FBH .DB 07H, 87H, 47H, 0C7H, 27H, 0A7H, 67H, 0E7H, 17H, 97H, 57H, 0D7H, 37H, 0B7H, 77H, 0F7H .DB 0FH, 8FH, 4FH, 0CFH, 2FH, 0AFH, 6FH, 0EFH, 1FH, 9FH, 5FH, 0DFH, 3FH, 0BFH, 7FH, 0FFH #ENDIF ; ; ; SDSTR_PREFIX .TEXT "SD:$" SDSTR_ARROW .TEXT "-->$" SDSTR_RC .TEXT "RC=$" SDSTR_TOK .TEXT "TOK=$" SDSTR_OK .TEXT "OK$" SDSTR_ERR .TEXT "ERR$" SDSTR_ERRRDYTO .TEXT "READY TIMEOUT$" SDSTR_ERRINITTO .TEXT "INIT TIMEOUT$" SDSTR_ERRCMD .TEXT "CMD ERR$" SDSTR_ERRDATA .TEXT "DATA ERR$" SDSTR_SDTYPE .TEXT "SD CARD TYPE: $" ; ;================================================================================================== ; SD DISK DRIVER - DATA ;================================================================================================== ; SD_STAT .DB 0 SD_TYPE .DB 0 SD_RC .DB 0 SD_TOK .DB 0 SD_CMDBUF .EQU $ SD_CMD .DB 0 SD_CMDP0 .DB 0 SD_CMDP1 .DB 0 SD_CMDP2 .DB 0 SD_CMDP3 .DB 0 SD_CMDCRC .DB 0