          NAM HDFORMAT
          OPT PAG
          PAG
* HDFORMAT PROGRAM FOR SK*DOS 68K
* SUPPORTS THE PERIPHERAL TECH PT68K-1 COMPUTER WINCHESTER
* USING THE WD1002 HARD DISK CONTROLLER
* COPYRIGHT (C) 1986 BY PETER A. STARK
* FOR STAR-K SOFTWARE SYSTEMS CORP.

* MOD 9-26-87 TO DEFAULT TO 32 SEC/TRK AND NOT ASK

* SK*DOS EQUATES

          LIB     SKEQUATE
WINTAB    EQU $200                 OFFSET FOR DOS'S WINTAB

WDREAD    EQU $E0020 READ DATA REGISTER
WDWRIT    EQU WDREAD WRITE DATA REGISTER
WDERRO    EQU $E0024 ERROR REGISTER
WDWPRE    EQU WDERRO WRITE PRECOMP REGISTER
WDSCNT    EQU $E0028 SECTOR COUNT REGISTER
WDSNUM    EQU $E002C SECTOR NUMBER
WDCYLO    EQU $E0030 CYLINDER NUMBER - LOW ORDER BYTE
WDCYHI    EQU $E0034 CYLINDER NUMBER - HIGH ORDER BYTE
WDSDHR    EQU $E0038 SIZE,DRIVE,HEAD REGISTER
WDSTAT    EQU $E003C STATUS REG - READ ONLY
WDCOMA    EQU WDSTAT COMMAND REG - WRITE ONLY


START     BRA.S START1

          DC.W  $0102              VERSION

* INITIALIZE EVERYTHING

START1    LEA OURWIN(PC),A0        POINT TO OUR WIN TABLE
          MOVE.B #16,D0
CLRTAB    MOVE.L #$FFFFFFFF,(A0)+  CLEAR 4 BYTES
          SUB.B #1,D0              DEC COUNTER
          BNE.S CLRTAB             REPEAT UNTIL FULL OF FF'S

* FIRST, FIND OUT WHICH DRIVE TO INITIALIZE > PHDRIV (B)

GETDRV    LEA DRVMSG(PC),A4
          DC PSTRNG                ASK "WHICH DRIVE- A OR B?"
          DC GETCH                 GET ANSWER
          AND.B #$DF,D5
          CMP.B #$41,D5            A?
          BEQ.S DRVOK
          CMP.B #$42,D5            B?
          BNE.S GETDRV             WRONG
DRVOK     SUB.B #$40,D5            A=1, B=2
          LEA PHDRIV(PC),A4
          MOVE.B D5,(A4)           AND STORE PHYSICAL DRIVE NUMB

* GET NUMBER OF PHYSICAL CYLINDERS ON THIS DRIVE > PHTRKS (W)

GETCYL    LEA PHTMSG(PC),A4        "HOW MANY CYLINDERS " MESSAGE
          DC PSTRNG
          DC INLINE                GO GET INPUT
          DC DECIN
          CMP.L #1000,D5           CHECK IT
          BHI.S GETCYL             REPEAT IF >1000
          CMP.L #5,D5
          BCS.S GETCYL
          LEA PHCYLS(PC),A0        WHERE TO PUT IT
          MOVE.W D5,(A0)

* GET NUMBER OF CYLINDER TO PARK ON > PARKCY (W)

GETPAR    LEA PRKMSG(PC),A4        "WHERE TO PARK " MESSAGE
          DC PSTRNG
          DC INLINE                GO GET INPUT
          DC DECIN
          CMP.L #1000,D5           CHECK IT
          BHI.S GETPAR             REPEAT IF >1000
          LEA PARKCY(PC),A0        WHERE TO PUT IT
          MOVE.W D5,(A0)

* GET PRECOMPENSATION CYLINDER NUMBER > PRECOM (B)

GETPRE    LEA PREMSG(PC),A4        "WHERE TO PRECOMP " MESSAGE
          DC PSTRNG
          DC INLINE                GO GET INPUT
          DC DECIN
          CMP.L #1023,D5           CHECK IT
          BHI.S GETPRE             REPEAT IF >1000
          CMP.L #5,D5
          BCS.S GETPRE
          LSR.L #2,D5              WD1002 WANTS IT DIVIDED BY 4
          LEA PRECOM(PC),A0        WHERE TO PUT IT
          MOVE.B D5,(A0)

* GET NUMBER OF HEADS > HEADS (B)

GETHDS    LEA HDSMSG(PC),A4        "HOW MANY HEADS " MESSAGE
          DC PSTRNG
          DC INLINE                GO GET INPUT
          DC DECIN
          CMP.L #16,D5             CHECK IT
          BHI.S GETHDS             REPEAT IF >16
          CMP.L #2,D5
          BCS.S GETHDS
          LEA HEADS(PC),A0         WHERE TO PUT IT
          MOVE.B D5,(A0)

* DEFAULT NUMBER OF SECTORS PER TRACK > SECPT (B)

GETSEC    LEA SPTMSG(PC),A4        "HOW MANY SEC/TR" MESSAGE
          DC PSTRNG
          LEA SECPT(PC),A0         WHERE TO PUT IT
          MOVE.B #32,(A0)          DEFAULT TO 32 SEC/TRK

* GET DRIVE STEP SPEED > STEPRT (B)

GETSEK    LEA SEKMSG(PC),A4        "SELECT STEP RATE" MESSAGE
          DC PSTRNG
          DC INLINE                GO GET INPUT
          DC DECIN
          CMP.L #15,D5             CHECK IT
          BHI.S GETSEK             REPEAT IF >15
          LEA STEPRT(PC),A0        WHERE TO PUT IT
          MOVE.B D5,(A0)

