mirror of https://github.com/wwarthen/RomWBW.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1376 lines
32 KiB
1376 lines
32 KiB
;
|
|
;=============================================================================
|
|
; SD/SDHC/SDXC CARD STORAGE DRIVER
|
|
;=============================================================================
|
|
;
|
|
;------------------------------------------------------------------------------
|
|
; SD Signal Active JUHA N8 CSIO PPI UART DSD MK4
|
|
; ------------ ------- ------- ------- ------- ------- ------- ------- -------
|
|
; CS (DAT3) LO -> RTC:2 RTC:2 RTC:2 ~PC:4 ~MCR:3 OPR:2 MK4_SD:2
|
|
; CLK HI -> RTC:1 RTC:1 N/A PC:1 ~MCR:2 OPR:1 N/A
|
|
; DI (CMD) HI -> RTC:0 RTC:0 N/A PC:0 ~MCR:0 OPR:0 N/A
|
|
; DO (DAT0) HI -> RTC:7 RTC:6 N/A PB:7 ~MSR:5 OPR:0 N/A
|
|
;------------------------------------------------------------------------------
|
|
;
|
|
; CS = CHIP SELECT (AKA DAT3 FOR NON-SPI MODE)
|
|
; CLK = CLOCK
|
|
; DI = DATA IN (HOST -> CARD, AKA CMD FOR NON-SPI MODE)
|
|
; DO = DATA OUT (HOST <- CARD, AKA DAT0 FOR NON-SPI MODE)
|
|
;
|
|
; NOTES:
|
|
; 1) SIGNAL NAMES ARE FROM THE SD CARD SPEC AND ARE NAMED FROM THE
|
|
; PERSPECTIVE OF THE SD CARD:
|
|
; DI = DATA IN: HOST -> CARD = MOSI (MASTER OUT/SLAVE IN)
|
|
; DO = DATA OUT: HOST <- CARD = MISO (MASTER IN/SLAVE OUT)
|
|
;
|
|
; 2) THE QUIESCENT STATE OF THE OUTPUT SIGNALS (HOST -> CARD) IS:
|
|
; CS = HI (NOT SELECTED)
|
|
; CLK = LO (HI FOR CSIO)
|
|
; DI = HI (ACTIVE IS THE NATURAL/DEFAULT STATE FOR DATA IN)
|
|
;
|
|
; 3) SPI MODE 0 IMPLEMENTATION IS USED (CPOL=0, CPHA=0)
|
|
; THE DATA MUST BE AVAILABLE BEFORE THE FIRST CLOCK SIGNAL RISING.
|
|
; THE CLOCK IDLE STATE IS ZERO. THE DATA ON MISO AND MOSI LINES
|
|
; MUST BE STABLE WHILE THE CLOCK IS HIGH AND CAN BE CHANGED WHEN
|
|
; THE CLOCK IS LOW. THE DATA IS CAPTURED ON THE CLOCK'S LOW-TO-HIGH
|
|
; TRANSITION AND PROPAGATED ON HIGH-TO-LOW CLOCK TRANSITION.
|
|
;
|
|
; NOTE: THE CSIO IMPLEMENTATION (INCLUDE MK4) USES SPI MODE 4
|
|
; (CPOL=1, CPHA=1) BECAUSE THAT IS THE WAY THAT THE Z180 CSIO
|
|
; INTERFACE WORKS. ALL OF THE CLOCK TRANSITIONS LISTED ABOVE
|
|
; ARE REVERSED FOR CSIO.
|
|
;
|
|
; 4) DI SHOULD BE LEFT HI (ACTIVE) WHENEVER UNUSED (FOR EXAMPLE, WHEN
|
|
; HOST IS RECEIVING DATA (HOST <- CARD)).
|
|
;
|
|
#IF (SDMODE == SDMODE_JUHA) ; JUHA MINI-BOARD
|
|
SD_UNITCNT .EQU 1 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_OPRREG .EQU RTC ; USES RTC LATCHES FOR OPERATION
|
|
SD_OPRDEF .EQU %00000001 ; QUIESCENT STATE???
|
|
SD_INPREG .EQU RTC ; INPUT REGISTER IS RTC
|
|
SD_CS .EQU %00000100 ; RTC:2 IS SELECT
|
|
SD_CLK .EQU %00000010 ; RTC:1 IS CLOCK
|
|
SD_DI .EQU %00000001 ; RTC:0 IS DATA IN (CARD <- CPU)
|
|
SD_DO .EQU %10000000 ; RTC:7 IS DATA OUT (CARD -> CPU)
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_N8) ; UNMODIFIED N8-2511
|
|
SD_UNITCNT .EQU 1 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_OPRREG .EQU RTC ; USES RTC LATCHES FOR OPERATION
|
|
SD_OPRDEF .EQU %00000001 ; QUIESCENT STATE???
|
|
SD_INPREG .EQU RTC ; INPUT REGISTER IS RTC
|
|
SD_CS .EQU %00000100 ; RTC:2 IS SELECT
|
|
SD_CLK .EQU %00000010 ; RTC:1 IS CLOCK
|
|
SD_DI .EQU %00000001 ; RTC:0 IS DATA IN (CARD <- CPU)
|
|
SD_DO .EQU %01000000 ; RTC:6 IS DATA OUT (CARD -> CPU)
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_CSIO) ; N8-2312
|
|
SD_UNITCNT .EQU 1 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_OPRREG .EQU RTC ; USES RTC LATCHES FOR OPERATION
|
|
SD_OPRDEF .EQU %00000000 ; QUIESCENT STATE
|
|
SD_CS .EQU %00000100 ; RTC:2 IS SELECT
|
|
SD_CNTR .EQU CPU_CNTR
|
|
SD_TRDR .EQU CPU_TRDR
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_PPI) ; PPISD
|
|
SD_UNITCNT .EQU 1 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_PPIBASE .EQU PPIBASE ; BASE IO PORT FOR PPI
|
|
SD_PPIB .EQU PPIBASE + 1 ; PPI PORT B (INPUT: DOUT)
|
|
SD_PPIC .EQU PPIBASE + 2 ; PPI PORT C (OUTPUT: CS, CLK, DIN)
|
|
SD_PPIX .EQU PPIBASE + 3 ; PPI CONTROL PORT
|
|
SD_OPRREG .EQU SD_PPIC ; PPI PORT C IS OPR REG
|
|
SD_OPRDEF .EQU %00110001 ; CS HI, DI HI
|
|
SD_INPREG .EQU SD_PPIB ; INPUT REGISTER IS PPI PORT B
|
|
SD_CS .EQU %00010000 ; PPIC:4 IS SELECT
|
|
SD_CLK .EQU %00000010 ; PPIC:1 IS CLOCK
|
|
SD_DI .EQU %00000001 ; PPIC:0 IS DATA IN (CARD <- CPU)
|
|
SD_DO .EQU %10000000 ; PPIB:7 IS DATA OUT (CARD -> CPU)
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_UART)
|
|
SD_UNITCNT .EQU 1 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_OPRREG .EQU SIO_MCR ; UART MCR PORT (OUTPUT: CS, CLK, DIN)
|
|
SD_OPRDEF .EQU %00001100 ; QUIESCENT STATE
|
|
SD_INPREG .EQU SIO_MSR ; INPUT REGISTER IS MSR
|
|
SD_CS .EQU %00001000 ; UART MCR:3 IS SELECT
|
|
SD_CLK .EQU %00000100 ; UART MCR:2 IS CLOCK
|
|
SD_DI .EQU %00000001 ; UART MCR:0 IS DATA IN (CARD <- CPU)
|
|
SD_DO .EQU %00100000 ; UART MSR:5 IS DATA OUT (CARD -> CPU)
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_DSD) ; DUAL SD
|
|
SD_UNITCNT .EQU 2 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_OPRREG .EQU $08 ; DEDICATED OPERATIONS REGISTER
|
|
SD_OPRDEF .EQU %00000001 ; QUIESCENT STATE
|
|
SD_INPREG .EQU SD_OPRREG ; INPUT REGISTER IS OPRREG
|
|
SD_SELREG .EQU SD_OPRREG + 1 ; DEDICATED SELECTION REGISTER
|
|
SD_SELDEF .EQU %00000000 ; SELECTION REGISTER DEFAULT
|
|
SD_CS .EQU %00000100 ; RTC:2 IS SELECT
|
|
SD_CLK .EQU %00000010 ; RTC:1 IS CLOCK
|
|
SD_DI .EQU %00000001 ; RTC:6 IS DATA IN (CARD <- CPU)
|
|
SD_DO .EQU %00000001 ; RTC:0 IS DATA OUT (CARD -> CPU)
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_MK4) ; MARK IV (CSIO STYLE INTERFACE)
|
|
SD_UNITCNT .EQU 1 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_OPRREG .EQU MK4_SD ; DEDICATED MK4 SDCARD REGISTER
|
|
SD_OPRDEF .EQU %00000000 ; QUIESCENT STATE
|
|
SD_CS .EQU %00000100 ; SELECT ACTIVE
|
|
SD_CNTR .EQU CPU_CNTR
|
|
SD_TRDR .EQU CPU_TRDR
|
|
#ENDIF
|
|
;
|
|
; SD CARD COMMANDS
|
|
;
|
|
SD_CMD0 .EQU $40 | 0 ; 0x40, GO_IDLE_STATE
|
|
SD_CMD1 .EQU $40 | 1 ; 0x41, SEND_OP_COND
|
|
SD_CMD8 .EQU $40 | 8 ; 0x48, SEND_IF_COND
|
|
SD_CMD9 .EQU $40 | 9 ; 0x49, SEND_CSD
|
|
SD_CMD10 .EQU $40 | 10 ; 0x4A, SEND_CID
|
|
SD_CMD16 .EQU $40 | 16 ; 0x50, SET_BLOCKLEN
|
|
SD_CMD17 .EQU $40 | 17 ; 0x51, READ_SINGLE_BLOCK
|
|
SD_CMD24 .EQU $40 | 24 ; 0x58, WRITE_BLOCK
|
|
SD_CMD55 .EQU $40 | 55 ; 0x77, APP_CMD
|
|
SD_CMD58 .EQU $40 | 58 ; 0x7A, READ_OCR
|
|
; SD APPLICATION SPECIFIC COMMANDS
|
|
SD_ACMD41 .EQU $40 | 41 ; 0x69, SD_APP_OP_COND
|
|
;
|
|
; SD CARD TYPE
|
|
;
|
|
SD_TYPEUNK .EQU 0 ; CARD TYPE UNKNOWN/UNDETERMINED
|
|
SD_TYPEMMC .EQU 1 ; MULTIMEDIA CARD (MMC STANDARD)
|
|
SD_TYPESDSC .EQU 2 ; SDSC CARD (V1)
|
|
SD_TYPESDHC .EQU 3 ; SDHC/SDXC CARD (V2)
|
|
;
|
|
; SD CARD STATUS (SD_STAT)
|
|
;
|
|
SD_STOK .EQU 0 ; OK
|
|
SD_STNOTRDY .EQU -1 ; NOT READY (INITIALIZATION PENDING)
|
|
SD_STRDYTO .EQU -2 ; TIMEOUT WAITING FOR CARD TO BE READY
|
|
SD_STINITTO .EQU -3 ; INITIALIZATOIN TIMEOUT
|
|
SD_STCMDTO .EQU -4 ; TIMEOUT WAITING FOR COMMAND RESPONSE
|
|
SD_STCMDERR .EQU -5 ; COMMAND ERROR OCCURRED (REF SD_RC)
|
|
SD_STDATAERR .EQU -6 ; DATA ERROR OCCURRED (REF SD_TOK)
|
|
SD_STDATATO .EQU -7 ; DATA TRANSFER TIMEOUT
|
|
SD_STCRCERR .EQU -8 ; CRC ERROR ON RECEIVED DATA PACKET
|
|
SD_STNOMEDIA .EQU -9 ; NO MEDIA IN CONNECTOR
|
|
SD_STWRTPROT .EQU -10 ; ATTEMPT TO WRITE TO WRITE PROTECTED MEDIA
|
|
;
|
|
;
|
|
;
|
|
SD_DISPATCH:
|
|
LD A,B ; GET REQUESTED FUNCTION
|
|
AND $0F
|
|
JP Z,SD_READ
|
|
DEC A
|
|
JP Z,SD_WRITE
|
|
DEC A
|
|
JP Z,SD_STATUS
|
|
DEC A
|
|
JP Z,SD_MEDIA
|
|
CALL PANIC
|
|
;
|
|
;
|
|
;
|
|
SD_MEDIA:
|
|
CALL SD_SELUNIT
|
|
;
|
|
; INITIALIZE THE SD CARD TO ACCOMMODATE HOT SWAPPING
|
|
CALL SD_INITCARD
|
|
LD A,MID_HD ; ASSUME SUCCESS
|
|
RET Z ; RETURN IF GOOD INIT
|
|
CALL SD_PRT
|
|
LD A,MID_NONE ; IF FAILURE, RETURN NO MEDIA
|
|
RET
|
|
;
|
|
SD_INIT:
|
|
PRTS("SD:$")
|
|
PRTS(" UNITS=$")
|
|
LD A,SD_UNITCNT
|
|
CALL PRTHEXBYTE
|
|
#IF (SDMODE == SDMODE_JUHA)
|
|
PRTS(" MODE=JUHA$")
|
|
PRTS(" IO=0x$")
|
|
LD A,SD_OPRREG
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_N8)
|
|
PRTS(" MODE=N8$")
|
|
PRTS(" IO=0x$")
|
|
LD A,SD_OPRREG
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_CSIO)
|
|
PRTS(" MODE=CSIO$")
|
|
#IF (SDCSIOFAST)
|
|
PRTS(" FAST$")
|
|
#ENDIF
|
|
PRTS(" OPR=0x$")
|
|
LD A,SD_OPRREG
|
|
CALL PRTHEXBYTE
|
|
PRTS(" CNTR=0x$")
|
|
LD A,SD_CNTR
|
|
CALL PRTHEXBYTE
|
|
PRTS(" TRDR=0x$")
|
|
LD A,SD_TRDR
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_PPI)
|
|
PRTS(" MODE=PPI$")
|
|
PRTS(" BASEIO=0x$")
|
|
LD A,SD_PPIBASE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_UART)
|
|
PRTS(" MODE=UART$")
|
|
PRTS(" MCR=0x$")
|
|
LD A,SIO_MCR
|
|
CALL PRTHEXBYTE
|
|
PRTS(" MSR=0x$")
|
|
LD A,SIO_MSR
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_DSD)
|
|
PRTS(" MODE=DSD$")
|
|
PRTS(" OPR=0x$")
|
|
LD A,SD_OPRREG
|
|
CALL PRTHEXBYTE
|
|
PRTS(" SEL=0x$")
|
|
LD A,SD_SELREG
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_MK4)
|
|
PRTS(" MODE=MK4$")
|
|
#IF (SDCSIOFAST)
|
|
PRTS(" FAST$")
|
|
#ENDIF
|
|
PRTS(" OPR=0x$")
|
|
LD A,SD_OPRREG
|
|
CALL PRTHEXBYTE
|
|
PRTS(" CNTR=0x$")
|
|
LD A,SD_CNTR
|
|
CALL PRTHEXBYTE
|
|
PRTS(" TRDR=0x$")
|
|
LD A,SD_TRDR
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
LD A,SD_STNOTRDY
|
|
LD HL,SD_STATLST
|
|
LD (SD_STATPTR),HL
|
|
LD (HL),A
|
|
INC HL
|
|
LD (HL),A
|
|
LD A,SD_TYPEUNK
|
|
LD HL,SD_TYPELST
|
|
LD (SD_TYPEPTR),HL
|
|
LD (HL),A
|
|
INC HL
|
|
LD (HL),A
|
|
;
|
|
LD B,SD_UNITCNT
|
|
LD C,0
|
|
SD_INIT1:
|
|
PUSH BC
|
|
CALL SD_SELUNIT
|
|
CALL SD_INITCARD
|
|
CALL SD_PRT
|
|
CALL Z,SD_PRTINFO
|
|
POP BC
|
|
INC C
|
|
DJNZ SD_INIT1
|
|
;
|
|
RET
|
|
;
|
|
SD_STATUS:
|
|
CALL SD_SELUNIT
|
|
LD HL,(SD_STATPTR)
|
|
LD A,(HL)
|
|
OR A
|
|
RET
|
|
;
|
|
SD_READ:
|
|
CALL SD_SELUNIT
|
|
CALL SD_RDSEC
|
|
JR SD_PRT
|
|
;
|
|
SD_WRITE:
|
|
CALL SD_SELUNIT
|
|
CALL SD_CHKWP
|
|
CALL NZ,SD_WRTPROT
|
|
CALL Z,SD_WRSEC
|
|
JR SD_PRT
|
|
;
|
|
SD_PRT:
|
|
#IF (SDTRACE >= 1)
|
|
RET Z
|
|
PUSH AF
|
|
CALL SD_PRTPREFIX
|
|
CALL PC_SPACE
|
|
CALL SD_PRTSTAT
|
|
POP AF
|
|
#ENDIF
|
|
RET
|
|
;
|
|
;=============================================================================
|
|
; SD HARDWARE INTERFACE ROUTINES
|
|
;=============================================================================
|
|
;
|
|
; TAKE ANY ACTIONS REQUIRED TO SELECT DESIRED PHYSICAL UNIT
|
|
;
|
|
SD_SELUNIT:
|
|
LD A,C
|
|
AND 0FH ; ISOLATE THE UNIT NIBBLE
|
|
CP SD_UNITCNT ; CHECK VALIDITY (EXCEED UNIT COUNT?)
|
|
CALL NC,PANIC ; PANIC ON INVALID VALUE
|
|
LD (SD_UNIT),A ; SAVE CURRENT UNIT NUM
|
|
#IF (SDMODE == SDMODE_DSD)
|
|
; SELECT REQUESTED UNIT
|
|
OUT (SD_SELREG),A ; ACTUALLY SELECT THE CARD
|
|
#ENDIF
|
|
LD HL,SD_STATLST ; POINT TO START OF STATUS LIST
|
|
LD D,0 ; SETUP DE TO HAVE OFFSET
|
|
LD E,A ; FOR CURRENT UNIT
|
|
ADD HL,DE ; APPLY THE OFFSET
|
|
LD (SD_STATPTR),HL ; SAVE IT
|
|
LD HL,SD_TYPELST ; POINT TO START OF CARD TYPE LIST
|
|
ADD HL,DE ; APPLY THE OFFSET
|
|
LD (SD_TYPEPTR),HL ; SAVE IT
|
|
RET
|
|
;
|
|
; PERFORM HARDWARE SPECIFIC INITIALIZATION
|
|
;
|
|
SD_SETUP:
|
|
;
|
|
#IF ((SDMODE == SDMODE_JUHA) | (SDMODE == SDMODE_N8) | (SDMODE == SDMODE_DSD))
|
|
LD A,SD_OPRDEF
|
|
LD (SD_OPRVAL),A
|
|
OUT (SD_OPRREG),A
|
|
#ENDIF
|
|
;
|
|
#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4))
|
|
; CSIO SETUP
|
|
; LD A,2 ; 18MHz/20 <= 400kHz
|
|
LD A,6 ; ???
|
|
OUT0 (SD_CNTR),A
|
|
LD A,SD_OPRDEF
|
|
LD (SD_OPRVAL),A
|
|
OUT (SD_OPRREG),A
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_PPI)
|
|
LD A,82H ; PPI PORT A=OUT, B=IN, C=OUT
|
|
OUT (PPIX),A
|
|
LD A,SD_OPRDEF
|
|
LD (SD_OPRVAL),A
|
|
OUT (SD_OPRREG),A
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_UART)
|
|
SD_OPRMSK .EQU (SD_CS | SD_CLK | SD_DI)
|
|
IN A,(SD_OPRREG) ; OPRREG == SIO_MCR
|
|
AND ~SD_OPRMSK ; MASK OFF SD CONTROL BITS
|
|
OR SD_OPRDEF ; SET DEFAULT BITS
|
|
LD (SD_OPRVAL),A ; RECORD THE WORKING VALLUE
|
|
OUT (SD_OPRREG),A ; OPRREG == SIO_MCR
|
|
#ENDIF
|
|
;
|
|
#IF ((SDMODE == SDMODE_DSD) | (SDMODE == SDMODE_MK4))
|
|
IN A,(SD_OPRREG)
|
|
BIT 5,A ; CARD DETECT
|
|
JP Z,SD_NOMEDIA ; NO MEDIA DETECTED
|
|
#ENDIF
|
|
;
|
|
XOR A
|
|
RET
|
|
;
|
|
; SELECT CARD
|
|
;
|
|
SD_SELECT:
|
|
LD A,(SD_OPRVAL)
|
|
#IF ((SDMODE == SDMODE_PPI) | (SDMODE == SDMODE_UART))
|
|
AND ~SD_CS ; SET SD_CS (CHIP SELECT)
|
|
#ELSE
|
|
OR SD_CS ; SET SD_CS (CHIP SELECT)
|
|
#ENDIF
|
|
LD (SD_OPRVAL),A
|
|
OUT (SD_OPRREG),A
|
|
RET
|
|
;
|
|
; DESELECT CARD
|
|
;
|
|
SD_DESELECT:
|
|
LD A,(SD_OPRVAL)
|
|
#IF ((SDMODE == SDMODE_PPI) | (SDMODE == SDMODE_UART))
|
|
OR SD_CS ; RESET SD_CS (CHIP SELECT)
|
|
#ELSE
|
|
AND ~SD_CS ; RESET SD_CS (CHIP SELECT)
|
|
#ENDIF
|
|
LD (SD_OPRVAL),A
|
|
OUT (SD_OPRREG),A
|
|
RET
|
|
;
|
|
; CHECK FOR WRITE PROTECT (NZ = WRITE PROTECTED)
|
|
;
|
|
SD_CHKWP:
|
|
#IF ((SDMODE == SDMODE_DSD) | (SDMODE == SDMODE_MK4))
|
|
IN A,(SD_OPRREG)
|
|
BIT 4,A
|
|
#ELSE
|
|
XOR A
|
|
#ENDIF
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4))
|
|
SD_WAITTX: ; WAIT FOR TX EMPTY
|
|
IN0 A,(SD_CNTR) ; GET CSIO STATUS
|
|
BIT 4,A ; TX EMPTY?
|
|
JR NZ,SD_WAITTX
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
SD_WAITRX:
|
|
IN0 A,(SD_CNTR) ; WAIT FOR RECEIVER TO FINISH
|
|
BIT 5,A
|
|
JR NZ,SD_WAITRX
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
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
|
|
;
|
|
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
|
|
;
|
|
; SEND ONE BYTE
|
|
;
|
|
SD_PUT:
|
|
#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4))
|
|
CALL MIRROR ; MSB<-->LSB MIRROR BITS, RESULT IN C
|
|
CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING
|
|
OUT0 (SD_TRDR),C ; PUT BYTE IN BUFFER
|
|
IN0 A,(SD_CNTR)
|
|
SET 4,A ; SET TRANSMIT ENABLE
|
|
OUT0 (SD_CNTR),A
|
|
#ELSE
|
|
#IF (SDMODE == SDMODE_UART)
|
|
XOR $FF ; DI IS INVERTED ON UART
|
|
#ENDIF
|
|
LD C,A ; C=BYTE TO SEND
|
|
LD B,8 ; SEND 8 BITS (LOOP 8 TIMES)
|
|
LD A,(SD_OPRVAL) ; LOAD CURRENT OPR VALUE
|
|
SD_PUT1:
|
|
RRA ; PREPARE TO GET DATA BIT FROM CF
|
|
RL C ; ROTATE NEXT BIT FROM C INTO CF
|
|
RLA ; ROTATE CF INTO A:0, SD_DO is OPR:0
|
|
OUT (SD_OPRREG),A ; ASSERT DATA BIT
|
|
XOR SD_CLK ; TOGGLE CLOCK
|
|
OUT (SD_OPRREG),A ; UPDATE CLOCK AND ASSERT DATA BIT
|
|
XOR SD_CLK ; TOGGLE CLOCK
|
|
OUT (SD_OPRREG),A ; UPDATE CLOCK
|
|
DJNZ SD_PUT1 ; REPEAT FOR ALL 8 BITS
|
|
LD A,(SD_OPRVAL) ; LOAD CURRENT OPR VALUE
|
|
OUT (SD_OPRREG),A ; LEAVE WITH CLOCK LOW
|
|
#ENDIF
|
|
RET ; DONE
|
|
;
|
|
; RECEIVE ONE BYTE
|
|
;
|
|
SD_GET:
|
|
#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4))
|
|
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
|
|
#ELSE
|
|
LD B,8 ; RECEIVE 8 BITS (LOOP 8 TIMES)
|
|
LD A,(SD_OPRVAL) ; LOAD CURRENT OPR VALUE
|
|
SD_GET1:
|
|
XOR SD_CLK ; TOGGLE CLOCK
|
|
OUT (SD_OPRREG),A ; UPDATE CLOCK
|
|
IN A,(SD_INPREG) ; READ THE DATA WHILE CLOCK IS ACTIVE
|
|
#IF ((SDMODE == SDMODE_JUHA) | (SDMODE == SDMODE_PPI))
|
|
RLA ; ROTATE INP:7 INTO CF
|
|
#ENDIF
|
|
#IF (SDMODE == SDMODE_N8)
|
|
RLA ; ROTATE INP:6 INTO CF
|
|
RLA ; "
|
|
#ENDIF
|
|
#IF (SDMODE == SDMODE_UART)
|
|
RLA ; ROTATE INP:5 INTO CF
|
|
RLA ; "
|
|
RLA ; "
|
|
#ENDIF
|
|
#IF (SDMODE == SDMODE_DSD)
|
|
RRA ; ROTATE INP:0 INTO CF
|
|
#ENDIF
|
|
RL C ; ROTATE CF INTO C:0
|
|
LD A,(SD_OPRVAL) ; BACK TO INITIAL VALUES (TOGGLE CLOCK)
|
|
OUT (SD_OPRREG),A ; DO IT
|
|
DJNZ SD_GET1 ; REPEAT FOR ALL 8 BITS
|
|
LD A,C ; GET BYTE RECEIVED INTO A
|
|
#IF (SDMODE == SDMODE_UART)
|
|
XOR $FF ; DO IS INVERTED ON UART
|
|
#ENDIF
|
|
#ENDIF
|
|
RET
|
|
;
|
|
;==================================================================================================
|
|
; SD DISK DRIVER PROTOCOL IMPLEMENTATION
|
|
;==================================================================================================
|
|
;
|
|
; SELECT CARD AND WAIT FOR IT TO BE READY ($FF)
|
|
;
|
|
SD_WAITRDY:
|
|
CALL SD_SELECT ; SELECT CARD
|
|
LD DE,0 ; LOOP MAX (TIMEOUT)
|
|
SD_WAITRDY1:
|
|
CALL SD_GET
|
|
INC A ; $FF -> $00
|
|
RET Z ; IF READY, RETURN
|
|
DEC DE
|
|
LD A,D
|
|
OR E
|
|
JR NZ,SD_WAITRDY1 ; KEEP TRYING UNTIL TIMEOUT
|
|
XOR A ; ZERO ACCUM
|
|
DEC A ; ACCUM := $FF TO SIGNAL ERROR
|
|
RET ; TIMEOUT
|
|
;
|
|
; COMPLETE A TRANSACTION - PRESERVE AF
|
|
;
|
|
SD_DONE:
|
|
PUSH AF
|
|
CALL SD_DESELECT
|
|
LD A,$FF
|
|
CALL SD_PUT
|
|
POP AF
|
|
RET
|
|
;
|
|
; SD_GETDATA
|
|
;
|
|
SD_GETDATA:
|
|
PUSH HL ; SAVE DESTINATION ADDRESS
|
|
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
|
|
POP HL ; RECOVER DEST ADDRESS
|
|
CP $FE ; PACKET START?
|
|
JR NZ,SD_GETDATA4 ; NOPE, ABORT, A HAS ERROR CODE
|
|
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 HL ; SAVE SOURCE ADDRESS
|
|
PUSH BC ; SAVE LENGTH TO SEND
|
|
|
|
LD A,$FE ; PACKET START
|
|
CALL SD_PUT ; SEND IT
|
|
|
|
POP DE ; RECOVER LENGTH TO SEND
|
|
POP HL ; RECOVER SOURCE ADDRESS
|
|
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:
|
|
CALL SD_WAITRDY
|
|
JP NZ,SD_ERRRDYTO ; RETURN VIA READY TIMEOUT HANDLER
|
|
XOR A
|
|
LD (SD_RC),A
|
|
LD (SD_TOK),A
|
|
LD HL,SD_CMDBUF
|
|
LD E,6 ; COMMANDS ARE 6 BYTES
|
|
SD_EXEC1:
|
|
LD A,(HL)
|
|
CALL SD_PUT
|
|
INC HL
|
|
DEC E
|
|
JR NZ,SD_EXEC1
|
|
LD DE,$100 ; LOOP MAX (TIMEOUT)
|
|
;LD DE,$8000 ; *DEBUG*
|
|
SD_EXEC2:
|
|
CALL SD_GET
|
|
;CALL PRTHEXBYTE ; *DEBUG*
|
|
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
|
|
;LD (SD_RC),A ; *DEBUG*
|
|
;CALL SD_PRTTRN ; *DEBUG*
|
|
JP SD_ERRCMDTO
|
|
SD_EXEC3:
|
|
LD (SD_RC),A
|
|
#IF (SDTRACE >= 2)
|
|
CALL SD_PRTTRN
|
|
#ENDIF
|
|
#IF (DSKYENABLE)
|
|
CALL SD_DSKY
|
|
#ENDIF
|
|
OR A
|
|
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:
|
|
;CALL SD_DONE ; SEEMS TO HELP SOME CARDS...
|
|
|
|
; 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
|
|
CALL SD_DONE ; SIGNAL COMMAND COMPLETE
|
|
JP P,SD_GOIDLE1 ; VALID RESULT, CHECK IT
|
|
CALL SD_EXEC ; 2ND TRY
|
|
CALL SD_DONE ; SIGNAL COMMAND COMPLETE
|
|
RET M ; COMMAND FAILED
|
|
;
|
|
SD_GOIDLE1: ; COMMAND OK, CHECK FOR EXPECTED RESULT
|
|
DEC A ; MAP EXPECTED $01 -> $00
|
|
RET Z ; IF $00, ALL GOOD, RETURN
|
|
JP SD_ERRCMD ; OTHERWISE, HANDLE COMMAND ERROR
|
|
;
|
|
; INIT CARD
|
|
;
|
|
SD_INITCARD:
|
|
CALL SD_SETUP ; DO HARDWARE SETUP/INIT
|
|
RET NZ
|
|
;
|
|
; WAKE UP THE CARD, KEEP DIN HI (ASSERTED) AND /CS HI (DEASSERTED)
|
|
LD B,$10 ; MIN 74 CLOCKS REQUIRED, WE USE 128 ($10 * 8)
|
|
SD_INITCARD000:
|
|
LD A,$FF
|
|
PUSH BC
|
|
CALL SD_PUT
|
|
POP BC
|
|
DJNZ SD_INITCARD000
|
|
|
|
;CALL SD_SELECT
|
|
|
|
; PUT CARD IN IDLE STATE
|
|
CALL SD_GOIDLE
|
|
RET NZ ; FAILED
|
|
|
|
SD_INITCARD00:
|
|
LD A,SD_TYPESDSC ; ASSUME SDSC CARD TYPE
|
|
LD HL,(SD_TYPEPTR) ; LOAD THE CARD TYPE ADDRESS
|
|
LD (HL),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
|
|
CALL M,SD_DONE ; CLOSE COMMAND IF ERROR
|
|
RET M ; ABORT DUE TO PROCESSING ERROR
|
|
AND ~$01 ; IGNORE BIT 0 (IDLE)
|
|
JR NZ,SD_INITCARD0 ; CMD RESULT ERR, SKIP AHEAD
|
|
|
|
; CMD8 WORKED, NEED TO CONSUME CMD8 RESPONSE BYTES (4)
|
|
CALL SD_GET
|
|
CALL SD_GET
|
|
CALL SD_GET
|
|
CALL SD_GET
|
|
|
|
SD_INITCARD0:
|
|
CALL SD_DONE
|
|
|
|
LD A,0
|
|
LD (SD_LCNT),A
|
|
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
|
|
CALL SD_EXECCMD0
|
|
CALL SD_DONE
|
|
RET M ; ABORT ON PROCESSING ERROR
|
|
AND ~$01 ; ONLY 0 (OK) OR 1 (IDLE) ARE OK
|
|
JP NZ,SD_ERRCMD
|
|
LD A,SD_ACMD41 ; SD_APP_OP_COND
|
|
LD BC,$4000 ; INDICATE WE SUPPORT HC
|
|
LD DE,$0000
|
|
CALL SD_EXECCMDP
|
|
CALL SD_DONE
|
|
RET M ; ABORT ON PROCESSING 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
|
|
LD HL,SD_LCNT ; POINT TO LOOP COUNTER
|
|
DEC (HL) ; DECREMENT LOOP COUNTER
|
|
JR NZ,SD_INITCARD1 ; LOOP UNTIL COUNTER EXHAUSTED
|
|
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
|
|
RET M ; ABORT ON PROCESSING ERROR
|
|
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 HL,(SD_TYPEPTR) ; LOAD THE CARD TYPE ADDRESS
|
|
LD A,SD_TYPESDHC ; CARD TYPE = SDHC
|
|
LD (HL),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
|
|
RET M ; ABORT ON PROCESSING ERROR
|
|
JP NZ,SD_ERRCMD
|
|
|
|
#IF (SDTRACE >= 2)
|
|
CALL NEWLINE
|
|
LD DE,SDSTR_SDTYPE
|
|
CALL WRITESTR
|
|
LD HL,(SD_TYPEPTR)
|
|
LD A,(HL)
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
|
|
#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4))
|
|
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 HL,(SD_STATPTR) ; LOAD STATUS ADDRESS
|
|
LD (HL),A ; SAVE IT
|
|
RET ; RETURN WITH A=0, AND Z SET
|
|
|
|
;
|
|
; GET AND PRINT CSD, CID
|
|
;
|
|
SD_PRTINFO:
|
|
CALL SD_PRTPREFIX
|
|
|
|
; PRINT CARD TYPE
|
|
PRTS(" TYPE=$")
|
|
LD HL,(SD_TYPEPTR)
|
|
LD A,(HL)
|
|
LD DE,SDSTR_TYPEMMC
|
|
CP SD_TYPEMMC
|
|
JR Z,SD_PRTINFO1
|
|
LD DE,SDSTR_TYPESDSC
|
|
CP SD_TYPESDSC
|
|
JR Z,SD_PRTINFO1
|
|
LD DE,SDSTR_TYPESDHC
|
|
CP SD_TYPESDHC
|
|
JR Z,SD_PRTINFO1
|
|
LD DE,SDSTR_TYPEUNK
|
|
SD_PRTINFO1:
|
|
CALL WRITESTR
|
|
|
|
LD A,SD_CMD10 ; SEND_CID
|
|
CALL SD_EXECCMD0
|
|
CALL NZ,SD_DONE
|
|
JP NZ,SD_ERRCMD ; ABORT IF PROBLEM
|
|
LD BC,16 ; 16 BYTES OF CID
|
|
LD HL,SD_BUF
|
|
CALL SD_GETDATA
|
|
CALL SD_DONE
|
|
|
|
#IF (SDTRACE >= 2)
|
|
CALL SD_PRTPREFIX
|
|
LD DE,SDSTR_CID
|
|
CALL WRITESTR
|
|
LD DE,SD_BUF
|
|
LD A,16
|
|
CALL PRTHEXBUF
|
|
#ENDIF
|
|
|
|
; PRINT PRODUCT NAME
|
|
PRTS(" NAME=$")
|
|
LD B,5
|
|
LD HL,SD_BUF + 3
|
|
SD_PRTINFO2:
|
|
LD A,(HL)
|
|
CALL COUT
|
|
INC HL
|
|
DJNZ SD_PRTINFO2
|
|
|
|
LD A,SD_CMD9 ; SEND_CSD
|
|
CALL SD_EXECCMD0
|
|
CALL NZ,SD_DONE
|
|
JP NZ,SD_ERRCMD ; ABORT IF PROBLEM
|
|
LD BC,16 ; 16 BYTES OF CSD
|
|
LD HL,SD_BUF
|
|
CALL SD_GETDATA
|
|
CALL SD_DONE
|
|
|
|
#IF (SDTRACE >= 2)
|
|
CALL SD_PRTPREFIX
|
|
LD DE,SDSTR_CSD
|
|
CALL WRITESTR
|
|
LD DE,SD_BUF
|
|
LD A,16
|
|
CALL PRTHEXBUF
|
|
#ENDIF
|
|
|
|
; PRINT SIZE
|
|
PRTS(" SIZE=$") ; PREFIX
|
|
PUSH IX ; SAVE IX
|
|
LD IX,SD_BUF ; POINT IX TO BUFFER
|
|
;
|
|
LD HL,(SD_TYPEPTR) ; POINT TO CARD TYPE
|
|
LD A,(HL) ; GET CARD TYPE
|
|
CP SD_TYPESDSC ; CSD V1?
|
|
JR Z,SD_PRTINFO3 ; HANDLE V1
|
|
CP SD_TYPESDHC ; CSD V2?
|
|
JR Z,SD_PRTINFO4 ; HANDLE V2
|
|
JR SD_PRTINFO6 ; UNK, CAN'T HANDLE
|
|
|
|
SD_PRTINFO3: ; PRINT SIZE FOR V1 CARD
|
|
LD A,(IX+6) ; GET C_SIZE MSB
|
|
AND %00000011 ; MASK OFF TOP 6 BITS (NOT PART OF C_SIZE)
|
|
LD C,A ; MSB -> C
|
|
LD D,(IX+7) ; D
|
|
LD E,(IX+8) ; LSB -> E
|
|
LD B,6 ; RIGHT SHIFT WHOLE THING BY 6 BITS
|
|
SD_PRTINFO3A:
|
|
SRA C ; SHIFT MSB
|
|
RR D ; SHIFT NEXT BYTE
|
|
RR E ; SHIFT LSB
|
|
DJNZ SD_PRTINFO3A ; LOOP TILL DONE
|
|
PUSH DE ; DE = C_SIZE
|
|
LD A,(IX+9) ; GET C_SIZE_MULT MSB
|
|
LD B,(IX+10) ; GET C_SIZE_MULT LSB
|
|
SLA B ; SHIFT LEFT MSB
|
|
RLA ; SHIFT LEFT LSB
|
|
AND %00000111 ; ISOLATE RELEVANT BITS
|
|
LD C,A ; C := C_SIZE_MULT
|
|
LD A,(IX+5) ; GET READ_BL_LEN
|
|
AND %00001111 ; ISLOATE RELEVANT BITS
|
|
LD B,A ; B := READ_BL_LEN
|
|
LD A,18 ; ASSUME RIGHT SHIFT OF 18
|
|
SUB B ; REDUCE BY READ_BL_LEN BITS
|
|
SUB C ; REDUCE BY C_SIZE_MULT BITS
|
|
LD B,A ; PUT IN LOOP COUNTER
|
|
POP HL ; RECOVER C_SIZE
|
|
JR Z,SD_PRTINFO5 ; HANDLE ZERO BIT SHIFT CASE
|
|
SD_PRTINFO3B:
|
|
SRA H ; SHIFT MSB
|
|
RR L ; SHIFT LSB
|
|
DJNZ SD_PRTINFO3B ; LOOP TILL DONE
|
|
JR SD_PRTINFO5 ; GO TO PRINT ROUTINE
|
|
;
|
|
SD_PRTINFO4: ; PRINT SIZE FOR V2 CARD
|
|
LD A,(IX + 7) ; GET C_SIZE MSB TO A
|
|
AND %00111111 ; ISOLATE RELEVANT BITS
|
|
LD H,(IX + 8) ; GET NEXT BYTE TO H
|
|
LD L,(IX + 9) ; GET C_SIZE LSB TO L
|
|
SRA A ; RIGHT SHIFT MSB BY ONE
|
|
RR H ; RIGHT SHIFT NEXT BYTE BY ONE
|
|
RR L ; RIGHT SHIFT LSB BY ONE
|
|
JR SD_PRTINFO5
|
|
;
|
|
SD_PRTINFO5: ; COMMON CODE TO PRINT RESULTANT SIZE (IN HL)
|
|
CALL PRTDEC ; PRINT SIZE IN DECIMAL
|
|
JR SD_PRTINFO7 ; FINISH UP
|
|
;
|
|
SD_PRTINFO6: ; UNKNOWN CARD TYPE
|
|
PRTC('?') ; UNKNOWN SIZE
|
|
;
|
|
SD_PRTINFO7:
|
|
PRTS("MB$") ; PRINT SIZE SUFFIX
|
|
POP IX ; RESTORE IX
|
|
;
|
|
CALL SD_CHKWP ; WRITE PROTECTED?
|
|
JR Z,SD_PRTINFO8 ; NOPE, BYPASS
|
|
CALL PC_SPACE ; SEPARATOR
|
|
PRTX(SDSTR_STWRTPROT) ; TELL THE USER
|
|
;
|
|
SD_PRTINFO8:
|
|
RET ; DONE
|
|
;
|
|
; CHECK THE SD CARD, ATTEMPT TO REINITIALIZE IF NEEDED
|
|
;
|
|
SD_CHKCARD:
|
|
LD HL,(SD_STATPTR) ; LOAD STATUS ADDRESS
|
|
LD A,(HL) ; 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_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
|
|
RET M ; ABORT ON PROCESSING ERROR
|
|
JP NZ,SD_ERRCMD ; FAIL IF NON-ZERO RC
|
|
|
|
LD HL,(DIOBUF)
|
|
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_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
|
|
RET M ; ABORT ON PROCESSING ERROR
|
|
JP NZ,SD_ERRCMD ; FAIL IF NON-ZERO RC
|
|
|
|
LD HL,(DIOBUF) ; SETUP DATA SOURCE ADDRESS
|
|
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 HL,(SD_TYPEPTR)
|
|
LD A,(HL)
|
|
CP SD_TYPESDSC
|
|
JR Z,SD_SETADDRSDSC
|
|
CP SD_TYPESDHC
|
|
JR Z,SD_SETADDRSDHC
|
|
CALL PANIC
|
|
|
|
;
|
|
; SDSC CARDS USE A BYTE OFFSET
|
|
;
|
|
; TT:SS = BC:DE -> TS:S0, THEN LEFT SHIFT ONE BIT
|
|
SD_SETADDRSDSC:
|
|
LD BC,(HSTTRK)
|
|
LD DE,(HSTSEC)
|
|
LD B,C
|
|
LD C,D
|
|
LD D,E
|
|
LD E,0
|
|
SLA E
|
|
RL D
|
|
RL C
|
|
RL B
|
|
RET
|
|
;
|
|
; SDHC CARDS USE SIMPLE LBA, NO TRANSLATION NEEDED
|
|
;
|
|
SD_SETADDRSDHC:
|
|
LD BC,(HSTTRK) ; LBA HIGH WORD
|
|
LD DE,(HSTSEC) ; LBA LOW WORD
|
|
RET ; DONE
|
|
;
|
|
; HANDLE READY TIMEOUT ERROR
|
|
;
|
|
SD_ERRRDYTO:
|
|
LD A,SD_STRDYTO
|
|
JR SD_CARDERR
|
|
;
|
|
SD_ERRINITTO:
|
|
LD A,SD_STINITTO
|
|
JR SD_CARDERR
|
|
;
|
|
SD_ERRCMDTO:
|
|
LD A,SD_STCMDTO
|
|
JR SD_CARDERR
|
|
;
|
|
SD_ERRCMD:
|
|
LD A,SD_STCMDERR
|
|
JR SD_CARDERR
|
|
;
|
|
SD_ERRDATA:
|
|
LD A,SD_STDATAERR
|
|
JR SD_CARDERR
|
|
;
|
|
SD_ERRDATATO:
|
|
LD A,SD_STDATATO
|
|
JR SD_CARDERR
|
|
;
|
|
SD_ERRCRC:
|
|
LD A,SD_STCRCERR
|
|
JR SD_CARDERR
|
|
;
|
|
SD_NOMEDIA:
|
|
LD A,SD_STNOMEDIA
|
|
JR SD_CARDERR
|
|
;
|
|
SD_WRTPROT:
|
|
LD A,SD_STWRTPROT
|
|
JR SD_CARDERR
|
|
;
|
|
; GENERIC ERROR HANDLER
|
|
;
|
|
SD_CARDERR:
|
|
PUSH HL ; IS THIS NEEDED?
|
|
LD HL,(SD_STATPTR)
|
|
LD (HL),A
|
|
POP HL ; IS THIS NEEDED?
|
|
#IF (SDTRACE >= 2)
|
|
CALL NEWLINE
|
|
PUSH AF ; IS THIS NEEDED?
|
|
PRTC('<')
|
|
CALL SD_PRTSTAT
|
|
PRTC('>')
|
|
POP AF ; IS THIS NEEDED?
|
|
#ENDIF
|
|
OR A
|
|
RET
|
|
;
|
|
; PRINT DIAGNONSTIC PREFIX
|
|
;
|
|
SD_PRTPREFIX:
|
|
CALL NEWLINE
|
|
LD DE,SDSTR_PREFIX
|
|
CALL WRITESTR
|
|
PUSH AF
|
|
LD A,(SD_UNIT)
|
|
ADD A,'0'
|
|
CALL COUT
|
|
POP AF
|
|
CALL PC_COLON
|
|
RET
|
|
;
|
|
; PRINT STATUS STRING
|
|
;
|
|
SD_PRTSTAT:
|
|
PUSH HL ; IS THIS NEEDED?
|
|
LD HL,(SD_STATPTR)
|
|
LD A,(HL)
|
|
POP HL ; IS THIS NEEDED?
|
|
OR A
|
|
LD DE,SDSTR_STOK
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SDSTR_STNOTRDY
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SDSTR_STRDYTO
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SDSTR_STINITTO
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SDSTR_STCMDTO
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SDSTR_STCMDERR
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SDSTR_STDATAERR
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SDSTR_STDATATO
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SDSTR_STCRCERR
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SDSTR_STNOMEDIA
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SDSTR_STWRTPROT
|
|
JR Z,SD_PRTSTAT1
|
|
LD DE,SDSTR_STUNK
|
|
;
|
|
SD_PRTSTAT1:
|
|
CALL WRITESTR
|
|
PUSH HL ; IS THIS NEEDED?
|
|
LD HL,(SD_STATPTR)
|
|
LD A,(HL)
|
|
POP HL ; IS THIS NEEDED?
|
|
CP SD_STCMDERR
|
|
JR Z,SD_PRTCMDERR
|
|
CP SD_STDATAERR
|
|
JR Z,SD_PRTDATAERR
|
|
RET
|
|
;
|
|
SD_PRTCMDERR:
|
|
LD A,(SD_RC)
|
|
JR SD_PRTCODE
|
|
;
|
|
SD_PRTDATAERR:
|
|
LD A,(SD_TOK)
|
|
JR SD_PRTCODE
|
|
;
|
|
SD_PRTCODE:
|
|
CALL PC_LPAREN
|
|
PUSH AF
|
|
LD A,(SD_CMD)
|
|
CALL PRTHEXBYTE
|
|
LD DE,SDSTR_ARROW
|
|
CALL WRITESTR
|
|
POP AF
|
|
CALL PRTHEXBYTE
|
|
CALL PC_RPAREN
|
|
RET
|
|
;
|
|
; PRT COMMAND TRACE
|
|
;
|
|
SD_PRTTRN:
|
|
PUSH AF
|
|
|
|
CALL SD_PRTPREFIX
|
|
|
|
LD DE,SD_CMDBUF
|
|
LD A,6
|
|
CALL PRTHEXBUF
|
|
LD DE,SDSTR_ARROW
|
|
CALL WRITESTR
|
|
|
|
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
|
|
;
|
|
;
|
|
;
|
|
SDSTR_PREFIX .TEXT "SD$"
|
|
SDSTR_ARROW .TEXT " -> $"
|
|
SDSTR_RC .TEXT "RC=$"
|
|
SDSTR_TOK .TEXT "TOK=$"
|
|
SDSTR_CSD .TEXT " CSD=$"
|
|
SDSTR_CID .TEXT " CID=$"
|
|
SDSTR_STOK .TEXT "OK$"
|
|
SDSTR_SDTYPE .TEXT "SD CARD TYPE: $"
|
|
;
|
|
SDSTR_STNOTRDY .TEXT "NOT READY$"
|
|
SDSTR_STRDYTO .TEXT "READY TIMEOUT$"
|
|
SDSTR_STINITTO .TEXT "INITIALIZATION TIMEOUT$"
|
|
SDSTR_STCMDTO .TEXT "COMMAND TIMEOUT$"
|
|
SDSTR_STCMDERR .TEXT "COMMAND ERROR$"
|
|
SDSTR_STDATAERR .TEXT "DATA ERROR$"
|
|
SDSTR_STDATATO .TEXT "DATA TIMEOUT$"
|
|
SDSTR_STCRCERR .TEXT "CRC ERROR$"
|
|
SDSTR_STNOMEDIA .TEXT "NO MEDIA$"
|
|
SDSTR_STWRTPROT .TEXT "WRITE PROTECTED$"
|
|
SDSTR_STUNK .TEXT "UNKNOWN$"
|
|
SDSTR_TYPEUNK .TEXT "UNK$"
|
|
SDSTR_TYPEMMC .TEXT "MMC$"
|
|
SDSTR_TYPESDSC .TEXT "SDSC$"
|
|
SDSTR_TYPESDHC .TEXT "SDHC/XC$"
|
|
;
|
|
;==================================================================================================
|
|
; SD DISK DRIVER - DATA
|
|
;==================================================================================================
|
|
;
|
|
SD_STATLST .FILL SD_UNITCNT,0 ; LIST OF UNIT STATUSES (2 UNITS)
|
|
SD_STATPTR .DW SD_STATLST ; ADDRESS OF STATUS FOR CURRENT UNIT
|
|
SD_TYPELST .FILL SD_UNITCNT,0 ; LIST OF CARD TYPES (2 UNITS)
|
|
SD_TYPEPTR .Dw SD_TYPELST ; ADDRESS OF CARD TYPE FOR CURRENT UNIT
|
|
SD_UNIT .DB 0 ; CURRENT UNIT NUMBER
|
|
SD_RC .DB 0 ; RETURN CODE FROM CMD
|
|
SD_TOK .DB 0 ; TOKEN FROM DATA XFR
|
|
SD_OPRVAL .DB 0 ; CURRENT OPR REG VALUE
|
|
SD_LCNT .DB 0 ; LOOP COUNTER
|
|
;
|
|
SD_BUF .FILL 16,0 ; WORK BUFFER
|
|
;
|
|
SD_CMDBUF: ; START OF STD CMD BUF
|
|
SD_CMD .DB 0
|
|
SD_CMDP0 .DB 0
|
|
SD_CMDP1 .DB 0
|
|
SD_CMDP2 .DB 0
|
|
SD_CMDP3 .DB 0
|
|
SD_CMDCRC .DB 0
|
|
|