forked from Apple-2-HW/AppleIISd
720 lines
19 KiB
ArmAsm
720 lines
19 KiB
ArmAsm
********************************
|
||
*
|
||
* Apple][Sd Firmware
|
||
* Version 0.5
|
||
*
|
||
* (c) Florian Reitz, 2017
|
||
*
|
||
* X register usually contains SLOT16
|
||
* Y register is used for counting or SLOT
|
||
*
|
||
********************************
|
||
|
||
DAT
|
||
|
||
XC ; enable 65C02 code
|
||
DEBUG = 0
|
||
DO DEBUG
|
||
ORG $8000
|
||
ELSE
|
||
ORG $C800 ; Expansion ROM
|
||
FIN
|
||
|
||
* Memory defines
|
||
|
||
SLOT16 = $2B ; $s0 -> slot * 16
|
||
WORK = $3C
|
||
SLOT = $3D ; $0s
|
||
CMDLO = $40
|
||
CMDHI = $41
|
||
|
||
CURSLOT = $07F8 ; $Cs
|
||
DATA = $C080
|
||
CTRL = DATA+1
|
||
DIV = DATA+2
|
||
SS = DATA+3
|
||
R30 = $0478
|
||
R31 = $04F8
|
||
R32 = $0578
|
||
R33 = $05F8
|
||
INITED = $0678
|
||
|
||
* Constants
|
||
|
||
SSNONE = $0F
|
||
SS0 = $0E
|
||
DUMMY = $FF
|
||
|
||
|
||
********************************
|
||
*
|
||
* Install SD card driver
|
||
*
|
||
********************************
|
||
|
||
* signature bytes
|
||
|
||
LDX #$20
|
||
LDY #$00
|
||
LDX #$03
|
||
===== Page 2 =====
|
||
|
||
STX WORK
|
||
|
||
* find slot nr
|
||
|
||
DO DEBUG
|
||
LDA #$04
|
||
STA SLOT
|
||
LDA #$C4
|
||
STA CURSLOT
|
||
LDA #$40
|
||
STA SLOT16
|
||
ELSE
|
||
JSR $FF58
|
||
TSX
|
||
LDA $0100,X
|
||
STA CURSLOT ; $Cs
|
||
AND #$0F
|
||
STA SLOT ; $0s
|
||
ASL A
|
||
ASL A
|
||
ASL A
|
||
ASL A
|
||
STA SLOT16 ; $s0
|
||
FIN
|
||
TAX ; X holds now SLOT16
|
||
|
||
BIT $CFFF
|
||
JSR INIT
|
||
|
||
DO 0
|
||
*
|
||
* TODO: check for init error
|
||
*
|
||
|
||
* see if slot has a driver already
|
||
|
||
LDX $BF31 ; get devcnt
|
||
INSLP LDA $BF32,X ; get a devnum
|
||
AND #$70 ; isolate slot
|
||
CMP SLOT16 ; slot?
|
||
BEQ INSOUT ; yes, skip it
|
||
DEX
|
||
BPL INSLP ; keep up the search
|
||
|
||
* restore the devnum to the list
|
||
|
||
LDX $BF31 ; get devcnt again
|
||
CPX #$0D ; device table full?
|
||
BNE INSLP2
|
||
|
||
JSR $FF3A ; bell
|
||
JMP INSOUT ; do something!
|
||
|
||
INSLP2 LDA $BF32-1,X ; move all entries down
|
||
STA $BF32,X ; to make room at front
|
||
DEX ; for a new entry
|
||
BNE INSLP2
|
||
===== Page 3 =====
|
||
|
||
LDA #$04 ; ProFile type device
|
||
ORA SLOT16
|
||
STA $BF32 ; slot, drive 1 at top of list
|
||
INC $BF31 ; update devcnt
|
||
|
||
* now insert the device driver vector
|
||
|
||
LDA SLOT
|
||
ASL
|
||
TAX
|
||
LDA #<DRIVER
|
||
STA $BF10,X ; write to driver table
|
||
DO DEBUG
|
||
LDA #>DRIVER
|
||
ELSE
|
||
LDA CURSLOT
|
||
FIN
|
||
STA $BF11,X
|
||
|
||
INSOUT RTS
|
||
FIN
|
||
|
||
BOOT LDA #$01
|
||
STA $42 ; load command
|
||
LDA SLOT16
|
||
TAX
|
||
STA $43 ; slot number
|
||
STZ $44 ; buffer lo
|
||
LDA #$08
|
||
STA $45 ; buffer hi
|
||
STZ $46 ; block lo
|
||
STZ $47 ; block hi
|
||
BIT $CFFF
|
||
JSR READ ; call driver
|
||
JMP $801 ; goto bootloader
|
||
|
||
|
||
********************************
|
||
*
|
||
* Jump table
|
||
*
|
||
********************************
|
||
|
||
DRIVER CLD
|
||
DO DEBUG
|
||
LDA #$04
|
||
STA SLOT
|
||
LDA #$C4
|
||
STA CURSLOT
|
||
LDA #$40
|
||
STA SLOT16
|
||
ELSE
|
||
JJR $FF58 ; find slot nr
|
||
TSS
|
||
LDA $0100,X
|
||
STA CURSLOT ; $Cs
|
||
AND #$0F
|
||
===== Page 4 =====
|
||
|
||
STA SLOT ; $0s
|
||
ASL A
|
||
ASL A
|
||
ASL A
|
||
ASL A
|
||
STA SLOT16 ; $s0
|
||
FIN
|
||
TAX ; X holds now SLOT16
|
||
|
||
BIT $CFFF
|
||
LDY SLOT
|
||
LDA INITED,Y ; check for init
|
||
CMP #$01
|
||
BCC :INIT
|
||
:CMD LDA $42 ; get command
|
||
CMP #$00
|
||
BEQ :STATUS
|
||
CMP #$01
|
||
BEQ :READ
|
||
CMP #$02
|
||
BEQ :WRITE
|
||
CMP #$03
|
||
BEQ :FORMAT
|
||
SEC ; unknown command
|
||
LDA #$01
|
||
RTS
|
||
|
||
:STATUS JMP STATUS
|
||
:READ JMP READ
|
||
:WRITE JMP WRITE
|
||
:FORMAT JMP FORMAT
|
||
:INIT JSR INIT
|
||
BRA :CMD
|
||
|
||
* Signature bytes
|
||
|
||
DS \ ; fill with zeroes
|
||
DS -4 ; locate to $C8FC
|
||
DW $FFFF ; 65535 blocks
|
||
DB $47 ; Status bits
|
||
DB #<DRIVER ; LSB of driver
|
||
|
||
|
||
********************************
|
||
*
|
||
* Initialize SD card
|
||
*
|
||
* C Clear - No error
|
||
* Set - Error
|
||
* A $00 - No error
|
||
* $27 - I/O error - Init failed
|
||
* $28 - No card inserted
|
||
*
|
||
********************************
|
||
|
||
INIT CLD
|
||
LDA #$03 ; set SPI mode 3
|
||
===== Page 5 =====
|
||
|
||
STA CTRL,X
|
||
LDA #SSNONE
|
||
STA SS,X
|
||
LDA #7
|
||
STA DIV,X
|
||
LDY #10
|
||
LDA #DUMMY
|
||
|
||
:LOOP STA DATA,X
|
||
:WAIT BIT CTRL,X
|
||
BPL :WAIT
|
||
DEY
|
||
BNE :LOOP ; do 10 times
|
||
LDA #SS0 ; set CS low
|
||
STA SS,X
|
||
|
||
LDA #<CMD0 ; send CMD0
|
||
STA CMDLO
|
||
LDA #>CMD0
|
||
STA CMDHI
|
||
JSR CMD
|
||
JSR GETR1 ; get response
|
||
CMP #$01
|
||
BNE :ERROR1 ; error!
|
||
|
||
LDA #<CMD8 ; send CMD8
|
||
STA CMDLO
|
||
LDA #>CMD8
|
||
STA CMDHI
|
||
JSR CMD
|
||
JSR GETR3
|
||
CMP #$01
|
||
BNE :SDV1 ; may be SD Ver. 1
|
||
|
||
* check for $01aa match!
|
||
:SDV2 LDA #<CMD55
|
||
STA CMDLO
|
||
LDA #>CMD55
|
||
STA CMDHI
|
||
JSR CMD
|
||
JSR GETR1
|
||
LDA #<ACMD4140
|
||
STA CMDLO
|
||
LDA #>ACMD4140
|
||
STA CMDHI
|
||
JSR CMD
|
||
JSR GETR1
|
||
CMP #$01
|
||
BEQ :SDV2 ; wait for ready
|
||
CMP #$00
|
||
BNE :ERROR1 ; error!
|
||
* send CMD58
|
||
* SD Ver. 2 initialized!
|
||
JMP :BLOCKSZ
|
||
|
||
:ERROR1 JMP :IOERROR ; needed for far jump
|
||
|
||
===== Page 6 =====
|
||
|
||
:SDV1 LDA #<CMD55
|
||
STA CMDLO
|
||
LDA #>CMD55
|
||
STA CMDHI
|
||
JSR CMD ; ignore response
|
||
LDA #<ACMD410
|
||
STA CMDLO
|
||
LDA #>ACMD410
|
||
STA CMDHI
|
||
JSR CMD
|
||
JSR GETR1
|
||
CMP #$01
|
||
BEQ :SDV1 ; wait for ready
|
||
CMP #$00
|
||
BNE :MMC ; may be MMC card
|
||
* SD Ver. 1 initialized!
|
||
JMP :BLOCKSZ
|
||
|
||
:MMC LDA #<CMD1
|
||
STA CMDLO
|
||
LDA #>CMD1
|
||
STA CMDHI
|
||
:LOOP1 JSR CMD
|
||
JSR GETR1
|
||
CMP #$01
|
||
BEQ :LOOP1 ; wait for ready
|
||
CMP #$00
|
||
BNE :IOERROR ; error!
|
||
* MMC Ver. 3 initialized!
|
||
|
||
:BLOCKSZ LDA #<CMD16
|
||
STA CMDLO
|
||
LDA #>CMD16
|
||
STA CMDHI
|
||
JSR CMD
|
||
JSR GETR1
|
||
CMP #$00
|
||
BNE :IOERROR ; error!
|
||
|
||
:END LDY SLOT ; all ok
|
||
LDA #$01
|
||
STA INITED,Y ; initialized
|
||
CLC
|
||
LDY #0
|
||
BCC :END1
|
||
:CDERROR SEC
|
||
LDY #$28 ; no card error
|
||
BCS :END1
|
||
:IOERROR SEC
|
||
LDY #$27 ; init error
|
||
:END1 LDA #SSNONE ; deselect card
|
||
STA SS,X
|
||
LDA #0 ; set div to 2
|
||
STA DIV,X
|
||
TYA ; retval in A
|
||
RTS
|
||
|
||
===== Page 7 =====
|
||
|
||
|
||
********************************
|
||
*
|
||
* Send SD command
|
||
* Call with command in CMDHI and CMDLO
|
||
*
|
||
********************************
|
||
|
||
CMD PHY
|
||
LDY #0
|
||
:LOOP LDA (CMDLO),Y
|
||
STA DATA,X
|
||
:WAIT BIT CTRL,X ; TC is in N
|
||
BPL :WAIT
|
||
INY
|
||
CPY #6
|
||
BCC :LOOP
|
||
PLY
|
||
RTS
|
||
|
||
|
||
********************************
|
||
*
|
||
* Get R1
|
||
* R1 is in A
|
||
*
|
||
********************************
|
||
|
||
GETR1 LDA #DUMMY
|
||
STA DATA,X
|
||
:WAIT BIT CTRL,X
|
||
BPL :WAIT
|
||
LDA DATA,X ; get response
|
||
STA WORK ; save R1
|
||
AND #$80
|
||
BNE GETR1 ; wait for MSB=0
|
||
LDA #DUMMY
|
||
STA DATA,X ; send another dummy
|
||
LDA WORK ; restore R1
|
||
RTS
|
||
|
||
|
||
********************************
|
||
*
|
||
* Get R3
|
||
* R1 is in A
|
||
* R3 is in scratchpad ram
|
||
*
|
||
********************************
|
||
|
||
GETR3 JSR GETR1 ; get R1 first
|
||
PHA ; save R1
|
||
PHY ; save Y
|
||
LDY #04 ; load counter
|
||
:LOOP LDA #DUMMY ; send dummy
|
||
STA DATA,X
|
||
:WAIT BIT CTRL,X
|
||
===== Page 8 =====
|
||
|
||
BPL :WAIT
|
||
LDA DATA,X
|
||
PHA
|
||
DEY
|
||
BNE :LOOP ; do 4 times
|
||
LDY SLOT
|
||
PLA
|
||
STA R33,Y ; save R3
|
||
PLA
|
||
STA R32,Y
|
||
PLA
|
||
STA R31,Y
|
||
PLA
|
||
STA R30,Y
|
||
PLY ; restore Y
|
||
LDA #DUMMY
|
||
STA DATA,X ; send another dummy
|
||
PLA ; restore R1
|
||
RTS
|
||
|
||
|
||
********************************
|
||
*
|
||
* Calculate block address
|
||
* Block no is in $46-47
|
||
* Address is in R30-R33
|
||
*
|
||
********************************
|
||
|
||
BLOCK PHX ; save X
|
||
PHY ; save Y
|
||
LDX SLOT
|
||
LDA $46 ; store block num
|
||
STA R33,X ; in R30-R33
|
||
LDA $47
|
||
STA R32,X
|
||
LDA #0
|
||
STA R31,X
|
||
STA R30,X
|
||
|
||
LDY #9 ; ASL can't be used with Y
|
||
:LOOP ASL R33,X ; mul block num
|
||
ROL R32,X ; by 512 to get
|
||
ROL R31,X ; real address
|
||
ROL R30,X
|
||
DEY
|
||
BNE :LOOP
|
||
PLY ; restore Y
|
||
PLX ; restore X
|
||
RTS
|
||
|
||
|
||
********************************
|
||
*
|
||
* Send SD command
|
||
* Cmd is in A
|
||
*
|
||
===== Page 9 =====
|
||
|
||
********************************
|
||
|
||
COMMAND PHY ; save Y
|
||
LDY SLOT
|
||
STA DATA,X ; send command
|
||
:WAIT BIT CTRL,X
|
||
BPL :WAIT
|
||
:ARG LDA R30,Y ; get arg from R30 on
|
||
STA DATA,X
|
||
:WAIT1 BIT CTRL,X
|
||
BPL :WAIT1
|
||
LDA R31,Y
|
||
STA DATA,X
|
||
:WAIT11 BIT CTRL,X
|
||
BPL :WAIT11
|
||
LDA R32,Y
|
||
STA DATA,X
|
||
:WAIT12 BIT CTRL,X
|
||
BPL :WAIT12
|
||
LDA R33,Y
|
||
STA DATA,X
|
||
:WAIT13 BIT CTRL,X
|
||
BPL :WAIT13
|
||
LDA #DUMMY
|
||
STA DATA,X ; dummy crc
|
||
:WAIT2 BIT CTRL,X
|
||
BPL :WAIT2
|
||
JSR GETR1
|
||
PLY ; restore Y
|
||
RTS
|
||
|
||
|
||
********************************
|
||
*
|
||
* Status request
|
||
* $43 Unit number DSSS000
|
||
* $44-45 Unused
|
||
* $46-47 Unused
|
||
*
|
||
* C Clear - No error
|
||
* Set - Error
|
||
* A $00 - No error
|
||
* $27 - I/O error
|
||
* $28 - No card inserted / no init
|
||
* $2B - Card write protected
|
||
* x - Blocks avail (low byte)
|
||
* y - Blocks avail (high byte)
|
||
*
|
||
********************************
|
||
|
||
STATUS CLC ; no error
|
||
LDA #0
|
||
LDX #$FF ; 32 MB partition
|
||
LDY #$FF
|
||
RTS
|
||
|
||
* TODO: check for card detect and write protect!
|
||
===== Page 10 =====
|
||
|
||
|
||
|
||
********************************
|
||
*
|
||
* Read 512 byte block
|
||
* $43 Unit number DSSS0000
|
||
* $44-45 Address (LO/HI) of buffer
|
||
* $46-47 Block number (LO/HI)
|
||
*
|
||
* C Clear - No error
|
||
* Set - Error
|
||
* A $00 - No error
|
||
* $27 - Bad block number
|
||
* $28 - No card inserted
|
||
*
|
||
********************************
|
||
|
||
* TODO: check for card detect!
|
||
|
||
READ JSR BLOCK ; calc block address
|
||
|
||
LDA #SS0 ; enable /CS
|
||
STA SS,X
|
||
LDA #$51 ; send CMD17
|
||
JSR COMMAND ; send command
|
||
|
||
:GETTOK LDA #DUMMY ; get daata token
|
||
STA DATA,X
|
||
:WAIT BIT CTRL,X
|
||
BPL :WAIT
|
||
LDA DATA,X ; get response
|
||
*
|
||
* TODO: check for error!
|
||
*
|
||
CMP #$FE
|
||
BNE :GETTOK ; wait for $FE
|
||
|
||
LDY #2 ; read data from card
|
||
:LOOPY STZ WORK
|
||
:LOOPW LDA #DUMMY
|
||
STA DATA,X
|
||
:WAIT1 BITT CTRL,X
|
||
BPL :WAIT1
|
||
LDA DATA,X
|
||
STA ($44)
|
||
INC $44
|
||
BNE :INW
|
||
INC $45 ; inc msb on page boundary
|
||
:INW INC WORK
|
||
BNE :LOOPW
|
||
DEY
|
||
BNE :LOOPY
|
||
|
||
JSR GETR3 ; read 2 bytes crc
|
||
LDA #SSNONE
|
||
STA SS,X ; disable /CS
|
||
CLC ; no error
|
||
===== Page 11 =====
|
||
|
||
LDA #$00
|
||
RTS
|
||
|
||
|
||
********************************
|
||
*
|
||
* Write 512 byte block
|
||
* $43 Unit number DSSS000
|
||
* $44-45 Address (LO/HI) of buffer
|
||
* $46-47 Block number (LO/HI)
|
||
*
|
||
* C Clear - No error
|
||
* Set - Error
|
||
* A $00 - No error
|
||
* $27 - I/O error or bad block number
|
||
* $28 - No card inserted
|
||
* $2B - Card write protected
|
||
*
|
||
********************************
|
||
|
||
* TODO: check for card detect and write protect!
|
||
|
||
WRITE JSR BLOCK ; calc block address
|
||
|
||
LDA #SS0 ; enable /CS
|
||
STA SS,X
|
||
LDA #$58 ; send CMD24
|
||
JSR COMMAND ; send command
|
||
|
||
LDA #DUMMY
|
||
STA DATA,X ; send dummy
|
||
:WAIT1 BIT CTRL,X
|
||
BPL :WAIT1
|
||
LDA #$FE
|
||
STA DATA,X ; send data token
|
||
:WAIT2 BIT CTRL,X
|
||
BPL :WAIT2
|
||
|
||
LDY #2 ; send data to card
|
||
:LOOPY STZ WORK
|
||
:LOOPW LDA ($44)
|
||
STA DATA,X
|
||
:WAIT3 BIT CTRL,X
|
||
BPL :WAIT3
|
||
INC $44
|
||
BNE :INW
|
||
INC $45 ; inc msb on page boundary
|
||
:INW INC WORK
|
||
BNE :LOOPW
|
||
DEY
|
||
BNE :LOOPY
|
||
|
||
LDY #2 ; send 2 dummy crc bytes
|
||
:CRC STA DATA,X
|
||
:WAIT4 BIT CTRL,X
|
||
BPL :WAIT4
|
||
DEY
|
||
===== Page 12 =====
|
||
|
||
BNE :CRC
|
||
|
||
LDA #DUMMY ; get data response
|
||
STA DATA,X
|
||
:WAIT5 BIT CTRL,X
|
||
BPL :WAIT5
|
||
LDA DATA,X
|
||
AND #$1F
|
||
CMP #$05
|
||
BNE :ERROR ; check for write error
|
||
|
||
:WAIT6 LDA #DUMMY ; wait for write cycle
|
||
STA DATA,X ; to complete
|
||
:WAIT61 BIT CTRL,X
|
||
BPL :WAIT61
|
||
LDA DATA,X
|
||
CMP #$00
|
||
BEQ :WAIT6
|
||
|
||
LDA #SSNONE ; disablee CS
|
||
STA SS,X
|
||
CLC ; no error
|
||
LDA #0
|
||
RTS
|
||
|
||
:ERROR
|
||
:WAIT7 LDA #DUMMY ; wait for write cycle
|
||
STA DATA,X ; to complete
|
||
:WAIT71 BIT CTRL,X
|
||
BPL :WAIT71
|
||
LDA DATA,X
|
||
CMP #$00
|
||
BEQ :WAIT7
|
||
LDA #SSNONE
|
||
STA SS,X ; disable /CS
|
||
SEC ; an error occured
|
||
LDA #$27
|
||
RTS
|
||
|
||
|
||
********************************
|
||
*
|
||
* Format
|
||
* not supported!
|
||
*
|
||
********************************
|
||
|
||
FORMAT SEC
|
||
LDA #$01 ; invalid command
|
||
RTS
|
||
|
||
|
||
CMD0 HEX 400000
|
||
HEX 000095
|
||
CMD1 HEX 410000
|
||
HEX 0000F9
|
||
CMD8 HEX 480000
|
||
===== Page 13 =====
|
||
|
||
HEX 01AA87
|
||
CMD16 HEX 500000
|
||
HEX 0200FF
|
||
CMD55 HEX 770000
|
||
HEX 000065
|
||
ACMD4140 HEX 694000
|
||
HEX 000077
|
||
ACMD410 HEX 690000
|
||
HEX 0000FF
|