* CALCULATE AND PRINT TOTAL DISK CAPACITY

          CLR.L D0
          CLR.L D7
          MOVE.B HEADS(PC),D0
          MOVE.B SECPT(PC),D7
          MULU D7,D0               SECTORS PER CYLINDER
          MOVE.W PHCYLS(PC),D7
          MULU D7,D0               SECTORS PER DRIVE
          MOVE.L D0,D4
          LSR.L #2,D4              DIVIDE BY 4
          LEA CAPMSG(PC),A4
          DC PSTRNG                PRINT "DISK CAP IS"
          CLR.L D5                 NO SPACES
          DC OUT5D                 OUTPUT SIZE IN K
          LEA CA2MSG(PC),A4
          DC PNSTRN                PRINT "K"
          CLR.W D0                 WILL BECOME LEFT HALF
          SWAP D0                  MOVE OVERFLOW INTO B
          CMP.W #3,D0              CHECK IF >3
          BLS.S NOTGT3             NO
          MOVE.B #3,D0             CHANGE >3 TO 3
NOTGT3    TST.B D0                 CHECK WHETHER PART'S NEEDED
          BEQ.S NOPART             NO
MUSPAR    LEA MUSMSG(PC),A4
          DC PSTRNG                PRINT "YOU MUST HAVE"
          CLR.L D4
          MOVE.B D0,D4
          ADD.B #1,D4              REQ'D NUMBER OF
          CLR.L D5                 NO SPACES
          DC OUT5D                 PRINT MINIMUM NUMBER
          LEA PARMSG(PC),A4
          DC PNSTRN                PRINT "PARTITIONS"
NOPART    LEA WOUMSG(PC),A4
          DC PSTRNG                ASK "WANT TO PARTITION?"
          DC GETCH
          AND.B #$DF,D5
          CMP.B #$59,D5            Y?
          BEQ.L YESPAR             YES, GO PARTITION
          CMP.B #$4E,D5            N?
          BNE.S NOPART             WRONG, ASK AGAIN
          TST.B D0                 CHECK IF PARTITIONS NEEDED
          BNE.S NOPART             YES, MUST PARTITION


* COME HERE IF NO PARTITIONING IS NEEDED, DISK IS ONE BIG PART

          LEA OURWIN(PC),A0        POINT TO WIN TABLE
          MOVE.B #0,(A0)           0 INTO OURWIN
          MOVE.W PHCYLS(PC),6(A0)  NUMBER OF CYLINDERS
          MOVE.W #0,8(A0)          FIRST CYLINDER USED
          BSR.S SETLOG             SET LOGICAL TRACK/SECTOR NOS
          BRA.L CHEKIT             GO CHECK IF OK TO PROCEED

* CONVERT INTO NUMBER OF TRACKS AND SCTRS ON LOG DRIVE. ENTER
* WITH 6(A0) = CYLINDERS ON THIS LOGICAL DRIVE, AND A0 POINTING
* TO OURWIN ENTRY TO PUT DATA INTO. ALSO SET 1(A0)-5(A0).
SETLOG    MOVE.B STEPRT(PC),1(A0)  SEEK SPEED CODE
          CLR.L D6
          CLR.L D7
          MOVE.B SECPT(PC),D6
          MOVE.B D6,2(A0)          SECT PER TRACK
          MOVE.B HEADS(PC),D7
          MOVE.B D7,3(A0)          NUMB OF HEADS
          MULU D6,D7               SECTORS PER CYLINDER
          MOVE.W D7,4(A0)
          MOVE.W 6(A0),D6          CYLINDERS ON THIS LOG DRIVE
          MULU D6,D7               TOTAL SECTORS / LOG DRIVE
          MOVE.L D7,D6
          CMP.L #$FFFF,D7          >65535 SECTORS ON DRIVE?
          BLS.S SETLOW             NO; CONTINUE TO CALCULATE
          MOVE.B #255,D6           YES, USE 256 SECTORS/TRACK
          MOVE.B #255,D7           AND 256 TRACKS
          BRA.S SETLO2
SETLOW    LSR.W #8,D6              GET LEFT BYTE
          ADD.W #1,D6              NUMBER OF SECTORS ON LOGICAL
SETLOO    CMP.W #$1F,D6            32 OR MORE?
          BHI.S SETLO1             WANT AT LEAST 32 SECTORS
          LSL.W #1,D6
          BRA.S SETLOO             REPEAT UNTIL AT LEAST 32
SETLO1    DIVU D6,D7               GIVES NUMBER OF TRACKS
          SUB.W #1,D6              LAST SECTOR
          SUB.W #1,D7              LAST TRACK
SETLO2    MOVE.B D7,10(A0)         LAST TRACK INTO OURWIN
          MOVE.B D6,11(A0)         LAST SECTOR INTO OURWIN
          MOVE.W PARKCY(PC),12(A0) PARK CYLINDER
          MOVE.B PRECOM(PC),14(A0) PRECOMP CYLINDER/4
          RTS

* YESPAR - YES, WE WANT TO (OR HAVE TO) PARTITION. LET'S
* GET INFO ON HOW. ENTER WITH D0 = MINIMUM NUMBER - 1 OF PARTS

YESPAR    ADD.B #1,D0              D0 = MINIMUM OF PARTS NEEDED
          MOVE.L D0,A3             SAVE IN A3
          CMP.B #1,D0              EXCEPT 1 IS NG
          BNE.S MORET1
          ADD.B #1,D0              SO CHANGE 1 TO 2
          MOVE.L D0,A3             SAVE IN A3
