          NAM FORMAT
          OPT PAG
          PAG
* FORMAT PROGRAM FOR SK*DOS 68K
* SUPPORTS THE PERIPHERAL TECH PT-68K COMPUTER
* COPYRIGHT (C) 1986 BY PETER A. STARK
* FOR STAR-K SOFTWARE SYSTEMS CORP.

* VER 1.4 MOD 10-10-86 TO SLOW DOWN STEP FOR 1772
* VER 1.5 10-18-86 TO UPDATE FOR DRUSED AND DRWPRO TABLES
* VER 1.6 1-11-87 TO UPDATE HELP MESSAGE
* VER 1.7 MOD >>A<< 3-25-87 TO SLOW DOWN STEP FOR 1772
* VER 1.8 MOD >>B<< 4-14-87 TO WRITE TO END OF TRACK, FIX PRINT
* VER 1.9 MOD >>C<< 7-26-87 TO CHANGE INTERLEAVE
* VER 2.0 MOD >>D<< 8-3-87 TO VERIFY FORWARD

* SK*DOS EQUATES

          LIB     SKEQUATE
DRUSED    EQU $13C                 DRUSED TABLE OFFSET
DRWPRO    EQU $146                 DR WR PROT TABLE OFFSET

COMREG    EQU $FE0081 FDC COMMAND REGISTER
STAREG    EQU COMREG FDC STATUS REGISTER
TRKREG    EQU $FE0083 FDC TRACK REGISTER
SECREG    EQU $FE0085 FDC SECTOR REGISTER
DATREG    EQU $FE0087 FDC DATA REGISTER
DLATCH    EQU $FE0061 DRIVE SELECT LATCH
DSTARG    EQU $FE0003 DUART STATUS REGISTER
DDATRG    EQU $FE0007 DUART DATA REGISTER
MONROM    EQU $FFC000 MONITOR ROM
* EXPLANATION OF DLATCH OPERATION:
*           BITS 0 & 1 SELECT DRIVE 0 & 1, RESP.
*           BIT 5 SELECTS DENSITY (0 = DD)
*           BIT 6 SELECTS SIDE (0 - SIDE A)
*           BITS 2, 3, 4, 7  - NOT USED

START     BRA.S START1

* DATA AREA FOR FORMAT

          DC.W  $0200              VERSION   >>D<<
SIDES     DC.B 0 NUMBER OF SIDES
SIDE      DC.B 0 CURRENT SIDE
SECTRS    DC.B 0 SECTORS ON CURRENT TRACK (ONE SIDE)
SECTR0    DC.B 0 SECTORS ON TRACK 0 (ONE SIDE)
TRDENS    DC.B 0 DENSITY OF CURRENT TRACK
TR0DEN    DC.B 0 DENSITY OF TRACK 0
PREIND    DC.W 0 PRE-INDEX GAP INFO FOR USE LATER
S1BEG     DC.L 0 BEG OF SECTOR 1 IN BUFFER
GRSIZE    DC.W 0 GROSS SIZE OF SECTOR (256+ALL ELSE)
TRKPTR    DC.L 0 LSB POINTS TO TRACK IN GROSS SECTOR
DATAPT    DC.L 0 POINTS TO DATA AREA IN GROSS FCB
INTADR    DC.L 0 ADDRESS OF INTERLEAVE TABLE
BUFEND    DC.L 0 POINT JUST PAST END OF BUFFER
PHYSEC    DC.B 0 PHYSICAL SECTOR NUMBER
LOGDRV    DC.B 0 LOGICAL DRIVE NUMBER TO FORMAT ON
PHYDRV    DC.B 0 PHYSICAL DRIVE NUMBER TO FORMAT ON
TRACK     DC.B 0 CURRENT TRACK
LAGOOD    DC.W 0 LAST GOOD TRACK-SECTOR
CHFLAG    DC.B 0 0=LAST WAS AN ERROR, 1=OK
TRCHAR    DC.B 0 TRACK INDICATOR
TRACKS    DC.B 0 NUMBER OF TRACKS TO FORMAT
INTERL    DC.B 0 INTERLEAVE CONSTANT >>C<<
FREE      DC.W 0 NUMBER OF FREE SECTOR
FIFREE    DC.W 0 FIRST FREE TRACK-SECTOR
LAFREE    DC.W 0 LAST FREE TRACK-SECTOR
NUMBER    DC.W 0 DISK NUMBER
MLATCH    DC.B 0 COPY OF DISK LATCH
* THE FOLLOWING FOUR LINES MUST STAY IN ORDER
DUMMY     DC.L 0 LEAVE THIS BEFORE NAME
NAME      DC.L 0,0 DISK NAME
EXT       DC.B 0,0,0 DISK EXTENSION
DUMMY2    DC.B 0 LEAVE THIS AFTER EXTENSION

START1    DC VPOINT                POINT TO VARIABLES
          MOVE.L MEMEND(A6),D0     CHECK IF ENOUGH MEMORY EXISTS
          LEA BUFFER(PC),A5        POINT TO END OF FORMAT
          SUB.L A5,D0
          CMP.L #$4000,D0          MINIMUM 16K NEEDED
          BCC.S MEMEOK             OK IF OVER 16K
          LEA MEMMSG(PC),A4        ELSE PRINT "NOT ENOUGH RAM"
          DC PSTRNG
          DC WARMST

MEMEOK    LEA MLATCH(PC),A6
          CLR.B (A6)               CLEAR MLATCH IN PREPARATION
          BSR.S GETDRV             GO GET DRIVE NUMBER
          BSR.L GETINL             GET INTERLEAVE CONSTANT >>C<<
          BSR.L ASKTRK             GET NUMBER OF TRACKS TO FORMAT
          BSR.L ASKSID             GET NUMBER OF SIDES
          BSR.L ASKDEN             GET DENSITY
          BSR.L ASKTR0             GET TRACK 0 DENSITY
          BSR.L GETNAN             GET NAME AND NUMBER
          BSR.L CHEKIT             CHECK IF OK TO PROCEED
          DC PCRLF
          MOVE.B #$D0,COMREG       RESET FDC
          BSR.L SETUP0             SETUP BUFFER WITH TEMPLATE FOR TRK 0
          BSR.L ONESEC             MOTOR ON AND WAIT
          BSR.L FORMAT             GO WRITE EVERY TRACK
          BSR.L CHKSEC             GO CHECK ALL SECTORS
          BSR.L DOBOOT             PUT ON BOOT
          BSR.L DOSIS              DO SYSTEM INFO RECORD
          BSR.L DODIR              DO DIRECTORY
          BSR.L REPORT             REPORT ON RESULTS
          DC WARMST                AND QUIT

* GET DRIVE NUMBER

GETDRV    DC DECIN                 GET DRIVE NUMBER
          BCS.S DRNONG             IF DRIVE NUMBER IS BAD
          TST.B D6
          BNE.S DRNOK              IF VALID NUMBER WAS FOUND
DRNONG    LEA HLPMSG(PC),A4        INVALID DRIVE NUMBER
          DC PSTRNG
          DC WARMST
DRNOK     CLR.L D4
          MOVE.B MAXDRV(A6),D4     EXTEND MXDRV TO LONG
          CMP.L D4,D5              CHECK VALID NUMBER
          BHI.S DRNONG             INVALID IF > MAXIMUM
          LEA LOGDRV(PC),A5
          MOVE.B D5,(A5)           SAVE LOGICAL NUMBER
          MOVE.L DOSORG(A6),A4     POINT TO DOS ORG
          LEA DRUSED(A4),A5        POINT TO DRUSED TABLE
          MOVE.B (A5,D5.W),D6      GET PHYSICAL DRIVE ENTRY
          BTST.B #4,D6             CHECK FLOPPY BIT
          BEQ.S NOTFLO             NOT FLOPPY
          AND.B #$0F,D6            KEEP ONLY PHYSICAL DRIVE NUM
          LEA DRWPRO(A4),A5        POINT TO DRWPRO TABLE
          TST.B (A5,D5.W)          TEST WRITE PROTECT ENTRY
          BMI.S WRIPRO             IS WRITE PROTECTED
          LEA PHYDRV(PC),A5
          MOVE.B D6,(A5)           SAVE PHYSICAL NUMBER
          RTS

NOTFLO    LEA NFLMSG(PC),A4        NOT FLOPPY DRIVE
          DC PSTRNG
          DC WARMST
