*================================= * READ/WRITE TRACK/SECTOR (RWTS). * (ENTER WITH (Y)/(A) POINTING AT * RWTS'S INPUT/OUTPUT BLOCK (IOB). *================================= RWTS STY PTR2IOB ;SET UP A Z-PG PTR 2 RWTS'S IOB. STA PTR2IOB+1 LDY #2 ;INITIALIZE CNTR FOR MAXIMUM STY RECLBCNT ;NUMBER OF RECALIBRATION TRIES. LDY #4 ;INITIALIZE COUNTER FOR MAXIMUM STY RSEEKCNT ;# OF RE-SEEKS BTW'N RECALIBS. LDY #1 ;(Y) = INDEX TO RWTS'S IOB. LDA (PTR2IOB),Y ;GET SLOT*16 FROM IOB IN (X), SO TAX ;CAN USE IT TO INDEX BASE ADRS ;FOR DRIVE FUNCTIONS. * CHK IF WANTED SLOT*16 = LAST SLOT*16? LDY #15 ;INDEX 4 VAL OF LAST SLOT USED. CMP (PTR2IOB),Y ;WANTED*16 VS LAST*16. BEQ SAMESLOT ;SLOT WANTED=SLOT LAST ACCESSED. * WANT TO USE A DIFFERENT SLOT SO * RESET (X) BACK TO INDEX OLD SLOT * SO CAN TEST OLD MOTOR. TXA ;SAVE SLOT*16 WANTED ON STK. PHA LDA (PTR2IOB),Y ;GET OLD SLOT*16 BACK. TAX ;PUT IT IN (X) 2 INDEX BASE ADRS. PLA ;PUT SLOT*16 WANTED IN (A) AND PHA ;KEEP IT SAVED ON STK. STA (PTR2IOB),Y ;UPDATE LAST-USED SLOT*16 FOR ;NEXT TIME AROUND. * CHECK TO SEE IF LAST-USED DRIVE * ASSOC WITH LAST-USED SLOT IS * STILL SPINNING. IF IT IS, WAIT * FOR IT TO STOP. LDA Q7L,X ;PREP LATCH FOR INPUT. CKSPIN LDY #8 ;SET CNTR 2 INSURE AT LEAST 8 CKS LDA Q6L,X ;STROBE LATCH TO READ. CHKCHNG CMP Q6L,X ;READ AGAIN & CMP TO LAST READ. BNE CKSPIN ;DATA CHANGED, SO STILL SPINNING. DEY ;NO CHANGE, SO CHK WITH SOME BNE CHKCHNG ;DELAYS JUST TO MAKE SURE. * GET INDEX FOR SLOT WANTED. PLA ;GET SLOT*16 BAK OFF STK & PUT IT TAX ;IN (X) SO WE CAN NDX BASE ADRS. * CHECK TO SEE IF A DRIVE ASSOC * WITH SLOT WANTED IS STILL * SPINNING. (AS SOON AS GET A * CHANGE, KNOW IT IS SPINNING. * IF NO CHANGE, CHK AT LEAST 8 * TIMES TO BE CERTAIN IT IS OFF.) SAMESLOT LDA Q7L,X ;SET READ MODE. LDA Q6L,X ;STROBE LATCH TO READ. LDY #8 ;SET CNTR FOR 8 CHKS IF NEEDED. STRBAGN LDA Q6L,X ;STROBE LATCH AGAIN. PHA ;DELAY 14 MACHINE CYCLES. PLA PHA PLA STX SLOTPG5 ;SAVE SLOT*16 WANTED IN PAGE5. CMP Q6L,X ;HAS DATA CHANGED YET? BNE DONETEST ;YES - DATA CHANGED, SO SPINNING. DEY ;NO - NO CHANGE, SEE IF CHKD ;ENOUGH TIMES YET. BNE STRBAGN ;CHK AT LEAST 8 TIMES. DONETEST PHP ;SAVE TEST RESULTS ON STK SO CAN ;LATER CHK IF NEED EXTRA DELAY ;OR NOT. * TURN MOTOR ON IN A DRIVE ASSOC * WITH SLOT WANTED (JUST IN CASE * IT WASN'T ALREADY SPINNING). * NOTE: THIS USES DRIVE WITH SAME * # AS LAST DRIVE USED. THIS MAY * OR MAY NOT BE THE SPECIFIC DRIVE * # WE WANT. HOWEVER, WE MUST USE * THIS INSTRUC TO SEND POWER VIA * THE CONTROLLER. ONCE SWITCH IS * THROWN, WE CAN LATER RE-ROUTE * THAT POWER TO WHICHEVER DRIVE WE * WANT BY THROWING ANOTHER SWITCH * TO SELECT DRIVE1 OR DRIVE2. LDA MTRON,X ;TURN MOTOR ON. * ESTABLISH Z-PAGE POINTERS TO * DEVICE CHARACTERISTIC TABLE & * RWTS'S I/O BUFFER (SO WE CAN * USE Z-PAGE INDIRECT ADDRESSING): * IBDCTP --> PTR2DCT (3C,3D). * IBBUFP --> PTR2BUF (3E,3F). LDY #6 MOVPTRS LDA (PTR2IOB),Y ;GET PTRS FROM RWTS'S IOB. STA: PTR2DCT-6,Y ;PUT THEM IN Z-PAGE. (":" USED INY ;2 FORCE A 3-BYTE ZERO-PAGE ADR.) CPY #10 ;4 BYTES TO COPY (6 TO 9). BNE MOVPTRS * CHECK DRIVE STATUS. LDY #3 ;SAVE HI BYTE OF MOTOR-ON-TIME LDA (PTR2DCT),Y ;COUNT IN Z-PAGE. STA MTRTIME+1 LDY #2 ;GET DRIVE # WANTED. LDA (PTR2IOB),Y LDY #16 ;SET (Y) = INDEX 2 LAST-USED DRV. CMP (PTR2IOB),Y ;DRV# WANTED VS DRV# LAST USED. BEQ SAMEDRV STA (PTR2IOB),Y ;DESIGNATE DRV# WANTED AS LAST- ;USED DRV# FOR NEXT TIME AROUND. PLP ;GET STATUS BACK OFF STK. LDY #0 ;RESET STATUS (Z-FLAG OFF) TO ;SIGNAL THAT SPECIFIC DRV # WE ;WANT IN SPECIFIC SLOT WANTED WAS ;NOT ORIGINALLY SPINNING. PHP ;PUSH UPDATED STATUS BACK ON STK. SAMEDRV ROR ;PUT LOW BIT OF DRV WNTED IN (C). BCC USEDRV2 ;BRANCH IF WANT DRIVE 2. LDA SELDRV1,X ;ROUTE POWER TO SELECT DRIVE 1. BCS USEDRV1 ;ALWAYS. USEDRV2 LDA SELDRV2,X ;ROUTE POWER TO SELECT DRIVE 2. USEDRV1 ROR DRVZPG ;PUT SIGN BIT FOR WHICH DRIVE ;USING IN Z-PAGE: NEG = DRIVE1. ; POS = DRIVE2. * CHK TO SEE IF A SPECIFIC DRIVE * WANTED IN SPECIFIC SLOT WANTED * WAS ORIGINALLY ON OR NOT. PLP ;GET PREVIOUS TEST RESULT. PHP ;PUT IT BACK ON STK 4 LATER USE. BNE WASON ;ORIG DRV IN ORIG SLOT WAS ON. * SPECIFIC DRIVE WANTED IN SPECIFIC * SLOT WANTED WAS ORIGINALLY OFF, * SO DELAY A BIT TO AVOID POS'NING * HEAD DURING THE PERIOD OF HEAVY * CURRENT FLOW THAT OCCURS WHEN * MOTOR IS TURNED ON. (THAT IS, * GIVE LINE/CAPACITOR TIME TO BLEED * DOWN CAUSE MOTOR ON/OFF SWITCH * REQUIRES MORE CURRENT THAN THE * STEPPER MOTOR.) * * (AMOUNT OF DELAY IS NOT CONSTANT * CAUSE IT DEPENDS ON WHAT IS IN * ACCUMULATOR & WE DON'T KNOW * CAUSE WE WERE JUST ACCESSING * HARDWARE.) LDY #7 WAIT4MTR JSR DELAY ;STALL. DEY BNE WAIT4MTR ;GO STALL SOME MORE. LDX SLOTPG5 ;RESTORE (X) = SLOT*16. WASON LDY #4 ;GET TRK WANTED. LDA (PTR2IOB),Y JSR SEEKTRK ;GO MOVE ARM TO CORRECT TRK. * CHECK TO SEE IF MOTOR WAS * ORIGINALLY ON. PLP ;GET EARLIER RESULT OF MOTOR TEST BNE BEGINCMD ;BRANCH IF DRV WAS ORIGINALLY ON. LDY MTRTIME+1 ;MOTOR WASN'T ORIGNALLY ON. ;HOWEVER, WE HAVE SINCE TURNED IT ;ON. NOW CHECK IF IT HAS BEEN ON ;LONG ENOUGH. BPL BEGINCMD ;YES -NO NEED TO WAIT ANY LONGER. * ALTHOUGH MOTOR IS TURNED ON, IT * HASN'T BEEN ON LONG ENOUGH TO DO * ACCURATE READING OF BYTES. THERE4 * DELAY UNTIL MOTOR ON TIME IS ONE * SECOND (AT WHICH TIME MTRTIME * COUNT IS 0). (PART OF TIME WAS * TAKEN UP TO SEEK TRACK.) TIME1 LDY #18 TIME2 DEY BNE TIME2 INC MTRTIME BNE TIME1 INC MTRTIME+1 BNE TIME1 *================================= * MOTOR IS UP TO SPEED SO NOW * PROCESS COMMAND (SEEK=00, * READ=01, WRITE=02, FORMAT=04). *--------------------------------- * USE THE FOLLOWING COUNTERS: * READCNTR = ALLOW UP TO 48 TIMES * TO FIND CORRECT ADR * PROLOGUE BETWEEN * RE-SEEKING. * RSEEKCNT = ALLOW UP TO 4 RE-SEEKS * BTWN RECALIBRATIONS. * RECLBCNT = ALLOW UP TO 2 RECALIBRATIONS. * * (THERE4, IF NECESSARY, ALLOW UP * TO 384 ATTEMPTS TO FIND CORRECT * PROLOGUE ADDR.) * BEGIN RWTS COMMAND PROCESSING. BEGINCMD LDY #12 ;GET CMD FROM IOB. LDA (PTR2IOB),Y BEQ WASEEK ;BRANCH IF CMD WAS "SEEK". CMP #4 ;WAS CMD "FORMAT"? BEQ FORMDSK ;BRANCH IF CMD WAS "FORMAT". *--------------------------------- * COMMAND WAS READ OR WRITE * (OPCODES $01 OR $02) *--------------------------------- ROR ;(C)=1 IF READ (OPCODE %00000001) ;(C)=0 IF WRIT (OPCODE %00000010) PHP ;SAVE (C) DENOTING CMD ON STK. BCS RESETCNT ;READING - SO SKIP PRENIBBLING. * COMMAND WAS WRITE WASWRITE JSR PRENIBL ;CONVERT 256 MEMORY BYTES TO 342 ;6-BIT NIBBLES NEEDED FOR WRITING. * COMMON TO READ OR WRITE. RESETCNT LDY #48 ;INIT COUNT TO READ ADR HEADER. STY READCNTR SETXSLT LDX SLOTPG5 ;SET (X)=SLOT*16. JSR RDADDR ;GO READ ADDR HEADER TO FIND SEC ;THAT WE WANT TO READ OR WRITE. BCC RDRIGHT ;ADDR READ WAS GOOD. * BAD ADDRESS (OR DATA) READ. REDUCERD DEC READCNTR ;REDUCE READ COUNT. BPL SETXSLT ;TRY AGAIN. * DO A RECALIBRATION CAUSE WE HAVE * EXHAUSTED ALL ATTEMPTS TO GET A * GOOD READ. DORECALB LDA PRESTRK ;SAVE TRK WANTED ON STK. PHA LDA #96 ;PRETEND PRESENTLY ON TRK #96 SO ;WE FORCE HEAD AGAIN STOP. ;(REPEATEDLY BANGING HEAD AGAINST ;STOP = FAMILIAR DISK CLATTER.) JSR SETTRK ;GO SELECT DRV & PUT TRK WANTED ;IN MEM LOCATION SPECIFIC 2 DRV. DEC RECLBCNT ;REDUCE RECALIBRATION COUNTER. BEQ DRVERR ;ERROR -EXHAUSTED RECALIBRATIONS. LDA #4 ;INDICATE 4 CHANCES TO RESEEK TRK STA RSEEKCNT ;BETWEEN RECALIBRATIONS. LDA #0 ;SEEK TRACK 0. JSR SEEKTRK ;GO MOVE ARM TO TRK 0. PLA ;GET TRK WANTED FROM STK. RESEEK JSR SEEKTRK ;NOW, MOVING OUT FROM TRK 0, TRY ;TO LOCATE TRK WANTED. JMP RESETCNT ;GO BACK & TRY TO DO READ AGAIN. * GOT A GOOD READ. RDRIGHT LDY TRKDSK ;(Y) = TRK# FOUND IN HEADER. CPY PRESTRK ;TRK FOUND = TRK WANTED? BEQ RTTRK ;YES - SEEEKED TO CORRECT TRK. * BAD SEEK (OR ELSE SOME KIND * OF PROTECTION SCHEME) CAUSE * TRK WANTED < > TRK FOUND. LDA PRESTRK ;SAVE TRK WANTED ON STK. PHA TYA ;SET (A) =PRESENT TRK =TRK FOUND. JSR SETTRK ;GO SELECT DRV & PUT TRK WANTED N ;MEMORY LOCATION SPECIFIC TO DRV. PLA ;GET TRK WANTED BACK OFF STACK. DEC RSEEKCNT ;ALLOW 4 ATTEMPTS TO FIND CORRECT ;TRK BETWEEN RECALIBRATIONS. BNE RESEEK ;MORE ATTEMPTS LEFT TO FIND TRK. BEQ DORECALB *--------------------------------- * GOT A DRIVE ERROR. *--------------------------------- DRVERR PLA LDA #$40 ;ERROR CODE FOR BAD DRIVE. TOERRWTS PLP JMP RWTSERR *--------------------------------- * RWTS COMMAND WAS SEEK (NULL). *--------------------------------- WASEEK BEQ RWTSEXIT ;IF CMD WAS SEEK, THEN GO EXIT ;RWTS CAUSE JUST COMPLETED MOVE. *--------------------------------- * RWTS COMMAND WAS FORMAT ($04). *--------------------------------- FORMDSK JMP FORMAT ;GO DO THE FORMAT. *--------------------------------- * FOUND CORRECT TRK FOR RWTS'S * READ OR WRITE COMMANDS. *--------------------------------- RTTRK LDY #3 ;GET VOL WANTED FROM IOB. LDA (PTR2IOB),Y PHA ;SAVE IT ON THE STACK. LDA VOLDSK ;GET VOL FOUND AND SAV IT IN IOB. LDY #14 STA (PTR2IOB),Y PLA ;RETRIEVE VOL WANTED OFF STK. BEQ CRCTVOL ;VOLUME 0 GOOD FOR ALL. CMP VOLDSK ;VOL WANTED = VOL FOUND? BEQ CRCTVOL ;YES - GOT CORRECT VOL#. * GOT A VOLUME MISMATCH. LDA #$20 ;SET CODE FOR VOL MISMATCH. BNE TOERRWTS ;ALWAYS. * FOUND CORRECT VOLUME SO NOW CHK * IF THE SECTOR IS ALSO CORRECT. CRCTVOL LDY #5 ;GET LOGICAL SECTOR # WANTED. LDA (PTR2IOB),Y TAY ;SET (Y) = LOGICAL SECTOR# WANTED. LDA PHYSECTR,Y ;(A) = PHYSICAL SECTOR # WANTED. CMP SECDSK ;PHYS SEC WANTED=PHYS SEC FOUND? BNE REDUCERD ;NO - GO TRY AGAIN. PLP ;GET TYPE OF OPERATION FROM STK: ; (C)=0=WRITE, (C)=1=READ. BCC WRITE ;BRANCH IF RWTS OPCODE WAS WRITE. * READ DATA SEC INTO RWTS'S BUFFERS. JSR READATA ;GO READ A SECTOR. PHP ;SAVE STATUS OF READ ON STACK JUST ;IN CASE WE NEED TO RE-READ. BCS REDUCERD ;BAD READ - GO TRY AGAIN. LEAVE ;SET (C) ON STK 2 DENOTE READING. ;(WE PREVIOUSLY PULLED THE SAVED ;STATUS OFF THE STK. THERE4, WE ;BETTER PUT A SET (C) BACK ON STK ;CAUSE WE ARE READING AND WE ARE ;ABOUT 2 BRANCH BACK 2 A ROUTINE ;THAT EXPECTS THE READ (C=1) OR ;WRITE (C=0) FLAG ON THE STACK. PLP ;GOOD READ -NOT BRANCHING BACK SO ;NO NEED TO PRESERVE FLAG ON STK. * POSTNIBBLE DATA & SHUT DOWN. LDX #0 STX PROSCRTH JSR POSTNB16 ;CONVERT 6- & 2-ENCODED BYTES IN ;RWTS BUFS TO NORMAL MEMORY BYTES ;(USUALLY PLACED IN DOS DATA ;SECTOR BUFFER). LDX SLOTPG5 ;SET (X) = SLOT*16 FROM PAGE 5. *---------------------------------- * SIGNAL SUCCESS OR FAILURE * AND THEN SHUT DOWN. *---------------------------------- * SEVERAL REFERENCES ERRONEOUSLY * STATE THAT THE RETURN CODE IS * ZERO IF NO ERRORS OCCURRED. * HOWEVER, A LONE SEEK OPERATION * ALWAYS SETS THE RTN CODE TO ZERO. * EVEN IF A READ OR WRITE OPERATION * WAS SUCCESSFUL, THE IOB RTN CODE * WILL ACQUIRE A RANDOM VALUE (AS * A RESULT OF ACCESSING A HARDWARE * SWITCH PRIOR TO ENTERING THIS * ROUTINE). THERE4, THE RTN CODE * IS ONLY RELEVANT IF AN ERROR IS * DENOTED (CARRY SET). RWTSEXIT CLC ;(C)=0, SIGNL SUCCESSFUL OPERAT'N HEX 24 ;"BIT $38" 2 IGNORE "SEC" INSTRUC RWTSERR SEC ;(C)=1, SIGNL UNSUCCESSFUL OPER'N LDY #13 ;STORE RETURN CODE IN IOB. STA (PTR2IOB),Y LDA MTROFF,X ;TURN MOTOR OFF. RTS *--------------------------------- * WRITE SECTOR. *--------------------------------- WRITE JSR WRITESEC ;WRITE SYNC GAP AFTR ADR EPILOGUE ;& THEN WRITE DATA PROLOGUE, DATA ;PROPER AND DATA EPILOGUE. BCC RWTSEXIT ;GOOD WRITE - GO EXIT. LDA #$10 ;WRITE PROTECT ERROR CODE. BCS RWTSERR ;BAD WRITE - HANDLE THE ERROR. *================================= * DETERMINE DRIVE TYPE & MOVE * DISK ARM TO DESIRED TRK. *================================= SEEKTRK PHA ;SAVE # OF TRK WANTED ON STK. LDY #1 ;GET DRIVE TYPE (EVEN VAL=2PHASE, LDA (PTR2DCT),Y ;ODD VAL=1PHASE) FROM DCT. ;(PS. THE "II" IN THE "DISK II" ;LOGO STAMPED ON APPLE'S DISK ;DRIVE DENOTES A 2-PHASE MOTOR.) ROR ;PUT LOW BYTE OF DRV TYPE IN (C). PLA ;GET TRK# WANTED BACK IN (A). BCC SEEKIT ;NOT USING STANDARD DRIVE II, ;USING A ONE-PHASE DRIVE INSTEAD, ;THERE4 SKIP DOUBLING OF TRK# AND ;USE SEEKIT AS PART OF ROUTINE ;INSTEAD OF AS A SEPERATE SUBRTN. * USING A TWO-PHASE DRIVE. ASL ;2*TRK# WANTED=1/2TRACK# WANTED. JSR SEEKIT ;MOVE THE DISK ARM 2 DESIRED TRK. LSR PRESTRK ;CONVERT HALFTRACK VALUE BACK TO RTS ;WHOLE TRACK VALUE. *===================================== * ROUTINE/SUBROUTINE TO MOVE DRIVE * ARM TO A SPECIFIC TRK POS'N. *===================================== * USED AS A SUBROUTINE WHEN USING * APPLE'S DISK DRIVE II. NOTE WHEN * SEEKIT IS USED AS A SUBROUTINE, * DESTRK, PRESTRK, TRK4DRV1, TRK4DR2, * STPSDONE AND HOLDPRES ARE ALL * EXPRESSED IN TERMS OF HALFTRACKS: * DESTRK = DESTINATION HALF-TRACK POS'N. * PRESTRK = PRESENT HALF-TRACK POS'N. * HOLDPRES = PRESENT HALF-TRACK POS'N. * TRK4DRV1 = BASE ADR (INDEXED BY SLOT*16) * TO POINT TO THE ADR THAT * CONTAINS THE LAST HALF- * TRACK # THAT DRIVE1 WAS * ALIGNED ONE. * TRK4DRV2 = BASE ADR (INDEXED BY SLOT*16) * TO POINT TO THE ADR THAT * CONTAINS THE LAST HALF- * TRACK # THAT DRIVE2 WAS * ALIGNED ON. * STPSDONE = NUMBER OF HALFTRACKS * MOVED SO FAR. * (NOTE: IF NOT USING A II-PHASE * DRIVE, CHANGE ALL THE COMMENTS * BELOW THAT REFER TO HALFTRACKS * TO REFER TO FULLTRACKS INSTEAD.) SEEKIT STA DESTRK ;(A) = HALFTRACK# WANTED. JSR SLOTX2Y ;CONVERT (X)=SLOT*16-->(Y)=SLOT. LDA TRK4DRV1,Y ;PRES HALFTRK # ASSOC WITH DRV1. BIT DRVZPG ;CONTAINS: NEG=DRV1, POS=DRV2. BMI SETPRSTK ;BRANCH IF USING DRIVE1. LDA TRK4DRV2,Y ;USING DRIVE2 SO GET PRESENT ;HALFTRACK # ASSOC WITH DRIVE 2. SETPRSTK STA PRESTRK ;SAVE PRESENT HALFTRK#. * DESIGNATE HALFTRK WE ARE ABOUT * TO SEEK AS PRESENT HALFTRK FOR * NEXT TIME AROUND. (PUT HALFTRK * INFO IN SLOT-DEPENDENT LOCATIONS.) LDA DESTRK ;HALFTRK WANTED. BIT DRVZPG ;CHK WHICH DRIVE WE'RE USING. BMI DRV1USG ;BRANCH IF USING DRIVE 1. STA TRK4DRV2,Y ;USING DRIVE2 -STORE HALFTRK INFO ;FOR NEXT TIME AROUND. BPL DRV2USG ;ALWAYS. DRV1USG STA TRK4DRV1,Y ;USING DRIVE1. STORE HALFTRK INFO ;FOR NEXT TIME AROUND. DRV2USG JMP SEEKABS ;GO MOVE DRIVE ARM. *=================================== * TRANSLATE (X)=SLOT*16 TO (Y)=SLOT. *=================================== SLOTX2Y TXA ;GET SLOT*16 FROM (X). LSR ;DIVIDE IT BY 16. LSR LSR LSR TAY ;PUT SLOT# IN (Y). RTS *================================= * GO SELECT DRIVE AND PUT TRACK # * WANTED IN MEMORY LOCATION ASSOC * WITH THE # OF THE DRIVE WE'RE * USING. *================================= SETTRK PHA ;SAVE PRESENT TRK # ON STK. LDY #2 ;GET DRV # WANTED FROM IOB. LDA (PTR2IOB),Y ROR ;CONDITION CARRY: ; (C)=0=DRV1, (C)=1=DRV2. ROR DRVZPG ;CONDITION ZERO-PAGE LOCATION: ; NEG=DRV1, POS=DRV2. JSR SLOTX2Y ;USE (X)=SLOT*16 TO GET (Y)=SLOT. PLA ;GET TRK # WANTED OFF STK. ASL ;TIMES TWO FOR 1/2TRACK # WANTED. BIT DRVZPG ;CHK WHICH DRIVE TO USE. BMI STORDRV1 ;BRANCH IF USING DRIVE 1. STA TRK4DRV2,Y ;SAV HALFTRK # WANTED FOR DRIVE2. BPL RTNSETRK ;ALWAYS. STORDRV1 STA TRK4DRV1,Y ;SAVE HALFTRK # WANTED 4 DRIVE1. RTNSETRK RTS *================================= * RWTS'S FORMAT COMMAND. *================================= * INITIALIZE ZERO-PAGE LOCATIONS. FORMAT LDY #3 ;GET VOL FRM IOB, STORE IN Z-PAGE. LDA (PTR2IOB),Y STA FRMTVOL LDA #$AA ;STORE "AA" AS CONSTANT IN Z-PAGE. STA HOLDAA LDY #$56 ;INITIALIZE INDEX TO BUFFER. LDA #0 ;INITIALIZE TRK COUNTER. STA FRMTKCTR ;NOTE: ALWAYS BEGIN FORMATTING ;WITH TRACK $00. * ZERO OUT THE RWTS BUFFERS. * (NOTE: WHEN FORMATTING, THESE * "$00" BUFFER BYTES WILL LATER BE * TRANSLATED AND WRITTEN TO THE * DISK AS "$96" DISK BYTES.) * ZERO OUT RWTS BUFFER THAT NORMALLY * CONTAINS 2-ENCODED NIBBLES. * (RWTSBUF2, $BC00 <--- $BC55.) ZBUF2 STA RWTSBUF1+$FF,Y ;($BC55 --> $BC00.) DEY BNE ZBUF2 * ZERO OUT RWTS BUFFER THAT NORMALLY * CONTAINS 6-ENCODED NIBBLES. * (RWTSBUF1, $BB00 ---> $BBFF.) ZBUF1 STA RWTSBUF1,Y DEY BNE ZBUF1 * PREPARE TO DO A RECALIBRATION. LDA #80 ;PRETEND WE'RE ON TRK #80. JSR SETTRK ;GO SELECT DRV & PUT HALFTRACK # ;WANTED IN MEMORY LOCATION ASSOC ;WITH THE # OF DRV BEING USED. LDA #40 ;SET UP FOR 40 SYNCS BTWN SECS STA SYNCNTR ;ON TRK0. NOTE THAT THIS # WILL ;LATER BE REDUCED AS WE WRITE ;SUBSEQUENT TRKS.(HIGHER NUMBERED ;TRKS ARE CLOSER TO THE CENTER OF ;THE DSK & THERE4 ARE REPRESENTED ;BY SMALLER CIRCLES. WE CAN CROWD ;ALL THE SECS INTO A SMALLER ;CIRCUMFERENCE BY REDUCING THE # ;OF SYNC BYTES BETWEEN SECS. * FORMAT THE NEXT TRACK. FRMNXTRK LDA FRMTKCTR ;USE TRK COUNTER AS TRK TO SEEK. JSR SEEKTRK ;POS'N ARM OVER CORRECT TRK. * GO FORMAT A SPECIFIC TRACK. JSR FORMATRK ;FORMAT A TRACK. LDA #8 ;SET (A) AS DEFAULT VALUE IN CASE ;COULDN'T FORMAT. NOTE THAT ANY ;TYPE OF ERROR ENCOUNTERED WHEN ;FORMATTING YEILDS AN I/O-ERROR ;MESSAGE. BCS ERRFRMT ;BRANCH IF COULDN'T FORMAT. * DO A READ CHK OF TRK JUST FORMATTED. * (EVENTHOUGH TRACK VERIFIED, READ * IT AGAIN UNTIL LOCATE TRK0. * (PRESUMABLY, THIS (PARTIALLY) * DOUBLE CHECKS VERIFICATION AND * KEEPS SECTORS IN DIFFERENT TRACKS * SOMEWHAT ADJACENT?) 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. JSR RDADDR ;GO READ ADDR HEADER TO FIND SEC ;THAT WE WANT TO READ OR WRITE. BCS RDAGAIN ;BAD READ - TRY AGAIN. LDA SECDSK ;WAS IT SECTOR 0? BNE RDAGAIN ;NO - TRY AGAIN. JSR READATA ;LAST CHANCE TO READ DATA. BCS RDAGAIN ;LAST CHANCE BOMBED OUT!!! INC FRMTKCTR ;KICK UP TRK COUNTER. LDA FRMTKCTR ;SET (A) FOR NEXT TRK COUNT. CMP #$23 ;DONE ALL TRACKS YET (#0 TO #34)? BCC FRMNXTRK ;NO - GO FORMAT THE NEXT TRACK. CLC ;SIGNAL FINISHED ALL TRACKS. BCC DONEFRMT ;ALWAYS - ONLY GOOD EXIT. * NOTE: NO MATTER WHAT KIND OF ERROR * WE MIGHT HAVE ENCOUNTERED WHEN * FORMATTING, THE IOB ERROR CODE IS * SET TO $08. THIS IS LATER TRANSLATED * TO AN FM ERROR CODE (ALSO $08) WHICH * DOS DISPLAYS AS AN I/O ERROR MSG. * (THIS IS WHY TRYING TO FORMAT A * WRITE-PROTECTED DISK RESULTS IN AN * I/O ERROR MSG INSTEAD OF A DISK- * WRITE-PROTECTED MSG.) * IF NO ERROR OCCURRED, THE IOB RETURN * CODE WILL BE SET TO SOME RANDOM * NUMBER (FROM REFERENCING A HARD- * WARE SWITCH ADDRESS). 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 THE MOTOR OFF, XIT WITH (C) RTS ;DENOTING SUCCESS STATUS. *------------------------------------ * SUBROUTINE 2 FORMAT A SPECIFIC TRK. *------------------------------------ * SECTORS ARE WRITTEN IN ASCENDING * ORDER FROM SEC $00 TO SEC $0F. * (NOTE THAT THE FORMAT ROUTINE ONLY * DEALS WITH PHYSICAL SECTOR NUMBERS.) FORMATRK LDA #0 ;ALWAYS START WITH SEC $00. STA FRMTSEC LDY #128 ;USE 128 SYNC BYTS BEFORE SEC$00. ;NOTE: THIS GAP WILL BE PARTIALLY ;OVERWRITTEN BY SEC $0F. BNE DOADDR ;ALWAYS. FRMTASEC LDY SYNCNTR ;SET (Y)= # OF 40-CYCLE SELF-SYNC ;BYTES TO BE WRITTEN BTWN SECS. ;(THIS # VARIES DEPENDING ON THE ;SPEED OF THE SPECIFIC DRV BEING ;USED & THE # OF THE TRK BEING ;WRITTEN.) DOADDR JSR WRITADR ;WRITE SYNC BYTES & ADDR HEADER. BCS VRFYRTN ;ERROR -DISK WAS WRITE PROTECTED. JSR WRITESEC ;WRITE SYNC GAP BTWN ADDR & DATA ;FIELDS, WRT DATA & WRITE A SYNC ;BYTE AFTER DATA EPILOGUE. BCS VRFYRTN ;IRRELEVANT - NEVER TAKEN BECAUSE ;WE ALREADY CHECKED THE WRITE- ;PROTECT SWTCH WHEN WE WROTE ADR. INC FRMTSEC ;INCREASE SEC #. LDA FRMTSEC CMP #$10 ;DONE ALL 16 SECS YET? BCC FRMTASEC ;NO - GO DO SOME MORE. *...................................... * VERIFY A SINGLE TRACK. *...................................... * NOTE WE JUST FINISHED FORMATTING * SEC $0F. BECAUSE SEC $0F SHOULDN'T * OVERWRITE TOO MUCH OF OF THE SYNC GAP * (ORIGINALLY 128 SYNC LONG) THAT WAS * 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. * INTIALIZE COUNTERS. LDY #$0F ;SET COUNTER 4 # OF SECS VERIFIED STY FRMTSEC LDA #48 ;SET COUNTER FOR # OF ATTEMPTS. STA READCNTR * FILL SECTOR MAP WITH POSITIVE NUMBERS. FILSECMP STA SECFLGS,Y DEY BPL FILSECMP * DELAY TO LET SOME SYNCS PASS BY. 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) BNE BYPSYNCS ;(3 CYC ON BRNCH, 2 ON FALL THRU) * READ ADDRESS OF FIRST SEC ENCOUNTERED. * (THIS BETTER BE SEC $00!!!! IF IT * ISN'T, OUR DRIVE IS TOO FAST & WE * WILL EVENTUALLY HAVE TO REFORMAT * THE TRACK.) JSR RDADDR ;READ ADR OF 1RST SEC ENCOUNTERED BCS REREADDR ;BAD READ, TRY AGAIN. LDA SECDSK ;WAS SEC READ = SEC00? BEQ RDNXTDAT ;YES - GO READ NEXT DATA SEC. * DIDN'T FIND SECTOR $00 WHEN EXPECTED!!!! * DRIVE MUST BE FASTER THAN ANTICIPATED * CAUSE SEC $0F OVERLAID TOO MUCH OF * THE LONG SYNC GAP (GAP1) THAT WAS * ORIGINALLY WRITTEN BEFORE SEC $00. * WE WILL EVENTUALLY HAVE TO REFORMAT * THIS TRK USING 128 SELF-SYNCS BEFORE * SEC $00 (GAP1) AND LESS SYNC BYTES * BETWEEN OTHER SECS (GAP3). THIS * WILL INSURE THAT LESS GAP-1 SYNCS * WILL BE OVERWRITTEN BY SEC $OF. * NOTE THAT DEPENDING ON JUST HOW * MUCH TOO FAST THE DRIVE IS, WE MAY * HAVE TO REFORMAT THIS TRK SEVERAL * TIMES BEFORE WE GET IT RIGHT. EACH * TIME WE REFORMAT, WE REDUCE THE # * OF GAP-3 SYNCS. IF THE SYNC COUNTER * IS > = 16, WE WRITE 2 LESS SYNCS. * IF THE COUNTER IS < 16, WE ONLY REDUCE * GAP-3 BY ONE SYNC. IN ORDER TO GIVE * THE MACHINE TIME TO DECODE INFO, WE * WON'T ALLOW A GAP LESS THAN 5 SYNCS * LONG. (NOTE THAT WE WON'T REFORMAT * THE TRACK UNTIL WE FIND THE ADR HEADER * FOR SEC $0F. THIS PRESUMABLY KEEPS * LIKE-NUMBERED SECS IN ADJACENT TRKS * IN SOME SEMBLANCE OF ORDER.) 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 AT RTS ;LEAST 5 SYNCS. DRIVE IS SO FAST * === ;THAT IT IS USELESS. WE CAN'T ;EVEN COMPENSATE 4 IT BY REDUCING ;THE NUMBER OF GAP-3 SYNCS. * READ THE SEC ADDR & DATA PROPER. RDNXTADR JSR RDADDR ;READ THE ADDR HEADER. BCS BADREAD ;BRANCH IF BAD ADDRESS READ. RDNXTDAT JSR READATA ;READ THE DATA PROPER. BCC CKSECMAP ;READ WAS GOOD -SO GO CHK IF THIS ;SEC HAS ALREADY BEEN READ. BADREAD DEC READCNTR ;EITHER GOT A BAD READ OR ELSE ;WE ALREADY VERIFIED THIS SEC. ;REDUCE THE # OF CHANCES LEFT. BNE RDNXTADR ;MORE CHANCES LEFT -GO TRY AGAIN. * DOING A RE-READ. WILL DEFINITELY * HAVE TO REFORMAT. REREADDR JSR RDADDR ;READ AN ADDR HEADER. BCS NOTLAST ;GOT A BAD READ. * WE WILL REFORMAT BUT WE DON'T WANT * TO DO SO UNTIL WE READ SEC $0F. * HAVE WE FOUND SEC $0F YET? LDA SECDSK ;GET PHYS # OF SEC JUST READ. CMP #$0F ;WAS IT SEC 15? BNE NOTLAST ;NO, SO GO LOOK SOME MORE. JSR READATA ;YES - READ THE DATA IN SEC $0F. BCC FORMATRK ;GOOD READ ON SEC15 SO NOW TIMING ;IS RIGHT TO GO REFORMAT THIS TRK NOTLAST DEC READCNTR ;BAD READ, CK IF MORE CHANCES LFT BNE REREADDR ;YES - GO TRY AGAIN. SEC ;EXHAUSTED ALL CHANCES, SO SET VRFYRTN RTS ;(C) AS ERROR FLAG & EXIT. * === * CHECK IF THIS SEC WAS PREVIOUSLY * VERIFIED. IF NOT, UPDATE SECTOR * VERIFICATION MAP. (IF TIMING IS * RIGHT, SHOULD NEVER ENCOUNTER AN * ALREADY VERIFIED SEC BEFORE FRMTSEC * DECREMENTS FROM $0F DOWN TO $FF.) CKSECMAP LDY SECDSK ;USE # OF SEC FOUND AS INDEX TO ;THE VERIFICATION MAP. LDA SECFLGS,Y ;GET MAP BYT (NEG=PREV VERIFIED). BMI BADREAD ;OH!OH! ALREADY VERIFIED THIS ONE LDA #$FF ;SET BYTE IN MAP TO SIGNAL THAT STA SECFLGS,Y ;THIS SEC WAS JUST VERIFIED. DEC FRMTSEC ;ANY SECS LEFT TO VERIFY? BPL RDNXTADR ;YES - GO DO SOME MORE. * ALL SECS VERIFIED, SO CHECK * IF WE JUST DID TRACK $00. LDA FRMTKCTR ;WAS TRK JUST FORMATTED =TRK $00? BNE NOTRK0 ;NO - SO EXIT CLEANLY. * JUST FORMATTED & VERIFIED TRK $00. * TRK $00 IS THE OUTSIDE TRK AND THERE4 * HAS THE LARGEST LENGTH IN WHICH TO * WRITE BYTES. BECAUSE SUBSEQUENT * TRKS HAVE A SMALLER CIRCUMFERENCE, * WE MUST REDUCE THE NUMBER OF SYNCS * TO WRITE BETWEEN SECS (GAP3) SO WE * CAN GET ALL THE NEEDED INFO INTO * A SMALLER SPACE. LDA SYNCNTR ;CHECK SYNC COUNT. CMP #16 ;LESS THAN 16 SYNCS? BCC VRFYRTN ;YES - EXIT CLEANLY. ;DON'T WANT TO START OFF WITH A ;SMALLER GAP SO SKIP CODE BELOW. * REDUCE THE SIZE OF GAP3. DEC SYNCNTR ;GAP > = 16 SYNCS LONG, SO CAN DEC SYNCNTR ;AFFORD 2 REDUCE IT BY 2 IN ORDER NOTRK0 CLC ;TO ACCOMMODATE A TIGHTER TRACK. RTS ;EXIT CLENALY. *================================= * FLAGS FOR SECTOR VERIFICATION. * ($BFA8 - $BFB7) * - NEG VAL = SECTOR VERIFIED. * - TABLE IS INDEXED BY (Y), * WHERE (Y) = SECTOR NUMBER. *================================= SECFLGS HEX FFFFFFFFFFFFFFFF ;SECS $00 TO $07. HEX FFFFFFFFFFFFFFFF ;SECS $08 TO $0F. *================================= * PHYSICAL SECTOR NUMBERS * ($BFB8 - $BFC7) * - LISTED IN LOGICAL ORDER. *================================= ;CORRESPONDING LOGICAL SECTOR#. PHYSECTR HEX 00 ; 00 HEX 0D ; 01 HEX 0B ; 02 HEX 09 ; 03 HEX 07 ; 04 HEX 05 ; 05 HEX 03 ; 06 HEX 01 ; 07 HEX 0E ; 08 HEX 0C ; 09 HEX 0A ; 0A HEX 08 ; 0B HEX 06 ; 0C HEX 04 ; 0D HEX 02 ; 0E HEX 0F ; 0F *================================= * CLOBBER THE LANGUAGE CARD. * ($BFD9 - $BFDB) * - PATCH CALLED BY BOOT2. *================================= CLOBCARD JSR SETVID ;SIMULATE A "PR#0" STATEMENT. LDA $C081 ;WRITE ENABLE RAM CARD. LDA $C081 ;(READ MOTHER/WRITE CARD BANK2.) LDA #0 ;SET LANGUAGE IDENTIFYING BYTE ON STA BASICCLD ;CARD TO $00 SO IF CARD IS TESTED ;(DURING AN "FP" CMD), THE ;MACHINE WILL BE FORCED TO USE ;MOTHERBOARD VERSION OF FP. JSR CONTCLOB ;NOW CLOBBER THE 80-COLUMN CARD. JMP BK2BOOT2 ;RTN TO ORIGINAL PART OF BOOT2. *=================================== * PATCH TO ZERO ADDED STORAGE BYTES. * ($BFDC - $BFE5) *=================================== ZEROPTCH STA TEMPBYT STA BYTPRSD STA BYTPRSD+1 RTS *================================= * PATCH TO SET CONDITION 0 AND * CLEAR THE RUN INTERRUPT FLAG. * ($BFE6 - $BFEC) *================================= RESTATIN JSR RESTAT0 ;ZERO OUT CONDNFLG & OPUTCOND. STY RUNTRUPT ;CLR THE RUN INTERRUPT FLAG. RTS *================================= * DISK-FULL ERROR PATCH. * ($BFED - $BFFF) *================================= FULLPTCH JSR CPYFMWA ;COPY FM WRK AREA--->FM WRK BUF. LDX STKSAV ;RESTORE STACK POINTER. TXS JSR CLOSEALL ;CLOSE ALL FILES. TSX STX STKSAV ;SAVE STACK POINTER. LDA #9 ;EXIT WITH DISK-FULL ERROR CODE. JMP BADFMXIT ********************************** * END OF DOS ($BFFF) * **********************************