MORET1    MOVE.L A3,D0             RESTORE MINIMUM NO OF PARTS
          LEA OURWIN(PC),A0        POINT TO DRIVE TABLE
          LEA NUMMSG(PC),A4
          DC PSTRNG                ASK "HOW MANY?"
          DC INLINE
          DC DECIN                 GET ANSWER
          CMP.L D0,D5              CHECK AGAINST MINIMUM
          BCS.S MORET1             TOO SMALL
          CMP.B #4,D5
          BHI.S MORET1             TOO BIG
          MOVE.L D5,D0             SAVE
          LEA PARTS(PC),A4
          MOVE.B D5,(A4)           SAVE NUMBER OF PARTITIONS
          LEA PA1MSG(PC),A4
          DC PSTRNG                PRINT "YOU WILL PART.."
* CALCULATE MAXIMUM NUMBER OF CYLINDERS ALLOWED
          MOVE.L #65536,D1         MAX NO OF SECTRS / DRIVE
          CLR.W D2
          MOVE.B HEADS(PC),D2
          CLR.W D7
          MOVE.B SECPT(PC),D7
          MULU D7,D2               SECTORS PER CYLINDER
          DIVU D2,D1               DIV BY SECT/CYLINDER=C/LD
          MOVE.W D1,D3
          MULU D0,D3               X NUMBER OF PARTITIONS
          CMP.W PHCYLS(PC),D3      COMPARE WITH ACTUAL
          BLS.S MCOK               IF MAX IS LESS THAN ACTUAL
          MOVE.W PHCYLS(PC),D3     ELSE USE ACTUAL MAXIMUM
MCOK      CLR.L D4
          MOVE.W D3,D4
          CLR.L D5                 NO SPACES
          DC OUT5D                 PRINT MAX CYLINDERS PER PHYS
          LEA PA2MSG(PC),A4
          DC PSTRNG                PRINT "MAX CYL PER PART'N"
          CLR.W D5
          MOVE.B PARTS(PC),D5      NUMBER OF PARTITIONS
          SUB.W #1,D5              LESS ONE
          MOVE.W #5,D4             EACH ONE MINIMUM 5 CYLINDERS
          MULU D4,D5               MINIMUM NUMBER NEEDED
          MOVE.W PHCYLS(PC),D4     ACTUAL NUMBER OF CYLS
          SUB.W D5,D4              MAX SIZE OF ONE PARTITION IN CYL
          BMI.S MAXNOG             NG IF NUMBER NEGATIVE
          CMP.W #5,D4
          BCC MAXOK                OK IF >=5 CYLINDERS
MAXNOG    LEA P2AMSG(PC),A4        IF NEGATIVE OR <5,
          DC PSTRNG                ..PRINT "NOT ENOUGH CYLS"
          BRA.L MORET1             TRY IT AGAIN
MAXOK     CMP.W D1,D4              CHECK AGAINST NUMBER AVAILABLE
          BCS.S PRTMAX
          MOVE.W D1,D4
PRTMAX    CLR.L D5                 NO SPACES
          DC OUT5D                 PRINT MAX CYL PER LOGICAL
          LEA PA3MSG(PC),A4
          DC PSTRNG                PRINT "DECIDE AND ENTER"
* NOW LOOP FOR EACH OF THE PARTITIONS
          MOVE.L #0,D2             LOOP COUNTER
          LEA OURWIN(PC),A0        POINT TO TABLE
          CLR.W D7
          MOVE.B PHDRIV(PC),D7     PH DRIVE 1=A, 2=B
          SUB.B #1,D7              0=A, 1=B
          LSL.B #2,D7              0=A, 4=B
          ADD.B #$30,D7            30=A, 34=B
          MOVE.W D7,A1             SAVE IN A1
          MOVE.L #0,A2             TO BE USED FOR TOTAL CYLS
PARLOO    LEA PA4MSG(PC),A4
          DC PSTRNG                PRINT "FOR PARTITION H"
          MOVE.W A1,D4             READY TO PRINT
          ADD.B D2,D4
          DC PUTCH                 OUTPUT NUMBER
          LEA PA5MSG(PC),A4
          DC PNSTRN                PRINT " ? "
          DC INLINE
          DC DECIN                 INPUT NUMBER
          CMP.L D1,D5              CHECK AGAINST LARGEST PART
          BLS.S PAROK1             NOT TOO BIG
          LEA PTBMSG(PC),A4
          DC PSTRNG                PRINT "TOO BIG"
          BRA.S PARLOO
PAROK1    CMP.L #5,D5              NO SMALLER THAN 5
          BCC.S PAROK2             IF OK
          LEA PTSMSG(PC),A4
          DC PSTRNG                PRINT "TOO SMALL"
          BRA.S PARLOO
PAROK2    MOVE.W A2,8(A0)          PART STARTS AT PREV TOTAL
          MOVE.W D5,6(A0)          AND HAS THIS MANY TRACKS
          ADD.W A2,D5              ADD CURRENT TO TOTAL
          MOVE.W D5,A2             AND RESTORE TOTAL
          ADD.L #16,A0             NEXT ENTRY IN OURWIN
          ADD.B #1,D2              COUNTER
          CMP.B D2,D0              CHECK DESIRED PARTITIONS
          BNE.S PARLOO             GET NEXT PARTITION DATA
          CMP.W D5,D3              CHECK AGAINST MAX TOTAL NUMBER
          BEQ.S TOTLOK             TOTAL IS OK
          LEA PA6MSG(PC),A4
          DC PSTRNG                PRINT "TOTAL DOESN'T ADD"
          BRA.L MORET1             AND REPEAT ALL OVER.
* TOTAL IS OK, SO SET PARAMETERS IN OURWIN
TOTLOK    LEA OURWIN(PC),A0        POINT TO TABLE
          CLR.L D2                 COUNTER
TOTLOO    MOVE.B D2,(A0)           PUT DRIVE NUMB IN OURWIN
          BSR.L SETLOG             SET LOGICAL TRACKS & SECTORS
          ADD.L #16,A0             NEXT ENTRY IN OURWIN
          ADD.B #1,D2              COUNTER
          CMP.B D0,D2              CHECK COUNTER
          BNE.S TOTLOO             REPEAT UNTIL ALL SET