WRIPRO    LEA WPRMSG(PC),A4        DRIVE IS WRITE PROTECTED
          DC PSTRNG
          DC WARMST

* GETINL - GET INTERLEAVE CONSTANT >>C<< NEW

GETINL    DC DECIN                 GET NUMBER FROM COMMAND
          LEA INTERL(PC),A5
          MOVE.B D5,(A5)           HOPE IT'S VALID
          RTS

* ASKTRK - GET NUMBER OF TRACKS DESIRED

ASKTRK    DC PCRLF
          LEA GTTMSG(PC),A4        ASK FOR NUMBER OF TRACKS
          DC PSTRNG
          DC INLINE                GET INPUT
          DC DECIN                 GET NUMBER
          BCS.S ASKTRK             ASK AGAIN IF NOTHING
          CMP.B #81,D5             CHECK NUMBER OF TRACKS
          BCC.S TRKSNG             81 OR ABOVE IS NG
          CMP.B #2,D5
          BCC.S TRKSOK             >1 SEEMS OK
TRKSNG    LEA TNGMSG(PC),A4        ELSE NUMBER OF TRACKS IS NG
          DC PSTRNG
          BRA.S ASKTRK             AND ASK AGAIN
TRKSOK    CMP.B #80,D5
          BHI.S TRKSNG             ABOVE 81 ALSO NG
          LEA TRACKS(PC),A4
          MOVE.B D5,(A4)           STORE IT
          RTS                      AND RETURN

* ASKSID - GET NUMBER OF SIDES

ASKSID    LEA SIDMSG(PC),A4
          DC PSTRNG                PRINT "SINGLE OR DOUBLE SIDED?"
          DC GETCH
          LEA SIDES(PC),A4
          AND.B #$DF,D5            CVT TO UPPER CASE
          CMP.B #$53,D5            S?
          BEQ.S SINSID             SINGLE
          CMP.B #$44,D5            D?
          BNE.S ASKSID             IF INVALID
          MOVE.B #1,(A4)           DOUBLE SIDED
          RTS

SINSID    CLR.B (A4)               SINGLE SIDED
          RTS

* ASKDEN - GET DESIRED DENSITY, AND COMPUTE INTERLEAVE
*    TABLE IF NEEDED
*  >>C<< ENTIRELY REVISED

ASKDEN    LEA DENMSG(PC),A4
          DC PSTRNG                PRINT "SINGLE OR DOUBLE DENSITY?"
          DC GETCH
          LEA DIDENS(PC),A4
          CLR.B (A4)               ASSUME SINGLE DENSITY
          AND.B #$DF,D5            CVT TO UPPER CASE
          CMP.B #$53,D5            S?
          BEQ.S SINDEN             SINGLE
          CMP.B #$44,D5            D?
          BNE.S ASKDEN             IF INVALID
          MOVE.B #18,(A4)          18 SEC/TR IN DOUBLE DENSITY
          MOVE.W #18,D5            NUMBER OF SECTORS
          LEA DDILTB-1(PC),A4            POINT TO INTERLEAVE TBL
          BRA.S SINDE1
SINDEN    CLR.B (A4)               SINGLE DENSITY
          MOVE.W #10,D5            NUMBER OF SECTORS
          LEA SDILTB-1(PC),A4            POINT TO INTERLEAVE TBL
SINDE1    CLR.L D7
          MOVE.B INTERL(PC),D7         CHECK INTERLEAVE
          BEQ.S ASKDEX             IGNORE IF NOT SPECIFIED
          CMP.B D5,D7              COMPARE WITH NUMBER
          BCC INTLER               INTERLEAVE ERROR IF >SECT
*   FOR D6=1 TO D5 : T(D6)=0 : NEXT D6
          MOVE.L #1,D6
ILVCLR    CLR.B (A4,D6.W)
          ADD.B #1,D6
          CMP.B D6,D5
          BCC.S ILVCLR
* D6=1
          MOVE.B #1,D6
* D4=1-D7
          MOVE.L #1,D4
          SUB.B D7,D4              INIT SECTOR WILL BE 1
* D4=D4+D7
L300      ADD.B D7,D4              NEXT SECTOR (INIT 1)
* IF D4>D5 THEN D4=D4-D5
L310      CMP.B D4,D5
          BCC.S MILVOK             OK IF NEXT <= MAX
          SUB.B D5,D4              ELSE START AGAIN
* IF T(D4)<>0 THEN D4=D4+1 : GOTO L310
MILVOK    TST.B (A4,D4.W)
          BEQ.S MILVO1
          ADD.B #1,D4
          BRA.S L310
* T(D4)=D6
MILVO1    MOVE.B D6,(A4,D4.W)
* D6=D6+1 : IF D6<=D5 THEN L300
          ADD.B #1,D6
          CMP.B D6,D5
          BCC.S L300
ASKDEX    RTS

INTLER    LEA ILEMSG(PC),A4        PRINT INTERLEAVE ERROR MSG
          DC PSTRNG
          DC WARMST

* ASKTR0 - GET DESIRED DENSITY FOR TRACK 0

ASKTR0    LEA TR0DEN(PC),A4        POINT TO TRACK 0 DENS FLAG
          MOVE.B DIDENS(PC),D7     CHECK DISK DENSITY
          BEQ.S SINTR0             IF DISK IS SD, SO IS TR 0
          LEA T0DMSG(PC),A4        IF DISK IS DD, THEN ASK
          DC PSTRNG                PRINT "SINGLE OR DOUBLE DENSITY?"
          DC GETCH
          LEA TR0DEN(PC),A4
          AND.B #$DF,D5            CVT TO UPPER CASE
          CMP.B #$53,D5            S?
          BEQ.S SINTR0             SINGLE
          CMP.B #$44,D5            D?
          BNE.S ASKTR0             IF INVALID
          MOVE.B #18,(A4)          IF DD ON TRACK 0
          RTS
SINTR0    CLR.B (A4)               SINGLE DENSITY
          RTS

* GETNAN - GET DISK NAME AND NUMBER

GETNAN    LEA NAMMSG(PC),A4        ASK FOR NAME
          DC PSTRNG
          DC INLINE                GET THE NAME
          LEA NAME-4(PC),A4        POINT BEFORE NAME
          DC GETNAM                GO GET THE NAME
          BCS.S GETNAN             ASK AGAIN FOR A VALID NAME
          LEA EXT(PC),A6
          MOVE.B (A6),D7           CHECK EXTENSION
          BNE.S GETNUM             EXTENSION IS OK
          MOVE.L #$534B2A00,(A6)   ELSE FORCE .SK* EXTENSION
GETNUM    LEA NUMMSG(PC),A4        ASK FOR NUMBER
          DC PSTRNG
          DC INLINE
          DC DECIN                 GET THE NUMBER
          BCS.S GETNUM             IF NO NUMBER
          LEA NUMBER(PC),A4
          MOVE.W D5,(A4)           ELSE STORE IT
          RTS                      AND RETURN

* CHEKIT - CHECK THAT USER REALLY WANTS TO FORMAT
* AND MAKE SURE DISK IS NOT WRITE PROTECTED

CHEKIT    DC PCRLF
          LEA CHKMSG(PC),A4        PRINT CHKMSG
          DC PSTRNG
          MOVE.B PHYDRV(PC),D4
          ADD.B #$30,D4            CVT TO ASCII
          DC PUTCH
          LEA RUSMSG(PC),A4        PRINT "ARE YOU SURE?"
          DC PSTRNG
          DC GETCH                 GET REPLY
          AND.B #$DF,D5            CVT TO UPPER
          CMP.B #$59,D5
          BNE.S ABORT
          MOVE.L A6,A4             POINT TO USER FCB
          MOVE.B LOGDRV(PC),FCBDRV(A4) PUT IN DRIVE NUMBER
          DC DIREST                SELECT DRIVE AND RESTORE IT
          MOVE.B STAREG,D1         GET FDC STATUS
          AND.B #$51,D1            CHECK NR, WP, SEEK, BUSY
          BNE.S CHEKNG             IF ERROR
          RTS                      ELSE JUST RETURN
CHEKNG    BTST.B #6,D1             CHECK WRITE PROTECT BIT
          BNE.S CHEKWP             IF WRITE PROTECTED
          LEA DERMSG(PC),A4
          DC PSTRNG                UNSPECIFIED ERROR MESSAGE
          BRA.S ABORT

