509 lines
44 KiB
Plaintext
509 lines
44 KiB
Plaintext
|
|
*-----------------------*
|
|
* *
|
|
* RWTSDRV1 USING FORMAT *
|
|
* CONTinued *
|
|
* *
|
|
*-----------------------*
|
|
.
|
|
.
|
|
.
|
|
(BF1F) BCS VRFYRTN ;Irrelevant -already chkd write-protect
|
|
;switch when we wrote the address.
|
|
(BF21) INC FRMTSEC ;Increase sec #.
|
|
LDA FRMTSEC
|
|
CMP #$10 ;Done all 16 secs yet?
|
|
(BF27) BCC FRMTASEC ;No - go do some more.
|
|
|
|
* VERIFY a single track.
|
|
|
|
* Note: We just finished formatting
|
|
* sector $0F. Because sector $OF
|
|
* shouldn't overwrite too much of the
|
|
* sync gap (originally 128 syncs long)
|
|
* that was written prior to sec $00, and
|
|
* because we don't waste too much time
|
|
* between writing the last byte of sec $0F
|
|
* and looking for the next addr header, we
|
|
* expect to begin our verification with
|
|
* sec $00.
|
|
|
|
* Initialize counters.
|
|
(BF29) LDY #$0F ;SET COUNTER FOR # OF SECS VERIFIED.
|
|
STY FRMTSEC
|
|
LDA #48 ;SET COUNTER FOR # OF ATTEMPTS.
|
|
(BF2F) STA READCNTR
|
|
|
|
* Fill sector map with POSITIVE #'s.
|
|
(BF32)
|
|
FILSECMP STA SECFLGS,Y
|
|
DEY
|
|
(BF36) BPL FILSECMP
|
|
|
|
* Delay to let some syncs pass by.
|
|
(BF38) LDY SYNCNTR ;Initialize (y).
|
|
BYPSYNCS JSR VRFYRTN ;(12 cyc)
|
|
JSR VRFYRTN ;(12 cyc)
|
|
JSR VRFYRTN ;(12 cyc)
|
|
PHA ;(3 cyc)
|
|
PLA ;(4 cyc)
|
|
NOP ;(2 cyc)
|
|
DEY ;(2 cyc)
|
|
(BF47) BNE BYPSYNCS ;(3 cyc on branch, 2 on fall thru)
|
|
|
|
* Read address of first sector encountered.
|
|
* (THIS BETTER BE SECTOR 0!!!! If it isn't,
|
|
* our drive is a bit too fast & we will
|
|
* eventually have to reformat the track.)
|
|
(BF49) JSR RDADDR ;Read addr of first sec encountered.
|
|
;(See dis'mbly below.)
|
|
(BF4C) BCS REREADDR ;Bad read, try again.
|
|
LDA SECDSK ;Was sec read = sector 0?
|
|
(BF50) BEQ RDNXTDAT ;Yes - go read next data sec.
|
|
|
|
* DIDN'T FIND SECTOR $00 WHEN EXPECTED.
|
|
* Drive must be faster than anticipated
|
|
* because sector $0F overlaid too much of
|
|
* the long sync gap (gap 1) that was
|
|
* originally written before sector $00.
|
|
* We will have to reformat this track using
|
|
* 128 self-syncs before sector $00 (gap 1)
|
|
* and less sync bytes between other sectors
|
|
* (gap 3). This will insure that less gap-1
|
|
* syncs will be overwritten by sector $0F.
|
|
* Note that, depending on just how much too
|
|
* fast the drive is, we may have to reformat
|
|
* this track several times before we get it
|
|
* right. Each time we reformat, we reduce
|
|
* the number of gap-3 syncs. If the sync
|
|
* counter is greater than or equal to 16,
|
|
* we write two less syncs. If the counter
|
|
* is less than 16, we only reduce the gap-3
|
|
* by one sync. In order to give the machine
|
|
* time to decode information, we won't
|
|
* allow a gap less than five syncs long.
|
|
* (Note that we won't reformat the track
|
|
* until we find the address header for sec $0F.
|
|
* This presumably keeps like-numbered sectors
|
|
* in adjacent tracks in some semblance of order.)
|
|
(BF52) LDA #16
|
|
CMP SYNCNTR ;Condition carry.
|
|
LDA SYNCNTR ;If sync count < 16, subtract 1.
|
|
SBC #1 ;Else subtract 2.
|
|
STA SYNCNTR
|
|
CMP #5 ;Do we have at least 5 syncs?
|
|
BCS REREADDR ;Yes.
|
|
SEC ;No - signal error cause need
|
|
(BF61) RTS ;at least 5 syncs. Drive is
|
|
============ ;so fast that it is out-to-lunch.
|
|
|
|
* Read the sector address.
|
|
(BF62)
|
|
RDNXTADR JSR RDADDR ;Read the address header.
|
|
;(See dis'mbly below.)
|
|
|
|
(BF65) BCS BADREAD ;Branch if addr read was bad.
|
|
|
|
* Read the data proper.
|
|
(BF67)
|
|
RDNXTDAT JSR READATA ;Read the actual data bytes.
|
|
(BF6A) BCC CKSECMAP ;Read was good so chk if this
|
|
;sec has already been read.
|
|
|
|
(BF6C)
|
|
BADREAD DEC READCNTR ;Either got a bad read or else we
|
|
;already verified this sector.
|
|
;Reduce the number of chances left.
|
|
(BF6F) BNE RDNXTADR ;More chances left. Go try again.
|
|
|
|
* Doing a re-read. Will definitely
|
|
* have to reformat.
|
|
(BF71)
|
|
REREADDR JSR RDADDR ;See dis'mbly below.
|
|
(BF74) BCS NOTLAST ;Got a bad read.
|
|
|
|
* We will reformat but we don't want
|
|
* to do so until we read sector $0F.
|
|
* Have we found sector $0F yet?
|
|
(BF76) LDA SECDSK ;Get phys # of sec just read.
|
|
CMP #$0F ;Was it sector 15?
|
|
BNE NOTLAST ;No, go look some more.
|
|
(BF7C) JSR READATA ;Yes. Read the data in sec $0F.
|
|
;(See dis'mbly below.)
|
|
(BF7F) BCC FORMATRK ;Good read on sec 15 so now the timing
|
|
(BF81) ;is right to GO REFORMAT THIS TRACK.
|
|
NOTLAST DEC READCNTR ;Bad read, chk if more chances left.
|
|
BNE REREADDR ;Yes - go try again.
|
|
SEC ;Exhausted all chances, so set
|
|
VRFYRTN RTS ;(c) as error flag & exit.
|
|
(BF87) ============
|
|
|
|
* Check if this sector was previously
|
|
* verified. If not, update sector
|
|
* verification map. (If timing is
|
|
* right, should never encounter an
|
|
* already verified sec before FRMTSEC
|
|
* decrements from $00 to $FF.)
|
|
(BF88)
|
|
CKSECMAP LDY SECDSK ;Use # of sec found as index
|
|
;to the verification map.
|
|
(BF8A) LDA SECFLGS,Y ;Get map byte (neg = prev verified).
|
|
BMI BADREAD ;Oh Oh! Already verified this one.
|
|
LDA #$FF ;Set byte in map to signal that
|
|
STA SECFLGS,Y ;this sector was just verified.
|
|
DEC FRMTSEC ;Any secs left to verify?
|
|
(BF96) BPL RDNXTADR ;Yes - go do some more.
|
|
|
|
* All secs verified. Check if
|
|
* we just did track $00.
|
|
(BF98) LDA FRMTKCTR ;Was trk just formatted = trk $00?
|
|
(BF9A) BNE NOTRK0 ;No - so exit cleanly.
|
|
|
|
* Just formatted & verified trk $00.
|
|
* Trk $00 is the outside track and
|
|
* therefore has the largest length
|
|
* in which to write bytes. Because
|
|
* subsequent tracks have a smaller
|
|
* circumference, we must reduce the
|
|
* number of syncs to write between
|
|
* sectors (gap-3) so we can get all
|
|
* the needed info into a smaller space.
|
|
(BF9C) LDA SYNCNTR ;Check sync count.
|
|
CMP #16 ;Less than 16 syncs?
|
|
(BFA0) BCC VRFYRTN ;Yes - exit cleanly.
|
|
;Don't want to start off with a
|
|
;smaller gap, so skip the following
|
|
;code which reduces the gap size.
|
|
|
|
* Reduce the size of gap-3.
|
|
(BFA2) DEC SYNCNTR ;Gap > = 16 syncs long, so can afford to
|
|
DEC SYNCNTR ;reduce it by two, so can accommodate
|
|
NOTRK0 CLC ;a tighter track. Exit cleanly.
|
|
(BFA7) RTS
|
|
===========
|
|
|
|
(BEDC) LDA #8 ;Set (a) as default value in case
|
|
;couldn't format.
|
|
(BEDF) BCS ERRFRMT ;Branch if couldn't format.
|
|
|
|
* Do a read of trk just formatted.
|
|
* (Eventhough track verified, read
|
|
* it again until locate track 0.
|
|
* Presumably, this (partially)
|
|
* double checks verification and
|
|
* keeps sectors in different tracks
|
|
* somewhat adjacent?)
|
|
(BEE0) LDA #48 ;Set 48 attempts to read.
|
|
STA READCNTR
|
|
RDAGAIN SEC ;Default (c)=1 to signal error.
|
|
DEC READCNTR ;Reduce chances to read.
|
|
BEQ ERRFRMT ;Exhausted all chances.
|
|
(BEEB) JSR RDADDR ;Go read addr header to find sector
|
|
;that we want to read or write.
|
|
|
|
* Read the address header.
|
|
(B944)
|
|
RDADDR LDY #$FC ;Designate 772 chances (#$FCFC to #$10000)
|
|
;to find the correct address prologue.
|
|
(B946) STY PROSCRTH
|
|
KICKNTR INY
|
|
BNE TRYD5
|
|
INC PROSCRTH
|
|
(B94D) BEQ ERRTN ;Error - can't find proglogue.
|
|
|
|
* Look for address prologue ("D5 AA 96").
|
|
(B94F)
|
|
TRYD5 LDA Q5L,X
|
|
BPL TRYD5 ;Wait for a full byte.
|
|
VERSUSD5 CMP #$D5 ;Was it a "D5"?
|
|
BNE KICKNTR ;No - try again.
|
|
NOP ;Wait 2 cycles.
|
|
TRYAA LDA Q6L,X
|
|
BPL TRYAA ;Wait for full byte.
|
|
CMP #$AA ;Was it an "AA"?
|
|
BNE VERSUSD5 ;No - retry sequence.
|
|
(B962) LDY #3 ;Set (y) for later reading of
|
|
;vol, trk, sec, checksum info
|
|
;from address field.
|
|
(B964)
|
|
TRY96 LDA Q6L,X
|
|
BPL TRY96 ;Wait for full byte.
|
|
CMP #$96 ;Was it a "96"?
|
|
(B96B) BNE VERSUSD5 ;No - retry sequence.
|
|
|
|
* Read odd-even encoded volume, track,
|
|
* sector and checksum values from the
|
|
* address field. (When reading,
|
|
* calculate a running checksum.)
|
|
* From: byte1: 1 b7 1 b5 1 b3 1 b1
|
|
* byte2: b6 1 b4 1 b2 1 b0 1
|
|
* -------------------------------
|
|
* To: byte: b7 b6 b5 b4 b3 b2 b1 b0
|
|
|
|
(B96D) LDA #0 ;Initialize running checksum val.
|
|
CALCK STA CKSUMCAL
|
|
GETHDR LDA Q6L,X ;Get odd-encoded byte.
|
|
BPL GETHDR ;Wait for a full byte.
|
|
(B976) ROL ;Shift bits & put set
|
|
;carry in bit0 pos'n.
|
|
(B977) STA PROSCRTH ;Save shifted version.
|
|
RDHDR LDA Q6L,X ;Get even-encoded byte.
|
|
BPL GETHDR ;Wait for full byte.
|
|
AND PROSCRTH ;Merge the bytes to normal.
|
|
(B980) STA: CKSUMDSK,Y ;Store info read from addr
|
|
;field in zero page:
|
|
;$2F = vol found, $2E = trk found,
|
|
;$2D = sec found, $2C = checksum found.
|
|
;(Use ":" to force 3-byte instruction.)
|
|
(B983) EOR CKSUMCAL ;Update running checksum.
|
|
DEY
|
|
BPL CALCK
|
|
TAY ;Put checksum found in (y).
|
|
(B989) BNE ERRTN ;If chec sum found < > 0, then error.
|
|
;Hackers often change these two bytes
|
|
;to "CLC" and "RTS" instructions in
|
|
;order to defeat the address checksum
|
|
;and ignore the address epilogue.
|
|
|
|
* Read first 2 bytes (only) of
|
|
* the address epilogue ("DE AA").
|
|
(B98B)
|
|
TRYEPIDE LDA Q6L,X ;Get first byte.
|
|
BPL TRYEPIDE ;Wait for a full byte.
|
|
CMP #$DE ;Was it a "DE"?
|
|
BNE ERRTN ;No - try again.
|
|
NOP ;Stall 2 cycles.
|
|
TRYEPIAA LDA Q6L,X ;Get second byte.
|
|
BPL TRYEPIAA ;Wait for a full byte.
|
|
CMP #$AA ;Was it an "AA"?
|
|
BNE ERRTN ;No - retry sequence.
|
|
GOODRTN CLC ;Signal good read.
|
|
(B99F) RTS
|
|
============
|
|
|
|
(B942)
|
|
ERRTN SEC ;Signal bad read.
|
|
(B943) RTS ;Hackers often change the "SEC" to
|
|
============ ;a "CLC" in order to defeat error
|
|
;checking.
|
|
|
|
(BEEE) BCS RDAGAIN ;Bad read - try again.
|
|
LDA SECDSK ;Was it sector 0?
|
|
BNE RDAGAIN ;No - try again.
|
|
(BEF4) JSR READATA ;Last chance to read data.
|
|
|
|
* Read data sector into RWTS's buffers.
|
|
* Look for data prologue.
|
|
(B8DC)
|
|
READATA LDY #32 ;Set (y) to designate 32
|
|
REDUCEY DEY ;attempts to find data prologue.
|
|
BEQ ERRTN ;Error - couldn't find data prologue.
|
|
PRODATD5 LDA Q6L,X ;Get byte from data prologue.
|
|
BPL PRODATD5 ;Wait for a full byte.
|
|
VERSD5 EOR #$D5 ;Check if byte was a "D5".
|
|
BNE REDUCEY ;Wasn't a "D5, reduce counter.
|
|
NOP ;Stall 2 cycles.
|
|
PRODATAA LDA Q6L,X ;Read next data prologue byte.
|
|
BPL PRODATAA ;Wait for a full byte.
|
|
CMP #$AA ;Was it an "AA"?
|
|
BNE VERSD5 ;No - restart sequence.
|
|
(B8F4) LDY #86 ;Set (y) for later use
|
|
;in the read data routine.
|
|
(B8F6)
|
|
PRODATAD LDA Q6L,X ;Read next byte in data prologue.
|
|
BPL PRODATAD ;Wait for a full byte.
|
|
CMP #$AD ;Was it an "AD"?
|
|
(B8FD) BNE VERSD5 ;No - restart search sequence.
|
|
|
|
* Read first 86 bytes of data into
|
|
* RWTSBUF2 ($BC55 --> $BC00).
|
|
*
|
|
* Use disk byte as index to the
|
|
* NDX2NIBL table which contains
|
|
* offsets that we would be using
|
|
* if we were accessing a table
|
|
* of disk bytes when writing.
|
|
* (That is, we are just doing
|
|
* the opposite of writing.)
|
|
* EOR value from NDX2NIBL table
|
|
* with the previous EOR result.
|
|
* (On entry, use #$00 for previous
|
|
* EOR result.)
|
|
(B8FF) LDA #0 ;Initialize (a) for later EORing.
|
|
RDUCY DEY ;Reduce index to RWTSBUF2.
|
|
STY PROSCRTH ;Save index.
|
|
RDSKBYT LDY Q6L,X ;(y) = disk byte.
|
|
BPL RDSKBYT ;Wait for a full byte.
|
|
(B909) EOR NDX2NIBL-$96,Y ;Use (y) as index to tbl
|
|
; of 2-encoded nibbles.
|
|
(B90C) LDY PROSCRTH ;Store 2-encoded nibble in RWTSBUF2.
|
|
STA RWTSBUF2,Y
|
|
(B911) BNE RDUCY ;Conditioned from the "LDY PROSCRTH".
|
|
|
|
* Read rest of sector into RWTSBUF1
|
|
* ($BB00 --> $BBFF).
|
|
*
|
|
* Use disk byte as index to the
|
|
* NDX2NIBL table which contains
|
|
* offsets that we would be using
|
|
* if we were accessing a table
|
|
* of disk bytes when writing.
|
|
* (That is, we are just doing
|
|
* the opposite of writing.)
|
|
* EOR value from NDX2NIBL table
|
|
* with the previous EOR result.
|
|
(B913)
|
|
SAVYNDX STY PROSCRTH ;Save index to RWTSBUF1.
|
|
RDSKBYT2 LDY Q6L,X ;(y) = disk byte.
|
|
BPL RDSKBYT2 ;Wait for a full byte.
|
|
EOR NDX2NIBL-$96,Y ;Get 6-encoded nibble from tbl.
|
|
LDY PROSCRTH ;Get index to RWTSBUF1.
|
|
STA RWTSBUF1,Y ;Store 6-encoded nibble in RWTSBUF1.
|
|
INY
|
|
(B923) BNE SAVYNDX ;More disk bytes to read.
|
|
|
|
* Read the data checksum.
|
|
(B925)
|
|
RDCHECK LDY Q6L,X ;Get data checksum.
|
|
BPL RDCHECK ;Wait for full byte.
|
|
(B92A) CMP NDX2NIBL-$96,Y ;Converted checksum = val in $BBFF?
|
|
;Remember: Val in $#BBFF is result of
|
|
;previous cummulative EORing. There4,
|
|
;this comparison with (a) detects any
|
|
;(non-cancelling) error(s) that may
|
|
;have occurred in the entire sector!!!
|
|
(B92D) BNE ERRTN ;No - got an error.
|
|
;Hackers often change these two bytes
|
|
;to "CLC" and "RTS" instructions in
|
|
;order to defeat the data checksum
|
|
;and ignore the data epilogue.
|
|
|
|
* Read the first two bytes (only)
|
|
* of the data epilogue ("DE AA").
|
|
(B92F)
|
|
EPIRDDE LDA Q6L,X ;Read first byte of data epilogue.
|
|
BPL EPIRDDE ;Wait for a full byte.
|
|
CMP #$DE ;Was it a "DE"?
|
|
BNE ERRTN ;No - got an error.
|
|
NOP ;Stall for 2 cycles.
|
|
EPIRDAA LDA Q6L,X ;Read 2nd data epilogue byte.
|
|
BPL EPIRDAA ;Wait for a full byte.
|
|
CMP #$AA ;Was it an "AA"?
|
|
BEQ GOODRTN ;Yes - got a good read.
|
|
ERRTN SEC ;Signal bad read.
|
|
(B943) RTS ;Hackers often change the "SEC" to a
|
|
============ ;"CLC" in order to defeat error checking.
|
|
|
|
(B99E)
|
|
GOODRTN CLC ;Signal good read.
|
|
(B99F) RTS
|
|
=============
|
|
|
|
(BEF7) BCS RDAGAIN ;Last chance bombed out!!!
|
|
INC FRMTKCTR ;Kick up trk counter.
|
|
LDA FRMTKCTR ;Set (a) for next trk count.
|
|
CMP #$23 ;Done all trks yet (#0 to #34)?
|
|
BCC FRMNXTRK ;No - GO FORMAT THE NEXT TRACK.
|
|
CLC ;Signal finished all tracks.
|
|
(BF02) BCC DONEFRMT ;ALWAYS - ONLY GOOD EXIT.
|
|
------------
|
|
|
|
* Note: No matter what kind of error we
|
|
* might have encountered when formatting,
|
|
* the IOB error code is always set to $08.
|
|
* This is later translated to an FM error
|
|
* code (also $08) which DOS displays as
|
|
* a I/O error message. (This is why trying
|
|
* to format a write-protected disk results
|
|
* in a an I/O error message instead of a
|
|
* disk-write-protected message.)
|
|
* If no error occurred, the IOB error byte
|
|
* will be set to some random number (as a result of
|
|
* referencing a hardware switch).
|
|
(BF04)
|
|
ERRFRMT LDY #13 ;Index to return code in IOB.
|
|
STA (PTR2IOB),Y ;Store return code.
|
|
SEC ;Signal that an error occurred.
|
|
DONEFRMT LDA MTROFF,X ;Turn motor off & exit with (c)
|
|
(BF0C) RTS ;denoting success status.
|
|
============
|
|
|
|
(B7BA) BCS ERRENTER ;Branch if operation unsuccessful.
|
|
PLP ;Throw status off stk.
|
|
CLC ;Signal successful.
|
|
(B7BE) RTS
|
|
============
|
|
|
|
(B7BF)
|
|
ERRENTER PLP ;Throw status off stk.
|
|
SEC ;Signal UNsuccessful.
|
|
(B7C1) RTS
|
|
============
|
|
|
|
(B093) LDA IBSMOD ;Get vol found from IOB
|
|
STA VOLFM ;& put it in Fm parm list.
|
|
LDA #$FF ;Designate vol wanted in
|
|
(B09B) STA IBVOL ;IOB as 255 for next time.
|
|
;(Actually using 0 cause FF EOR FF = 0.)
|
|
(B09E) BCS ERRWTSDR ;Branch if UNsuccessful operation.
|
|
(B0A0) RTS
|
|
=============
|
|
|
|
* Operation was NOT successful.
|
|
(B0A1)
|
|
ERRWTSDR LDA IBSTAT ;Get RWTS'S error code.
|
|
|
|
* Translate IOB error code (a) to
|
|
* FM error code (y). (DOS later employs
|
|
* the FM error code in the routine used
|
|
* to print error messages.)
|
|
(B0A4) LDY #7 ;Set (y) for FM vol mismatch.
|
|
CMP #$20 ;Vol mismatch?
|
|
BEQ SETFMERR ;Yes.
|
|
LDY #$04 ;No.
|
|
CMP #$10 ;Write protected?
|
|
BEQ SETFMERR ;Yes.
|
|
LDY #8 ;Must have been other, so
|
|
SETFMERR TYA ;designate as general I/O error.
|
|
(B0B3) JMP BADFMXIT ;Go handler error.
|
|
------------
|
|
|
|
(B385)
|
|
BADFMXIT SEC ;(c) = 1 to signal UNsuccessful.
|
|
FMEXIT PHP ;Preserve success of operation on stk.
|
|
STA RTNCODFM ;Put appropriate return code in FM parm list.
|
|
LDA #0 ;Avoid that infamous $48 bug.
|
|
STA STATUS
|
|
(B38E) JSR CPYFMWA
|
|
|
|
(AE7E)
|
|
CPYFMWA JSR SELWKBUF
|
|
|
|
* Point the A4L/H pointer at the DOS work buffer (chain).
|
|
(AF08)
|
|
SELWKBUF LDX #0 ;Designate work area buffer.
|
|
(AF0A) BEQ PT2FMBUF ;ALWAYS.
|
|
|
|
(AF12)
|
|
PT2FMBUF LDA WRKBUFFM,X ;Get addr of DOS's work buffer
|
|
STA A4L ;(chain) from FM parm list and put
|
|
LDA WRKBUFFM+1,X ;it in the A4L/H pointer.
|
|
STA A4L+1
|
|
(AF1C) RTS
|
|
|
|
* Copy work area buffer (non-chain)
|
|
* to DOS work buffer (chain).
|
|
(AE81) LDY #0
|
|
STORWRK LDA FMWKAREA,Y
|
|
STA (A4L),Y
|
|
INY
|
|
CPY #45
|
|
BNE STORWRK
|
|
(AE8D) RTS
|
|
|
|
(B391) PLP ;Exit with (c) conditioned accordingly.
|
|
LDX STKSAV ;Reset the stack pointer so execution will
|
|
TXS ;return to the caller of the function.
|
|
(B396) RTS ;(Normally returns to AFTRFUNC ($A6AB)
|
|
============ ;located in the FMDRIVER routine ($A6A8).)
|