* CHEKIT - CHECK THAT USER REALLY WANTS TO FORMAT

CHEKIT    DC PCRLF
          LEA CHKMSG(PC),A4        PRINT CHKMSG
          DC PSTRNG
          MOVE.B PHDRIV(PC),D4
          ADD.B #$40,D4            CVT 1 TO A, 2 TO B
          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
          BEQ.S INTLVE             GO INITIALIZE THE DRIVE
          LEA NOTMSG(PC),A4
          DC PSTRNG                PRINT "ABORTING"
          DC WARMST

* CALCULATE INTERLEAVE TABLE

INTLVE    MOVE.L #20,D5            USE INTERLEAVE = 20
          CLR.L D7
          MOVE.B SECPT(PC),D7      SECTORS PER TRACK
          LEA BUFFER(PC),A3        POINT TO BUFFER
ERASIL    MOVE.B #$FF,(A3)+        ERASE ENTRY
          SUB.B #1,D7              SUBTRACT FROM COUNTER
          BNE.S ERASIL             ERASE ENTIRE SEC TABLE
          CLR.B D7                 RESET COUNTER
          CLR.B D6                 RESET INTERLEAVE STEP
          LEA BUFFER(PC),A3        POINT TO BUFFER
INTLV     CMP.B SECPT(PC),D6       STEPPED PAST NUM OF SEC/TR?
          BCS.S INTLV1             NO
          SUB.B SECPT(PC),D6       YES, DO MODULO SEC/TR
INTLV1    CMP.B #$FF,(A3,D6.W)     CHECK NEXT ENTRY IN TABLE
          BNE.S INTLV2             IF ALREADY SET
          MOVE.B D7,(A3,D6.W)      ELSE SET IT IF NOT YET
          BRA.S INTLV3
INTLV2    ADD.B #1,D6              ENTRY ALREADY SET, GO TO NEXT
          BRA.S INTLV
INTLV3    ADD.B D5,D6              STEP TO NEXT
          ADD.B #1,D7              BUMP COUNTER
          CMP.B SECPT(PC),D7       CHECK WHETHER ALL DONE
          BNE.S INTLV              NO

* INITIALIZE THE DRIVE AND GET READY FOR FORMATTING

          MOVE.B PHDRIV(PC),D0     DRIVE NUMBER (1 OR 2)
          LSL.B #3,D0              INTO BITS 3 AND 4
          OR.B #$80,D0             SELECT ECC BIT
          LEA SDHMEM(PC),A4
          MOVE.B D0,(A4)           SAVE INTO SDH MEMORY
          MOVE.B D0,WDSDHR         ECC,SEC=256,DRIVE N,HEAD 0
          MOVE.B PRECOM(PC),WDWPRE SET PRECOMP
          MOVE.B #$10,D0           RESTORE COMMAND CODE
          ADD.B STEPRT(PC),D0      ADD IN STEP RATE CODE
          MOVE.B D0,WDCOMA         DO A SLOW RESTORE AT 2.0 MSEC
          BSR.L CHBUSY             WAIT FOR WD1002 NOT BUSY

* NEXT LOOP FOR EACH TRACK AND HEAD TO DO LOW LEVEL FORMAT

          DC PCRLF                 START ON NEW LINE
          CLR.L D0                 TRACK COUNTER
          MOVE.B PHDRIV(PC),D2     DRIVE NUMBER
          LSL.B #3,D2              MOVE INTO BITS 4&3
          OR.B #$80,D2             OR IN ECC BIT FOR SDH REG
FTRLOO    BSR.L CHBUSY             CHECK THAT WD IS NOT BUSY
          LEA LLFMSG(PC),A4
          DC PNSTRN                PRINT "HDWE FOR'ING'
          MOVE.W D0,D4
          CLR.L D5                 NO SPACES
          DC OUT5D                 AND OUTPUT TRACK NUMBER
          MOVE.L D0,D7             TRACK NUMBER
          MOVE.B D7,WDCYLO         TO WD 1002
          LSR.W #8,D7
          MOVE.B D7,WDCYHI          DITTO
          CLR.L D1                 HEAD COUNTER
FHDLOO    MOVE D2,D7               ECC AND DRIVE BITS
          ADD.B D1,D7              PLUS HEAD NUMBER
          MOVE.B D7,WDSDHR         TO SIDE-DRV-HD REGISTER
          MOVE.B SECPT(PC),WDSCNT  SECTOR COUNT REGISTER
          MOVE.B #$50,WDCOMA       SEND WRITE TRACK COMMAND
          BSR.L CHBUSY             JUST IN CASE
          LEA BUFFER(PC),A5        POINT TO BUFFER
          MOVE.B #128,D7           256/2 BYTES TO OUTPUT
FBYLOO    MOVE.B #0,WDWRIT         00 = THIS SECTOR OK
          MOVE.B (A5)+,WDWRIT      FOLLOWED BY SECTOR NUMBER
          SUB.B #1,D7              DEC BYTE COUNTER
          BNE FBYLOO               OUTPUT 256 BYTES (INCL GARBAGE)
          BSR.L CHBUSY             WAIT FOR COMPLETION
          ADD.B #1,D1              INC HEAD COUNTER
          CMP.B HEADS(PC),D1       CHECK IF DONE
          BNE.S FHDLOO             DO MORE HEADS
          ADD.W #1,D0              INC TRACK COUNTER
          CMP.W PHCYLS(PC),D0      CHECK IF DONE
          BNE.S FTRLOO             DO MORE TRACKS


* LOW LEVEL FORMAT COMPLETE. NOW CHECK EACH SECTOR, AND
* WRITE LINKS IN EACH PARTITION

          BSR.L CLRBUF             CLEAR THE BUFFER
          LEA OURWIN(PC),A0        POINT TO TABLE