CHEKWP    LEA WPMSG(PC),A4
          DC PSTRNG                DISK WRITE PROTECTED
ABORT     LEA NOTMSG(PC),A4
          DC PSTRNG                PRINT "ABORTING"
          DC WARMST

* SETUP - SET UP A TRACK DATA TEMPLATE WHICH WILL
* LATER BE FILLED IN WITH TRACK AND SECTOR DATA
* AND PTRS FOR EACH ACTUAL TRACK
* HAS TWO ENTRY POINTS: SETUP0 FOR TRACK 0,
*    AND SETUPD FOR DOUBLE DENSITY

SETUP0    MOVE.B TR0DEN(PC),D7     GET DENSITY OF TRACK 0
          BNE.S SET0DD             SET0DD IF DOUBLE DEN
          LEA TRDENS(PC),A2        ELSE ...
          CLR.B (A2)               THIS TRACK IS SINGLE
          LEA SDTABL(PC),A2        POINT TO SINGLE DENSITY SETUP TABLE
          LEA SECTR0(PC),A5
          MOVE.B (A2)+,(A5)        NO OF SECTORS ON TRACK 0
          LEA SECTRS(PC),A5
          MOVE.B (A2)+,(A5)        NO OF SECTORS ON OTHER TRACKS
          BRA.S SETUP1 THEN CONTINUE

SET0DD    LEA SECTR0(PC),A5        ON DD TRACK 0, SET NUMBER ...
          MOVE.B DDTABL(PC),(A5)   ...OF SECT ON TRACK 0 FIRST
SETUPD    LEA TRDENS(PC),A2
          MOVE.B #1,(A2)           THIS TRACK IS DOUBLE
          LEA DDTABL(PC),A2        POINT TO DOUBLE DENSITY SETUP TABLE
          LEA SECTRS(PC),A5
          LEA 1(A2),A2             LEAVE TRK 0 SECT UNCHANGED
          MOVE.B (A2)+,(A5)        NO OF SECTORS ON REMAINING TRACKS

SETUP1    LEA BUFFER(PC),A1        POINT TO BUFFER
          BSR.L PUTBNY             PRE-INDEX GAP
          BSR.L PUTBNY             SYNC BYTES BEFORE INDEX MARK
          BSR.L PUTBNY             3 BYTES OF C2 IN DD ONLY
          BSR.L PUTBNY             INDEX MARK
          BSR.S PUTBNY             DO GAP 1
          LEA S1BEG(PC),A6
          MOVE.L A1,(A6)           SECTOR 1 BEGINNING
          MOVE.L #0,A0             PTR/COUNTER
          BSR.S PUTBNY             SYNC BYTES
          BSR.S PUTBNY             3 BYTES OF A1 IN DD ONLY
          BSR.S PUTBNY             ID ADDRESS MARK
          LEA TRKPTR(PC),A6
          MOVE.L A0,(A6)           A0-> TRACK NUMBER WITHIN GROSS SECTOR
          BSR.S PUTBNY             TRACK BYTE
          BSR.S PUTBNY             SIDE BYTE
          BSR.S PUTBNY             SECTOR BYTE
          BSR.S PUTBNY             SECTOR LENGTH
          BSR.S PUTBNY             CRC
          BSR.S PUTBNY             GAP 2
          BSR.S PUTBNY             SYNC
          BSR.S PUTBNY             3 BYTES OF A1 IN DD ONLY
          BSR.S PUTBNY             DATA ADDRESS MARK
          LEA DATAPT(PC),A6
          MOVE.L A0,(A6)           A0-> TO DATA WITHIN GROSS SECTOR
          BSR.S PUTBNY             128 ZEROES IN SECTOR
          BSR.S PUTBNY             PLUS 128 MORE = 256
          BSR.S PUTBNY             CRC
          BSR.S PUTBNY             GAP 3
          LEA PREIND(PC),A6
          MOVE.B (A2)+,(A6)+       PRE-INDEX (END OF TRACK) INFO
          MOVE.B (A2)+,(A6)
          LEA INTADR(PC),A6
          MOVE.L A2,(A6)           INTERLEAVE TABLE ADDRESS
          LEA GRSIZE(PC),A6
          MOVE.W A0,(A6)           SIZE OF SECTOR

* HAVING SETUP THE FIRST SECTOR, COPY IT INTO ALL THE
* FOLLOWING SECTORS

          CLR.W D1
          MOVE.B SECTRS(PC),D1     NUM OF SECT PER SIDE ON CURR TRK
          MOVE.W A0,D0             GROSS SIZE OF EACH SECTOR
          MULU D1,D0               TOTAL LENGTH OF ALL SECTORS
          ADD.L S1BEG(PC),D0       ADD TO BEG ADDR OF SECTOR 1
          MOVE.L D0,A3             END OF BUFFER
          MOVE.L S1BEG(PC),A0      POINT TO BEGINNING OF SECTOR 1
SECOPY    MOVE.B (A0)+,(A1)+       COPY A BYTE
          CMP.L A3,A1              FINISHED?
          BNE.S SECOPY             NO, KEEP COPYING
          BSR.S PUTBNP
          BSR.S PUTBNP             PRE-INDEX DATA
          LEA BUFEND(PC),A6
          MOVE.L A1,(A6)           REAL BUFFER END
          RTS                      EXIT WHEN ENTIRE TRACK IS SET UP

* PUTBNY & PUTBNP - PUT DATA INTO SECTOR BUFFER
* HAS TWO ENTRY POINTS:
*   PUTBNY TAKES A AND B FROM (A2)+, AND PUTS
*     A BYTES OF B INTO (A1)+
*   PUTBNP TAKES A AND B FROM PREIND
* BOTH EXIT WITH A2 POINTING TO NEXT EMPTY BYTE

PUTBNP    MOVE.B PREIND(PC),D0     COUNT
          MOVE.B PREIND+1(PC),D1       WHAT TO PUT
          BRA.S PUTAN2             THEN CONTINUE
PUTBNY    MOVE.B (A2)+,D0          COUNT A
          MOVE.B (A2)+,D1          WHAT TO PUT IN B
          TST.B D0                 CHECK COUNT
          BEQ.S PUTRTS             DO NOTHING IF 0
PUTAN2    MOVE.B D1,(A1)+          PUT IN THE BYTE
          ADD.L #1,A0              INCREMENT A0
          SUB.B #1,D0              DECR COUNTER
          BNE.S PUTAN2             REPEAT UNTIL DONE
PUTRTS    RTS                      THEN RETURN

* FORMAT - GO FILL IN DATA INTO TRACK TEMPLATE AND WRITE IT

* FOR TRACK = 0 TO TRACKS-1
FORMAT    LEA FORMSG(PC),A4        >>D<<
          DC PSTRNG                PRINT "FORMATTING" >>D<<
          LEA TRACK(PC),A6         >>D<<
          CLR.B (A6)               START WITH TRACK 0
          LEA TRCHAR(PC),A4
          MOVE.B #$30,(A4)         INDICATOR STARTS WITH ASCII 0
* DO TRACK
TRLOOP    MOVE.B TRCHAR(PC),D4
          DC PUTCH                 PRINT TRACK INDICATOR DIGIT
          LEA TRCHAR(PC),A4
          ADD.B #1,(A4)            INCREMENT IT
          MOVE.B (A4),D7           CHECK IT
          CMP.B #$39,D7            PAST 9?
          BLS.S FORSID             NO, STILL OK
          MOVE.B #$30,(A4)         YES, CHANGE BACK TO 0
* FOR SIDE = 0 TO SIDES
FORSID    LEA SIDE(PC),A6
          CLR.B (A6)               CLEAR SIDE
* DO SIDE
SILOOP    BSR.S FMTMEM             FORMAT MEMORY FOR TRACK
          BSR.L WRITRK             GO WRITE THE TRACK ONTO DISK
* NEXT SIDE
          LEA SIDE(PC),A6
          ADD.B #1,(A6)            GO TO NEXT SIDE
          MOVE.B (A6),D0
          CMP.B SIDES(PC),D0       CHECK IT
          BLS.S SILOOP             REPEAT FOR SECOND SIDE
* NEXT TRACK
          LEA TRACK(PC),A6
          ADD.B #1,(A6)            INCREMENT TRACK
          MOVE.B DIDENS(PC),D0     CHECK DISK DENSITY
          CMP.B TRDENS(PC),D0      COMP WITH CURRENT TRACK
          BEQ.S DENSOK             IF SAME
          BSR.L SETUPD             ELSE SWITCH FOR DOUBLE IF DIFFERENT
