mirror of
https://github.com/wwarthen/RomWBW.git
synced 2026-02-06 22:43:15 -06:00
- Dual SD support in sd.asm was broken for two cards when the SC126 dual SD card support was added. This should fix all scenarios.
2260 lines
64 KiB
NASM
2260 lines
64 KiB
NASM
;
|
|
;=============================================================================
|
|
; 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 = MOSI = DATA IN (HOST -> CARD, AKA CMD FOR NON-SPI MODE)
|
|
; DO = MISO = 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 3
|
|
; (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 WITHIN 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
|
|
;
|
|
SD_DEVCNT .EQU SDCNT ; SET SD_DEVCNT TO SDCNT CONFIG VAR
|
|
;
|
|
#IF (SDMODE == SDMODE_JUHA) ; JUHA MINI-BOARD
|
|
SD_DEVMAX .EQU 1 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_OPRREG .EQU RTCIO ; USES RTC LATCHES FOR OPERATION
|
|
SD_OPRDEF .EQU %00000001 ; QUIESCENT STATE
|
|
SD_OPRMSK .EQU %10000111 ; MASK FOR BITS WE OWN IN RTC LATCH PORT
|
|
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)
|
|
SD_IOBASE .EQU SD_OPRREG ; IOBASE
|
|
;
|
|
RTCDEF .SET RTCDEF | SD_OPRDEF ; SET DEFAULT IN HBIOS MAINLINE
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_N8) ; UNMODIFIED N8-2511
|
|
SD_DEVMAX .EQU 1 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_OPRREG .EQU RTCIO ; USES RTC LATCHES FOR OPERATION
|
|
SD_OPRDEF .EQU %00000001 ; QUIESCENT STATE
|
|
SD_OPRMSK .EQU %01000111 ; MASK FOR BITS WE OWN IN RTC LATCH PORT
|
|
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)
|
|
SD_IOBASE .EQU SD_OPRREG ; IOBASE
|
|
;
|
|
RTCDEF .SET RTCDEF | SD_OPRDEF ; SET DEFAULT IN HBIOS MAINLINE
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_CSIO) ; N8-2312
|
|
SD_DEVMAX .EQU 1 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_OPRREG .EQU RTCIO ; USES RTC LATCHES FOR OPERATION
|
|
SD_OPRDEF .EQU %00000000 ; QUIESCENT STATE
|
|
SD_OPRMSK .EQU %00000100 ; MASK FOR BITS WE OWN IN RTC LATCH PORT
|
|
SD_CS0 .EQU %00000100 ; RTC:2 IS SELECT
|
|
SD_CNTR .EQU Z180_CNTR
|
|
SD_TRDR .EQU Z180_TRDR
|
|
SD_IOBASE .EQU SD_OPRREG ; IOBASE
|
|
;
|
|
RTCDEF .SET RTCDEF | SD_OPRDEF ; SET DEFAULT IN HBIOS MAINLINE
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_PPI) ; PPISD
|
|
SD_DEVMAX .EQU 1 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_PPIBASE .EQU SDPPIBASE ; BASE IO PORT FOR PPI
|
|
SD_PPIB .EQU SDPPIBASE + 1 ; PPI PORT B (INPUT: DOUT)
|
|
SD_PPIC .EQU SDPPIBASE + 2 ; PPI PORT C (OUTPUT: CS, CLK, DIN)
|
|
SD_PPIX .EQU SDPPIBASE + 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)
|
|
SD_IOBASE .EQU SD_PPIBASE ; IOBASE
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_UART)
|
|
SD_DEVMAX .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_OPRMSK .EQU %00101101 ; MASK FOR BITS WE OWN IN RTC LATCH PORT
|
|
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)
|
|
SD_IOBASE .EQU UARTIOB ; IOBASE
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_DSD) ; DUAL SD
|
|
SD_DEVMAX .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_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)
|
|
SD_IOBASE .EQU SD_OPRREG ; IOBASE
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_MK4) ; MARK IV (CSIO STYLE INTERFACE)
|
|
SD_DEVMAX .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
|
|
SD_IOBASE .EQU SD_OPRREG ; IOBASE
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_SC) ; SC
|
|
SD_DEVMAX .EQU 2 ; NUMBER OF PHYSICAL UNITS (SOCKETS)
|
|
SD_OPRREG .EQU RTCIO ; USES RTC LATCHES FOR OPERATION
|
|
SD_OPRDEF .EQU %00001100 ; QUIESCENT STATE (/CS1 & /CS2 DEASSERTED)
|
|
SD_OPRMSK .EQU %00001100 ; MASK FOR BITS WE OWN IN RTC LATCH PORT
|
|
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
|
|
SD_IOBASE .EQU SD_OPRREG ; IOBASE
|
|
;
|
|
RTCDEF .SET RTCDEF | SD_OPRDEF ; SET DEFAULT IN HBIOS MAINLINE
|
|
#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.
|
|
;
|
|
; NOTE THAT DOING AN "IN RDTR" WILL RETURN THE *EXISTING* CONTENTS
|
|
; OF THE SHIFT REGISTER, THEN INITIATE AN SPI READ. SO THE "IN" WILL BE
|
|
; RETURNING THE DATA RECEIVED FROM THE PRIOR "IN RDTR", OR "OUT WRTR".
|
|
; "IN RDNTR" WILL RETURN THE EXISTING SHIFT REGISTER CONTENTS WITHOUT
|
|
; INITIATING A NEW SPI READ.
|
|
;
|
|
; THANKS TO DOUGLAS MILLER FOR BRINGING THIS BEHAVIOR TO MY ATTENTION
|
|
; AND SUPPLYING ASSOCIATED FIXES.
|
|
;
|
|
SD_BASE .EQU $5C ; Module base address
|
|
SD_DEVMAX .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
|
|
#IF (!SDMTSWAP)
|
|
; USE NATURAL ORDER
|
|
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
|
|
#ELSE
|
|
; REVERSE THE PORTS
|
|
SD_CD0 .EQU %00000100 ; IN:SD_OPREG:2 = CD2, IN=0 Card detect switch
|
|
SD_CD1 .EQU %00000010 ; IN:SD_OPREG:1 = CD1, IN=0 Card detect switch
|
|
#ENDIF
|
|
SD_CSX .EQU %00001000 ; IN/OUT:SD_OPREG:3 = CS0, PMOD SPI CS
|
|
#IF (!SDMTSWAP)
|
|
; USE NATURAL ORDER
|
|
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
|
|
#ELSE
|
|
; REVERSE THE PORTS
|
|
SD_CS0 .EQU %00100000 ; IN/OUT:SD_OPREG:5 = CS2, SDCARD2 CS, IN=1 Card present
|
|
SD_CS1 .EQU %00010000 ; IN/OUT:SD_OPREG:4 = CS1, SDCARD1 CS, IN=1 Card present
|
|
#ENDIF
|
|
SD_IOBASE .EQU SD_BASE ; IOBASE
|
|
#ENDIF
|
|
;
|
|
#IF (SD_DEVCNT > SD_DEVMAX)
|
|
.ECHO "*** ERROR: SDCNT EXCEEDS MAXIMUM SUPPORTED BY INTERFACE!!!\n"
|
|
!!! ; FORCE AN ASSEMBLY ERROR
|
|
#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,(HB_RTCVAL) ; GET RTC PORT SHADOW VALUE
|
|
AND ~SD_OPRMSK ; CLEAR OUR BITS
|
|
OR SD_OPRDEF ; SET OUR BIT DEFAULTS
|
|
LD (HB_RTCVAL),A ; SAVE IT
|
|
#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_N8)
|
|
PRTS(" MODE=N8$")
|
|
PRTS(" IO=0x$")
|
|
LD A,SD_OPRREG
|
|
CALL PRTHEXBYTE
|
|
;
|
|
LD A,(HB_RTCVAL) ; GET RTC PORT SHADOW VALUE
|
|
AND ~SD_OPRMSK ; CLEAR OUR BITS
|
|
OR SD_OPRDEF ; SET OUR BIT DEFAULTS
|
|
LD (HB_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,(HB_RTCVAL) ; GET RTC PORT SHADOW VALUE
|
|
AND ~SD_OPRMSK ; CLEAR OUR BITS
|
|
OR SD_OPRDEF ; SET OUR BIT DEFAULTS
|
|
LD (HB_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,(HB_RTCVAL) ; GET RTC PORT SHADOW VALUE
|
|
AND ~SD_OPRMSK ; CLEAR OUR BITS
|
|
OR SD_OPRDEF ; SET OUR BIT DEFAULTS
|
|
LD (HB_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
|
|
;
|
|
XOR A ; SIGNAL SUCCESS
|
|
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 SYSCHK ; INVALID SUB-FUNCTION
|
|
LD A,ERR_NOTIMPL
|
|
OR A
|
|
RET
|
|
;
|
|
;
|
|
;
|
|
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 ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4) | (SDMODE == SDMODE_SC))
|
|
; CONSIDER CAPTURING CURRENT CNTR VALUE HERE AND USE IT
|
|
; IN SD_CSIO_DEF
|
|
|
|
; SET CSIO FOR HIGH SPEED OPERATION
|
|
CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING
|
|
CALL DLY32 ; WAIT A BIT MORE FOR FINAL BIT
|
|
XOR A ; ZERO MEANS MAX SPEED
|
|
OUT0 (SD_CNTR),A ; NOW SET CSIO PORT
|
|
; HOOK RETURN TO RESTORE CSIO TO DEFAULT SPEED
|
|
LD HL,SD_CSIO_DEF ; ROUTE RETURN
|
|
PUSH HL ; ... THRU CSIO RESTORE
|
|
#ENDIF
|
|
;
|
|
#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 Z ; RETURN IF SUCCESS
|
|
LD A,ERR_IO ; SIGNAL IO ERROR
|
|
OR A ; SET FLAGS
|
|
RET ; AND DONE
|
|
;
|
|
;
|
|
;
|
|
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 >= 3)
|
|
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
|
|
LD H,SDMODE ; H := MODE
|
|
LD L,(SD_IOBASE) ; L := BASE I/O ADDRESS
|
|
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
|
|
LD A,ERR_NOMEDIA ; NO MEDIA ERROR
|
|
OR A ; SET FLAGS
|
|
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
|
|
;
|
|
#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4) | (SDMODE == SDMODE_SC))
|
|
CALL SD_CSIO_DEF ; ENSURE CSIO AT DEFAULT SPEED
|
|
#ENDIF
|
|
;
|
|
; 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
|
|
;
|
|
; MAKE SURE WE FINISH SENDING
|
|
#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4) | (SDMODE == SDMODE_SC))
|
|
CALL SD_WAITTX ; WAIT FOR TE TO CLEAR
|
|
CALL DLY32 ; WAIT A BIT MORE FOR FINAL BIT
|
|
#ENDIF
|
|
;
|
|
; 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
|
|
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
|
|
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
|
|
; 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
|
|
|
|
; HIGH SPEED CSIO OPERATION IS NOW SET AT THE START OF SD_IO
|
|
;
|
|
;#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
|
|
; CALL DLY32 ; WAIT A BIT MORE FOR FINAL BIT
|
|
; XOR A ; ZERO MEANS MAX SPEED
|
|
; OUT0 (SD_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
|
|
JR Z,SD_INITCARD5A ; HANDLE 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
|
|
;
|
|
SD_INITCARD5A:
|
|
CALL SYSCHK
|
|
JP SD_NOMEDIA
|
|
;
|
|
; 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
|
|
LD A,ERR_INTERNAL
|
|
OR A
|
|
RET
|
|
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
|
|
#IF (DSKYENABLE)
|
|
CALL HB_DSKACT ; SHOW ACTIVITY
|
|
#ENDIF
|
|
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
|
|
; THE CRC POSITION IS ACTUALLY 7 BITS OF CRC (HIGH BITS) AND
|
|
; 1 BIT INDICATING END OF COMMAND. MOST CARDS DON'T REALLY
|
|
; CARE ABOUT THE END OF COMMAND BIT, BUT I HAVE WORKED WITH
|
|
; AT LEAST ONE PERSON THAT HAD A CARD THAT NEEDED THIS.
|
|
; SO, BELOW WE STUFF THE CRC POSITION WITH $FF.
|
|
DEC A ; $FF TO ACCUM
|
|
LD (SD_CMDCRC),A ; PUT $FF IN CRC POSITION
|
|
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
|
|
;
|
|
; THE Z180 -K REVISION CSIO DOES NOT KEEP MOSI HIGH WHEN
|
|
; RECEIVING VIA MISO. INSTEAD MOSI IS LEFT AT WHICHEVER LOGIC
|
|
; LEVEL IT WAS LAST SET TO. THIS CAUSES SOME SD CARDS A PROBLEM
|
|
; BECAUSE THEY EXPECT MOSI TO BE CONSISTENTLY HIGH WHEN IDLE.
|
|
; BY USING A PUT INSTEAD OF A GET, WE CAN FORCE MOSI TO BE
|
|
; LEFT AT THE PROPER LOGIC LEVEL. THE SD CARD DOES NOT CARE
|
|
; IF A PUT OR A GET IS USED TO IGNORE THE BYTE BECAUSE THE
|
|
; CLOCK RUNS IN EITHER CASE.
|
|
LD A,$FF ; KEEP MOSI HI
|
|
CALL SD_PUT ; SEND 8 CLOCKS
|
|
#ENDIF
|
|
;
|
|
; GET RESULT
|
|
LD E,0 ; INIT TIMEOUT LOOP COUNTER
|
|
#IF (SDMODE == SDMODE_MT)
|
|
CALL SD_GET ; DISCARD STALE DATA FROM PUT
|
|
#ENDIF
|
|
;
|
|
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)
|
|
IN A,(SD_RDTR) ; DISCARD STALE DATA FROM OUT
|
|
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)
|
|
#IF (SDMODE == SDMODE_MT)
|
|
CALL SD_GET ; DISCARD STALE DATA - UNKNOWN CONTEXT
|
|
#ENDIF
|
|
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 ; DIV 80, 225KHZ @ 18MHZ CLK
|
|
LD A,6 ; DIV 1280, 14KHZ @ 18MHZ CLK
|
|
OUT0 (SD_CNTR),A
|
|
#ENDIF
|
|
;
|
|
#IF ((SDMODE == SDMODE_JUHA) | (SDMODE == SDMODE_N8) | (SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_SC))
|
|
LD A,(HB_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)
|
|
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:
|
|
; ; FINISH SENDING BEFORE ASSERTING CS!
|
|
;#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4) | (SDMODE == SDMODE_SC))
|
|
; CALL SD_WAITTX
|
|
;#ENDIF
|
|
;
|
|
#IF (SDMODE == SDMODE_SC)
|
|
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
|
|
#ELSE
|
|
LD A,(SD_OPRVAL) ; GET CURRENT OPRVAL BACK
|
|
OR SD_CS0
|
|
#ENDIF
|
|
;
|
|
SD_SELECT2:
|
|
; ADJUST BIT(S) FOR INTERFACES USING INVERTED CS BITS
|
|
#IF ((SDMODE == SDMODE_PPI) | (SDMODE == SDMODE_UART) | (SDMODE == SDMODE_SC))
|
|
#IF ((SDMODE == SDMODE_SC) & (SD_DEVCNT > 1))
|
|
XOR SD_CS0 | SD_CS1
|
|
#ELSE
|
|
XOR SD_CS0
|
|
#ENDIF
|
|
#ENDIF
|
|
LD (SD_OPRVAL),A
|
|
OUT (SD_OPRREG),A
|
|
;;
|
|
;#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4) | (SDMODE == SDMODE_SC))
|
|
; CALL DLY32 ; DELAY FOR FINAL BIT
|
|
;#ENDIF
|
|
;
|
|
RET
|
|
;
|
|
; DESELECT CARD
|
|
;
|
|
SD_DESELECT:
|
|
#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4) | (SDMODE == SDMODE_SC))
|
|
; DON'T REMOVE CS UNTIL WE ARE DONE SENDING!
|
|
CALL SD_WAITTX ; WAIT FOR TE TO CLEAR
|
|
;
|
|
; ACCORDING TO Z180 DOCS, IT MAY TAKE UP TO 1 BIT TIME TO
|
|
; FINISH SENDING AFTER TE IS CLEARED. THE DELAY BELOW WILL
|
|
; DO THIS FOR THE SLOWEST POSSIBLE SEND RATE WHICH IS
|
|
; CLK / 1320, SO DELAY AT LEAST 1320 T-STATES
|
|
;
|
|
; IN PRACTICE, A SMALLER DELAY IS FINE BASED ON LOGIC ANALYZER
|
|
; TRACES.
|
|
CALL DLY32 ; DELAY FOR FINAL BIT
|
|
#ENDIF
|
|
;
|
|
LD A,(SD_OPRVAL)
|
|
#IF ((SDMODE == SDMODE_SC) & (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 ((SDMODE == SDMODE_SC) & (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:
|
|
IN0 A,(SD_CNTR) ; GET CSIO STATUS
|
|
BIT 4,A ; TX EMPTY?
|
|
JR NZ,SD_WAITTX ; LOOP WHILE BUSY
|
|
RET ; DONE
|
|
;
|
|
; CSIO WAIT FOR RECEIVER READY (BYTE AVAILABLE)
|
|
;
|
|
SD_WAITRX:
|
|
IN0 A,(SD_CNTR) ; WAIT FOR RECEIVER TO FINISH
|
|
BIT 5,A ; RX EMPTY?
|
|
JR NZ,SD_WAITRX ; LOOP WHILE BUSY
|
|
RET ; DONE
|
|
;
|
|
#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,(SD_CNTR) ; GET CSIO STATUS
|
|
SET 5,A ; START RECEIVER
|
|
OUT0 (SD_CNTR),A
|
|
CALL SD_WAITRX
|
|
IN0 A,(SD_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
|
|
;
|
|
; SET CSIO TO DEFAULT SPEED
|
|
;
|
|
#IF ((SDMODE == SDMODE_CSIO) | (SDMODE == SDMODE_MK4) | (SDMODE == SDMODE_SC))
|
|
;
|
|
SD_CSIO_DEF:
|
|
; SET CSIO FOR DEFAULT OPERATION
|
|
PUSH AF ; PRESERVE AF
|
|
CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING
|
|
CALL DLY32 ; WAIT A BIT MORE FOR FINAL BIT
|
|
LD A,Z180_CNTR_DEF ; DIV 1280, 14KHZ @ 18MHZ CLK
|
|
OUT0 (SD_CNTR),A ; DO IT
|
|
POP AF ; RESTORE AF
|
|
RET
|
|
;
|
|
#ENDIF
|
|
;
|
|
;
|
|
;=============================================================================
|
|
; 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
|
|
LD A,(IY+SD_STAT)
|
|
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
|