LPALOO    MOVE.B 0(A0),D4          CHECK PARTITION NUMBER
          BMI.L DONE               NONE LEFT TO DO
          LEA FLNMSG(PC),A4
          DC PSTRNG                PRINT "FORMAT PAR'N'
          ADD.B #$30,D4
          DC PUTCH                 PRINT PARTITION NUMBER
          DC PCRLF

          LEA PRTNUM(PC),A6        PREV TRACK NUM FOR PRINTING
          CLR.B (A6)               CLEAR IT
          CLR.L D0
          CLR.L D1
          MOVE.B 10(A0),D0         LAST LOG TRACK
          MOVE.B 11(A0),D1         LAST LOG SECTOR
          ADD.W #1,D1              NUMBER OF LOGICAL SECTORS
          MULU D0,D1               NUMBER OF FREE SECTORS
          LSL.W #8,D0
          MOVE.B 11(A0),D0         COMBINE LOG TR & SECT
          MOVE.L #0,A2             INITIALIZE FIRST FREE PTR
          MOVE.L A2,A3             INITIALIZE LAST FREE PTR
          MOVE.L A2,A1             INITIALIZE PREV OK
          LEA CHFLAG(PC),A4
          MOVE.B #1,(A4)           LAST PTR WAS OK

CHLOOP    CLR.L D4
          MOVE.W D0,D4             CURRENT LOG TR-SEC
          LSR.W #8,D4              TRACK INTO BYTE
          CMP.B PRTNUM(PC),D4      SAME AS PREVIOUS?
          BEQ.S CHLOO1             YES, JUST GO ON
          LEA PRTNUM(PC),A4
          MOVE.B D4,(A4)           NO, STORE THE NEW
          LEA FLTMSG(PC),A4
          DC PNSTRN                PRINT 'LOG TRK NUM"
          CLR.L D5                 NO SPACES
          DC OUT5D                 PRINT THE NUMBER
          MOVE.B #$20,D4
          DC PUTCH                 SPACE
CHLOO1    BSR.L LPCONV             CONV LOG TO PHYSICAL TR/SEC
          BSR.L CLRBUF             CLEAR THE BUFFER
          LEA BUFFER(PC),A4        POINT TO BUFFER
          MOVE.W A1,(A4)           PUT IN LINK TO PREV OK
          BSR.L HWRITE             WRITE IT TO DISK
          BNE.S CHWRNG             IF ERROR
          BSR.L HREAD              READ CURRENT SECTOR
          BNE.S CHWRNG             IF DEFINITE ERROR
          BTST #2,D7               CHECK CORRECTED BIT
          BEQ.S CHROK              IF NO CORRECTION REQUIRED
          BSR.L HREAD              AFTER CORRECTION, TRY READ AGAIN
          BNE.S CHWRNG             IF DEFINITE ERROR
          BTST #2,D7               CHECK CORRECTED BIT
          BEQ.S CHROK              IF NO CORRECTION REQUIRED
* IF SECTOR COULDN'T BE READ, DELETE IT
CHWRNG    SUB.L #1,D1              SUBTRACT 1 FROM FREE
          LEA CHFLAG(PC),A4
          CLR.B (A4)               AND MARK IT DEFECTIVE
          LEA BDSMSG(PC),A4        PRINT "DEFECTIVE SECTOR AT"
          DC PSTRNG
          MOVE.L D0,D4
          LSR.W #8,D4              TRACK NUMBER
          CLR.L D5                 SUPPRESS SPACES
          DC OUT5D                 OUTPUT TRACK NUMBER
          MOVE.B #$2D,D4
          DC PUTCH                 OUTPUT DASH
          MOVE.B D0,D4             SECTOR NUMBER
          CLR.L D5                 SUPPRESS SPACES
          DC OUT5D                 OUTPUT SECTOR NUMBER
          DC PCRLF
          BRA.S CHNEXT             AND THEN CONTINUE

* SECTOR READ WAS OK
CHROK     MOVE.W A3,D7             CHECK LAST FREE
          BNE.S CHROK1             NON-ZERO MEANS THIS IS NOT LAST
          MOVE.L D0,A3             ELSE CURR TR-SEC IS LAST FREE
CHROK1    MOVE.B CHFLAG(PC),D7     WAS PREVIOUS OK TOO?
          BEQ.S CHPRNG             NO, SO UPDATE PTR
          MOVE.L D0,A1             SAVE CURRENT TRACK-SECTOR
          BRA.S CHNEXT             AND GO TO NEXT SECTOR

* THIS SECTOR OK, BUT PREVIOUS ONE OR MORE NG
CHPRNG    BSR.L CLRBUF             CLEAR THE BUFFER
          MOVE.W A1,(A4)           PUT NEW PTR INTO SECTOR
          BSR.L HWRITE             WRITE SECTOR BACK
          BNE.L CHWRNG             WRITE WAS NG, SAME AS A NG READ
          MOVE.W D0,A1             SAVE CURRENT TRACK-SECTOR
          LEA CHFLAG(PC),A4
          MOVE.B #1,(A4)           MARK THIS SECTOR AS OK

* THEN STEP TO NEXT PREVIOUS SECTOR
CHNEXT    SUB.B #01,D0             STEP BACK ONE SECTOR
          BCC.L CHLOOP             OK IF NOT < ZERO
          MOVE.B 11(A0),D0         LAST SECTOR ON PREVIOUS TRACK
          MOVE.W D0,D7             CURRENT TR-SEC
          CLR.B D7                 SECTOR = 0
          SUB.W #$0100,D7          GO BACK ONE TRACK
          CMP.W #$FF00,D7          FINISHED TRACK 0?
          BEQ.S DOSIS              YES, FINISHED DISK
          MOVE.W D7,D6
          MOVE.B D0,D6             RECOMBINE TRACK AND SECTOR
          MOVE.W D6,D0             AND BACK INTO D0
          TST.W D7                 ENTERING TRACK 0?
          BNE.L CHLOOP             NO, OK TO CONTINUE
          MOVE.W A1,A2             YES, SAVE PREV TR-SECT AS FIRST FREE
          MOVE.L D1,D3             SAVE NUMBER OF FREE SECTORS
          BRA.L CHLOOP             AND REPEAT AGAIN

          MOVE.L D0,A2             THAT IS NOW NEW FIRST FREE

