ProDOS8/MLI.SRC/XRW1.S

568 lines
19 KiB
ArmAsm

TTL 'xdos R/W routines revised'
****************************************************
*
* PRODOS 8 DISK II DRIVER (RWTS)
*
* COPYRIGHT APPLE COMPUTER INC., 1980-1986
*
* ALL RIGHTS RESERVED
*
* REVISED 11/8/82 BY J.R.H.
*
****************************************************
****************************
* *
* critical timing *
* requires page bound *
* considerations for *
* code and data *
* code----- *
* virtually the entire *
* 'write' routine *
* must not cross *
* page boundaries. *
* critical branches in *
* the 'write', 'read', *
* and 'read adr' subrs *
* which must not cross *
* page boundaries are *
* noted in comments. *
* *
****************************
* *
* Equates *
* *
maxCmd EQU 4 ;Commands 0-3 only
dvMot EQU $E8
DUM $3A
wTemp DS 1
midNib1 DS 1
midNib2 DS 1
lstNib DS 1
slotZ DS 1
yEnd DS 1
DEND
************************
* *
* device address *
* assignments *
* *
************************
phaseOff EQU $C080 ;stepper phase off.
*phaseOn EQU $C081 ;stepper phase on.
q6l EQU $C08C ;q7l,q6l=read
q6h EQU $C08D ;q7l,q6h=sense wprot
q7l EQU $C08E ;q7h,q6l=write
q7h EQU $C08F ;q7h,q6h=write store
****************************************
*
* Equates for rwts and block
*
****************************************
motorOff EQU $C088
motorOn EQU $C089
drv0En EQU $C08A
*drv1en EQU $C08B
ORG $D000
************************
* *
* block i/o *
* *
************************
BlockIO CLD ;This must be first as it is an ID value
JSR ResetPhase
* this is patch 76 part 1. part 2 is in xrw2.
* this is patch 77, use to be 'lda q7l+14,x'.
LDA q7l,X ;Turn off write enable please!!!
* (pad is just spare bytes but the number is critical for page
NOP
NOP
JSR doCheck
BCS BadBlk ;Branch if block # is out of range
LDY #$05
:loop ASL
ROL ibTrk
DEY
BNE :loop
ASL
BCC :1
ORA #$10 ;Adjust for upper 4 blks of trk
:1 LSR
LSR
LSR
LSR
PHA ;Save sector#
JSR RegRWTS
PLA ;Restore sector #
BCS Quit ;Branch if error encountered
INC bufPtr+1
ADC #$02
JSR RegRWTS ;Get second half of block
DEC bufPtr+1
Quit LDA ibStat
RTS
BadBlk LDA #drvrIOError
SEC
RTS
**************************
* *
* read/write a *
* track and sector *
* *
**************************
RegRWTS LDY #$01 ;Retry count
STY seekCnt ;Only one recalibrate per call
STA ibSect
LDA unitNum ;Get slot # for this operation
AND #$70
STA slotZ
JSR ChkPrev ;Make sure other drives in other slots are stopped
*
* Now check if the motor is on, then start it
*
JSR ChkDrv ;Set zero flag if motor stopped
PHP ;Save test results
LDA #dvMot
STA monTimeH
LDA unitNum ;Determine drive one or two
CMP iobPrevDn ;Same drive used before?
STA iobPrevDn ;Save it for next time
PHP ;Keep results of compare
ASL ;Get drive number into carry
LDA motorOn,X ;Turn on the drive
BCC DrvSel ;Branch if drive 1 selected
INX ;Select drive 2
DrvSel LDA drv0En,X
PLP ;Was it same drive?
BEQ :1 ;Yes
PLP ;Must indicate drive off by setting zero flag
LDY #$07 ;Delay 150 ms before stepping
:WaitLoop JSR msWait ;(on return A=0)
DEY
BNE :WaitLoop
PHP ;Now zero flag set
:1 LDA dhpCmd ;Make sure this command needs seeking
BEQ :2 ;Branch if status check
LDA ibTrk ;Get destination track
JSR MySeek ; & go to it
* Now at the desired track. Was the motor
* on to start with?
:2 PLP ;Was motor on?
BNE TryTrk ;If so, don't delay, get it today!
* Motor was off, wait for it to speed up.
MotOff LDA #$01 ;Wait exactly 100 us for each count in monTime
JSR msWait
LDA monTimeH
BMI MotOff ;count up to 0000
****************************************
*
* Motor should be up to speed.
* If it still looks stopped then
* the drive is not present.
*
****************************************
JSR ChkDrv ;Is drive present?
BEQ HndlErr ;Branch if no drive
* Now check: if it is not the format disk command,
* locate the correct sector for this operation.
TryTrk LDA dhpCmd ;Get command code #
BEQ StatCmd ;If $00, then status command
LSR ;Set carry=1 for read, 0 for write
BCS :1 ;Must prenibblize for write
JSR PreNibl16
:1 LDY #$40 ;Only 64 retries of any kind
STY retryCnt
TryAdr LDX slotZ ;Get slot num into X-reg
JSR RdAdr16 ;Read next address field
BCC RdRight ;If read it right, hurrah!
TryAdr2 DEC retryCnt ;Another mistake!!
BPL TryAdr ;Well, let it go this time...
LDA #drvrIOError ;Anticipate a bad drive error
DEC seekCnt ;Only recalibrate once!
BNE HndlErr ;Tried to recalibrate a second time, error!
LDA curTrk ;Save track we really want
PHA
ASL
ADC #$10 ;Pretend track is 8>curtrk
LDY #$40
STY retryCnt ;Reset retries to 64 max
BNE ReCal1 ;Branch always
* Have now read an address field correctly.
* Make sure this is the desired track, sector, and volume.
RdRight LDY track ;On the right track?
CPY curTrk
BEQ RtTrk ;if so, good
* Recalibrating from this track
LDA curTrk ;Preserve destination track
PHA
TYA
ASL ;(washing machine fix!)
ReCal1 JSR SetTrk
PLA
JSR MySeek
BCC TryAdr ;Go ahead and recalibrate
* Drive is on right track, check volume mismatch
RtTrk LDA sector ;Check if this is the right sector
CMP ibSect
BNE TryAdr2 ;No, try another sector
LDA dhpCmd ;read or write?
LSR ;The carry will tell
BCC WriteIt ;Carry was set for read operation,
JSR Read16 ; cleared for write
BCS TryAdr2 ;Carry set upon return if bad read
AllDone EQU * ;Was CLC
LDA #$00 ;No error
DB $D0 ;Branch never (skip 1 byte)
HndlErr SEC ;Indicate an error
STA ibStat ;Give him error #
LDX slotZ ;Get the slot offset
LDA motorOff,X ;Turn it off...
RTS ;All finished!
WriteIt JSR Write16 ;Write nybbles now
StatDone BCC AllDone ;If no errors
LDA #drvrWrtProt ;Disk is write protected!!
BNE HndlErr ;Branch always
StatCmd LDX slotZ
LDA q6h,X ;Test for write protected
LDA q7l,X
ROL ;Write protect-->carry-->bit-0=1
LDA q6l,X ;Keep in read mode...
JMP StatDone ;Branch always taken
* This is the 'seek' routine
* seeks track 'n' in slot #x/$10
* If drivno is negative, on drive 0
* If drivno is positive, on drive 1
MySeek ASL ;Assume two phase stepper
STA track ;Save destination track(*2)
JSR AllOff ;Turn all phases off to be sure
JSR DrvIndx ;Get index to previous track for current drive
LDA drv0Trk,X
STA curTrk ;This is where i am
LDA track ; & where i'm going to
STA drv0Trk,X
JSR Seek ;Go there!
AllOff LDY #$03 ;Turn off all phases before returning
NxtOff TYA ;(send phase in Acc)
JSR ClrPhase ;Carry is clear, phases should be turned off
DEY
BPL NxtOff
LSR curTrk ;Divide back down
CLC
RTS ;All off... now it's dark
**************************
* *
* fast seek subroutine *
**************************
* *
* on entry ---- *
* *
* x-reg holds slotnum *
* times $10. *
* *
* a-reg holds desired *
* halftrack. *
* (single phase) *
* *
* curtrk holds current *
* halftrack. *
* *
* on exit ----- *
* *
* a-reg uncertain. *
* y-reg uncertain. *
* x-reg undisturbed. *
* *
* curtrk and trkn hold *
* final halftrack. *
* *
* prior holds prior *
* halftrack if seek *
* was required. *
* *
* montimel and montimeh *
* are incremented by *
* the number of *
* 100 usec quantums *
* required by seek *
* for motor on time *
* overlap. *
* *
* --- variables used --- *
* *
* curtrk, trkn, count, *
* prior, slottemp *
* montimel, montimeh *
* *
**************************
Seek STA trkNbr ;Save target track
CMP curTrk ;On desired track?
BEQ SetPhase ;Yes,energize phase and return
LDA #$00
STA trkCnt ;Halftrack count
SeekLoop LDA curTrk ;Save curTrk for
STA prior ; delayed turnoff
SEC
SBC trkNbr ;delta-tracks
BEQ SeekEnd ;branch if curTrk=destination
BCS Out ;(move out, not in)
EOR #$FF ;Calc trks to go
INC curTrk ;Incr current track (in)
BCC MinTst ;(always taken)
Out ADC #$FE ;Calc trks to go
DEC curTrk ;Decr current track (out)
MinTst CMP trkCnt
BCC MaxTst ; & 'trks moved'
LDA trkCnt
MaxTst CMP #$09
BCS Step2 ;If trkcnt>$8 leave y alone (y=$8)
TAY ;else set acceleration index in y
SEC
Step2 JSR SetPhase
LDA OnTable,Y ;For 'ontime'
JSR msWait ;(100 usec intervals)
LDA prior
CLC ;For phaseoff
JSR ClrPhase ;Turn off prior phase
LDA OffTable,Y
JSR msWait
INC trkCnt ;'tracks moved' count
BNE SeekLoop ;(always taken)
SeekEnd JSR msWait ;Settle 25 msec
CLC ;Set for phase off
SetPhase LDA curTrk ;Get current track
ClrPhase AND #$03 ;Mask for 1 of 4 phases
ROL ;Double for phaseon/off index
ORA slotZ
TAX
LDA phaseOff,X ;Turn on/off one phase
LDX slotZ ;Restore x-reg
RTS ; & return
**************************
* *
* 7-bit to 6-bit *
* 'deniblize' tabl *
* (16-sector format) *
* *
* valid codes *
* $96 to $ff only. *
* *
* codes with more than *
* one pair of adjacent *
* zeroes or with no *
* adjacent ones (except *
* bit 7) are excluded. *
* *
* *
* nibls in the ranges *
* of $a0-$a3, $c0-$c7, *
* $e0-$e3 are used for *
* other tables since no *
* valid nibls are in *
* these ranges. *
**************************
dNibble EQU *-$96
HEX 0004
HEX FFFF080C
HEX FF101418
TwoBit3 HEX 008040C0 ;Used in fast prenib as
HEX FFFF1C20 ; lookup for 2-bit quantities
HEX FFFFFF24
HEX 282C3034
HEX FFFF383C
HEX 4044484C
HEX FF505458
HEX 5C606468
TwoBit2 HEX 00201030 ;Used in fast prenib
EndMarks HEX DEAAEBFF ;Table using 'unused'
HEX FFFFFF6C ; nibls ($c4,$c5,$c6,$c7)
HEX FF707478
HEX FFFFFF7C
HEX FFFF8084
HEX FF888C90
HEX 94989CA0
TwoBit1 HEX 0008040C ;Used in fast prenib
HEX FFA4A8AC
HEX FFB0B4B8
HEX BCC0C4C8
HEX FFFFCCD0
HEX D4D8DCE0
HEX FFE4E8EC
HEX F0F4F8FC
* page align the following tables.
***************************
* *
* 6-bit to 2-bit *
* conversion tables. *
* *
* dnibl2 abcdef-->0000fe *
* dnibl3 abcdef-->0000dc *
* dnibl4 abcdef-->0000ba *
* *
***************************
* *
* 6-bit to 7-bit *
* nibl conversion table *
* *
* codes with more than *
* one pair of adjacent *
* zeroes or with no *
* adjacent ones (except *
* b7) are excluded. *
* *
***************************
dNibble2 DB $00
dNibble3 DB $00
dNibble4 DB $00
Nibbles HEX 9602000097
HEX 0100009A0300009B
HEX 0002009D0202009E
HEX 0102009F030200A6
HEX 000100A7020100AB
HEX 010100AC030100AD
HEX 000300AE020300AF
HEX 010300B2030300B3
HEX 000002B4020002B5
HEX 010002B6030002B7
HEX 000202B9020202BA
HEX 010202BB030202BC
HEX 000102BD020102BE
HEX 010102BF030102CB
HEX 000302CD020302CE
HEX 010302CF030302D3
HEX 000001D6020001D7
HEX 010001D9030001DA
HEX 000201DB020201DC
HEX 010201DD030201DE
HEX 000101DF020101E5
HEX 010101E6030101E7
HEX 000301E9020301EA
HEX 010301EB030301EC
HEX 000003ED020003EE
HEX 010003EF030003F2
HEX 000203F3020203F4
HEX 010203F5030203F6
HEX 000103F7020103F9
HEX 010103FA030103FB
HEX 000303FC020303FD
HEX 010303FE030303FF
nBuf2 DS $56,0 ;nibble buffer for R/W of low 2-bits of each byte
ibTrk DB $00
ibSect DB $00
ibStat DB $00
iobPrevDn DB $00
curTrk DB $00
drv0Trk EQU *-2
HEX 00000000000000 ;for slots 1 thru 7
HEX 00000000000000 ;drives 1 & 2
retryCnt DS 1,0
seekCnt DS 1,0
************************
* *
* readadr---- *
* *
************************
count EQU * ;'must find' count
last DS 1,0 ;'odd bit' nibls
chkSum DS 1,0 ;Used for address header cksum
csSTV DS 4,0
* checksum, sector, track, and volume.
sector EQU csSTV+1
track EQU csSTV+2
volume EQU csSTV+3
trkCnt EQU count ;Halftracks moved count
prior DS 1,0
trkNbr DS 1,0
************************
* *
* mswait ---- *
* *
************************
monTimeL equ csSTV+2 ;Motor-on time
monTimeH equ monTimeL+1 ;counters.
**************************
* *
* phase on-, off-time *
* tables in 100-usec *
* intervals. (seek) *
* *
**************************
OnTable HEX 013028
HEX 24201E
HEX 1D1C1C
OffTable HEX 702C26
HEX 221F1E
HEX 1D1C1C
**************************
* *
* mswait subroutine *
* *
**************************
* *
* delays a specified *
* number of 100 usec *
* intervals for motor *
* on timing. *
* *
* on entry ---- *
* *
* a-reg: holds number *
* of 100 usec *
* intervals to *
* delay. *
* *
* on exit ----- *
* *
* a-reg: holds $00. *
* x-reg: holds $00. *
* y-reg: unchanged. *
* carry: set. *
* *
* montimel, montimeh *
* are incremented once *
* per 100 usec interval*
* for moton on timing. *
* *
* assumes ---- *
* *
* 1 usec cycle time *
* *
**************************
msWait LDX #$11
:loop DEX ;Delay 86 usec
BNE :loop
INC monTimeL
BNE :1 ;double-byte
INC monTimeH ; increment
:1 SEC
SBC #$01 ;Done 'n' intervals?
BNE msWait ;(A-reg counts)
RTS