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.
2079 lines
57 KiB
2079 lines
57 KiB
;
|
|
;=============================================================================
|
|
; MMC/SD/SDHC/SDXC CARD STORAGE DRIVER
|
|
;=============================================================================
|
|
;
|
|
; 1) TESTING
|
|
; - TRY TO TEST GOIDLE, FIND CARD THAT REQUIRES 2 REQUESTS
|
|
; - DUAL CARDS
|
|
; - TEST XC CARD TYPE DETECTION
|
|
; - TRY TO GET INIT TO FAIL, REMOVE DELAYS AT START OF GOIDLE?
|
|
;
|
|
;----------------------------------------------------------------------------------------------
|
|
; SD Signal Active JUHA N8 CSIO PPI UART DSD MK4 SC MT
|
|
; ------------ ------- ------- ------- ------- ------- ------- ------- ------- ------- -------
|
|
; CS (DAT3) LO -> RTC:2 RTC:2 RTC:2 ~PC:4 ~MCR:3 OPR:2 SD:2 ~RTC:2/3OPR:4/5
|
|
; CLK HI -> RTC:1 RTC:1 CSIO PC:1 ~MCR:2 OPR:1 CSIO CSIO SPI
|
|
; DI (CMD) HI -> RTC:0 RTC:0 CSIO PC:0 ~MCR:0 OPR:0 CSIO CSIO SPI
|
|
; DO (DAT0) HI -> RTC:7 RTC:6 CSIO PB:7 ~MSR:5 OPR:0 CSIO CSIO SPI
|
|
;----------------------------------------------------------------------------------------------
|
|
;
|
|
; 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 (SLAVE):
|
|
; 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)).
|
|
;
|
|
;------------------------------------------------------------------------------
|
|
;
|
|
; === R1 RESPONSE ===
|
|
; ALL COMMAND RESPONSES START WITH R1
|
|
;
|
|
; 7 6 5 4 3 2 1 0
|
|
; +---+---+---+---+---+---+---+---+
|
|
; | 0 | X | X | X | X | X | X | X |
|
|
; +---+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
; | | | | | | |
|
|
; | | | | | | +--- IDLE
|
|
; | | | | | +------- ERASE RESET
|
|
; | | | | +----------- ILLEGAL COMMAND
|
|
; | | | +--------------- COM CRC ERROR
|
|
; | | +------------------- ERASE SEQUENCE ERROR
|
|
; | +----------------------- ADDRESS ERROR
|
|
; +--------------------------- PARAMETER ERROR
|
|
;
|
|
; === DATA ERROR TOKEN ===
|
|
;
|
|
; 7 6 5 4 3 2 1 0
|
|
; +---+---+---+---+---+---+---+---+
|
|
; | 0 | 0 | 0 | 0 | X | X | X | X |
|
|
; +---+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
; | | | |
|
|
; | | | +--- ERROR - GENERAL OR UNKNOWN ERROR
|
|
; | | +------- CC ERROR - INTERNAL CARD CONTROLER ERROR
|
|
; | +----------- CARD ECC FAILED - CARD INTERNAL ECC FAILED TO CORRECT DATA
|
|
; +--------------- OUT OF RANGE - PARAMAETER OUT OF RANGE ALLOWED FOR CARD
|
|
;
|
|
;------------------------------------------------------------------------------
|
|
;
|
|
; *** HACK FOR MISSING PULLUP RESISTORS ***
|
|
;
|
|
; THERE IS A RECENT TREND FOR SD ADAPTER BOARDS (SUCH AS THOSE USED TO ATTACH AN
|
|
; SD CARD TO AN ARDUINO OR RASPBERRY PI) TO OMIT THE PULLUP RESISTORS THAT ARE SUPPOSED
|
|
; TO BE ON ALL LINES. DESPITE BEING A CLEAR VIOLATION OF THE SPEC, IT IS SOMETHING THAT
|
|
; WE WILL NOW NEED TO LIVE WITH. THE CLK, CS, AND MOSI SIGNALS ARE NOT AN ISSUE SINCE
|
|
; WE ARE DRIVING THOSE SIGNALS AS THE HOST. THE PROBLEM IS WITH THE MISO SIGNAL.
|
|
; FORTUNATELY, MOST OF THE TIME, THE SD CARD WILL BE DRIVING THE SIGNAL. HOWEVER,
|
|
; THERE ARE TWO SCEANRIOS WE NEED TO ACCOMMODATE IN THE CODE:
|
|
;
|
|
; 1. MISO WILL NOT BE DRIVEN BY THE SD CARD (FLOATING) PRIOR TO RESETING THE
|
|
; CARD WITH CMD0. NORMALLY, A COMMAND SEQUENCE INVOLVES WAITING FOR THE
|
|
; CARD TO BE "READY" BY READING BYTES FROM THE CARD AND LOOKING FOR $FF.
|
|
; WHEN MISO IS FLOATING THIS WILL NOT BE RELIABLE. SINCE THE SPEC INDICATES
|
|
; IT IS NOT NECESSARY TO WAIT FOR READY PRIOR TO CMD0, THE CODE HAS BEEN
|
|
; MODIFIED TO ISSUE CMD0 WITHOUT WAITING FOR READY.
|
|
;
|
|
; 2. MISO MAY NOT BE DRIVEN IMMEDIATELY AFTER SENDING A COMMAND (POSSIBLY
|
|
; JUST CMD0, BUT NOT SURE). NORMALLY, AFTER SENDING A COMMAND, YOU
|
|
; LOOK FOR "FILL" BYTES OF $FF THAT MAY OCCUR PRIOR TO THE RESULT. WHEN MISO
|
|
; IS FLOATING IT IS IMPOSSIBLE TO DETERMINE IF THE BYTE RECEIVED IS A FILL
|
|
; BYTE OR NOT. BASED ON WHAT I HAVE READ, THERE WILL ALWAYS BE AT LEAST
|
|
; ONE FILL BYTE PRIOR TO THE ACTUAL RESULT. ADDITIONALLY, THE SD CARD WILL
|
|
; START DRIVING MISO SOMETIME WITHING THAT FIRST FILL BYTE. SO, WE NOW
|
|
; JUST DISCARD THE FIRST BYTE RECEIVED AFTER A COMMAND IS SENT WITH THE
|
|
; ASSUMPTION THAT IT MUST BE A FILL BYTE AND IS NOT RELIABLE DUE TO FLOATING
|
|
; MISO.
|
|
;
|
|
; THESE CHANGES ARE CONSISTENT WITH THE POPULAR ARDUINO SDFAT LIBRARY, SO THEY ARE
|
|
; PROBABLY PRETTY SAFE. HOWEVER, I HAVE BRACKETED THE CHANGES WITH THE EQUATE BELOW.
|
|
; IF YOU WANT TO REVERT THESE HACKS, JUST SET THE EQUATE TO FALSE.
|
|
;
|
|
SD_NOPULLUP .EQU TRUE ; ASSUME NO PULLUP
|
|
;
|
|
#IF (SDMODE == SDMODE_JUHA) ; JUHA MINI-BOARD
|
|
SD_DEVCNT .EQU 1 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_OPRREG .EQU RTCIO ; USES RTC LATCHES FOR OPERATION
|
|
SD_OPRDEF .EQU %00000001 ; QUIESCENT STATE
|
|
SD_INPREG .EQU RTCIO ; INPUT REGISTER IS RTC
|
|
SD_CS0 .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_DEVCNT .EQU 1 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_OPRREG .EQU RTCIO ; USES RTC LATCHES FOR OPERATION
|
|
SD_OPRDEF .EQU %00000001 ; QUIESCENT STATE
|
|
SD_INPREG .EQU RTCIO ; INPUT REGISTER IS RTC
|
|
SD_CS0 .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_DEVCNT .EQU 1 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_OPRREG .EQU RTCIO ; USES RTC LATCHES FOR OPERATION
|
|
SD_OPRDEF .EQU %00000000 ; QUIESCENT STATE
|
|
SD_CS0 .EQU %00000100 ; RTC:2 IS SELECT
|
|
SD_CNTR .EQU Z180_CNTR
|
|
SD_TRDR .EQU Z180_TRDR
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_PPI) ; PPISD
|
|
SD_DEVCNT .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_CS0 .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_DEVCNT .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_CS0 .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_DEVCNT .EQU SDCNT ; 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_CS0 .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_DEVCNT .EQU 1 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_OPRREG .EQU $89 ; DEDICATED MK4 SDCARD REGISTER
|
|
SD_OPRDEF .EQU %00000000 ; QUIESCENT STATE
|
|
SD_CS0 .EQU %00000100 ; SELECT ACTIVE
|
|
SD_CNTR .EQU Z180_CNTR
|
|
SD_TRDR .EQU Z180_TRDR
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_SC) ; SC
|
|
SD_DEVCNT .EQU SDCNT ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_OPRREG .EQU RTCIO ; USES RTC LATCHES FOR OPERATION
|
|
SD_OPRDEF .EQU %00001100 ; QUIESCENT STATE (/CS1 & /CS2 DEASSERTED)
|
|
SD_CS0 .EQU %00000100 ; RTC:2 IS SELECT FOR PRIMARY SPI CARD
|
|
SD_CS1 .EQU %00001000 ; RTC:3 IS SELECT FOR SECONDARY SPI CARD
|
|
SD_CNTR .EQU Z180_CNTR
|
|
SD_TRDR .EQU Z180_TRDR
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_MT) ; MT shift register for RC2014 (ref SDMODE_CSIO)
|
|
;
|
|
; 3 SPI CHANNELS. CHANNEL 0 (CDX & CSX) IS A DEDICATED CONNECTION TO ONBOARD
|
|
; WIZNET W5500 AND IS NOT USED HERE. CHANNEL 1 (CD0 & CS0) & 2 (CD1 & CS1)
|
|
; ARE ASSUMED TO BE CONNECTED TO SD CARDS.
|
|
;
|
|
SD_BASE .EQU $5C ; Module base address
|
|
SD_DEVCNT .EQU 2 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_WRTR .EQU SD_BASE + 0 ; Write data and transfer
|
|
SD_RDTR .EQU SD_BASE + 1 ; Read data and transfer
|
|
SD_RDNTR .EQU SD_BASE + 0 ; Read data and NO transfer
|
|
SD_OPRREG .EQU SD_BASE + 2 ; SD CHIP SELECTOR
|
|
SD_OPRDEF .EQU %00000000 ; QUIESCENT STATE
|
|
SD_CDX .EQU %00000001 ; IN/OUT:SD_OPREG:0 = CD0, PMOD pull CD0 low
|
|
SD_CD0 .EQU %00000010 ; IN:SD_OPREG:1 = CD1, IN=0 Card detect switch
|
|
SD_CD1 .EQU %00000100 ; IN:SD_OPREG:2 = CD2, IN=0 Card detect switch
|
|
SD_CSX .EQU %00001000 ; IN/OUT:SD_OPREG:3 = CS0, PMOD SPI CS
|
|
SD_CS0 .EQU %00010000 ; IN/OUT:SD_OPREG:4 = CS1, SDCARD1 CS, IN=1 Card present
|
|
SD_CS1 .EQU %00100000 ; IN/OUT:SD_OPREG:5 = CS2, SDCARD2 CS, IN=1 Card present
|
|
|
|
#ENDIF
|
|
;
|
|
; SD CARD COMMANDS
|
|
;
|
|
SD_CMD_GO_IDLE_STATE .EQU $40 + 0 ; $40, CMD0 -> R1
|
|
SD_CMD_SEND_OP_COND .EQU $40 + 1 ; $41, CMD1 -> R1
|
|
SD_CMD_SEND_IF_COND .EQU $40 + 8 ; $48, CMD8 -> R7
|
|
SD_CMD_SEND_CSD .EQU $40 + 9 ; $49, CMD9 -> R1
|
|
SD_CMD_SEND_CID .EQU $40 + 10 ; $4A, CMD10 -> R1
|
|
SD_CMD_SET_BLOCKLEN .EQU $40 + 16 ; $50, CMD16 -> R1
|
|
SD_CMD_READ_SNGL_BLK .EQU $40 + 17 ; $51, CMD17 -> R1
|
|
SD_CMD_WRITE_BLOCK .EQU $40 + 24 ; $58, CMD24 -> R1
|
|
SD_CMD_APP_CMD .EQU $40 + 55 ; $77, CMD55 -> R1
|
|
SD_CMD_READ_OCR .EQU $40 + 58 ; $7A, CMD58 -> R3
|
|
;
|
|
; SD CARD APPLICATION COMMANDS (PRECEDED BY APP_CMD COMMAND)
|
|
;
|
|
SD_ACMD_SEND_OP_COND .EQU $40 + 41 ; $69, ACMD41 -> R1
|
|
SD_ACMD_SEND_SCR .EQU $40 + 51 ; $73, ACMD51 -> R1
|
|
;
|
|
; 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 CARD (V2)
|
|
SD_TYPESDXC .EQU 4 ; SDXC CARD (V3)
|
|
;
|
|
; SD CARD STATUS (SD_STAT)
|
|
;
|
|
SD_STOK .EQU 0 ; OK
|
|
SD_STINVUNIT .EQU -1 ; INVALID UNIT
|
|
SD_STRDYTO .EQU -2 ; TIMEOUT WAITING FOR CARD TO BE READY
|
|
SD_STINITTO .EQU -3 ; INITIALIZATION 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
|
|
;
|
|
; IDE DEVICE CONFIGURATION
|
|
;
|
|
SD_CFGSIZ .EQU 12 ; SIZE OF CFG TBL ENTRIES
|
|
;
|
|
; PER DEVICE DATA OFFSETS
|
|
;
|
|
SD_DEV .EQU 0 ; OFFSET OF DEVICE NUMBER (BYTE)
|
|
SD_STAT .EQU 1 ; LAST STATUS (BYTE)
|
|
SD_TYPE .EQU 2 ; DEVICE TYPE (BYTE)
|
|
SD_FLAGS .EQU 3 ; FLAG BITS (BYTE)
|
|
SD_MEDCAP .EQU 4 ; MEDIA CAPACITY (DWORD)
|
|
SD_LBA .EQU 8 ; OFFSET OF LBA (DWORD)
|
|
;
|
|
SD_CFGTBL:
|
|
; DEVICE 0, PRIMARY MASTER
|
|
.DB 0 ; DRIVER DEVICE NUMBER
|
|
.DB 0 ; DEVICE STATUS
|
|
.DB 0 ; DEVICE TYPE
|
|
.DB 0 ; FLAGS BYTE
|
|
.DW 0,0 ; DEVICE CAPACITY
|
|
.DW 0,0 ; CURRENT LBA
|
|
#IF (SD_DEVCNT >= 2)
|
|
; DEVICE 1, PRIMARY SLAVE
|
|
.DB 1 ; DRIVER DEVICE NUMBER
|
|
.DB 0 ; DEVICE STATUS
|
|
.DB 0 ; DEVICE TYPE
|
|
.DB 0 ; FLAGS BYTE
|
|
.DW 0,0 ; DEVICE CAPACITY
|
|
.DW 0,0 ; CURRENT LBA
|
|
#ENDIF
|
|
;
|
|
#IF ($ - SD_CFGTBL) != (SD_DEVCNT * SD_CFGSIZ)
|
|
.ECHO "*** INVALID SD CONFIG TABLE ***\n"
|
|
#ENDIF
|
|
;
|
|
.DB $FF ; END MARKER
|
|
;
|
|
;=============================================================================
|
|
; INITIALIZATION ENTRY POINT
|
|
;=============================================================================
|
|
;
|
|
SD_INIT:
|
|
CALL NEWLINE ; FORMATTING
|
|
PRTS("SD:$")
|
|
;
|
|
#IF (SDMODE == SDMODE_JUHA)
|
|
PRTS(" MODE=JUHA$")
|
|
PRTS(" IO=0x$")
|
|
LD A,SD_OPRREG
|
|
CALL PRTHEXBYTE
|
|
;
|
|
LD A,(RTCVAL) ; GET RTC PORT SHADOW VALUE
|
|
OR SD_OPRDEF ; SET OUR BIT DEFAULTS
|
|
LD (RTCVAL),A ; SAVE IT
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_N8)
|
|
PRTS(" MODE=N8$")
|
|
PRTS(" IO=0x$")
|
|
LD A,SD_OPRREG
|
|
CALL PRTHEXBYTE
|
|
;
|
|
LD A,(RTCVAL) ; GET RTC PORT SHADOW VALUE
|
|
OR SD_OPRDEF ; SET OUR BIT DEFAULTS
|
|
LD (RTCVAL),A ; SAVE IT
|
|
#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
|
|
;
|
|
LD A,(RTCVAL) ; GET RTC PORT SHADOW VALUE
|
|
OR SD_OPRDEF ; SET OUR BIT DEFAULTS
|
|
LD (RTCVAL),A ; SAVE IT
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_PPI)
|
|
PRTS(" MODE=PPI$")
|
|
PRTS(" IO=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
|
|
;
|
|
#IF (SDMODE == SDMODE_SC)
|
|
PRTS(" MODE=SC$")
|
|
#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
|
|
;
|
|
LD A,(RTCVAL) ; GET RTC PORT SHADOW VALUE
|
|
OR SD_OPRDEF ; SET OUR BIT DEFAULTS
|
|
LD (RTCVAL),A ; SAVE IT
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_MT)
|
|
PRTS(" MODE=MT$")
|
|
PRTS(" IO=0x$")
|
|
LD A,SD_BASE
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
CALL SD_PROBE ; CHECK FOR HARDWARE
|
|
JR Z,SD_INIT00 ; CONTINUE IF PRESENT
|
|
;
|
|
; HARDWARE NOT PRESENT
|
|
PRTS(" NOT PRESENT$")
|
|
OR $FF ; SIGNAL FAILURE
|
|
RET
|
|
;
|
|
SD_INIT00:
|
|
;
|
|
; SETUP THE DISPATCH TABLE ENTRIES
|
|
;
|
|
PRTS(" DEVICES=$")
|
|
LD A,SD_DEVCNT
|
|
CALL PRTDECB
|
|
;
|
|
; SETUP THE DISPATCH TABLE ENTRIES
|
|
;
|
|
LD B,SD_DEVCNT ; LOOP CONTROL
|
|
LD IY,SD_CFGTBL ; START OF CFG TABLE
|
|
SD_INIT0:
|
|
PUSH BC ; SAVE LOOP CONTROL
|
|
LD BC,SD_FNTBL ; BC := FUNC TABLE ADR
|
|
PUSH IY ; CFG ENTRY POINTER
|
|
POP DE ; COPY TO DE
|
|
CALL DIO_ADDENT ; ADD ENTRY, BC IS NOT DESTROYED
|
|
LD BC,SD_CFGSIZ ; SIZE OF CFG ENTRY
|
|
ADD IY,BC ; BUMP IY TO NEXT ENTRY
|
|
POP BC ; RESTORE BC
|
|
DJNZ SD_INIT0 ; LOOP AS NEEDED
|
|
;
|
|
; INITIALIZE THE SD INTERFACE NOW
|
|
CALL SD_SETUP ; DO HARDWARE SETUP/INIT
|
|
RET NZ ; ABORT ON ERROR
|
|
;
|
|
; INITIALIZE INDIVIDUAL UNIT(S) AND DISPLAY DEVICE INVENTORY
|
|
LD B,SD_DEVCNT ; INIT LOOP COUNTER TO DEVICE COUNT
|
|
LD IY,SD_CFGTBL ; START OF CFG TABLE
|
|
SD_INIT1:
|
|
PUSH BC ; SAVE LOOP COUNTER/INDEX
|
|
CALL SD_INITUNIT ; INITIALIZE IT
|
|
#IF (SDTRACE < 2)
|
|
CALL NZ,SD_PRTSTAT ; IF ERROR, SHOW IT
|
|
#ENDIF
|
|
LD BC,SD_CFGSIZ ; SIZE OF CFG ENTRY
|
|
ADD IY,BC ; BUMP IY TO NEXT ENTRY
|
|
POP BC ; RESTORE LOOP CONTROL
|
|
DJNZ SD_INIT1 ; DECREMENT LOOP COUNTER AND LOOP AS NEEDED
|
|
;
|
|
RET ; DONE
|
|
;
|
|
; INITIALIZE UNIT DESIGNATED IN ACCUM
|
|
;
|
|
SD_INITUNIT:
|
|
CALL SD_SELUNIT ; SELECT UNIT
|
|
RET NZ ; ABORT ON ERROR
|
|
;
|
|
CALL SD_INITCARD ; INIT THE SELECTED CARD
|
|
RET NZ ; ABORT ON ERROR
|
|
;
|
|
CALL SD_PRTPREFIX
|
|
CALL PC_SPACE
|
|
;
|
|
; PRINT CARD TYPE
|
|
LD A,(IY+SD_TYPE) ; GET CARD TYPE VALUE TO A
|
|
LD DE,SD_STR_TYPEMMC
|
|
CP SD_TYPEMMC
|
|
JR Z,SD_INITUNIT1
|
|
LD DE,SD_STR_TYPESDSC
|
|
CP SD_TYPESDSC
|
|
JR Z,SD_INITUNIT1
|
|
LD DE,SD_STR_TYPESDHC
|
|
CP SD_TYPESDHC
|
|
JR Z,SD_INITUNIT1
|
|
LD DE,SD_STR_TYPESDXC
|
|
CP SD_TYPESDXC
|
|
JR Z,SD_INITUNIT1
|
|
LD DE,SD_STR_TYPEUNK
|
|
SD_INITUNIT1:
|
|
CALL WRITESTR
|
|
|
|
; GET CID (WHICH CONTAINS PRODUCT NAME)
|
|
LD A,SD_CMD_SEND_CID ; SEND_CID
|
|
CALL SD_INITCMD ; SETUP COMMAND BUFFER
|
|
CALL SD_EXECCMD ; RUN COMMAND
|
|
RET NZ ; ABORT ON ERROR
|
|
LD BC,16 ; 16 BYTES OF CID
|
|
LD HL,SD_BUF
|
|
CALL SD_GETDATA
|
|
CALL SD_DONE
|
|
JP NZ,SD_ERRDATA ; DATA XFER ERROR
|
|
|
|
#IF (SDTRACE >= 3)
|
|
CALL SD_PRTPREFIX
|
|
LD DE,SD_STR_CID
|
|
CALL WRITESTR
|
|
LD DE,SD_BUF
|
|
LD A,16
|
|
CALL PRTHEXBUF
|
|
#ENDIF
|
|
|
|
; PRINT PRODUCT NAME
|
|
PRTS(" NAME=$") ; PRINT LABEL
|
|
LD B,5 ; PREPARE TO PRINT 5 BYTES
|
|
LD HL,SD_BUF + 3 ; AT BYTE OFFSET 3 IN RESULT BUFFER
|
|
SD_INITUNIT2:
|
|
LD A,(HL) ; GET NEXT BYTE
|
|
CALL COUT ; PRINT IT
|
|
INC HL ; POINT TO NEXT BYTE
|
|
DJNZ SD_INITUNIT2 ; LOOP FOR ALL 5 BYTES
|
|
;
|
|
; PRINT STORAGE CAPACITY (BLOCK COUNT)
|
|
PRTS(" BLOCKS=0x$") ; PRINT FIELD LABEL
|
|
LD A,SD_MEDCAP ; OFFSET TO CAPACITY FIELD
|
|
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
|
|
CALL LD32 ; GET THE CAPACITY VALUE
|
|
CALL PRTHEX32 ; PRINT HEX VALUE
|
|
;
|
|
; PRINT STORAGE SIZE IN MB
|
|
PRTS(" SIZE=$") ; PRINT FIELD LABEL
|
|
LD B,11 ; 11 BIT SHIFT TO CONVERT BLOCKS --> MB
|
|
CALL SRL32 ; RIGHT SHIFT
|
|
CALL PRTDEC ; PRINT LOW WORD IN DECIMAL (HIGH WORD DISCARDED)
|
|
PRTS("MB$") ; PRINT SUFFIX
|
|
;
|
|
; CHECK FOR WRITE PROTECT AND NOTIFY USER IF SO
|
|
CALL SD_CHKWP ; WRITE PROTECTED?
|
|
RET Z ; IF NOT, DONE
|
|
PRTS(" WP$") ; NOTIFY USER
|
|
;
|
|
RET ; DONE
|
|
;
|
|
;----------------------------------------------------------------------
|
|
; PROBE FOR SD HARDWARE
|
|
;----------------------------------------------------------------------
|
|
;
|
|
; ON RETURN, ZF SET INDICATES HARDWARE FOUND
|
|
;
|
|
SD_PROBE:
|
|
;
|
|
#IF (SDMODE == SDMODE_DSD)
|
|
; ON DSD, SELREG, BIT 0 IS READ BACK AS WRITTEN, BIT 1
|
|
; IS ALWAYS READ AS ZERO. TO TEST FOR EXISTENCE, WE
|
|
; WRITE 00 AND MAKE SURE IT READS BACK AS 00, THEN WE
|
|
; WRITE 11 AND MAKE SURE IT READS BACK AS 01.
|
|
LD C,SD_SELREG ; USE C TO ADDRESS PORT
|
|
XOR A ; A := 0
|
|
OUT (C),A ; SELREG := 0
|
|
IN A,(C) ; READ SELREG BACK
|
|
AND $03 ; ISOLATE 2 LOWEST BITS
|
|
CP $00 ; BOTH BITS SHOULD BE 0
|
|
RET NZ ; FAIL IF NOT
|
|
LD A,$03 ; SET 2 LOWEST BITS
|
|
OUT (C),A ; DO IT
|
|
IN A,(C) ; READ SELREG BACK
|
|
AND $03 ; ISOLATE 2 LOWEST BITS
|
|
CP $01 ; SHOULD READ BACK AS $01
|
|
RET ; RETURN W/ ZF SET AS NEEDED
|
|
#ENDIF
|
|
;
|
|
;#IF (SDMODE == SDMODE_MT)
|
|
; LD A,SD_OPRDEF
|
|
; OUT (SD_OPRREG),A ; MAKE SURE CONTROL REGISTER IS CLEARED
|
|
;;
|
|
; ; TEST WITH PMOD NOT CONNECTED
|
|
;; IN A,(SD_OPRREG)
|
|
;; AND SD_CD0+SD_CS0 ; ISOLATE CD0 AND CS0
|
|
;; CP SD_CD0+SD_CS0 ; BOTH SHOULD BE HIGH
|
|
;; JR NZ,SD_PROBE_FAIL ; FAIL IF NOT
|
|
; ; TEST CD0
|
|
;; LD A,SD_CD0 ; D1=DNP CANNOT TEST
|
|
;; OUT (SD_OPRREG),A
|
|
;; IN A,(SD_OPRREG)
|
|
;; AND SD_CD0
|
|
;; JR NZ,SD_PROBE_FAIL ; FAIL IF NOT PULLED LOW
|
|
; ; TEST CS0
|
|
;; LD A,SD_CS0 ; D2=DNP CANNOT TEST
|
|
;; OUT (SD_OPRREG),A
|
|
;; IN A,(SD_OPRREG)
|
|
;; AND SD_CS0
|
|
;; JR NZ,SD_PROBE_FAIL ; FAIL IF NOT PULLED LOW
|
|
; ; TEST CS1
|
|
;; LD A,SD_CS1
|
|
;; OUT (SD_OPRREG),A
|
|
;; IN A,(SD_OPRREG)
|
|
;; AND SD_CS1
|
|
;; JR NZ,SD_PROBE_FAIL ; FAIL IF NOT PULLED LOW
|
|
;; ; TEST CS2
|
|
;; LD A,SD_CS2
|
|
;; OUT (SD_OPRREG),A
|
|
;; IN A,(SD_OPRREG)
|
|
;; AND SD_CS2
|
|
;; JR NZ,SD_PROBE_FAIL ; FAIL IF NOT PULLED LOW
|
|
;
|
|
; LD A,SD_OPRDEF
|
|
; OUT (SD_OPRREG),A ; MAKE SURE CONTROL REGISTER IS CLEARED
|
|
;#ENDIF
|
|
;
|
|
XOR A ; SIGNAL SUCCESS
|
|
;
|
|
;#IF (SDMODE == SDMODE_MT)
|
|
;SD_PROBE_FAIL:
|
|
; LD A,SD_OPRDEF
|
|
; OUT (SD_OPRREG),A ; MAKE SURE CONTROL REGISTER IS CLEARED
|
|
;#ENDIF
|
|
RET ; AND RETURN
|
|
;
|
|
;=============================================================================
|
|
; DRIVER FUNCTION TABLE
|
|
;=============================================================================
|
|
;
|
|
SD_FNTBL:
|
|
.DW SD_STATUS
|
|
.DW SD_RESET
|
|
.DW SD_SEEK
|
|
.DW SD_READ
|
|
.DW SD_WRITE
|
|
.DW SD_VERIFY
|
|
.DW SD_FORMAT
|
|
.DW SD_DEVICE
|
|
.DW SD_MEDIA
|
|
.DW SD_DEFMED
|
|
.DW SD_CAP
|
|
.DW SD_GEOM
|
|
#IF (($ - SD_FNTBL) != (DIO_FNCNT * 2))
|
|
.ECHO "*** INVALID IDE FUNCTION TABLE ***\n"
|
|
#ENDIF
|
|
;
|
|
SD_VERIFY:
|
|
SD_FORMAT:
|
|
SD_DEFMED:
|
|
CALL PANIC ; INVALID SUB-FUNCTION
|
|
;
|
|
;
|
|
;
|
|
SD_READ:
|
|
CALL HB_DSKREAD ; HOOK HBIOS DISK READ SUPERVISOR
|
|
LD A,SD_CMD_READ_SNGL_BLK ; SETUP FOR SINGLE BLOCK READ CMD
|
|
JR SD_IO ; CONTINUE TO GENERIC IO ROUTINE
|
|
;
|
|
;
|
|
;
|
|
SD_WRITE:
|
|
CALL HB_DSKWRITE ; HOOK HBIOS DISK WRITE SUPERVISOR
|
|
LD A,SD_CMD_WRITE_BLOCK ; SETUP FOR BLOCK WRITE CMD
|
|
JR SD_IO ; CONTINUE TO GENERIC IO ROUTINE
|
|
;
|
|
;
|
|
;
|
|
SD_IO:
|
|
LD (SD_CMDVAL),A ; SAVE THE SD CARD COMMAND
|
|
LD (SD_DSKBUF),HL ; SAVE DISK BUFFER ADDRESS
|
|
LD A,E ; GET BLOCK COUNT REQUESTED
|
|
LD (SD_BLKCNT),A ; ... AND SAVE IT
|
|
OR A ; SET FLAGS
|
|
RET Z ; ZERO SECTOR I/O, RETURN W/ E=0 & A=0
|
|
#IF (SDTRACE == 1)
|
|
LD HL,SD_PRTERR ; SET UP SD_PRTERR
|
|
PUSH HL ; ... TO FILTER ALL EXITS
|
|
#ENDIF
|
|
CALL SD_SELUNIT ; HARDWARE SELECTION OF TARGET UNIT
|
|
RET NZ ; ABORT ON ERROR
|
|
LD A,(SD_CMDVAL) ; GET COMMAND VALUE
|
|
CP SD_CMD_READ_SNGL_BLK ; IS THIS A READ?
|
|
CALL NZ,SD_CHKWP ; CHECK FOR WRITE PROTECT IF NOT A READ
|
|
JP NZ,SD_WRTPROT ; HANDLE WRITE PROTECT ERR
|
|
LD A,(SD_BLKCNT) ; BLOCK COUNT TO A
|
|
LD E,A ; ... AND TO E IN CASE OF ZERO ERR BELOW
|
|
OR A ; SET FLAGS
|
|
RET Z ; ZERO SECTOR I/O, RETURN W/ E=0 & A=0
|
|
LD B,A ; INIT SECTOR DOWNCOUNTER
|
|
LD C,0 ; INIT SECTOR READ/WRITE COUNT
|
|
SD_IO1:
|
|
PUSH BC ; SAVE COUNTERS
|
|
LD A,(SD_CMDVAL) ; SET COMMAND
|
|
LD C,A ; ... AND PUT IN C
|
|
CALL SD_SECTIO ; DO SECTOR I/O
|
|
JR NZ,SD_IO2 ; IF ERROR, SKIP INCREMENT
|
|
; INCREMENT LBA
|
|
LD A,SD_LBA ; LBA OFFSET
|
|
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
|
|
CALL INC32HL ; INCREMENT THE VALUE
|
|
; INCREMENT DMA
|
|
LD HL,SD_DSKBUF+1 ; POINT TO MSB OF BUFFER ADR
|
|
INC (HL) ; BUMP DMA BY
|
|
INC (HL) ; ... 512 BYTES
|
|
XOR A ; SIGNAL SUCCESS
|
|
SD_IO2:
|
|
POP BC ; RECOVER COUNTERS
|
|
JR NZ,SD_IO3 ; IF ERROR, BAIL OUT
|
|
INC C ; BUMP COUNT OF SECTORS READ
|
|
DJNZ SD_IO1 ; LOOP AS NEEDED
|
|
SD_IO3:
|
|
LD E,C ; SECTOR READ COUNT TO E
|
|
LD HL,(SD_DSKBUF) ; CURRENT DMA TO HL
|
|
OR A ; SET FLAGS BASED ON RETURN CODE
|
|
RET ; AND RETURN, A HAS RETURN CODE
|
|
;
|
|
;
|
|
;
|
|
SD_STATUS:
|
|
; RETURN DEVICE STATUS
|
|
LD A,(IY+SD_STAT) ; GET STATUS OF SELECTED DEVICE
|
|
OR A ; SET FLAGS
|
|
RET ; AND RETURN
|
|
;
|
|
;
|
|
;
|
|
SD_RESET:
|
|
CALL SD_SELUNIT ; SET CUR UNIT
|
|
; RE-INITIALIZE THE SD CARD TO ACCOMMODATE HOT SWAPPING
|
|
CALL SD_INITCARD ; RE-INIT SELECTED UNIT
|
|
#IF (SDTRACE == 1)
|
|
CALL SD_PRTERR ; PRINT ANY ERRORS
|
|
#ENDIF
|
|
OR A ; SET RESULT FLAGS
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
SD_DEVICE:
|
|
LD D,DIODEV_SD ; D := DEVICE TYPE
|
|
LD E,(IY+SD_DEV) ; E := PHYSICAL DEVICE NUMBER
|
|
LD C,%01010000 ; C := ATTRIBUTES, REMOVABLE, SD CARD
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
SD_MEDIA:
|
|
LD A,E ; GET FLAGS
|
|
OR A ; SET FLAGS
|
|
JR Z,SD_MEDIA2 ; JUST REPORT CURRENT STATUS AND MEDIA
|
|
;
|
|
; GET CURRENT STATUS
|
|
LD A,(IY+SD_STAT) ; GET STATUS
|
|
OR A ; SET FLAGS
|
|
JR NZ,SD_MEDIA1 ; ERROR ACTIVE, GO RIGHT TO RESET
|
|
;
|
|
; USE SEND_CSD TO CHECK CARD
|
|
CALL SD_SELUNIT ; SET CUR UNIT
|
|
LD A,SD_CMD_SEND_CSD ; SEND_CSD
|
|
CALL SD_INITCMD ; SETUP COMMAND BUFFER
|
|
CALL SD_EXECCMD ; EXECUTE COMMAND
|
|
JR NZ,SD_MEDIA1 ; ERROR, NEED RESET
|
|
LD BC,16 ; 16 BYTES OF CSD
|
|
LD HL,SD_BUF ; PUT IN OUR PRIVATE BUFFER
|
|
CALL SD_GETDATA ; GET THE DATA
|
|
CALL SD_DONE ; CLOSE THE TRANSACTION
|
|
JR Z,SD_MEDIA2 ; IF SUCCESS, BYPASS RESET
|
|
;
|
|
SD_MEDIA1:
|
|
CALL SD_RESET ; RESET CARD
|
|
;
|
|
SD_MEDIA2:
|
|
LD A,(IY+SD_STAT) ; GET STATUS
|
|
OR A ; SET FLAGS
|
|
LD D,0 ; NO MEDIA CHANGE DETECTED
|
|
LD E,MID_HD ; ASSUME WE ARE OK
|
|
RET Z ; RETURN IF GOOD INIT
|
|
LD E,MID_NONE ; SIGNAL NO MEDIA
|
|
RET ; AND RETURN
|
|
;
|
|
;
|
|
;
|
|
;
|
|
SD_SEEK:
|
|
BIT 7,D ; CHECK FOR LBA FLAG
|
|
CALL Z,HB_CHS2LBA ; CLEAR MEANS CHS, CONVERT TO LBA
|
|
RES 7,D ; CLEAR FLAG REGARDLESS (DOES NO HARM IF ALREADY LBA)
|
|
LD (IY+SD_LBA+0),L ; SAVE NEW LBA
|
|
LD (IY+SD_LBA+1),H ; ...
|
|
LD (IY+SD_LBA+2),E ; ...
|
|
LD (IY+SD_LBA+3),D ; ...
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET ; AND RETURN
|
|
;
|
|
;
|
|
;
|
|
SD_CAP:
|
|
LD A,(IY+SD_STAT) ; GET STATUS
|
|
PUSH AF ; SAVE IT
|
|
LD A,SD_MEDCAP ; OFFSET TO CAPACITY FIELD
|
|
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
|
|
CALL LD32 ; GET THE CURRENT CAPACITY INTO DE:HL
|
|
LD BC,512 ; 512 BYTES PER BLOCK
|
|
POP AF ; RECOVER STATUS
|
|
OR A ; SET FLAGS
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
SD_GEOM:
|
|
; FOR LBA, WE SIMULATE CHS ACCESS USING 16 HEADS AND 16 SECTORS
|
|
; RETURN HS:CC -> DE:HL, SET HIGH BIT OF D TO INDICATE LBA CAPABLE
|
|
CALL SD_CAP ; GET TOTAL BLOCKS IN DE:HL, BLOCK SIZE TO BC
|
|
LD L,H ; DIVIDE BY 256 FOR # TRACKS
|
|
LD H,E ; ... HIGH BYTE DISCARDED, RESULT IN HL
|
|
LD D,16 | $80 ; HEADS / CYL = 16, SET LBA BIT
|
|
LD E,16 ; SECTORS / TRACK = 16
|
|
RET ; DONE, A STILL HAS SD_CAP STATUS
|
|
;
|
|
;=============================================================================
|
|
; FUNCTION SUPPORT ROUTINES
|
|
;=============================================================================
|
|
;
|
|
; (RE)INITIALIZE CARD
|
|
;
|
|
SD_INITCARD:
|
|
;
|
|
CALL SD_CHKCD ; CHECK CARD DETECT
|
|
JP Z,SD_NOMEDIA ; Z=NO MEDIA, HANDLE IF SO
|
|
;
|
|
; 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_INITCARD1:
|
|
LD A,$FF ; KEEP DIN HI
|
|
PUSH BC ; SAVE LOOP CONTROL
|
|
CALL SD_PUT ; SEND 8 CLOCKS
|
|
POP BC ; RESTORE LOOP CONTROL
|
|
DJNZ SD_INITCARD1 ; LOOP AS NEEDED
|
|
;
|
|
; PUT CARD IN IDLE STATE
|
|
CALL SD_GOIDLE ; GO TO IDLE
|
|
JP NZ,SD_NOMEDIA ; CONVERT ERROR TO NO MEDIA
|
|
;
|
|
SD_INITCARD2:
|
|
LD (IY+SD_TYPE),SD_TYPESDSC ; ASSUME SDSC CARD TYPE
|
|
;
|
|
; CMD8 IS REQUIRED FOR V2 CARDS. FAILURE HERE IS OK AND
|
|
; JUST MEANS THAT IT IS A V1 CARD
|
|
LD A,SD_CMD_SEND_IF_COND ; SEND_IF_COND
|
|
CALL SD_INITCMD ; SETUP COMMAND BUFFER
|
|
LD HL,SD_CMDP2 ; POINT TO 3RD PARM BYTE
|
|
LD (HL),1 ; VHS=1, 2.7-3.6V
|
|
INC HL ; POINT TO 4TH PARM BYTE
|
|
LD (HL),$AA ; CHECK PATTERN
|
|
INC HL ; POINT TO CRC
|
|
LD (HL),$87 ; ... AND SET IT TO KNOWN VALUE OF $87
|
|
CALL SD_EXECCMDND ; EXEC COMMAND W/ NO DATA RETURNED
|
|
;
|
|
; GET CARD OUT OF IDLE STATE BY SENDING SD_APP_OP_COND
|
|
; REPEATEDLY UNTIL IDLE BIT IS CLEAR
|
|
LD A,0
|
|
LD (SD_LCNT),A
|
|
SD_INITCARD3:
|
|
; DELAY A BIT PER SPEC
|
|
LD DE,300 ; 16US * 300 = ~5MS
|
|
CALL VDELAY ; CPU SPEED NORMALIZED DELAY
|
|
; SEND APP CMD INTRODUCER
|
|
CALL SD_EXECACMD ; SEND APP COMMAND INTRODUCER
|
|
;#IF (SDMODE == SDMODE_MT)
|
|
; CALL NZ,SD_EXECACMD ; retry any fail
|
|
;#ENDIF
|
|
CP SD_STCMDERR ; COMMAND ERROR?
|
|
JR Z,SD_INITCARD3A ; IF SO, TRY MMC CARD INIT
|
|
OR A ; SET FLAGS
|
|
RET NZ ; ABORT IF ANY OTHER ERROR
|
|
; SEND APP_OP_COND
|
|
LD A,SD_ACMD_SEND_OP_COND ; SD_APP_OP_COND
|
|
CALL SD_INITCMD ; SETUP COMMAND BUFFER
|
|
LD A,$40 ; P0 = $40 INDICATES WE SUPPORT V2 CARDS
|
|
LD (SD_CMDP0),A ; SET COMMAND PARM 0
|
|
CALL SD_EXECCMDND ; EXEC COMMAND W/ NO DATA RETURNED
|
|
RET NZ ; ABORT ON ERROR
|
|
; CHECK FOR IDLE, EXIT LOOP IF IDLE CLEARED
|
|
LD A,(SD_RC) ; GET CARD RESULT CODE
|
|
OR A ; SET FLAGS
|
|
JR Z,SD_INITCARD4 ; IF IDLE BIT CLEAR, EXIT LOOP
|
|
; LOOP AS NEEDED
|
|
LD HL,SD_LCNT ; POINT TO LOOP COUNTER
|
|
DEC (HL) ; DECREMENT LOOP COUNTER
|
|
JR NZ,SD_INITCARD3 ; LOOP UNTIL COUNTER EXHAUSTED
|
|
JP SD_ERRINITTO ; HANDLE INIT TIMEOUT ERROR
|
|
;
|
|
SD_INITCARD3A:
|
|
; TRY MMC CARD INITIALIZATION
|
|
; CALL SEND_OP_COND UNTIL CARD IS READY (NOT IDLE)
|
|
LD A,0
|
|
LD (SD_LCNT),A
|
|
SD_INITCARD3B:
|
|
; DELAY A BIT PER SPEC
|
|
LD DE,300 ; 16US * 300 = ~5MS
|
|
CALL VDELAY ; CPU SPEED NORMALIZED DELAY
|
|
; SEND OP_COND COMMAND
|
|
LD A,SD_CMD_SEND_OP_COND ; SD_OP_COND
|
|
CALL SD_INITCMD ; SETUP COMMAND BUFFER
|
|
CALL SD_EXECCMDND ; EXEC COMMAND WITH NO DATA
|
|
RET NZ ; ABORT ON ERROR
|
|
; CHECK FOR IDLE, EXIT LOOP IF IDLE CLEARED
|
|
LD A,(SD_RC) ; GET CARD RESULT CODE
|
|
OR A ; SET FLAGS
|
|
JR Z,SD_INITCARD3C ; IDLE BIT CLEAR, EXIT LOOP
|
|
; LOOP AS NEEDED
|
|
LD HL,SD_LCNT ; POINT TO LOOP COUNTER
|
|
DEC (HL) ; DECREMENT LOOP COUNTER
|
|
JR NZ,SD_INITCARD3B ; LOOP UNTIL COUNTER EXHAUSTED
|
|
JP SD_ERRINITTO ; HANDLE INIT TIMEOUT ERROR
|
|
;
|
|
SD_INITCARD3C:
|
|
; SUCCESSFUL MMC CARD INITIALIZATION
|
|
LD C,SD_TYPEMMC ; MMC CARD TYPE
|
|
JR SD_INITCARD5 ; RESUME FLOW
|
|
;
|
|
SD_INITCARD4:
|
|
; CMD58 RETURNS THE 32 BIT OCR REGISTER (R3), WE WANT TO CHECK
|
|
; BIT 30, IF SET THIS IS SDHC/XC CARD
|
|
LD A,SD_CMD_READ_OCR ; READ_OCR
|
|
CALL SD_INITCMD ; SETUP COMMAND BUFFER
|
|
CALL SD_EXECCMD ; EXECUTE COMMAND
|
|
RET NZ ; ABORT ON ERROR
|
|
; CMD58 WORKED, GET OCR DATA AND SET CARD TYPE
|
|
CALL SD_GET ; BITS 31-24
|
|
CALL SD_DONE ; FINISH THE TRANSACTION
|
|
AND $40 ; ISOLATE BIT 30 (CCS)
|
|
LD C,SD_TYPESDSC ; ASSUME V1 CARD
|
|
JR Z,SD_INITCARD5 ; IF BIT NOT SET, THIS IS SDSC CARD
|
|
;
|
|
SD_INITCARD4A:
|
|
; ACMD51 RETURNS THE 64 BIT SCR REGISTER (ONLY AVAILABLE ON SDSC AND ABOVE)
|
|
; SD_SPEC3 (BIT 47) IS SET IF CARD IS SDXC OR GREATER
|
|
CALL SD_EXECACMD ; SEND APP COMMAND INTRODUCER
|
|
RET NZ ; ABORT ON ERROR (THIS SHOULD ALWAYS WORK)
|
|
LD A,SD_ACMD_SEND_SCR ; APP CMD SEND_SCR
|
|
CALL SD_INITCMD ; SETUP COMMAND BUFFER
|
|
CALL SD_EXECCMD ; EXECUTE COMMAND
|
|
RET NZ ; ABORT ON ERROR (THIS SHOULD ALWAYS WORK)
|
|
; ACMD51 SUCCEEDED, NOW GET THE SCR REGISTER CONTENTS
|
|
LD BC,8 ; 8 BYTES OF SCR
|
|
LD HL,SD_BUF ; PUT IN OUR PRIVATE BUFFER
|
|
CALL SD_GETDATA ; GET THE DATA
|
|
CALL SD_DONE ; CLOSE THE TRANSACTION
|
|
JP NZ,SD_ERRDATA ; DATA XFER ERROR
|
|
;
|
|
#IF (SDTRACE >= 3)
|
|
; IF TRACING, DUMP THE SCR CONTENTS
|
|
CALL SD_PRTPREFIX
|
|
LD DE,SD_STR_SCR
|
|
CALL WRITESTR
|
|
LD DE,SD_BUF
|
|
LD A,8
|
|
CALL PRTHEXBUF
|
|
#ENDIF
|
|
;
|
|
; EXTRACT THE SD_SECURITY FIELD AND SET SDHC/SDXC BASED ON VALUE
|
|
LD A,(SD_BUF + 1) ; GET THIRD BYTE (BITS 47-40) (55-48)
|
|
AND %01110000 ; ISOLATE SD_SECURITY BITS
|
|
CP $40 ; CHECK FOR SDXC VALUE
|
|
LD C,SD_TYPESDHC ; ASSUME CARD TYPE = SDHC
|
|
JR NZ,SD_INITCARD5 ; IF NOT SDXC, DONE
|
|
LD C,SD_TYPESDXC ; OTHERWISE, THIS IS SDXC CARD
|
|
;
|
|
SD_INITCARD5:
|
|
LD (IY+SD_TYPE),C ; SAVE CARD TYPE
|
|
|
|
#IF (SDTRACE >= 3)
|
|
CALL SD_PRTPREFIX
|
|
LD DE,SD_STR_SDTYPE
|
|
CALL WRITESTR
|
|
LD A,C
|
|
CALL PRTHEXBYTE
|
|
#ENDIF
|
|
;
|
|
; SET OUR DESIRED BLOCK LENGTH (512 BYTES)
|
|
LD A,SD_CMD_SET_BLOCKLEN ; SET_BLOCKLEN
|
|
CALL SD_INITCMD ; SETUP COMMAND BUFFER
|
|
LD DE,512 ; 512 BYTE BLOCK LENGTH
|
|
LD HL,SD_CMDP2 ; PUT VALUE INTO PARMS
|
|
LD (HL),D ; ... HIGH WORD (P0, P1) REMAIN ZERO
|
|
INC HL ; ... VALUE OF DE GET PUT IN LOW WORD (P2, P3)
|
|
LD (HL),E ; ... BUT OBSERVE BIG ENDIAN LAYOUT
|
|
CALL SD_EXECCMDND ; EXEC COMMAND W/ NO DATA
|
|
RET NZ ; ABORT ON ERROR
|
|
|
|
#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4) | (SDMODE == SDMODE_SC))
|
|
; PER SPEC, THE CARD SHOULD NOW BE ABLE TO HANDLE FULL SPEED OPERATION
|
|
; SO, FOR CSIO OPERATION, WE SET CSIO TO MAXIMUM SPEED
|
|
CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING
|
|
XOR A ; ZERO MEANS MAX SPEED
|
|
OUT (Z180_CNTR),A ; NOW SET CSIO PORT
|
|
#ENDIF
|
|
;
|
|
; ISSUE SEND_CSD (TO DERIVE CARD CAPACITY)
|
|
LD A,SD_CMD_SEND_CSD ; SEND_CSD
|
|
CALL SD_INITCMD ; SETUP COMMAND BUFFER
|
|
CALL SD_EXECCMD ; EXECUTE COMMAND
|
|
RET NZ ; ABORT ON ERROR
|
|
LD BC,16 ; 16 BYTES OF CSD
|
|
LD HL,SD_BUF ; PUT IN OUR PRIVATE BUFFER
|
|
CALL SD_GETDATA ; GET THE DATA
|
|
CALL SD_DONE ; CLOSE THE TRANSACTION
|
|
JP NZ,SD_ERRDATA ; DATA XFER ERROR
|
|
;
|
|
#IF (SDTRACE >= 3)
|
|
; IF TRACING, DUMP THE CSD CONTENTS
|
|
CALL SD_PRTPREFIX
|
|
LD DE,SD_STR_CSD
|
|
CALL WRITESTR
|
|
LD DE,SD_BUF
|
|
LD A,16
|
|
CALL PRTHEXBUF
|
|
#ENDIF
|
|
;
|
|
; GET SIZE OF DEVICE IN BLOCKS
|
|
LD A,(IY+SD_TYPE) ; GET CARD TYPE
|
|
OR A ; SET FLAGS
|
|
CALL Z,PANIC ; PANIC IF CARD TYPE UNKNOWN
|
|
CP SD_TYPESDHC ; COMPARE TO SDHC (V2)
|
|
JP NC,SD_INITCARD8 ; HANDLE SDHC (V2) OR BETTER
|
|
JR SD_INITCARD6 ; HANDLE MMC OR SDSC
|
|
;
|
|
; CAPACITY CALCULATION FOR MMC OR SDSC (V1) CARDS:
|
|
; BYTES = (C_SIZE + 1) * 2^(2+C_SIZE_MULT+READ_BL_LEN) = (C_SIZE+1) << (2+C_SIZE_MULT+READ_BL_LEN)
|
|
; BLOCKS = BYTES / 512 = BYTES >> 9
|
|
;
|
|
SD_INITCARD6: ; GET SIZE FOR V1 CARD
|
|
PUSH IX ; SAVE IX
|
|
LD IX,SD_BUF ; POINT IX TO BUFFER
|
|
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_INITCARD7:
|
|
SRA C ; SHIFT MSB
|
|
RR D ; SHIFT NEXT BYTE
|
|
RR E ; SHIFT LSB
|
|
DJNZ SD_INITCARD7 ; LOOP TILL DONE
|
|
PUSH DE ; DE = C_SIZE, SAVE IT
|
|
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
|
|
; FINAL MULTIPLIER IS 2^(C_SIZE_MULT + READ_BL_LEN + 2)
|
|
LD A,B ; READ_BL_LEN
|
|
ADD A,C ; AND C_SIZE_MULT
|
|
ADD A,2 ; AND 2 MORE BY DEFINITION
|
|
; RELOAD C_SIZE AND CONVERT TO 32 BIT VALUE IN DE:HL
|
|
POP HL ; RECOVE C_SIZE
|
|
INC HL ; ADD 1
|
|
LD DE,0 ; HI WORD IS ZERO
|
|
; ADJUST TO 512 BYTE BLOCK COUNT
|
|
LD B,A ; NORMALIZE TO BYTE COUNT
|
|
CALL SLA32 ; BIT SHIFT LEFT ACCORDING TO MULTIPLIERS
|
|
LD B,9 ; NORMALIZE TO 512 BYTE BLOCK COUNT
|
|
CALL SRL32 ; BIT SHIFT RIGHT 9 BITS
|
|
POP IX ; RESTORE IX
|
|
JR SD_INITCARD9 ; RECORD VALUE
|
|
;
|
|
; CAPACITY CALCULATION FOR SDHC/SDXC (V2/V3) CARDS:
|
|
; BLOCKS = (C_SIZE + 1) * 1024 = C_SIZE << 10
|
|
;
|
|
SD_INITCARD8: ; GET SIZE FOR V2 CARD
|
|
PUSH IX ; SAVE IX
|
|
LD IX,SD_BUF ; POINT IX TO BUFFER
|
|
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
|
|
POP IX ; RESTORE IX
|
|
; ADD 1 TO C_SIZE IN A:HL
|
|
LD DE,1 ; LOAD 1
|
|
ADD HL,DE ; ADD TO HL
|
|
ADC A,0 ; HANDLE CARRY
|
|
; CONVERT TO 32 BIT, A:HL -> DE:HL
|
|
LD D,0
|
|
LD E,A
|
|
; DIVIDE BY 1024 TO NORMALIZE, LEFT SHIFT 10 BITS
|
|
LD B,10 ; SHIFT BY 10 BITS
|
|
CALL SLA32 ; SHIFT THE 32 BIT VALUE
|
|
JR SD_INITCARD9 ; CONTINUE
|
|
;
|
|
SD_INITCARD9:
|
|
; SAVE DERIVED CAPACITY VALUE IN DE:HL
|
|
PUSH HL ; SAVE HL
|
|
LD A,SD_MEDCAP ; OFFSET TO CAPACITY FIELD
|
|
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
|
|
PUSH HL ; MOVE ADDRESS
|
|
POP BC ; ... TO BC
|
|
POP HL ; RECOVER HL
|
|
CALL ST32 ; SAVE THE CAPACITY VALUE (DWORD)
|
|
;
|
|
; RESET CARD STATUS TO 0 (OK)
|
|
XOR A ; A := 0 (STATUS = OK)
|
|
LD (IY+SD_STAT),A ; SAVE IT
|
|
;
|
|
RET ; RETURN, A=0, Z SET
|
|
|
|
; SECTOR I/O
|
|
; SD CARD COMMAND BYTE MUST BE PASSED IN C
|
|
;
|
|
SD_SECTIO:
|
|
PUSH BC
|
|
CALL SD_CHKCARD ; CHECK / REINIT CARD AS NEEDED
|
|
POP BC
|
|
RET NZ ; ABORT IF REINIT FAILED
|
|
|
|
LD A,C ; LOAD SD CARD COMMAND BYTE
|
|
CALL SD_INITCMD ; SETUP COMMAND BUFFER
|
|
CALL SD_SETADDR ; SETUP LBA ADDRESS
|
|
CALL SD_EXECCMD ; EXECUTE COMMAND
|
|
RET NZ ; ABORT ON ERROR
|
|
|
|
LD HL,(SD_DSKBUF)
|
|
LD BC,512 ; LENGTH TO READ
|
|
LD A,(SD_CMD) ; GET THE COMMAND
|
|
CP SD_CMD_READ_SNGL_BLK ; READ_SINGLE_BLOCK?
|
|
JR Z,SD_SECTIO1 ; HANDLE READ
|
|
CP SD_CMD_WRITE_BLOCK ; WRITE_BLOCK?
|
|
JR Z,SD_SECTIO2 ; HANDLE WRITE
|
|
CALL PANIC ; PANIC ON ANYTHING ELSE
|
|
SD_SECTIO1:
|
|
; GET SECTOR DATA
|
|
CALL SD_GETDATA ; GET THE BLOCK
|
|
JR SD_SECTIO3 ; AND CONTINUE
|
|
SD_SECTIO2:
|
|
; PUT SECTOR DATA
|
|
CALL SD_PUTDATA ; PUT THE BLOCK AND FALL THRU
|
|
SD_SECTIO3:
|
|
; CONTINUE WITH COMMON CODE
|
|
CALL SD_DONE ; CLOSE THE TRANSACTION
|
|
RET Z ; RETURN WITH A=0 AND Z SET
|
|
JP SD_ERRDATA ; DATA XFER ERROR
|
|
;
|
|
; CHECK THE SD CARD, ATTEMPT TO REINITIALIZE IF NEEDED
|
|
;
|
|
SD_CHKCARD:
|
|
; FIX: NEED TO CHECK CARD DETECT HERE AND
|
|
; HANDLE AS ERROR.
|
|
;
|
|
LD A,(IY+SD_STAT) ; GET CURRENT STATUS
|
|
OR A ; SET FLAGS
|
|
RET Z ; RETURN WITH A=0 AND Z SET
|
|
JP SD_INITCARD ; OTHERWISE INIT CARD
|
|
;
|
|
; CONVERT LBA ADDRESS TO CARD SPECIFIC ADDRESS IN CMD PARMS
|
|
; V1 CARDS REQUIRE BYTE ADDRESSING, SO A TRANSLATION IS DONE IN THAT CASE
|
|
;
|
|
SD_SETADDR:
|
|
LD A,(IY+SD_TYPE) ; GET CARD TYPE
|
|
PUSH AF ; SAVE IT
|
|
LD A,SD_LBA ; OFFSET OF LBA VALUE
|
|
CALL LDHLIYA ; HL := IY + A, REG A TRASHED
|
|
CALL LD32 ; LOAD IT TO DE:HL, AF IS TRASHED
|
|
POP AF ; GET CARD TYPE BACK
|
|
CP SD_TYPESDHC ; IS IT V2 OR BETTER?
|
|
JR NC,SD_SETADDR1 ; IF SO, BYPASS TRANSLATION
|
|
;
|
|
; TRANSLATE BLOCK ADDRESS TO BYTE ADDRESS FOR V1 CARDS
|
|
LD D,E
|
|
LD E,H
|
|
LD H,L
|
|
LD L,0
|
|
SLA L
|
|
RL H
|
|
RL E
|
|
RL D
|
|
;
|
|
SD_SETADDR1:
|
|
; STORE RESULTANT ADDRESS INTO PARMS (BIG ENDIAN!)
|
|
PUSH HL ; SAVE LOW WORD OF ADDRESS
|
|
LD HL,SD_CMDP0 ; POINT TO START OF PARM BYTES
|
|
LD (HL),D ; SAVE MSB OF HI WORD
|
|
INC HL ; NEXT BYTE
|
|
LD (HL),E ; SAVE LSB OF HI WORD
|
|
INC HL ; NEXT BYTE
|
|
POP DE ; RECOVER LOW WORD OF ADDRESS INTO DE
|
|
LD (HL),D ; SAVE MSB OF LO WORD
|
|
INC HL ; NEXT BYTE
|
|
LD (HL),E ; SAVE LSB OF LO WORD
|
|
RET ; DONE
|
|
;
|
|
;=============================================================================
|
|
; COMMAND PROCESSING
|
|
;=============================================================================
|
|
;
|
|
; PUT CARD IN IDLE STATE
|
|
;
|
|
SD_GOIDLE:
|
|
CALL SD_GOIDLE1 ; FIRST ATTEMPT
|
|
RET Z ; DONE IF SUCCEEDED
|
|
; FALL THRU FOR SECOND ATTEMPT IF NEEDED
|
|
;
|
|
SD_GOIDLE1:
|
|
; SEEMS TO HELP SOME CARDS?
|
|
;CALL SD_SELECT ; ASSERT CS
|
|
;CALL SD_DONE ; SEND 8 CLOCKS AND DEASSERT CS
|
|
|
|
; SMALL DELAY HERE HELPS SOME CARDS
|
|
;;LD DE,300 ; 16US * 300 = ~5MS
|
|
;LD DE,60 ; 16US * 60 = ~1MS
|
|
;CALL VDELAY ; CPU SPEED NORMALIZED DELAY
|
|
|
|
; PUT CARD IN IDLE STATE
|
|
LD A,SD_CMD_GO_IDLE_STATE ; CMD0 = ENTER IDLE STATE
|
|
CALL SD_INITCMD ; INIT COMMAND BUFFER
|
|
LD A,$95 ; CRC FOR GO_IDLE_STATE COMMAND IS $95
|
|
LD (SD_CMDCRC),A ; SET CRC
|
|
CALL SD_EXECCMDND ; EXECUTE COMMAND W/ NO DATA RETURNED
|
|
RET NZ ; ABORT ON ERROR
|
|
LD A,(SD_RC) ; GET CARD RESULT
|
|
DEC A ; MAP EXPECTED $01 -> $00
|
|
RET Z ; ALL IS GOOD, RETURN WITH A=0 AND Z SET
|
|
JP SD_ERRCMD ; SET COMMAND ERROR VALUE
|
|
;
|
|
; INITIALIZE COMMAND BUFFER
|
|
; COMMAND BYTE IN ACCUM
|
|
; HL AND AF DESTROYED
|
|
;
|
|
SD_INITCMD:
|
|
LD HL,SD_CMDBUF ; POINT TO START OF BUFFER
|
|
LD (HL),A ; SET THE COMMAND BYTE
|
|
XOR A ; CLEAR ACCUM
|
|
LD B,7 ; PREPARE TO CLEAR NEXT 7 BYTES (PARMS, CRC, RC, TOK)
|
|
SD_INITCMD1:
|
|
INC HL ; POINT TO NEXT BYTE
|
|
LD (HL),A ; CLEAR IT
|
|
DJNZ SD_INITCMD1 ; LOOP TILL DONE
|
|
RET
|
|
;
|
|
; EXECUTE APP COMMAND
|
|
;
|
|
SD_EXECACMD:
|
|
LD A,SD_CMD_APP_CMD ; APP_CMD, AN APP CMD IS NEXT
|
|
CALL SD_INITCMD ; SETUP COMMAND BUFFER
|
|
JR SD_EXECCMDND ; EXEC COMMAND W/ NO DATA RETURNED
|
|
;
|
|
; EXECUTE COMMAND WITH NO DATA
|
|
;
|
|
SD_EXECCMDND:
|
|
CALL SD_EXECCMD ; RUN THE COMMAND
|
|
JP Z,SD_DONE ; RETURN THRU SD_DONE IF NO ERROR
|
|
RET ; ERROR STATUS, JUST RETURN, SD_DONE WAS ALREADY RUN
|
|
;
|
|
; EXECUTE A COMMAND
|
|
; WILL FINISH TRANSACTION IF ERROR OCCURS
|
|
; RETURNS STATUS IN A WITH ZF SET ACCORDINGLY
|
|
;
|
|
SD_EXECCMD:
|
|
#IF (SDTRACE >= 3)
|
|
PUSH AF
|
|
CALL SD_PRTPREFIX
|
|
LD DE,SD_CMDBUF
|
|
PRTS(" CMD$")
|
|
LD A,6
|
|
CALL PRTHEXBUF
|
|
LD DE,SD_STR_ARROW
|
|
CALL WRITESTR
|
|
POP AF
|
|
#ENDIF
|
|
;
|
|
CALL SD_SELECT
|
|
;
|
|
#IF (SD_NOPULLUP)
|
|
; DO NOT WAIT FOR READY PRIOR TO CMD0! THIS HACK IS REQUIRED BY
|
|
; STUPID SD CARD ADAPTERS THAT NOW OMIT THE MISO PULL-UP. SEE
|
|
; COMMENTS AT TOP OF THIS FILE.
|
|
LD A,(SD_CMDBUF)
|
|
CP SD_CMD_GO_IDLE_STATE
|
|
JR Z,SD_EXECCMD0
|
|
#ENDIF
|
|
;
|
|
; WAIT FOR CARD TO BE READY
|
|
CALL SD_WAITRDY ; WAIT FOR CARD TO BE READY FOR A COMMAND
|
|
JP NZ,SD_ERRRDYTO ; HANDLE TIMEOUT ERROR
|
|
;
|
|
SD_EXECCMD0:
|
|
; SEND THE COMMAND
|
|
LD HL,SD_CMDBUF ; POINT TO COMMAND BUFFER
|
|
LD E,6 ; COMMANDS ARE 6 BYTES
|
|
SD_EXECCMD1:
|
|
LD A,(HL) ; PREPARE TO SEND NEXT BYTE
|
|
CALL SD_PUT ; SEND IT
|
|
INC HL ; POINT TO NEXT BYTE
|
|
DEC E ; DEC LOOP COUNTER
|
|
JR NZ,SD_EXECCMD1 ; LOOP TILL DONE W/ ALL 6 BYTES
|
|
;
|
|
#IF (SD_NOPULLUP)
|
|
; THE FIRST FILL BYTE IS DISCARDED! THIS HACK IS REQUIRED BY
|
|
; STUPID SD CARD ADAPTERS THAT NOW OMIT THE MISO PULL-UP. SEE
|
|
; COMMENTS AT TOP OF THIS FILE.
|
|
CALL SD_GET ; GET A BYTE AND DISCARD IT
|
|
#ENDIF
|
|
;
|
|
; GET RESULT
|
|
LD E,0 ; INIT TIMEOUT LOOP COUNTER
|
|
SD_EXECCMD2:
|
|
CALL SD_GET ; GET A BYTE FROM THE CARD
|
|
OR A ; SET FLAGS
|
|
JP P,SD_EXECCMD3 ; IF HIGH BIT IS 0, WE HAVE RESULT
|
|
DEC E ; OTHERWISE DECREMENT LOOP COUNTER
|
|
JR NZ,SD_EXECCMD2 ; AND LOOP UNTIL TIMEOUT
|
|
JP SD_ERRCMDTO
|
|
;
|
|
SD_EXECCMD3:
|
|
; COMMAND COMPLETE, SAVE RC AND PRINT DIAGNOSTICS AS APPROPRIATE
|
|
LD (SD_RC),A ; RECORD THE RESULT
|
|
#IF (SDTRACE >= 3)
|
|
CALL SD_PRTRC ; IF MAX TRACING, PRINT RC
|
|
#ENDIF
|
|
#IF (DSKYENABLE)
|
|
PUSH AF
|
|
CALL SD_DSKY ; IF USING DSKY, SHOW IT THERE
|
|
POP AF
|
|
#ENDIF
|
|
AND ~$01 ; MASK OFF IDLE BIT AND SET FLAGS
|
|
RET Z ; IF RC = 0, NO ERROR, RETURN
|
|
CALL SD_DONE ; IF ERROR, COMPLETE TRANSACTION
|
|
JP SD_ERRCMD ; ... AND HANDLE IT
|
|
;
|
|
; SD_GETDATA
|
|
;
|
|
SD_GETDATA:
|
|
#IF (SDMODE == SDMODE_MT)
|
|
LD DE,$7FFF ; LOOP MAX (TIMEOUT)
|
|
SD_GETDATA1:
|
|
IN A,(SD_RDTR)
|
|
|
|
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 ; SAVE TOKEN VALUE
|
|
#IF (SDTRACE >= 3)
|
|
PUSH AF
|
|
CALL SD_PRTTOK
|
|
POP AF
|
|
#ENDIF
|
|
|
|
CP $FE ; PACKET START?
|
|
JR NZ,SD_GETDATA4 ; NOPE, ABORT, A HAS ERROR CODE
|
|
|
|
LD D,B ; SIZE TO DB
|
|
LD B,C
|
|
LD C,(SD_RDTR)
|
|
|
|
INC B
|
|
DEC B
|
|
JR Z,SD_GETDATA3
|
|
INC D
|
|
SD_GETDATA3:
|
|
INIR ; GET BLOCK
|
|
|
|
DEC D
|
|
JR NZ,SD_GETDATA3 ; LOOP FOR ALL BYTES
|
|
|
|
IN A,(SD_RDTR) ; DISCARD CRC BYTE 1
|
|
IN A,(SD_RDTR) ; DISCARD CRC BYTE 2
|
|
#ELSE
|
|
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 ; SAVE TOKEN VALUE
|
|
#IF (SDTRACE >= 3)
|
|
PUSH AF
|
|
CALL SD_PRTTOK
|
|
POP AF
|
|
#ENDIF
|
|
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
|
|
#ENDIF
|
|
XOR A ; RESULT IS ZERO
|
|
SD_GETDATA4:
|
|
RET
|
|
;
|
|
; SD_PUTDATA
|
|
;
|
|
SD_PUTDATA:
|
|
#IF (SDMODE == SDMODE_MT)
|
|
LD D,B ; length to DB
|
|
LD B,C
|
|
LD A,$FE ; PACKET START
|
|
OUT (SD_WRTR),A ; SEND IT
|
|
|
|
LD C,SD_WRTR
|
|
|
|
INC B ; IF B!=0
|
|
DEC B
|
|
JR Z,SD_PUTDATA1
|
|
INC D ; THEN D=D+1
|
|
SD_PUTDATA1:
|
|
OTIR ; SEND B BYTES
|
|
|
|
DEC D
|
|
JR NZ,SD_PUTDATA1 ; LOOP FOR ALL BYTES
|
|
|
|
LD A,$FF ; DUMMY CRC BYTE
|
|
OUT (SD_WRTR),A
|
|
OUT (SD_WRTR),A ; SEND IT TWICE
|
|
|
|
LD DE,$7FFF ; LOOP MAX (TIMEOUT)
|
|
SD_PUTDATA2:
|
|
IN A,(SD_RDTR)
|
|
#ELSE
|
|
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
|
|
#ENDIF
|
|
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:
|
|
LD (SD_TOK),A
|
|
#IF (SDTRACE >= 3)
|
|
PUSH AF
|
|
CALL SD_PRTTOK
|
|
POP AF
|
|
#ENDIF
|
|
AND $1F
|
|
CP $05
|
|
RET NZ
|
|
XOR A
|
|
RET
|
|
;
|
|
; WAIT FOR CARD TO BE READY ($FF). MUST ALREADY BE SELECTED.
|
|
;
|
|
SD_WAITRDY:
|
|
LD DE,$FFFF ; 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
|
|
;
|
|
; FINISH A TRANSACTION - PRESERVE AF
|
|
;
|
|
; PER SPEC: AFTER THE LAST SPI BUS TRANSACTION, THE HOST IS REQUIRED, TO PROVIDE
|
|
; 8 (EIGHT) CLOCK CYCLES FOR THE CARD TO COMPLETE THE OPERATION BEFORE SHUTTING
|
|
; DOWN THE CLOCK. THROUGHOUT THIS 8 CLOCKS PERIOD THE STATE OF THE CS SIGNAL IS
|
|
; IRRELEVANT. IT CAN BE ASSERTED OR DE-ASSERTED.
|
|
;
|
|
; NOTE THAT I HAVE FOUND AT LEAST ONE MMC CARD THAT FAILS UNLESS THE CS SIGNAL
|
|
; REMAINS ACTIVE DURING THE 8 CLOCKS, SO THE CLOCKS ARE SENT BEFORE DESELECTING THE CARD.
|
|
;
|
|
SD_DONE:
|
|
PUSH AF
|
|
LD A,$FF
|
|
CALL SD_PUT
|
|
CALL SD_DESELECT
|
|
POP AF
|
|
RET
|
|
;
|
|
;=============================================================================
|
|
; HARDWARE INTERFACE ROUTINES
|
|
;=============================================================================
|
|
;
|
|
; PERFORM HARDWARE SPECIFIC INITIALIZATION
|
|
;
|
|
SD_SETUP:
|
|
;
|
|
#IF (SDMODE == SDMODE_PPI)
|
|
; PPISD IS DESIGNED TO CORESIDE ON THE SAME PARALLEL PORT
|
|
; AS A DSKY. SEE DSKY.ASM FOR DETAILS.
|
|
LD A,82H ; PPI PORT A=OUT, B=IN, C=OUT
|
|
OUT (SD_PPIX),A
|
|
#ENDIF
|
|
;
|
|
#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4) | (SDMODE == SDMODE_SC))
|
|
; CSIO SETUP FOR Z180 CSIO
|
|
; LD A,2 ; 18MHz/20 <= 400kHz
|
|
LD A,6 ; ???
|
|
OUT0 (SD_CNTR),A
|
|
#ENDIF
|
|
;
|
|
#IF ((SDMODE == SDMODE_JUHA) | (SDMODE == SDMODE_N8) | (SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_SC))
|
|
LD A,(RTCVAL)
|
|
LD (SD_OPRVAL),A
|
|
OUT (SD_OPRREG),A
|
|
#ENDIF
|
|
;
|
|
#IF ((SDMODE == SDMODE_MK4) | (SDMODE == SDMODE_DSD) | (SDMODE == SDMODE_PPI)| (SDMODE == SDMODE_MT))
|
|
LD A,SD_OPRDEF
|
|
LD (SD_OPRVAL),A
|
|
OUT (SD_OPRREG),A
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_UART)
|
|
SD_OPRMSK .EQU (SD_CS0 | 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
|
|
;
|
|
XOR A
|
|
RET
|
|
;
|
|
; TAKE ANY ACTIONS REQUIRED TO SELECT DESIRED PHYSICAL UNIT
|
|
; UNIT IS SPECIFIED IN A
|
|
;
|
|
SD_SELUNIT:
|
|
LD A,(IY+SD_DEV) ; GET CURRENT DEVICE
|
|
;
|
|
#IF (SDMODE == SDMODE_DSD)
|
|
; SELECT REQUESTED UNIT
|
|
OUT (SD_SELREG),A ; ACTUALLY SELECT THE CARD
|
|
#ENDIF
|
|
XOR A ; SIGNAL SUCCESS
|
|
RET ; DONE
|
|
;
|
|
; CHECK FOR CARD DETECT (NZ = MEDIA PRESENT)
|
|
;
|
|
SD_CHKCD:
|
|
#IF ((SDMODE == SDMODE_DSD) | (SDMODE == SDMODE_MK4))
|
|
IN A,(SD_OPRREG) ; GET OPERATIONS REGISTER
|
|
BIT 5,A ; TEST CARD DETECT BIT
|
|
#ELSE
|
|
OR $FF ; ASSUME CARD PRESENT
|
|
#ENDIF
|
|
RET ; DONE
|
|
;
|
|
; CHECK FOR WRITE PROTECT (NZ = WRITE PROTECTED)
|
|
;
|
|
SD_CHKWP:
|
|
#IF ((SDMODE == SDMODE_DSD) | (SDMODE == SDMODE_MK4))
|
|
IN A,(SD_OPRREG) ; GET OPERATIONS REGISTER
|
|
BIT 4,A ; TEST WP BIT
|
|
#ELSE
|
|
XOR A ; WP NOT SUPPORTED BY HARDWARE, ASSUME WP OFF
|
|
#ENDIF
|
|
RET ; AND RETURN
|
|
;
|
|
; SELECT CARD
|
|
;
|
|
SD_SELECT:
|
|
LD A,(IY+SD_DEV) ; GET CURRENT DEVICE
|
|
OR A ; SET FLAGS
|
|
LD A,(SD_OPRVAL) ; GET CURRENT OPRVAL BACK
|
|
JR NZ,SD_SELECT1 ; IF NOT ZERO, DO SECONDARY
|
|
; ASSERT PRIMARY CS, DEASSERT SECONDARY (IF ANY)
|
|
OR SD_CS0
|
|
#IF (SD_DEVCNT > 1)
|
|
AND ~SD_CS1
|
|
#ENDIF
|
|
JR SD_SELECT2
|
|
SD_SELECT1:
|
|
; DEASSERT PRIMARY CS, ASSERT SECONDARY (IF ANY)
|
|
AND ~SD_CS0
|
|
#IF (SD_DEVCNT > 1)
|
|
OR SD_CS1
|
|
#ENDIF
|
|
SD_SELECT2:
|
|
; ADJUST BIT(S) FOR INTERFACES USING INVERTED CS BITS
|
|
#IF ((SDMODE == SDMODE_PPI) | (SDMODE == SDMODE_UART) | (SDMODE == SDMODE_SC))
|
|
#IF (SD_DEVCNT > 1)
|
|
XOR SD_CS0 | SD_CS1
|
|
#ELSE
|
|
XOR SD_CS0
|
|
#ENDIF
|
|
#ENDIF
|
|
LD (SD_OPRVAL),A
|
|
OUT (SD_OPRREG),A
|
|
RET
|
|
;
|
|
; DESELECT CARD
|
|
;
|
|
SD_DESELECT:
|
|
LD A,(SD_OPRVAL)
|
|
#IF (SD_DEVCNT > 1)
|
|
AND ~(SD_CS0 | SD_CS1)
|
|
#ELSE
|
|
AND ~SD_CS0
|
|
#ENDIF
|
|
; ADJUST BIT(S) FOR INTERFACES USING INVERTED CS BITS
|
|
#IF ((SDMODE == SDMODE_PPI) | (SDMODE == SDMODE_UART) | (SDMODE == SDMODE_SC))
|
|
#IF (SD_DEVCNT > 1)
|
|
XOR SD_CS0 | SD_CS1
|
|
#ELSE
|
|
XOR SD_CS0
|
|
#ENDIF
|
|
#ENDIF
|
|
LD (SD_OPRVAL),A
|
|
OUT (SD_OPRREG),A
|
|
RET
|
|
;
|
|
#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4) | (SDMODE == SDMODE_SC))
|
|
;
|
|
; CSIO WAIT FOR TRANSMIT READY (TX REGSITER EMPTY)
|
|
;
|
|
SD_WAITTX: ; WAIT FOR TX EMPTY
|
|
IN0 A,(SD_CNTR) ; GET CSIO STATUS
|
|
BIT 4,A ; TX EMPTY?
|
|
JR NZ,SD_WAITTX
|
|
RET
|
|
;
|
|
; CSIO WAIT FOR RECEIVER READY (BYTE AVAILABLE)
|
|
;
|
|
SD_WAITRX:
|
|
IN0 A,(SD_CNTR) ; WAIT FOR RECEIVER TO FINISH
|
|
BIT 5,A
|
|
JR NZ,SD_WAITRX
|
|
RET
|
|
;
|
|
#ENDIF
|
|
;
|
|
; SEND ONE BYTE
|
|
;
|
|
SD_PUT:
|
|
;
|
|
#IF (SDMODE == SDMODE_MT)
|
|
OUT (SD_WRTR),A
|
|
#ELSE
|
|
;
|
|
#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4) | (SDMODE == SDMODE_SC))
|
|
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
|
|
#ENDIF
|
|
RET ; DONE
|
|
;
|
|
; RECEIVE ONE BYTE
|
|
;
|
|
;
|
|
SD_GET:
|
|
;
|
|
#IF (SDMODE == SDMODE_MT)
|
|
IN A,(SD_RDTR)
|
|
#ELSE
|
|
#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4) | (SDMODE == SDMODE_SC))
|
|
CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING
|
|
IN0 A,(Z180_CNTR) ; GET CSIO STATUS
|
|
SET 5,A ; START RECEIVER
|
|
OUT0 (Z180_CNTR),A
|
|
CALL SD_WAITRX
|
|
IN0 A,(Z180_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
|
|
#ENDIF
|
|
RET
|
|
;
|
|
;=============================================================================
|
|
; ERROR HANDLING AND DIAGNOSTICS
|
|
;=============================================================================
|
|
;
|
|
; ERROR HANDLERS
|
|
;
|
|
SD_INVUNIT:
|
|
LD A,SD_STINVUNIT
|
|
JR SD_ERR2 ; SPECIAL CASE FOR INVALID UNIT
|
|
;
|
|
SD_ERRRDYTO:
|
|
LD A,SD_STRDYTO
|
|
JR SD_ERR
|
|
;
|
|
SD_ERRINITTO:
|
|
LD A,SD_STINITTO
|
|
JR SD_ERR
|
|
;
|
|
SD_ERRCMDTO:
|
|
LD A,SD_STCMDTO
|
|
JR SD_ERR
|
|
;
|
|
SD_ERRCMD:
|
|
LD A,SD_STCMDERR
|
|
JR SD_ERR
|
|
;
|
|
SD_ERRDATA:
|
|
LD A,SD_STDATAERR
|
|
JR SD_ERR
|
|
;
|
|
SD_ERRDATATO:
|
|
LD A,SD_STDATATO
|
|
JR SD_ERR
|
|
;
|
|
SD_ERRCRC:
|
|
LD A,SD_STCRCERR
|
|
JR SD_ERR
|
|
;
|
|
SD_NOMEDIA:
|
|
LD A,SD_STNOMEDIA
|
|
JR SD_ERR
|
|
;
|
|
SD_WRTPROT:
|
|
LD A,SD_STWRTPROT
|
|
JR SD_ERR2 ; DO NOT UPDATE UNIT STATUS!
|
|
;
|
|
SD_ERR:
|
|
LD (IY+SD_STAT),A ; SAVE NEW STATUS
|
|
SD_ERR2:
|
|
#IF (SDTRACE >= 2)
|
|
CALL SD_PRTSTAT
|
|
CALL SD_REGDUMP
|
|
#ENDIF
|
|
PUSH AF
|
|
CALL SD_DESELECT ; De-select if there was an error
|
|
POP AF
|
|
OR A ; SET FLAGS
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
SD_PRTERR:
|
|
RET Z ; DONE IF NO ERRORS
|
|
; FALL THRU TO SD_PRTSTAT
|
|
;
|
|
; PRINT STATUS STRING
|
|
;
|
|
SD_PRTSTAT:
|
|
PUSH AF
|
|
PUSH DE
|
|
PUSH HL
|
|
OR A
|
|
LD DE,SD_STR_STOK
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SD_STR_STINVUNIT
|
|
JR Z,SD_PRTSTAT2 ; INVALID UNIT IS SPECIAL CASE
|
|
INC A
|
|
LD DE,SD_STR_STRDYTO
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SD_STR_STINITTO
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SD_STR_STCMDTO
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SD_STR_STCMDERR
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SD_STR_STDATAERR
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SD_STR_STDATATO
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SD_STR_STCRCERR
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SD_STR_STNOMEDIA
|
|
JR Z,SD_PRTSTAT1
|
|
INC A
|
|
LD DE,SD_STR_STWRTPROT
|
|
JR Z,SD_PRTSTAT1
|
|
LD DE,SD_STR_STUNK
|
|
SD_PRTSTAT1:
|
|
CALL SD_PRTPREFIX ; PRINT UNIT PREFIX
|
|
JR SD_PRTSTAT3
|
|
SD_PRTSTAT2:
|
|
CALL NEWLINE
|
|
PRTS("SD:$") ; NO UNIT NUM IN PREFIX FOR INVALID UNIT
|
|
SD_PRTSTAT3:
|
|
CALL PC_SPACE ; FORMATTING
|
|
CALL WRITESTR
|
|
POP HL
|
|
POP DE
|
|
POP AF
|
|
RET
|
|
;
|
|
SD_PRTRC:
|
|
PUSH AF
|
|
PUSH DE
|
|
LD DE,SD_STR_RC
|
|
CALL WRITESTR
|
|
LD A,(SD_RC)
|
|
CALL PRTHEXBYTE
|
|
POP DE
|
|
POP AF
|
|
RET
|
|
;
|
|
SD_PRTTOK:
|
|
PUSH AF
|
|
PUSH DE
|
|
LD DE,SD_STR_TOK
|
|
CALL WRITESTR
|
|
LD A,(SD_TOK)
|
|
CALL PRTHEXBYTE
|
|
POP DE
|
|
POP AF
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
SD_REGDUMP:
|
|
PUSH AF
|
|
PUSH BC
|
|
PUSH HL
|
|
CALL PC_SPACE
|
|
CALL PC_LBKT
|
|
LD HL,SD_CMDBUF
|
|
LD B,8
|
|
SD_REGDUMP1:
|
|
LD A,(HL)
|
|
INC HL
|
|
CALL PRTHEXBYTE
|
|
DJNZ SD_REGDUMP1
|
|
CALL PC_RBKT
|
|
POP HL
|
|
POP BC
|
|
POP AF
|
|
RET
|
|
|
|
;
|
|
; PRINT DIAGNONSTIC PREFIX
|
|
;
|
|
SD_PRTPREFIX:
|
|
PUSH AF
|
|
CALL NEWLINE
|
|
PRTS("SD$")
|
|
LD A,(IY+SD_DEV) ; GET CURRENT DEVICE NUM
|
|
ADD A,'0'
|
|
CALL COUT
|
|
CALL PC_COLON
|
|
POP AF
|
|
RET
|
|
;
|
|
; DISPLAY COMMAND, LOW ORDER WORD OF PARMS, AND RC
|
|
;
|
|
#IF (DSKYENABLE)
|
|
SD_DSKY:
|
|
PUSH AF
|
|
PUSH HL
|
|
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 HL
|
|
POP AF
|
|
RET
|
|
#ENDIF
|
|
;
|
|
;=============================================================================
|
|
; STRING DATA
|
|
;=============================================================================
|
|
;
|
|
SD_STR_ARROW .TEXT " -->$"
|
|
SD_STR_RC .TEXT " RC=$"
|
|
SD_STR_TOK .TEXT " TOK=$"
|
|
SD_STR_CSD .TEXT " CSD =$"
|
|
SD_STR_CID .TEXT " CID =$"
|
|
SD_STR_SCR .TEXT " SCR =$"
|
|
SD_STR_SDTYPE .TEXT " SD CARD TYPE ID=$"
|
|
;
|
|
SD_STR_STOK .TEXT "OK$"
|
|
SD_STR_STINVUNIT .TEXT "INVALID UNIT$"
|
|
SD_STR_STRDYTO .TEXT "READY TIMEOUT$"
|
|
SD_STR_STINITTO .TEXT "INITIALIZATION TIMEOUT$"
|
|
SD_STR_STCMDTO .TEXT "COMMAND TIMEOUT$"
|
|
SD_STR_STCMDERR .TEXT "COMMAND ERROR$"
|
|
SD_STR_STDATAERR .TEXT "DATA ERROR$"
|
|
SD_STR_STDATATO .TEXT "DATA TIMEOUT$"
|
|
SD_STR_STCRCERR .TEXT "CRC ERROR$"
|
|
SD_STR_STNOMEDIA .TEXT "NO MEDIA$"
|
|
SD_STR_STWRTPROT .TEXT "WRITE PROTECTED$"
|
|
SD_STR_STUNK .TEXT "UNKNOWN$"
|
|
SD_STR_TYPEUNK .TEXT "UNK$"
|
|
SD_STR_TYPEMMC .TEXT "MMC$"
|
|
SD_STR_TYPESDSC .TEXT "SDSC$"
|
|
SD_STR_TYPESDHC .TEXT "SDHC$"
|
|
SD_STR_TYPESDXC .TEXT "SDXC$"
|
|
;
|
|
;=============================================================================
|
|
; DATA STORAGE
|
|
;=============================================================================
|
|
;
|
|
SD_OPRVAL .DB 0 ; CURRENT OPR REG VALUE
|
|
SD_LCNT .DB 0 ; LOOP COUNTER
|
|
SD_CMDVAL .DB 0 ; PENDING COMMAND FOR IO FUCNTIONS
|
|
SD_BLKCNT .DB 0 ; BLOCK COUNT REQUESTED FOR IO FUNCTIONS
|
|
;
|
|
SD_BUF .FILL 16,0 ; WORK BUFFER
|
|
;
|
|
SD_CMDBUF: ; START OF STD CMD BUF
|
|
SD_CMD .DB 0 ; COMMAND BYTE
|
|
SD_CMDP0 .DB 0 ; FIRST PARM BYTE (MSB)
|
|
SD_CMDP1 .DB 0
|
|
SD_CMDP2 .DB 0
|
|
SD_CMDP3 .DB 0 ; LAST PARM BYTE (LSB)
|
|
SD_CMDCRC .DB 0 ; CRC
|
|
;
|
|
SD_RC .DB 0 ; RETURN CODE FROM CMD
|
|
SD_TOK .DB 0 ; TOKEN FROM DATA XFR
|
|
;
|
|
SD_DSKBUF .DW 0 ; ADR OF ACTIVE DISK BUFFER
|
|
;
|
|
;=============================================================================
|
|
; HELPER ROUTINES
|
|
;=============================================================================
|
|
;
|
|
; MSB<-->LSB MIRROR BITS IN A, RESULT IN C
|
|
;
|
|
MIRROR:
|
|
#IF (((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4) | (SDMODE == SDMODE_SC)) & SDCSIOFAST)
|
|
; 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
|
|
#ELSE
|
|
; SLOWER BUT LESS CODE SPACE
|
|
LD C,A ; A = 76543210
|
|
RLCA
|
|
RLCA ; A = 54321076
|
|
XOR C
|
|
AND 0AAH
|
|
XOR C ; A = 56341270
|
|
LD C,A
|
|
RLCA
|
|
RLCA
|
|
RLCA ; A = 41270563
|
|
RRC C ; C = 05634127
|
|
XOR C
|
|
AND 066H
|
|
XOR C ; A = 01234567
|
|
LD C,A ; RETURN RESULT IN C
|
|
RET
|
|
#ENDIF
|
|
;
|
|
; LOOKUP TABLE TO MIRROR BITS IN A BYTE
|
|
;
|
|
#IF (((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4) | (SDMODE == SDMODE_SC)) & 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
|
|
|