* FINISHED WHEN WE FINISH TRACK 0; NEXT DO SIS

DOSIS     BSR.L CLRBUF             CLEAR THE BUFFER
          DC VPOINT
          MOVE.W #$0003,D0         TRACK 0 SECTOR 3
          BSR.L LPCONV             CONV LOG TO PHYSICAL TR/SEC
          LEA BUFFER+16(PC),A5     POINT TO NAME AREA OF SIS
          MOVE.B #$48,(A5)+        H
          MOVE.B #$44,(A5)+        D
          MOVE.B #$3A,(A5)+        :
          MOVE.B PHDRIV(PC),D6
          ADD.B #$40,D6            CVT TO A OR B
          MOVE.B D6,(A5)+          LETTER A OR B
          MOVE.B #$20,(A5)+        SPACE
          MOVE.B #$50,(A5)+        P
          MOVE.B #$3A,(A5)+        :
          MOVE.B 0(A0),D6          PARTITION NUMBER
          ADD.B #$30,D6            CVT TO ASCII
          MOVE.B D6,(A5)+          DIGIT 0 THROUGH 3
          CLR.B (A5)+              NO EXTENSION
          CLR.B (A5)+              "
          CLR.B (A5)+              "
          CLR.B (A5)+              NO VOLUME NUMBER
          CLR.B (A5)+              "
          MOVE.W A2,D6             FIRST FREE
          MOVE.W D6,D7
          LSR.W #8,D7
          MOVE.B D7,(A5)+          FIRST FREE TRACK
          MOVE.B D6,(A5)+          FIRST FREE SECTOR
          MOVE.W A3,D6             LAST FREE
          MOVE.W D6,D7
          LSR.W #8,D7
          MOVE.B D7,(A5)+          LAST FREE TRACK
          MOVE.B D6,(A5)+          LAST FREE SECTOR
          MOVE.W D3,D7
          LSR.W #8,D7
          MOVE.B D7,(A5)+          NUMBER FREE (MSB)
          MOVE.B D3,(A5)+          NUMBER FREE (LSB)
          MOVE.B CMONTH(A6),(A5)+
          MOVE.B CDAY(A6),(A5)+    TODAY'S DATE
          MOVE.B CYEAR(A6),(A5)+
          MOVE.B 10(A0),(A5)+      LAST TRACK
          MOVE.B 11(A0),(A5)+      LAST SECTOR
          BSR.L HWRITE
          BNE.L FERROR             FATAL ERROR

* NOW END OF DIRECTORY

          LEA BUFFER(PC),A4        POINT TO BUFFER
          MOVE.W #$0005,D0         TRACK 0 SECTOR 5
DODIR1    BSR.L LPCONV             CONV LOG TO PHYSICAL TR/SEC
          BSR.L HREAD              READ DIRECTORY SECTOR
          BNE.L FERROR             FATAL ERROR IF UNREADABLE
          TST.B (A4)               TEST TRACK POINTER
          BNE.S DODIR2             MEANS LAST SECTOR ON THIS TRACK
          MOVE.W (A4),D0           ELSE SETUP TO READ NEXT
          BRA.S DODIR1             GO DO IT
DODIR2    BSR.L CLRBUF             CLEAR THE BUFFER
          BSR.L HWRITE             WRITE EMPTY BUFFER BACK
          BNE.L FERROR             IF FATAL ERROR

* STORE NUMBER OF NEXT FREE CYLINDER

          LEA OURWIN(PC),A1        POINT TO BEG OF TABLE
          MOVE.L 54(A1),D6         4TH PARTITION DATA
          MOVE.B 48(A1),D7         IS THERE A 4TH PARTITION?
          BPL.S ISTHER             YES
          MOVE.L 38(A1),D6         3RD PARTITION DATA
          MOVE.B 32(A1),D7         IS THERE A 3RD PARTITION?
          BPL.S ISTHER             YES
          MOVE.L 22(A1),D6         2ND PARTITION DATA
          MOVE.B 16(A1),D7         IS THERE A 2ND PARTITION?
          BPL.S ISTHER             YES
          MOVE.L 6(A1),D6          1ST PARTITION DATA
ISTHER    MOVE.W D6,D7             FIRST CYL NUMBER IN LAST PARTITION
          SWAP D6                  NUM OF CYLS IN LAST PARTITION
          ADD.W D6,D7              NEXT CYL AFTER LAST PARTITION
          LEA NEXCYL(PC),A1        WHERE TO PUT IT
          MOVE.W D7,(A1)           STORE NUMBER OF NEXT FREE CYL

* WRITE OURWIN TABLE INTO TRACK 0 SECTOR 0

          CLR.L D0                 TR 0 SEC 0
          BSR.L LPCONV             CONV LOG TO PHYSICAL TR/SEC
          BSR.L HREAD              READ IT
          BNE.S FERROR             FATAL ERROR IF UNREADABLE
          BSR.L CLRBUF             CLEAR THE BUFFER
          LEA OURWIN(PC),A1        POINT TO BEG OF TABLE
          LEA BUFFER(PC),A2        AND SECTOR BUFFER
          MOVE.B #16,D7            COUNTER = 64/4