DENSOK    MOVE.B TRACK(PC),D0      GET TRACK NUMBER
          CMP.B TRACKS(PC),D0      CHECK FOR MAXIMUM TRACK
          BNE.S TRLOOP             REPEAT UNTIL DONE
          RTS                      THEN EXIT

* FMTMEM FILL IN TRACK AND SECTOR DATA IN TEMPLATE

FMTMEM    MOVE.L S1BEG(PC),A0      POINT TO FIRST SECTOR
          MOVE.L INTADR(PC),A1     POINT TO INTERLEAVE TABLE
          SUB.L #1,A1              ACTUALLY, JUST BEFORE IT
          LEA PHYSEC(PC),A6
          MOVE.B #1,(A6)           PHYSICAL SECTOR NUMBER
FMTSEC    MOVE.B TRACK(PC),D0
          MOVE.L TRKPTR(PC),D1     WHERE TO PUT TRACK NUMBER
          MOVE.B D0,(A0,D1.W)      PUT IN TRACK NUMBER
          MOVE.B SIDE(PC),1(A0,D1.W) PUT IN SIDE NUMBER NEXT
          MOVE.L DATAPT(PC),D2     WHERE TO PUT LINK TO NEXT TRACK
          MOVE.B D0,(A0,D2.W)      TEMP ASSUME LINK TO CURRENT TRACK
          CLR.L D3                 WE'RE GOING TO USE D3.W!
          MOVE.B PHYSEC(PC),D3     GET PHYSICAL SECTOR NUMBER
          MOVE.B (A1,D3.W),D0      GET LOGICAL SECTOR NUMBER
          MOVE.B SIDE(PC),D7       WHICH SIDE?
          BEQ.S SIDE0              OK IF FIRST SIDE
          ADD.B SECTRS(PC),D0      ON SECOND SIDE CHANGE SECTOR NUMBER
SIDE0     MOVE.B D0,2(A0,D1.W)     PUT IN SECTOR NUMBER
          ADD.B #01,D0             PTR TO NEXT SECTOR
          MOVE.B D0,1(A0,D2.W)     TEMP ASSUME LINK IS TO NEXT SECTOR
* NOW CHECK IF AT END OF CYLINDER
          MOVE.B SECTRS(PC),D3     SECTORS PER SIDE
          MOVE.B SIDES(PC),D7      IS DISK TWO SIDED?
          BEQ.S FMT1SI             NO, JUST ONE
          ASL.B #1,D3              DOUBLE FOR TWO SIDES
FMT1SI    CMP.B D0,D3              CHECK AGAINST CURRENT SECTOR PTR
          BCC.S FMTSOK             OK IF CURRENT LOWER OR SAME
* LINK POINTS PAST CYLINDER, SO CHANGE IT
FMTSNG    MOVE.B #1,1(A0,D2.W)     GO TO SEC 1 ON NEXT TRACK
          ADD.B #1,(A0,D2.W)       AND TEMP STEP TO NEXT TRACK
          MOVE.B (A0,D2.W),D0      NOW GET NEXT TRACK
          CMP.B TRACKS(PC),D0      CHECK IF PAST LAST TRACK
          BCS.S FMTSOK             IF STILL NOT DONE
          CLR.B (A0,D2.W)          ELSE PUT IN A PTR OF 00-00
          CLR.B 1(A0,D2.W)
FMTSOK    CLR.L D1
          MOVE.W GRSIZE(PC),D1     GROSS SIZE OF SECTOR
          ADD.L D1,A0              STEP TO NEXT SECTOR'S DATA
          LEA PHYSEC(PC),A6
          ADD.B #1,(A6)            GO TO NEXT PHYSICAL SECTOR
          MOVE.B (A6),D1           LOOK AT IT
          CMP.B SECTRS(PC),D1      CHECK W MAX NUMBER OF SECTORS ON 1 SIDE
          BLS.L FMTSEC             REPEAT UNTIL ALL SECTORS ARE DONE
          RTS                      THEN RETURN

* WRITRK - WRITE AN ENTIRE TRACK TO DISK

WRITRK    MOVE.B SIDE(PC),D7       SIDE A OR B?
          BNE.S DISINT             SIDE B, SKIP SEEK
          BSR.L DSEEK              SIDE A, SEEK TO NEW TRACK
          BNE.L ABORT              ON ERROR

* AT THIS POINT, WE WANT TO TURN OFF INTERRUPTS
DISINT    DC INTDIS                CALL DOS TO TURN OFF INTERRUPTS

* ACTUAL LOOP TO WRITE A TRACK
          LEA BUFFER(PC),A5        POINT TO BUFFER
          LEA STAREG,A6            POINT TO STATUS REGISTER
          LEA DATREG,A4            POINT TO DATA REGISTER
          MOVE.B SIDE(PC),D0       GET SIDE NUMBER
          LSL.B #6,D0              CVT SIDE B INTO A $40
          ADD.B MLATCH(PC),D0      COMBINE WITH DENSITY AND DRIVE
          MOVE.B D0,DLATCH         GIVE TO DISK LATCH
          MOVE.B #$F4,COMREG       WRITE TRACK COMMAND
          BSR.L WAITF              WAIT FOR COMREG TO SETTLE
WRITS1    MOVE.B (A6),D6           GET FDC STATUS
          BTST.B #1,D6             DRQ?
          BNE.S WRITS2             YES, GO GIVE IT
          BTST.B #0,D6             BUSY?
          BNE.S WRITS1             YES, WAIT SOME MORE
          BRA.S WRITEX             NO, FINISH UP
WRITS2    MOVE.B (A5)+,(A4)        WRITE DATA BYTE
          BRA.S WRITS1             KEEP GOING >>B<<
WRITEX    DC INTENA                CALL DOS TO ENABLE INTERRUPTS
          BSR.S WABUSY             WAIT AS LONG AS FDC IS BUSY
          RTS                      AND EXIT

* WAITF - WAIT FOR COMREG TO SETTLE - SHOULD BE ABOUT 28 OR 56
* USEC, DEPENDING ON SYSTEM

WAITF     MOVE.B #8,D7
WAITF1    SUB.B #1,D7
          BNE.S WAITF1
          RTS

* WABUSY - WAIT WHILE FDC IS BUSY

WABUSY    MOVE.B STAREG,D6         GET FDC STATUS
          BTST.B #0,D6             CHECK BUSY BIT
          BNE.S WABUSY             WAIT WHILE STILL BUSY
          RTS                      THEN EXIT

**************************************
* DSEEK - SEEK TO NEW TRACK AND SECTOR
* THIS ROUTINE IS VERY SIMILAR TO THAT
* IN THE BIOS
**************************************
*
* CALLED BY: WRITRK
* INPUT: PHYDRV HAS PHYSICAL DRIVE NUMBER,
*        TRACK(PC) HAS TRACK NUMBER
* OUTPUT: RETURN ZERO  IF NO ERROR;
*                ELSE D6 CONTAINS ANY FDC ERROR CODE

DSEEK     MOVE.B PHYDRV(PC),D6     GET DRIVE NUMBER
          ADD.B #1,D6              CONVERT INTO DRIVE CODE
          MOVE.B TRACK(PC),D7      CHECK TRACK NUMBER
          BNE.S DSEEK1             CONTINUE IF NOT TRK 0
          MOVE.B TR0DEN(PC),D7     ON TRK 0 CHECK ITS DENSITY
          BEQ.S DSEEK3             IF SINGLE DENSITY
          BRA.S DSEEK2             IF DOUBLE DENSITY
DSEEK1    MOVE.B DIDENS(PC),D7     CHECK DENSITY
          BEQ.S DSEEK3             IF SINGLE DENSITY
DSEEK2    OR.B #$20,D6             ELSE ADD DOUBLE DENSITY BIT
DSEEK3    CMP.B MLATCH(PC),D6      CHECK IF SAME AS BEFORE
          BEQ.S NOD2               YES, LEAVE AS IS
          MOVE.B D6,DLATCH         SELECT DRIVE, DENSITY (NO SIDE YET)
          LEA MLATCH(PC),A6
          MOVE.B D6,(A6)           SAVE MEMORY