WINLOO    MOVE.L (A1)+,(A2)+
          SUB.B #1,D7
          BNE.S WINLOO             REPEAT UNTIL MOVED IN
          MOVE.W NEXCYL(PC),(A2)+  NEXT FREE CYLINDER GOES AT END
          BSR.L HWRITE             WRITE BACK TO DISK
          BNE.S FERROR             FATAL ERROR

* ENTIRE PARTITION HAS BEEN INITIALIZED; GO DO THE NEXT ONE

          ADD.L #16,A0             POINT TO NEXT OURWIN ENTRY
          BRA.L LPALOO             REPEAT FOR NEXT PARTITION

* DISK IS FINALLY FINISHED, WRITE OURWIN TABLE INTO SK*DOS'S
* WINTAB SO SK*DOS CAN IMMEDIATELY USE IT

DONE      LEA OURWIN(PC),A4        POINT TO OUR TABLE
          DC VPOINT
          MOVE.L DOSORG(A6),A5     POINT TO BEGINNING OF DOS
          LEA WINTAB(A5),A5        POINT TO DOS'S WINTAB
          MOVE.B #16,D7            COUNTER = 64/4
          MOVE.B PHDRIV(PC),D6     CHECK PHYSICAL DRIVE NUMBER
          SUB.B #1,D6              DRIVE A?
          BEQ.S DONELO             YES, USE ADDRESS AS IS
          ADD.L #64,A5             NO, POINT TO DRIVE B PORTION
DONELO    MOVE.L (A4)+,(A5)+       MOVE FOUR BYTES
          SUB.B #1,D7
          BNE.S DONELO             REPEAT FOR 64 BYTES
          SUB.L #64,A5             POINT BACK TO BEGINNING OF WINTAB
          LSL.B #2,D6              A=0, B=4
          ADD.B #$20,D6            A=20, B=24
          OR.B D6,(A5)             UPDATE 0 TO 20 OR 24, ETC.
          OR.B D6,16(A5)
          OR.B D6,32(A5)
          OR.B D6,48(A5)

* FINALLY FINISHED ... EXIT

          CLR.B WDSDHR             DESELECT DRIVE
          LEA DONMSG(PC),A4
          DC PSTRNG                PRINT "DONE"
          DC WARMST                AND QUIT


* FATAL ERROR ROUTINE

FERROR    CLR.B WDSDHR             DESELECT DRIVE
          LEA FERMSG(PC),A4
          DC PSTRNG                PRINT "FATAL ERROR"
          DC WARMST

* CLRBUF - CLEAR SECTOR BUFFER

CLRBUF    MOVEM.L A4/D7,-(A7)
          LEA BUFFER(PC),A4        POINT TO BUFFER
          MOVE.B #256/4,D7         256 BYTES TO CLEAR
CLRLOO    CLR.L (A4)+              CLEAR BUFFER
          SUB.B #1,D7
          BNE.S CLRLOO
          MOVEM.L (A7)+,A4/D7
          RTS

* LPCONV - CONVERT A LOGICAL TRACK AND SECTOR NUMBER (IN D0
* AS 0000TRSE) INTO PHYSICAL TRACK, HEAD, AND SECTOR NUMBERS AND
* PUT INTO WD REGS, USING INFO IN OURWIN ENTRY POINTED TO BY A0

LPCONV    MOVE.W D0,D6
          LSR.W #8,D6              LOGICAL TRACK
          CLR.L D7
          MOVE.B 11(A0),D7         LOG SECT/TRACK
          ADD.W #1,D7              NUMBER PER TRACK
          MULU D7,D6               SECT BEFORE THIS TRACK
          CLR.L D7
          MOVE.B D0,D7             LOG SECTOR
          ADD.W D7,D6              BLOCK NUMBER
          MOVE.W 4(A0),D7          SECT/CYL ON HARD DISK
          DIVU D7,D6               REMAINDER | TRACK NUMBER
          ADD.W 8(A0),D6           PLUS START OF PARTITION
          MOVE.B D6,WDCYLO
          LSR.L #8,D6
          MOVE.B D6,WDCYHI         CYLINDER NUMBER TO WD1002
          LSR.L #8,D6              REMAINDER IN RIGHT HALF
          CLR.L D7
          MOVE.B 2(A0),D7          SECTORS PER TRACK
          DIVU D7,D6               SECTOR | HEAD
          ADD.B SDHMEM(PC),D6      COMBINE WITH OTHER SDH BITS
          MOVE.B D6,WDSDHR         PUT INTO SDH REGISTER
          SWAP D6                  MOVE SECTOR RIGHT
          MOVE.B D6,WDSNUM         SECTOR NUMBER TO WD1002
          RTS

* HWRITE - WRITE A SECTOR TO DISK FROM BUFFER POINTED TO BY A4

HWRITE    MOVE.B #1,WDSCNT         SECTOR COUNT = 1
          MOVE.L A4,A6             POINT TO BUFFER
          MOVE.B #$30,WDCOMA       SEND WRITE COMMAND
          MOVE.B #64,D7            COUNTER = 256/4
HWRLOO    MOVE.L (A6)+,WDWRIT      OUTPUT 4 BYTES
          SUB.B #1,D7              DECREMENT COUNTER
          BNE.S HWRLOO             REPEAT FOR 256 BYTES
          BSR.S CHBUSY             WAIT FOR COMPLETION
          MOVE.B WDSTAT,D7         GET WD STATUS BYTE
          BTST.B #0,D7             CHECK ERROR BIT
          RTS                      EXIT WITH ZERO IF NO ERROR


* HREAD - READ A SECTOR FROM DISK INTO BUFFER POINTED TO BY A4

HREAD     MOVE.B #1,WDSCNT         SECTOR COUNT = 1
          MOVE.B #$20,WDCOMA       SEND READ COMMAND
          BSR.S CHBUSY             WAIT FOR COMPLETION
          MOVE.L A4,A6             POINT TO BUFFER
          MOVE.B #64,D7            COUNTER = 256/4
HRDLOO    MOVE.L WDREAD,(A6)+      READ 4 BYTES
          SUB.B #1,D7              DECREMENT COUNTER
          BNE.S HRDLOO             REPEAT FOR 256 BYTES
          BSR.S CHBUSY             WAIT FOR COMPLETION
          MOVE.B WDSTAT,D7         GET WD STATUS BYTE
          BTST.B #0,D7             CHECK ERROR BIT
          RTS                      EXIT WITH ZERO IF NO ERROR

* CHBUSY - WAIT IF BUSY, BUT ABORT IF IT TAKES TOO LONG

CHBUSY    MOVEM.L D6,-(A7)
          MOVE.L #$100000,D6        TIMEOUT COUNTER
CHBUS1    SUB.L #1,D6              DROP TIMEOUT COUNT
          BEQ.S CHBUS2             SOMETHING WRONG?
          TST.B WDSTAT             CHECK WD1002 STATUS
          BMI.S CHBUS1             WAIT UNTIL NOT BUSY
          MOVEM.L (A7)+,D6
          RTS

CHBUS2    CLR.B WDSDHR             DESELECT DRIVE
          LEA RESMSG(PC),A4
          DC PSTRNG                PRINT "HARDWARE PROBLEM - SLOW
          DC WARMST                AND QUIT


DRVMSG    FCC 'Which drive - A or B? ',4
PHTMSG    FCC 'Number of cylinders (Tracks/Side) to use on drive? ',4
PRKMSG    FCC 'Which cylinder should the drive be parked on? ',4
PREMSG    FCC 'Which cylinder to start precompensation? ',4
HDSMSG    FCC 'How many heads on the drive? ',4
SPTMSG    FCC '(There are 32 sectors per track/side.)',4
SEKMSG    FCB $D,$A
          FCC 'Enter the required code for drive step rate -'
          FCB $D,$A
          FCC '0 if buffered, 1 to 15 for 0.5 to 7.5 msec respectively: ',4
CAPMSG    FCB $D,$A
          FCC 'Total disk capacity is ',4
CA2MSG    FCC ' K.',4
MUSMSG    FCB $D,$A
          FCC 'THIS EXCEEDS THE MAXIMUM LOGICAL DRIVE CAPACITY; you must'
          FCB $D,$A
          FCC 'therefore partition the disk into ',4
PARMSG    FCC ' to 4 partitions.',4
WOUMSG    FCC 'Would you like to partition the disk (Y/N)? ',4
NUMMSG    FCC 'How many partitions would you like? ',4
PA1MSG    FCB $D,$A
          FCC 'You will now partition the disk by Cylinders (Tracks). The'
          FCB $0D,$0A
          FCC 'TOTAL number of usable cylinders on this drive is ',4
PA2MSG    FCB $D,$A
          FCC 'The MAXIMUM number of cylinders allowed in any one'
          FCB $0D,$0A
          FCC '    partition is ',4
P2AMSG    FCB $D,$A
          FCC 'Oops ... not enough cylinders for this many partitions - try again.',4
PA3MSG    FCB $D,$A
          FCC 'The MINIMUM number of cylinders allowed in any one'
          FCB $0D,$0A
          FCC '    partition is 5.'
          FCB $0D,$0A
          FCC 'Decide how you would like to split up the TOTAL number of'
          FCB $0D,$0A
          FCC '   cylinders and enter the counts:',4
PA4MSG    FCC 'Cylinders for Partition H',4
PA5MSG    FCC '? ',4
PTBMSG    FCC 'Partition too big ... Try it again.',4
PTSMSG    FCC 'Partition too small ... Try it again.',4
PA6MSG    FCC "TOTAL Cylinders don't add up correctly. Try again.",4
CHKMSG    FCC 'READY TO FORMAT HARD DRIVE ',4
RUSMSG    FCC 'ARE YOU SURE YOU WANT TO GO AHEAD? ',4
NOTMSG    FCC 'Formatting aborted.',4
LLFMSG    FCB $0D                 CR ONLY, NO LF
          FCC 'Low level format - Physical cylinder ',4
FLNMSG    FCC 'Formatting and verifying partition ',4
FLTMSG    FCB $0D                 CR ONLY, NO LF
          FCC '   Logical track ',4
DONMSG    FCC 'Formatting completed.',4
RESMSG    FCC 'Hardware problem - BUSY too long - Aborting Format.',4
BDSMSG    FCC 'DEFECTIVE SECTOR AT LOGICAL TRACK/SECTOR ',4
FERMSG    FCC 'FATAL ERROR - FORMATTING ABORTED.',4

* DATA AREA FOR FORMAT

HEADS     DC.B 0                   NUMBER OF HEADS
SDHMEM    DC.B 0                   S-D-H MEMORY
CHFLAG    DC.B 0                   0=LAST WAS AN ERROR, 1=OK
PHDRIV    DC.B 0                   PHYSICAL DRIVE A=1, B=2
SECPT     DC.B 0                   SECTORS PER TRACK OR SIDE
PARTS     DC.B 0                   NUMBER OF PARTITIONS ON DISK
STEPRT    DC.B 0                   STEPRATE CODE FOR SDH REG
PRTNUM    DC.B 0                   PREVIOUS TRACK NUMBER
PRECOM    DC.B 0                   PRECOMPENSATION START CYL
          EVEN
PARKCY    DC.W 0                   CYLINDER TO PARK DRIVE ON
OURWIN    DS.B 64                  WINCHESTER CONFIG TABLE
          DC.W $FFFF               *** END MARKER FOR ABOVE ***
NEXCYL    DC.W 0                   NEXT FREE CYLINDER
PHCYLS    DC.W 0                   NUMBER OF CYLINDERS ON DRIVE
BUFFER    DS.B 256                 SECTOR BUFFER FOR DATA

          END START