NOD2      MOVE.B TRACK(PC),D5
          CMP.B TRKREG,D5          ALREADY ON DESIRED TRACK?
          BEQ.S ONTRK              YES, WAIT AND EXIT
          MOVE.B D5,DATREG         AND GIVE NEW TRACK TO FDC
          BSR WAIT
* FOLLOWING IS 11 FOR 1772, 13 FOR OTHER WESTERN DIGITAL FDC'S
          MOVE.B #$11,COMREG       SEEK COMMAND, SLOW (FOR 1772)
          MOVE.L #DLATCH,A2        (WNBUSY WANTS THIS)
          BSR WNBUSY               WAIT FOR COMPLETION
          AND.B #$18,D0            CHECK NR,SK,CRC ERRORS
          RTS
ONTRK     BSR WAIT                 WAIT FOR COMPLETION
          MOVE.L #0,D0             IF NO ERROR
          RTS

***********************************************************
* ONE-SECOND TIME DELAY, TO ALLOW MOTOR TO COME UP TO SPEED
***********************************************************

ONESEC    MOVE.L #$30000,D7        SET DELAY TIMER
ONEWAI    SUB.L #1,D7              WAIT ABOUT 1-1/4 SECOND
          BNE.S ONEWAI
          RTS

* CHKSEC CHECK ALL SECTORS TO REMOVE DEFECTIVE ONES
* TOTALLY REWRITTEN IN >>D<< TO VERIFY FORWARD

CHKSEC    LEA VERMSG(PC),A4
          DC PSTRNG                PRINT "VERIFYING"
          MOVE.B #'0',D4
          DC PUTCH                 PRINT "0"
          MOVE.L A6,A4             POINT TO FCB
          MOVE.B LOGDRV(PC),FCBDRV(A4) LOGICAL DRIVE NUMBER
          MOVE.W #$0001,FCBCTR(A4) TR 0 SEC 1
          DC SREAD                 READ IT
          BNE.L SYSERR             FATAL ERROR
          MOVE.W #$0002,FCBCTR(A4) SEC 2
          DC SREAD
          BNE.L SYSERR
          MOVE.W #$0003,FCBCTR(A4) SEC 3
          DC SREAD
          BNE.L SYSERR
          MOVE.W #$0004,FCBCTR(A4) SEC 4
          DC SREAD
          BNE.L SYSERR
          MOVE.W #$0005,FCBCTR(A4) SEC 5
          DC SREAD
          BNE.L SYSERR
          MOVE.W #$0006,FCBCTR(A4) SEC 6
          DC SREAD
          BNE.L SYSERR
* NOW CHECK REST OF TRACK 0
          MOVE.W #$0007,D3         NEXT DO TR 0 SEC 7
          MOVE.W #$0006,D2         LAST GOOD
          MOVE.B TR0DEN(PC),D0     0=SD, $12=DD
          BNE.S T0ISDD             IF DD
          MOVE.B #10,D0            ELSE USE 10 IF SD
T0ISDD    MOVE.B SIDES(PC),D7      DOUBLE SIDED?
          BEQ.S T0LOOP             NO, USE AS IS
          ASL.B #1,D0              YES, DOUBLE THE NUMBER
T0LOOP    MOVE.W D3,FCBCTR(A4)
          DC SREAD                 READ NEXT DIR SECTOR
          BEQ.S RDIROK             IF OK
          LEA BDSMSG(PC),A4        PRINT "DEFECTIVE SECTOR AT"
          DC PSTRNG
          CLR.L D4
          MOVE.B FCBCTR(A6),D4     TRACK NUMBER
          CLR.L D5                 SUPPRESS SPACES
          DC OUT5D                 OUTPUT TRACK NUMBER
          MOVE.B #$2D,D4
          DC PUTCH                 OUTPUT DASH
          CLR.L D4
          MOVE.B FCBCSE(A6),D4     SECTOR NUMBER
          CLR.L D5                 CLRB SUPPRESS SPACES
          DC OUT5D                 OUTPUT SECTOR NUMBER
          DC PCRLF
          MOVE.B #'0',D4
          DC PUTCH                 PRINT "0" AGAIN
          MOVE.L A6,A4             POINT BACK TO FCB
          ADD.B #1,D3              NEXT SECTOR?
          CMP.B D0,D3              AT END?
          BLS.S MORE0              IF THERE'S MORE ON 0
          MOVE.W #$0101,D3         ELSE POINT OFF TRACK 0
MORE0     MOVE.W D3,FCBDAT(A4)     PUT IN POINTER
          MOVE.W D2,FCBCTR(A4)     INTO LAST GOOD SECTOR
          DC SWRITE                REWRITE OLD SECTOR
          BNE.L SYSERR             ABORT IF ERROR
          CMP.W #$0101,D3          PAST END?
          BEQ.S CHREST             YES
          BRA.S T0LOOP             NO, CONTINUE
RDIROK    MOVE.W D3,D2             IF OK, LAST GOOD = CURRENT
          ADD.B #1,D3              TO NEXT SECTOR
          CMP.B D0,D3              END OF TRACK?
          BLS.S T0LOOP             NO, CONTINUE
* NOW CHECK REST OF DISK
CHREST    MOVE.B #'1',D4           ASCII TRACK INDICATOR
          DC PUTCH
          MOVE.B TRACKS(PC),D0     NUMBER OF TRACKS
          SUB.B #1,D0              LAST TRACK
          LSL.W #8,D0              INTO LEFT BYTE
          MOVE.B SECTRS(PC),D0     SECTORS
          MOVE.B SIDES(PC),D7      DOUBLE SIDED?
          BEQ.S CHKS1              NO, USE AS IS
          ASL.B #1,D0              YES, DOUBLE THE NUMBER
CHKS1     MOVE.W #$0101,D2         LAST FREE = 0101
          MOVE.W D2,FCBCTR(A4)
          DC SREAD                 READ IT
          BNE.L SYSERR             ABORT IF 0101 NO GOOD
          MOVE.L #1,D1             COUNT 1 GOOD SECTOR
          LEA FIFREE(PC),A0        FIRST FREE
          MOVE.W D2,(A0)           SAVE FIRST FREE
          MOVE.W #$0102,D3         NEXT CURRENT
TDLOOP    MOVE.W D3,FCBCTR(A4)
          MOVE.W D3,A1             TEMP SAVE IT
          ADD.L #1,D1              ASSUME IT'S OK
          DC SREAD                 NEXT SECTOR
          BEQ.S TDNEXT             DO NEXT IF IT WAS OK
          SUB.L #1,D1              SUBTRACT IT FROM COUNT
          NEG.L D1                 NEGATE COUNT TO SIGNAL ERROR
          MOVE.L D4,A3             TEMP SAVE TRACK INDICATOR
          LEA BDSMSG(PC),A4        PRINT "DEFECTIVE SECTOR AT"
          DC PSTRNG
          CLR.L D4
          MOVE.B FCBCTR(A6),D4     TRACK NUMBER
          CLR.L D5                 SUPPRESS SPACES
          DC OUT5D                 OUTPUT TRACK NUMBER
          MOVE.B #$2D,D4
          DC PUTCH                 OUTPUT DASH
          CLR.L D4
          MOVE.B FCBCSE(A6),D4     SECTOR NUMBER
          CLR.L D5                 CLRB SUPPRESS SPACES
          DC OUT5D                 OUTPUT SECTOR NUMBER
          DC PCRLF
          MOVE.L A6,A4             POINT BACK TO FCB
          MOVE.L A3,D4             RESTORE TRACK INDICATOR
* GO TO NEXT SECTOR
TDNEXT    ADD.B #1,D3              NEXT SECTOR
          CMP.B D0,D3              PAST END OF TRACK?
          BLS.S NOTFVE             NO, SAME TRACK
          CLR.B D3                 YES, RESET
          ADD.W #$0101,D3          SEC 1 ON NEXT TRACK
          CMP.W D0,D3              PAST LAST TRACK?
          BHI.S YESFVE             YES, FINISHED VERIFYING
          ADD.B #01,D4
          CMP.B #$39,D4            IS IT PAST 9?
          BLS.S NPAST9             NOT YET
          MOVE.B #$30,D4           YES, RESTORE TO 0
NPAST9    DC PUTCH                 NEXT TRACK INDICATOR
          BRA.S NOTFVE
YESFVE    CLR.L D3                 YES, SO MARK US DONE
NOTFVE    TST.L D1                 CHECK ERROR FLAG
          BPL.S TDISOK             CONTINUE IF NO ERROR
          NEG.L D1                 FIX ERROR FLAG
          MOVE.W D2,FCBCTR(A4)     GO BACK TO REWRITE LAST GOOD
          MOVE.W D3,FCBDAT(A4)     ...WITH POINTER TO HERE
          DC SWRITE
          BNE.L SYSERR             VERY BAD IF CAN'T DO SO
          TST.L D3                 DONE?
          BNE.S TDLOOP             NO, SO TRY NEXT SECTOR
TDISOK    MOVE.W A1,D2             LAST FREE IS ONE WE JUST DID
          TST.L D3                 DONE?
          BNE.S TDLOOP             NO, SO TRY NEXT SECTOR
          LEA LAFREE(PC),A5        LAST FREE
          MOVE.W D2,(A5)
          LEA FREE(PC),A5
          MOVE.W D1,(A5)           NUMBER FREE
          RTS

* DOBOOT - PUT BOOT ON DISK TR 0 SEC 1 AND 2

DOBOOT    LEA BOOT(PC),A0          POINT TO SUPER BOOT'S FIRST SECTOR
          LEA FCBDAT(A6),A1        AND FCB
          MOVE.L #64,D1            COUNTER = 256/4
DOBOO1    MOVE.L (A0)+,(A1)+       MOVE FOUR BYTES
          SUB.B #01,D1             DECR COUNTER
          BNE.S DOBOO1             DO 64 TIMES
          MOVE.L A6,A4             POINT TO FCB
          MOVE.W #0001,FCBCTR(A4)  TR 0 SEC 1
          DC SWRITE                GO WRITE IT
          BNE.S SYSERR             ERROR PUTTING BOOT THERE
          LEA BOOT+256(PC),A0      POINT TO SUPER BOOT'S SECOND SECTOR
          LEA FCBDAT(A6),A1        AND FCB
          MOVE.L #64,D1            COUNTER = 256/4
DOBOO2    MOVE.L (A0)+,(A1)+       MOVE FOUR BYTES
          SUB.B #01,D1             DECR COUNTER
          BNE.S DOBOO2             DO 64 TIMES
          MOVE.B #02,FCBCSE(A4)    TR 0 SEC 2
          DC SWRITE                GO WRITE IT
          BNE.S SYSERR             ERROR PUTTING BOOT THERE
          RTS                      ELSE RETURN

* SYSERR - SYSTEM ERROR ON TRACK 0

SYSERR    LEA TR0MSG(PC),A4        PRINT "ERROR ON TRACK 0"
          DC PSTRNG
          DC WARMST                AND STOP

* DOSIS - WRITE SIS TO DISK

DOSIS     MOVE.W #$0003,FCBCTR(A4) TRACK 0 SEC 3
          LEA FCBDAT(A4),A1        POINT A1 TO DATA AREA
          MOVE.B #64,D1            COUNTER = 256/4
ERASIS    CLR.L (A1)+              ERASE NEXT 4 BYTES
          SUB.B #01,D1             DECR COUNTER
          BNE.S ERASIS             ERASE 256 BYTES
          MOVE.B FIFREE(PC),FCBDAT+29(A4) FIRST FREE
          MOVE.B FIFREE+1(PC),FCBDAT+30(A4)
          MOVE.B LAFREE(PC),FCBDAT+31(A4)   LAST FREE
          MOVE.B LAFREE+1(PC),FCBDAT+32(A4)
          MOVE.B FREE(PC),FCBDAT+33(A4)     NUMBER FREE
          MOVE.B FREE+1(PC),FCBDAT+34(A4)
          MOVE.B CMONTH(A6),FCBDAT+35(A4) MONTH
          MOVE.B CDAY(A6),FCBDAT+36(A4)  DAY
          MOVE.B CYEAR(A6),FCBDAT+37(A4) YEAR
          MOVE.B TRACKS(PC),D0     NUMBER OF TRACKS
          SUB.B #01,D0             STARTS WITH 0
          MOVE.B D0,FCBDAT+38(A4)  LAST TRACK NUMBER
          MOVE.B SECTRS(PC),D1     NUMBER OF SECTORS ON ONE SIDE
          MOVE.B SIDES(PC),D7      HOW MANY SIDES?
          BEQ.S SISLAS             USE AS IS IF SS
          ASL.B #1,D1              ELSE *2 FOR DS
SISLAS    MOVE.B D1,FCBDAT+39(A4)
          LEA NAME(PC),A1          POINT TO NAME
          LEA FCBDAT+16(A4),A0     POINT TO NAME LOCATION
          MOVE.L (A1)+,(A0)+
          MOVE.L (A1)+,(A0)+       MOVE 11 BYTES - NAME AND EXT
          MOVE.L (A1)+,(A0)+       (AND ONE EXTRA)
          MOVE.B NUMBER(PC),FCBDAT+27(A4) NUMBER
          MOVE.B NUMBER+1(PC),FCBDAT+28(A4)
          DC SWRITE                GO WRITE SECTOR BACK
          BNE.L SYSERR             REPORT ERROR
          RTS                      THEN RETURN

* DODIR - PUT AN END ON DIRECTORY

DODIR     MOVE.W #$0005,FCBCTR(A4) TRACK 0 SEC 5
DODIR1    DC SREAD                 GO READ SECTOR
          BNE.L SYSERR             ERROR IF CAN'T READ
          MOVE.B FCBDAT(A4),D0     GET NEXT TRACK POINTER
          MOVE.W FCBDAT(A4),D1     GET NEXT TRACK & SEC POINTER
          TST.B D0                 CHECK TRACK
          BNE.S DODIR2             MEANS LAST SECTOR ON THIS TRACK
          MOVE.B D1,FCBCSE(A4)     ELSE SETUP TO READ NEXT
          BRA.S DODIR1             GO DO IT
DODIR2    CLR.W FCBDAT(A4)         MARK END OF DIRECTORY
          DC SWRITE                GO REWRITE SECTOR
          BNE.L SYSERR
          RTS                      RTS AND QUIT

* REPORT - REPORT THAT FORMATTING IS DONE

REPORT    LEA FCMMSG(PC),A4        PRINT "FORMATTING COMPLETE."
          DC PSTRNG
          MOVE.W FREE(PC),D4
          MOVE.L #0,D5             SUPPRESS SPACES
          DC OUT5D                 PRINT NUMBER OF FREE SECTORS
          RTS                      AND RETURN

* TEST STRINGS

HLPMSG    DC.B 'FORMAT is used to initialize a blank diskette for use with'
          DC.B $0D,$0A
          DC.B 'SK*DOS. It may also be used to completely erase all data on a'
          DC.B $0D,$0A
          DC.B 'disk and initialize it as if it were brand new. The syntax is'
          DC.B $0D,$0A
          DC.B '   FORMAT <drive-number> <optional interleave constant>' >>C<<
          DC.B $0D,$0A
          DC.B 'The <drive-number> must be specified, and must apply to a' >>C<<
          DC.B $0D,$0A
          DC.B 'valid floppy drive. The <optional interleave count>, if' >>C<<
          DC.B $0D,$0A
          DC.B 'given, overrides the default interleave constant.' >>C<<
          DC.B $0D,$0A
          DC.B '    FORMAT will then ask for further information' >>C<<
          DC.B $0D,$0A
          DC.B 'on the number of tracks, number of sides, density, and' >>C<<
          DC.B $0D,$0A
          DC.B 'disk name and number. Remember that to be bootable, the' >>C<<
          DC.B $0D,$0A
          DC.B 'disk must be double-density throughout. Caution: FORMAT does'
          DC.B $0D,$0A
          DC.B 'really erase everything on the diskette!',4
* TEXT STRINGS

ILEMSG    FCC 'Invalid interleave constant specified.',4 >>C<<
MEMMSG    FCC 'Minimum 16K of RAM is needed.',4
NFLMSG    FCC 'Specified logical drive is not a floppy.',4
CHKMSG    FCC 'About to format physical floppy drive number ',4
WPRMSG    FCC 'Drive is write-protected.',4
GTTMSG    FCC 'How many tracks? ',4
TNGMSG    FCC 'Invalid number of tracks.',4
SIDMSG    FCC 'Single or double sided? ',4
DENMSG    FCC 'Single or double density? ',4
T0DMSG    FCC 'Single or double density track 0? ',4
NAMMSG    FCC 'Enter disk name: ',4
NUMMSG    FCC 'Enter disk number: ',4
RUSMSG    FCC 'Are you sure you really want to? ',4
NOTMSG    FCC 'No formatting done.',4
DERMSG    FCC 'Disk error - cannot format.',4
WPMSG     FCC 'Disk is write protected',4
FCMMSG    FCC 'Disk is formatted; free sectors = ',4
BDSMSG    FCC 'Defective sector at track-sector (decimal) ',4
TR0MSG    FCC 'Error on track 0 - formatting aborted.',4
FORMSG    FCC 'Formatting:',$0D,$0A,4 >>D<<
VERMSG    FCC 'Verifying:',$0D,$0A,4 >>D<<


* DISK FORMAT TABLES

SDTABL    DC.B 10,10 SECTORS/TRACK (TRACK 0 AND OTHER TRACKS)
          DC.B 12,$FF PRE-INDEX GAP
          DC.B 6,0 SYNC BYTES BEFORE INDEX MARK
          DC.B 0,0 NOT USED IN SINGLE DENSITY
          DC.B 1,$FC INDEX MARK
          DC.B 8,$FF GAP 1 (POST INDEX)
          DC.B 6,0 SYNC BYTES BEFORE ID FIELD
          DC.B 0,0 NOT USED IN SINGLE DENSITY
          DC.B 1,$FE ID ADDRESS MARK
          DC.B 1,0 TRACK NUMBER BYTE
          DC.B 1,0 SIDE NUMBER BYTE
          DC.B 1,0 SECTOR NUMBER BYTE
          DC.B 1,1 SECTOR LENGTH (1=256 BYTES)
          DC.B 1,$F7 CRC
          DC.B 11,$FF GAP 2
          DC.B 6,0 SYNC BYTES BEFORE DATA FIELD
          DC.B 0,0 NOT USED IN SINGLE DENSITY
          DC.B 1,$FB DATA ADDRESS MARK
          DC.B 128,0,128,0 128+128=256 BYTES OF DATA
          DC.B 1,$F7 CRC
          DC.B 14,$FF GAP 3
          DC.B 75,$FF PRE-INDEX GAP
SDILTB    DC.B 1,4,7,9,2,5,8,10,3,6 INTERLEAVE TABLE >>C<<
DDTABL    DC.B 10,18 SECTORS/TRACK (TRACK 0 AND OTHER TRACKS)
          DC.B 24,$4E PRE-INDEX GAP
          DC.B 12,0 SYNC BYTES BEFORE INDEX MARK
          DC.B 3,$F6 C2 IN DOUBLE DENSITY ONLY
          DC.B 1,$FC INDEX MARK
          DC.B 16,$4E GAP 1 (POST INDEX)
          DC.B 12,0 SYNC BYTES BEFORE ID FIELD
          DC.B 3,$F5 A1 IN DOUBLE DENSITY ONLY
          DC.B 1,$FE ID ADDRESS MARK
          DC.B 1,0 TRACK NUMBER BYTE
          DC.B 1,0 SIDE NUMBER BYTE
          DC.B 1,0 SECTOR NUMBER BYTE
          DC.B 1,1 SECTOR LENGTH (1=256 BYTES)
          DC.B 1,$F7 CRC
          DC.B 22,$4E GAP 2
          DC.B 12,0 SYNC BYTES BEFORE DATA FIELD
          DC.B 3,$F5 A1 IN DOUBLE DENSITY ONLY
          DC.B 1,$FB DATA ADDRESS MARK
          DC.B 128,0,128,0 128+128=256 BYTES OF DATA
          DC.B 1,$F7 CRC
          DC.B 16,$4E GAP 3
          DC.B 168,$4E PRE-INDEX GAP
DDILTB    DC.B 1,4,7,10,13,16,2,5,8,11,14,17,3,6,9,12,15,18 INTERLEAVE TABLE >>C<<

* THE FOLLOWING SUPER-BOOT PROGRAM IS PUT ON
* TRACK 0 SECTORS 1 AND 2 OF DISK

* SUPER-BOOT FOR PTA COMPUTER
* POSITION-INDEPENDENT CODE FOR SK*DOS
* (C) 1986 BY PETER A. STARK

BOOT      BRA.S BOOT1

SBBUFF    EQU *+$0200              SECTOR BUFFER GOES AFTER BOOT
TYPE      DC.B 'PTA'               TYPE OF BOOT
FIRSTS    DC.B 0,0                 FIRST TRACK-SECTOR OF DOS
DIDENS    DC.B 0                   0=SD DISK; ELSE NUM OF SCTRS ON OTHER TRKS
SECSID    DC.B 10                  SECTORS PER SIDE (DEFAULT 10 FOR SD)

BOOT1     MOVE.L #DLATCH,A2        POINT A2 TO DLATCH
          LEA BOOT(PC),A4          POINT TO THIS BOOT
          MOVE.B #$21,(A2)         FORCE DRIVE 0, DD, SIDE A
* FOLLOWING IS 01 FOR 1772, 03 FOR OTHER WESTERN DIGITAL FDC'S >>A<<
          MOVE.B #$01,COMREG-DLATCH(A2) RESTORE, LOAD HEAD, SLOW STEP >>A<<
          CLR.B D4                 DOUBLE-STEP FLAG
          BSR.L WNBUSY             PAUSE AND WAIT FOR NOT BUSY
          LEA BOOT+256(PC),A3      ADDRESS OF 2ND 256 BYTES
          MOVE.W #$0002,SBBUFF-BOOT(A4) MAKE PTR TO TR 0 SEC 02
          BSR.S GETSEC             READ SECOND HALF OF SUPER BOOT
          BNE.S BOOT1              IMMEDIATELY RETRY ON ERROR
          MOVE.B DIDENS(PC),D0     CHECK DISK DENSITY
          BEQ.S DISKSD             ZERO MEANS DISK IS SINGLE DENSITY
          MOVE.B D0,SECSID-BOOT(A4) ELSE UPDATE SECTORS PER SIDE
DISKSD    MOVE.B FIRSTS(PC),SBBUFF-BOOT(A4) FIRST TR-S IS NOW NEXT
          MOVE.B FIRSTS+1(PC),SBBUFF+1-BOOT(A4)
          BEQ.L LNKERR             IF NOT LINKED
          CLR.L D3                 CLEAR DATA POINTER
          MOVE.L #-1,A5            ERASE TRANSFER ADDRESS
          BRA.L MLOOP              CONTINUE WITH MAIN LOOP

* GET THE NEXT SECTOR

GETSEC    MOVE.W SBBUFF(PC),D7     GET NEXT TR-SEC
          BEQ.L DONE               NEXT IS 00-00 SO END
          MOVE.B D7,SECREG-DLATCH(A2) GIVE SECTOR TO FDC
          CLR.B D5                 ASSUME SIDE 0
          CMP.B SECSID(PC),D7      COMPARE WITH SECTORS PER SIDE
          BLS.S SIDEA              IF SIDE A
          MOVE.B #$40,D5           ELSE GET SIDE B BIT
SIDEA     ASR.W #8,D7              MOVE TRACK TO RIGHT BYTE
          CMP.B TRKREG-DLATCH(A2),D7 ALREADY ON RIGHT TRACK?
          BEQ.S TRKOK              YES
          TST.B D4                 CHECK IF WE'RE DOUBLE-STEPPING
          BEQ.S GOSEEK             NO, SEEK NORMALLY
          MOVE.B TRKREG-DLATCH(A2),D0
          LSL.B #1,D0              MAKE BELIEVE FDC ON TRACK * 2
          MOVE.B D0,TRKREG-DLATCH(A2)
          LSL.B #1,D7              AND DESIRED TRACK IS ALSO * 2
GOSEEK    MOVE.B D7,DATREG-DLATCH(A2) NO, GIVE TRACK TO FDC
* FOLLOWING IS 11 FOR 1772, 13 FOR OTHER WESTERN DIGITAL FDC'S >>A<<
          MOVE.B #$11,COMREG-DLATCH(A2) SEEK, LOAD, SLOW STEP >>A<<
          BSR.S WNBUSY             WAIT FOR COMPLETION
          TST.B D4                 CHECK IF DOUBLE-STEPPING
          BEQ.S TRKOK              IF NOT, THEN TRACK REG IS OK
          MOVE.B TRKREG-DLATCH(A2),D0
          LSR.B #1,D0              ELSE UNFOOL FDC
          MOVE.B D0,TRKREG-DLATCH(A2)

TRKOK     MOVE.B #$21,D0           SWITCH TO DD ON DRIVE 0

* READ SECTOR ROUTINE
* ASSUME INTERRUPTS ARE ALREADY OFF

READ      ADD.B D5,D0              COMBINE WITH SIDE BIT
          MOVE.B D0,(A2)           SELECT DENSITY, SIDE, DR 0
          LEA DATREG-DLATCH(A2),A0 POINT A0 TO DATA REG
          LEA STAREG-DLATCH(A2),A1 POINT A1 TO STATUS REG
          MOVE.B #$84,COMREG-DLATCH(A2) READ COMMAND
          BSR.S WAIT

SDLOOP    MOVE.B (A1),D0           CHECK STATUS
          BTST #1,D0               DRQ?
          BNE.S SDGETD             YES, GET THE DATA
          BTST #0,D0               BUSY?
          BNE.S SDLOOP             YES, WAIT FOR IT
SDFINI    BSR.S WNBUSY             WAIT FOR READY
          AND.B #$1C,D0            RNF, CRC, LD ERRORS
          RTS                      AND QUIT

SDGETD    MOVE.B (A0),(A3)+        GET AND PUT DATA
          BRA.S SDLOOP             REPEAT UNTIL DONE

* WAIT LOOP TO STABILIZE COMMAND REGISTER. SHOULD BE
* EITHER 28 OR 56 USED, DEPENDING ON SYSTEM, BUT IT
* DOESN'T HURT TO MAKE IT LONGER, WHICH TAKES LESS CODE.
WAIT      CLR.B D7
WAIT1     SUB.B #1,D7
          BNE.S WAIT1
          RTS

* WNBUSY - WAIT FOR NOT BUSY
WNBUSY    BSR.S WAIT
          MOVE.B STAREG-DLATCH(A2),D0         CHECK STATUS
          BTST.B #0,D0             CHECK BUSY FLAG
          BNE.S WNBUSY             WAIT IF STILL BUSY
          RTS                      ELSE RETURN WITH B=STATUS

**** PREVIOUS PART MUST BE ON FIRST SECTOR ****

* MAIN READ LOOP
MLOOP     BSR.S GETBYT             GET A BYTE
          CMP.B #2,D0              DATA FOLLOWS?
          BEQ.S R2DATA             YES, GO READ IT
          CMP.B #3,D0              DATA FOLLOWS?
          BEQ.S R3DATA             YES, GO READ IT
          CMP.B #$16,D0            ADDRESS FOLLOWS?
          BEQ.S R6ADDR             YES, GO GET IT
          CMP.B #$17,D0            ADDRESS FOLLOWS?
          BEQ.S R7ADDR             YES, GO GET IT
          BRA.S MLOOP              ELSE REPEAT

* GETBYT ROUTINE - GET NEXT BYTE FROM FILE

GETBYT    TST.B D3                 CHECK DATA POINTER
          BNE.S GETBY1             OK TO CONTINUE IF NOT 0
          LEA SBBUFF(PC),A3        READ INTO SBBUFF
          BSR.L GETSEC             ELSE GET SECTOR
          BEQ.S BYTEOK             IF NO ERROR
          BTST.B #4,D0             ON ERROR, CHECK IF RECORD NOT FOUND
          BEQ.L ERROR              ANYTHING ELSE IS AN ERROR
          EOR.B #$FF,D4            COMPLEMENT DOUBLE FLAG
* FOLLOWING IS 01 FOR 1772, 03 FOR OTHER WESTERN DIGITAL FDC'S >>A<<
          MOVE.B #$01,COMREG-DLATCH(A2) RESTORE, LOAD, SLOW >>A<<
          BSR.S WNBUSY             WAIT FOR COMPLETION
          LEA SBBUFF(PC),A3        READ INTO SBBUFF
          BSR.L GETSEC             AND TRY AGAIN
          BNE.S ERROR              QUIT ON ANY ERRORS
BYTEOK    MOVE.B #4,D3             NEXT BYTE IS BYTE 4
GETBY1    LEA SBBUFF(PC),A0        POINT TO SECTOR BUFFER
          CLR.L D0
          MOVE.B (A0,D3),D0        GET NEXT BYTE OF DATA
          ADD.B #1,D3              BUMP POINTER
          RTS                      RETURN WITH BYTE IN D0

* GETWRD - GET A PAIR OF BYTES INTO D0; USES D1 FOR TEMP

GETWRD    BSR.S GETBYT             GET MSB BYTE
          MOVE.L D0,D1             SAVE IN D1
          LSL.W #8,D1              MOVE INTO SECOND BYTE
          BSR.S GETBYT             GET LSB BYTE
          ADD.W D1,D0              COMBINE INTO D0
          RTS                      AND RETURN

* R2DATA - READ DATA FROM SECTOR IN SHORT FORMAT

R2DATA    BSR.S GETWRD             GET 2-BYTE LOAD ADDRESS
          MOVE.L D0,A6             MOVE INTO A6
          BSR.S GETBYT             GET COUNT
R23DAT    MOVE.L D0,D2             COUNTER
RDMEM     BSR.S GETBYT             GET NEXT BYTE
          MOVE.B D0,(A6)+          SAVE IT
          SUB.W #01,D2             DECREMENT COUNTER
          BNE.S RDMEM              REPEAT UNTIL DONE
          BRA.S MLOOP              GO LOOK FOR MORE

* R3DATA - READ DATA FROM SECTOR IN LONG FORMAT

R3DATA    BSR.S GETWRD             GET LEFT BYTE OF ADDRESS
          SWAP D0                  MOVE INTO LEFT HALF
          MOVE.L D0,A6             MOVE INTO A6
          BSR.S GETWRD             GET RIGHT HALF OF ADDRESS
          MOVE.W D0,A6             COMBINE WITH LEFT
          BSR.S GETWRD             GET COUNT
          BRA.S R23DAT             REJOIN OTHER ROUTINE

* R6ADDR - READ 16-BIT ADDRESS FROM SECTOR

R6ADDR    BSR.S GETWRD             GO GET LOAD ADDRESS
          MOVE.L D0,A5             SAVE INTO A5
          BRA.L MLOOP              GO GET MORE

* R7ADDR - READ 32-BIT ADDRESS FROM SECTOR

R7ADDR    BSR.S GETWRD             GO GET MSB OF LOAD ADDRESS
          SWAP D0                  MOVE INTO LEFT HALF
          MOVE.L D0,A5             SAVE INTO A5
          BSR.S GETWRD             GET LSB OF ADDRESS
          MOVE.W D0,A5             COMBINE WITH MSB
          BRA.L MLOOP              GO GET MORE

* WHEN DONE, CHECK TRANSFER ADDR AND GO DO IF OK

DONE      ADD.L #8,A7              REMOVE TWO RETURN ADDRESSES FROM STACK
          CMP.L #-1,A5             VALID TRANSFER ADDRESS?
          BEQ.S ERROR              NO
          JMP (A5)                 ELSE GO TO PROGRAM

* ERROR ROUTINES

LNKERR    LEA LNKMSG(PC),A5        PRINT "DISK NOT LINKED"
          BRA.S PRINT
ERROR     LEA ERRMSG(PC),A5        PRINT "ERROR - TRY AGAIN?"
PRINT     MOVE.B (A5)+,D5          GET NEXT CHAR >>B<<
          CMP.B #4,D5              END OF STRING?
          BEQ.S QUIT
          BSR.S PUTCHR             OUTPUT CHARACTER
          BRA.S PRINT
QUIT      MOVE.L MONROM+4,A6       THEN RETURN TO MONITOR
          JMP (A6)

PUTCHR    BTST.B #2,DSTARG         CHECK IF OUTPUT FREE
          BEQ.S PUTCHR             NO
          MOVE.B D5,DDATRG         OUTPUT IT
          RTS

LNKMSG    DC.B $0D,$0A
          FCC 'DISK NOT LINKED ',4
ERRMSG    DC.B $0D,$0A
          FCC 'ERROR - TRY AGAIN? ',4

* END OF SUPERBOOT PROGRAM

* TRACK BUFFER BEGINS HERE

BUFFER    EQU * TRACK BUFFER

          END START
