          NAM BIOS
          OPT PAG
          PAG

* SK*DOS BIOS FOR THE PT-68K COMPUTER >>B<<

* (C) 1986, 1987 BY PETER A. STARK FOR STAR-K SOFTWARE SYSTEMS CORP >>D<<

* LATEST CHANGE TO BIOS IS CODED IN THE TEXT WITH REVISION
* LETTERS AS IN >>A<< FOR REVISION A, ETC.

* REV. A: 10-10-86 BY CHANGING ADDRESSES OF STPRAT, DRUSED,
*     AND VERFLG, CHANGING FUNCTION OF DRUSED, AND CHANGING DRIVE
*     DRIVE NUMBER TEST TO USE PHYSICAL RATHER THAN LOGICAL DRIVE
* REV.  : 10-24-86 BY ADDING WINCHESTER DRIVERS, CONVERTING TO
*     PT-68K COMPUTER, AND USING WD1770 RATHER THAN 2797.
* REV. B: 11-09-86 TO CHANGE CLOCK FROM BCD TO BINARY
* REV. C: 1-16-87 TO MODIFY INPUT STATUS AND ADD OUTPUT STATUS
* REV. D: 2-23-87 TO ADD GET DATE AND TIME FUNCTION
* REV. E: 3-15-87. USES BIOS JUMP VECTORS AT 10B0, 10B6,
*     FIXES PROBLEM WITH CDAY, CMONTH, CYEAR, AND CHANGES A
*     FEW .L JUMPS INTO .S
* REV. F: 8-06-87. REMOVES FLOPPY READ DELAY; CHANGES TIME ROUTINES
* REV. G: 6-18-88. UPDATED FOR TYPEAHEAD BUFFER CALLS
* REV. H. 8-20-88. UPDATED FOR NRETRY COUNTER AND FOTHER FLAG

* >>E<< ONE OR MORE LINES DELETED

* EXTERNAL REFERENCES - ALL OF THESE ARE REFERENCED TO 'DOSORG', >>D<<
* WHICH IS THE BEGINNING POINT OF SK*DOS. >>D<<
* FOR EXAMPLE, A TYPICAL SK*DOS BEGINS AT $1000, SO DOSORG IS >>D<<
* SET TO $1000 BELOW. MAKE SURE TO MODIFY DOSORG AS NECESSARY. >>D<<

DOSORG    EQU $1000               BEGINNING LOCATION OF SK*DOS >>D<<
WINTAB    EQU DOSORG+$200         WINCHESTER DATA TABLE >>D<<
VRBLES    EQU DOSORG+$400         BEGINNING OF SK*DOS VARIABLE AREA >>D<<
GETDAT    EQU DOSORG+$00C         VECTOR TO GET THE DATE >>D<<
INTIME    EQU DOSORG+$012         VECTOR TO GET THE TIME >>D<<
CDAY      EQU VRBLES+751          Current date - day >>E<<
CMONTH    EQU VRBLES+750          Current date - month >>E<<
CYEAR     EQU VRBLES+752          Current date - year >>E<<
DICOLD    EQU DOSORG+$100         DISK COLD-START INIT >>D<<
DIWARM    EQU DOSORG+$106         DISK WARM-START INIT >>D<<
DIREAD    EQU DOSORG+$10C         DISK READ >>D<<
DIWRIT    EQU DOSORG+$112         DISK WRITE >>D<<
DICHEK    EQU DOSORG+$118         DISK READY CHECK >>D<<
DIMOFF    EQU DOSORG+$11E         TURN OFF DISK MOTOR >>D<<
DIREST    EQU DOSORG+$124         PRIMARY DISK RESTORE >>D<<
DISEEK    EQU DOSORG+$12A         PRIMARY DISK SEEK >>D<<
ERRTYP    EQU VRBLES+782          ERROR TYPE >>D<<
INECHO    EQU VRBLES+800          INPUT ECHO FLAG >>D<<
STPRAT    EQU DOSORG+$130         STEPRATES FOR THREE DRIVES >>D<<
VERFLG    EQU DOSORG+$13A         VERIFY FLAG >>D<<
DRUSED    EQU DOSORG+$13C         DRIVE USED TABLE >>D<<
NRETRY    EQU DOSORG+$150         FLOPPY RETRY COUNTER >>H<<
FOTHER    EQU DOSORG+$151         =0 IF SK*DOS, ELSE # SECT/SIDE >>H<<
SINITV    EQU DOSORG+$180         SERIAL PORT INIT >>D<<
STATVE    EQU DOSORG+$186         SERIAL PORT STATUS CHECK >>D<<
STATV1    EQU DOSORG+$1D4         INPUT STATUS CHECK W/O TYPEAHEAD >>G<<
OUTCHV    EQU DOSORG+$18C         OUTPUT TO PORT >>D<<
OFFINI    EQU DOSORG+$018         INITIAL OFFSET VALUE >>D<<
INCHV     EQU DOSORG+$192         INPUT FROM KBD WITH ECHO >>D<<
KINPUV    EQU DOSORG+$198         INPUT W/O ECHO >>D<<
KINPV1    EQU DOSORG+$1DA         INPUT W/O ECHO >>D<< W/O TYPEAHEAD >>G<<
MONITV    EQU DOSORG+$1AA         RETURN TO MONITOR >>D<<
RESETV    EQU DOSORG+$1B0         RESET MONITOR/SYSTEM >>D<<
TIMINI    EQU DOSORG+$1B6         TIMER INITIALIZE >>D<<
TIMOFF    EQU DOSORG+$1BC         TIMER OFF >>D<<
TIMON     EQU DOSORG+$1C2         TIMER ON >>D<<
OSTATV    EQU DOSORG+$1C8         OUTPUT STATUS VECTOR >>D<<
GETDTV    EQU DOSORG+$1CE         GET DATE AND TIME VECTOR >>D<<
KILLV1    EQU DOSORG+$1E0         FLUSH TYPEAHEAD BUFFER >>G<<

* SK*DOS FCB EQUATES

FCBPHY  EQU  72        Physical drive number >>A<<
FCBDAT  EQU  96        Beginning of data buffer (256 bytes)
FCBCSE  EQU  35        Current sector in buffer
FCBCTR  EQU  34        Current track in buffer
FCBDRV  EQU  3         Logical Drive number >>A<<
FCBERR  EQU  1         Error code

* THE FOLLOWING ORG POINT DEPENDENT ON TOP OF SK*DOS

          ORG   $6200  >>H<< NOTE INCREASE

***************************************
**** --- PART 1 - DISK DRIVERS --- ****
***************************************

* CAUTION - THESE DRIVERS MUST PRESERVE ALL REGISTERS!!! >>B<<

****************************************
**** --- PART 1A - DRIVER SELECT -- ****
*   PART 1A TOTALLY NEW IN REV. >>B<<  *
****************************************

* THIS PART SELECTS EITHER THE FLOPPY DRIVERS OR HARD DRIVERS

************************
*** READ ENTRY POINT ***
************************

* THIS IS ESSENTIALLY SREAD OPERATION

* ENTER: A4 POINTS TO FCB WHICH NEEDS DATA.
*        FCBPHY(A4) HAS PHYSICAL DRIVE NUMBER
*        FCBCTR(A4) HAS TRACK NUMBER
*        FCBCSE(A4) HAS SECTOR NUMBER

* EXIT:  ZERO IF NO ERROR;
*        IF ERROR: NON-ZERO,
*                  FCBERR(A4) AND ERRTYP BOTH HAVE ERROR CODE
*        ALL REGISTERS RESTORED!

PRIMRD    MOVEM.L D3-D7/A3/A5/A6,-(A7)

          MOVE.B FCBPHY(A4),D7     CHECK PHYSICAL DRIVE NUMBER
          BTST #4,D7               FLOPPY?
          BNE.S FLOPRD             YES
          BTST #5,D7               WINCHESTER?
          BNE.L HARDRD             YES
          MOVE.B #15,D6            NEITHER, ERROR 15
          BRA.L RWERR4             AND QUIT

*************************
*** WRITE ENTRY POINT ***
*************************

* THIS IS ESSENTIALLY SWRITE OPERATION

* ENTER: A4 POINTS TO FCB WHICH NEEDS DATA.
*        FCBPHY(A4) HAS PHYSICAL DRIVE NUMBER
*        FCBCTR(A4) HAS TRACK NUMBER
*        FCBCSE(A4) HAS SECTOR NUMBER

* EXIT:  ZERO IF NO ERROR;
*        IF ERROR: NON-ZERO,
*                  FCBERR(A4) AND ERRTYP BOTH HAVE ERROR CODE
*        ALL REGISTERS RESTORED!

PRIMWR    MOVEM.L D3-D7/A3/A5/A6,-(A7)

          MOVE.B FCBPHY(A4),D7     CHECK PHYSICAL DRIVE NUMBER
          BTST #4,D7               FLOPPY?
          BNE.S FLOPWR             YES
          BTST #5,D7               WINCHESTER?
          BNE.L HARDWR             YES
          MOVE.B #15,D6            NEITHER, ERROR 15
          BRA.L RWERR4             AND QUIT


***********************************************
**** --- PART 1B - FLOPPY DISK DRIVERS --- ****
*   THIS PART GREATLY REVISED IN REV. >>B<<,  *
* INCLUDING ALL NEW EQUATES AND COMMENTS AND  *
* SOME CHANGES IN FOLLOWING CODE AS INDICATED *
***********************************************
* EQUATES

DLATCH    EQU $E0060
* EXPLANATION OF DLATCH OPERATION:
*           BITS 0 & 1 SELECT DRIVES 0 & 1, RESP.
*           BITS 2-5 UNUSED
*           BIT 5 SELECTS DENSITY (0 = DD)
*           BIT 6 SELECTS SIDE (0 = SIDE A)
*           BIT 7 - NOT USED
*
* SIDE SELECTION IS HANDLED THROUGH SSO OF 2797 CONTROLLER
*
* THE 1772 IS SLIGHTLY DIFFERENT FROM 2790-SERIES FDC'S,
* PARTICULARLY IN COMMAND REG BIT 3 (WHICH IS USUALLY 1 IN
* THE 2790 SERIES, 0 IN THE 1772), AND IN STATUS REGISTER
* BIT 7 (WHICH IS 'NOT READY' AND SHOULD BE TESTED IN THE 279X,
* BUT WHICH MEANS MOTOR IS ON AND SHOULD NOT BE TESTED IN 1772)

COMREG    EQU $E0081
STAREG    EQU COMREG
TRKREG    EQU $E0083
SECREG    EQU $E0085
DATREG    EQU $E0087

*********************************************
* READ ENTRY POINT FOR FLOPPY DISK DRIVERS >>B<<
*********************************************

* >>B<< ONE OR MORE LINES DELETED

FLOPRD    MOVE.B NRETRY,D3         RETRY COUNTER >>B<< >>H<<
          JSR DDRIVE               SELECT DRIVE AND MOTOR ON
          BNE.L RWERR4             IF DRIVE NUMBER ERROR

PRLOOP    JSR DSEEK                SEEK TO TRACK
          BNE.S RDAGIN             REPEAT READ IF ERROR
          JSR DREAD                GO TRY TO READ
          BEQ.L RWEXIT             EXIT NORMALLY IF NO ERROR >>B<<

RDAGIN    SUB.B #1,D3              DECR RETRY COUNTER
          BEQ.S RDERR1             GIVE UP AND QUIT IF 0
          JSR DREST                ELSE RESTORE DISK >>B<<
          BRA.S PRLOOP             AND TRY AGAIN

*********************************************
* WRITE ENTRY POINT FOR FLOPPY DISK DRIVERS
*********************************************

* >>B<< ONE OR MORE LINES DELETED

FLOPWR    MOVE.B NRETRY,D3         RETRY COUNTER >>B<< >>H<<
          JSR DDRIVE               SELECT DRIVE AND MOTOR ON
          BNE.S RWERR4             IF DRIVE NUMBER ERROR

PWLOOP    JSR DSEEK                SEEK TO TRACK
          BNE.S WRAGIN             REPEAT WRITE IF ERROR

          JSR DWRITE               GO TRY TO WRITE
          BNE.S WRAGIN             IF ERROR
          TST.B VERFLG             VERIFY?
          BEQ.S RWEXIT             NO, SO JUST QUIT
          JSR DVERIF               YES, GO VERIFY SECTOR
          BEQ.S RWEXIT             EXIT NORMALLY IF NO ERROR

WRAGIN    BTST.B #6,D6             WRITE PROTECT?
          BNE.S WRERR1             YES, IMMED PROCESS ERROR
          SUB.B #1,D3              DECR RETRY COUNTER >>B<<
          BEQ.S WRERR1             GIVE UP AND QUIT IF 0
          JSR DREST                ELSE RESTORE DISK, IGNORE ERR >>B<<
          BRA.S PWLOOP             AND TRY AGAIN >>B<<

*************************************************
* ERROR PROCESSING FOR BOTH FLOPPY READ AND WRITE >>B<<
*************************************************

* TRANSLATE INTO SK*DOS ERROR CODES AND
* STORE IN FCB
RDERR1    MOVE.B STAREG,D6         GET FDC ERROR
          AND.B #$7F,D6            *** USE FOR 1772 ONLY *** >>B<<
          LEA RDETAB,A6            POINT TO READ ERROR CODE TABLE
          BRA.S RWERR2
WRERR1    MOVE.B STAREG,D6         GET FDC ERROR
          AND.B #$7F,D6            *** USE FOR 1772 ONLY *** >>B<<
          LEA WRETAB,A6            POINT TO WRITE ERROR CODE TABLE
RWERR2    ASL.B #1,D6              SHIFT ERROR CODE LEFT
          BCS.S RWERR3             GOT ERROR BIT IN CARRY
          LEA 1(A6),A6             POINT TO NEXT ERROR CODE
          BRA.S RWERR2             AND LOOK AT NEXT BIT
RWERR3    MOVE.B (A6),D6           GET ERROR CODE
RWERR4    MOVE.B D6,FCBERR(A4)     PUT INTO FCB
          MOVE.B D6,ERRTYP
RWEXIT    MOVEM.L (A7)+,D3-D7/A3/A5/A6 >>E<<
          RTS

* >>E<< ONE OR MORE LINES DELETED

RDETAB    DC.B 16                  BIT 7 = DISK NOT READY
          DC.B 9                   BIT 6 = UNKNOWN ERROR
          DC.B 9                   BIT 5 = RECORD TYPE
          DC.B 14                  BIT 4 = SEEK ERROR
          DC.B 9                   BIT 3 = CRC ERROR
          DC.B 9                   BIT 2 = LOST DATA
          DC.B 16                  NOT READY
          DC.B 29                  VERIFY ERROR
WRETAB    DC.B 16                  BIT 7 = DISK NOT READY
          DC.B 11                  BIT 6 = WRITE PROTECT
          DC.B 10                  BIT 5 = WRITE ERROR
          DC.B 14                  BIT 4 = SEEK ERROR
          DC.B 9                   BIT 3 = CRC ERROR
          DC.B 9                   BIT 2 = LOST DATA
          DC.B 16                  NOT READY
          DC.B 29                  VERIFY ERROR


*****************************************************
* DDRIVE - SELECT DRIVE SPECIFIED BY FCB+3, AND >>B<<
* TURN MOTOR ON >>B<<
*****************************************************
*
* CALLED BY: PRIMWR AND PRIMRD
* INPUT: A4 POINTS TO FCB, FCBPHY(A4) IS PHYS DRIVE NUMBER >>A<<
* OUTPUT: RETURN ZERO  IF NO ERROR;
*                NONZERO AND ERROR 15 IN D6 IF BAD DR NUM
* REGISTERS USED: D5, D6, A5, A6

DDRIVE    JSR CHKRDY               CHECK IF DRIVE IS READY
          BNE.S DRIVNG             IF DRIVE NUMBER NG >>E<<
          CLR.L D5
          MOVE.B FCBPHY(A4),D5     GET PHYS DRIVE NUMBER FROM FCB >>A<<
          AND.B #$0F,D5            REMOVE CONTROLLER TYPE >>A<<
          CLR.L D6
          MOVE.B DRIVNO,D6         GET OLD DRIVE NUMBER
          CMP.B D5,D6              SAME DRIVE NUMBER?
          BEQ.S SAMEDR             YES
          LEA TRTABL,A6            POINT TO DRIVE DATA TABLE
          MOVE.B TRKREG,0(A6,D6.L) SAVE LAST TRACK IN TABLE
          MOVE.B D5,DRIVNO         NEW DRIVE NUMBER
          MOVE.B 0(A6,D5.L),TRKREG GIVE NEW TRACK TO FDC
SAMEDR    MOVE.B D5,D6             DRIVE NUMBER >>B<<
          AND.B #1,D6              DR NUM IS BIT 0 >>B<<
          ADD.B #1,D6              CONVERT TO DRIVE CODE >>B<<
          JSR SIDENS               COMBINE DENSITY AND SIDE >>B<<
          CMP.B MLATCH,D6          CHECK IF ALREADY IN DLATCH
          BEQ.S NOD1               DON'T SEND IF YES
          MOVE.B D6,DLATCH         SELECT DRIVE, DENSITY, SIDE

NOD1      MOVE.B D6,MLATCH         SAVE NEW LATCH STATUS
          CLR.L D6                 0 MEANS THERE WAS NO ERROR
          AND.B #$FE,CCR           CLEAR CARRY
          RTS

DRIVNG    MOVE.B #15,D6            ERROR 15 - DRIVE NUM NG
          OR.B #$01,CCR            SET CARRY
          RTS                      RETURN ON ERROR

* >>B<< ONE OR MORE LINES DELETED

********************************************************
* RESTORE - SELECT DRIVE SPEC BY FCB AND RESTORE IT TO 0
********************************************************
*
* CALLED BY: PRIMWR AND PRIMRD
* INPUT: A4 POINTS TO FCB, FCBPHY(A4) IS PHYS DRIVE NUMBER >>A<<
* OUTPUT: RETURN ZERO IF NO ERROR;
*                NONZERO AND ERROR IN D6 IF BAD DR NUM
* REGISTERS USED: D5, D6, A6

DREST     CLR.B TRKREG             SO DDRIVE STORES 0 IN TABLE
          BSR.S DDRIVE             SELECT DRIVE >>E<<
          BNE.S RTS                ON ERROR
          MOVE.B #$00,D6           USE 08 FOR OTHER FDC'S >>B<<
          OR.B STPRAT,D6           PLUS STEP RATE BITS >>B<<
          MOVE.B D6,COMREG         RESTORE, LOAD HEAD, SLOW STEP
          BSR.S WNBUSY             WAIT UNTIL NOT BUSY
          AND.B #$18,D6            CHECK NR, SK, CRC ERRORS >>B<<
          AND.B #$FE,CCR           CLEAR CARRY
RTS       RTS                      AND RETURN

**************************************
* WAIT - WAIT ROUTINE TO WAIT A WHILE
* CAUTION - THIS ROUTINE MAY NEED TO
* BE ENTIRELY REVISED FOR A 68010 OR
* 68020 TO MAINTAIN THE REQUIRED DELAY
* AS REQUIRED BY THE FDC CHIP, SINCE
* SINCE THE INSTRUCTION CACHE WILL
* GREATLY SPEED THIS ROUTINE UP. >>E<<
**************************************
*
* CALLED BY: WNBUSY, SEEK, READ, WRITE
* INPUT: NONE
* OUTPUT: NONE
* REGISTERS USED: NONE

WAIT      BSR.S WAIT4
          NOP
WAIT4     BSR.S WAIT2
          NOP
WAIT2     BSR.S WAIT1
          NOP
WAIT1     BSR.S WAIT0 >>B<<
          NOP >>B<<
WAIT0     RTS >>B<<

************************************************
* WNBUSY - WAIT FOR FDC CHIP TO BECOME NOT BUSY
************************************************
*
* CALLED BY: RESTOR, SEEK, READ, WRITE, VERIFY
* INPUT: NONE
* OUTPUT: RETURN ZERO WHEN FDC BECOMES NOT BUSY
*                ELSE D6 CONTAINS ANY FDC ERROR CODE
* REGISTERS USED: D6

WNBUSY    BSR.S WAIT               WAIT FOR COMMAND TO SETTLE
          MOVE.B STAREG,D6         GET STATUS
          BTST.B #0,D6             CHECK BUSY FLAG
          BNE.S WNBUSY             WAIT IF STILL BUSY
          RTS                      ELSE RETURN WITH B=STATUS

*******************************************************
* SIDENS - GET SIDE AND DENSITY FOR CURRENT DRIVE/TRACK
*******************************************************
*
* CALLED BY: DDRIVE AND DSEEK
* INPUT: A4 POINTS TO FCB
*        D6 CONTAINS DRIVE BITS >>B<<
* OUTPUT: SIDE = 0 FOR SIDE A, 1 FOR SIDE B
*         D6 CONTAINS DRIVE, DENSITY, SIDE BITS FOR DLATCH >>B<<
* REGISTERS USED: D5, D6, A6

SIDENS    CLR.L D5
          MOVE.B FCBPHY(A4),D5     GET PHYS DRIVE NUMBER FROM FCB >>A<<
          AND.B #$0F,D5            REMOVE CONTROLLER TYPE >>A<<
          LEA DSTABL,A6            DRIVE DATA TABLE FOR TR>0
          TST.B FCBCTR(A4)         CHECK TRACK NUMBER
          BNE.S NOTTR0             USE THIS TABLE IF T<>0
          LEA D0TABL,A6            ELSE SWITCH TO TR 0 TABLE
NOTTR0    ADD.L D5,A6              POINT TO DRIVE'S ENTRY IN IT
          MOVE.L A6,DSPTR          SAVE POINTER FOR LATER
          CLR.L D5                 TEMP ASSUME SINGLE DENSITY
          MOVE.B (A6),D5           GET CURRENT ENTRY
          AND.B #1,D5              KEEP ONLY DENSITY
          ASL.B #5,D5              D5=0 ON SD, 20 ON DD >>B<<
          MOVE.B D5,DENSTY         >>B<<
          OR.B D5,D6               AND ADD TO DRIVE BITS >>B<<
          TST.B FOTHER             MS-DOS DISK? >>H<<
          BEQ.S NOTMS1             NO >>H<<
          MOVE.B FOTHER,D5         ELSE SET UP FOR 9/SIDE >>H<<
          BRA.S NOTMS2
NOTMS1    ASR.B #2,D5              D5=0 ON SD, 8 ON DD >>B<< >>H<<
          ADD.B #10,D5             D5=10 ON SD, 18 ON DD
NOTMS2    CMP.B FCBCSE(A4),D5      COMPARE WITH DESIRED SECTOR >>B<< >>H<<
          BCS.S SWSIDB             USE SIDE B IF >10 (SD) OR 18(DD)
          CLR.B SIDE               SIDE A
          BRA.S SIDEOK
SWSIDB    MOVE.B #$40,SIDE         SIDE B >>B<<
SIDEOK    OR.B SIDE,D6             OR IN SIDE BIT >>B<<
          RTS                      AND THEN RETURN WITH D6

*********************************
* DSEEK - SEEK TO TR-SEC IN FCB
********************************
*
* CALLED BY: READ, WRITE
* INPUT: A4 POINTS TO FCB
* OUTPUT: RETURN ZERO  IF NO ERROR;
*                ELSE D6 CONTAINS ANY FDC ERROR CODE
* REGISTERS USED: D5 - D7, A6 (ALL DESTROYED)

DSEEK     MOVE.B FCBCSE(A4),D6     DESIRED SECTOR
          TST.B FOTHER             MS-DOS DISK? >>H<<
          BEQ.S DSEEK1             NO >>H<<
          CMP.B FOTHER,D6          YES, CHECK WHICH SIDE >>H<<
          BLS.S DSEEK1             <=9 IS STILL SIDE A >>H<<
          SUB.B FOTHER,D6          >9 IS B, SO RENUMBER >>H<<
DSEEK1    MOVE.B D6,SECREG         GIVE SECTOR NUMBER TO FDC >>H<<
          MOVE.B MLATCH,D6         GET CURRENT MLATCH IMAGE
          JSR SIDENS               COMBINE WITH DENSITY BIT
          CMP.B MLATCH,D6          CHECK IF SAME AS BEFORE
          BEQ.S NOD2               YES, LEAVE AS IS
          MOVE.B D6,DLATCH         SELECT DRIVE, DENSITY, SIDE >>B<<
          MOVE.B D6,MLATCH         SAVE MEMORY >>B<<
NOD2      MOVE.B FCBCTR(A4),D5
          CMP.B TRKREG,D5          ALREADY ON DESIRED TRACK?
          BEQ.S TRKOK              YES, WAIT AND EXIT
          CLR.L D6
          MOVE.B (A6),D6           CHECK DISK PARAMETERS
          AND.B #2,D6              DOUBLE STEPPING?
          MOVE.B D6,DUBSTE         STORE FOR LATER
          BEQ.S NODUB1             IF NOT DOUBLE STEPPING
          MOVE.B TRKREG,D6         GET CURRENT TRACK
          ASL.B #1,D6              FOOLS FDC INTO DOUBLE-STEPPING
          MOVE.B D6,TRKREG
          ASL.B #1,D5
NODUB1    MOVE.B D5,DATREG         AND GIVE NEW TRACK TO FDC
          BSR WAIT
          MOVE.B #$10,D5           SEEK COMMAND >>B<<
          OR.B STPRAT,D5           OR STEP RATE >>B<<
          MOVE.B D5,COMREG         SEEK,  COMMAND >>B<<
          BSR WNBUSY               WAIT FOR COMPLETION
          TST.B DUBSTE             DOUBLE-STEPPING?
          BEQ.S NODUB2             NO
          MOVE.B TRKREG,D6         YES, FIX UP FDC TRACK REG
          LSR.B #1,D6
          MOVE.B D6,TRKREG
          BSR WNBUSY               CHECK FDC BITS ONCE MORE
NODUB2    AND.B #$18,D6            CHECK NR,SK,CRC ERRORS >>B<<
          RTS
TRKOK     BSR WAIT                 WAIT FOR COMPLETION
          MOVE.L #0,D6             IF NO ERROR
          RTS

******************************
* DREAD - READ SECTOR ROUTINE
******************************
*
* CALLED BY: PRIMRD
* INPUT: A4 POINTS TO FCB
* OUTPUT: RETURN ZERO IF NO ERROR;
*                ELSE D6 CONTAINS ANY DOS ERROR CODE
* REGISTERS USED: D5 - D7, A5 - A6 (ALL DESTROYED)
*                    A4 USED AND PRESERVED

DREAD     MOVE.W SR,D5             SAVE CURRENT SR >>B<<
          OR.W #$0700,SR           TURN OFF INTERRUPTS >>B<<
          MOVE.L A4,D7             SAVE A4 IN D7 >>B<<
          LEA FCBDAT(A4),A5        POINT A5 TO FCB DATA AREA
* >>B<< ONE OR MORE LINES DELETED
          LEA STAREG,A6            POINT A6 TO STATUS REG
          LEA DATREG,A4            POINT A4 TO DATA REG
* >>B<< ONE OR MORE LINES DELETED
          MOVE.B #$80,COMREG       READ COMMAND >>F<<
          BSR WAIT                 WAIT FOR FDC TO SETTLE

RDLOOP    MOVE.B (A6),D6           CHECK STATUS
          BTST.B #1,D6             DRQ?
          BNE.S RDBYTE             YES
          BTST.B #0,D6             BUSY?
          BNE.S RDLOOP             YES, SO WAIT
          BRA.S RDFINR             THEN EXIT
RDBYTE    MOVE.B (A4),(A5)+        GET DATA BYTE
          BRA.S RDLOOP

RDFINR    BSR WNBUSY               WAIT FOR NOT BUSY
          BTST.B #4,D6             RNF ERROR?
          BEQ.S READEX             NO, SOMETHING ELSE?
          MOVE.L DSPTR,A6          YES, POINT TO DRIVE DATA BYTE
          ADD.B #1,(A6)            TRY NEXT SETTING
READEX    MOVE.W D5,SR             RESTORE INTERRUPTS
          AND.B #$1C,D6            NR, RNF, CRC, OR LOST DATA? >>B<<
          MOVE.L D7,A4             RESTORE A4
          RTS                      RTS AND RETURN

*********************************
* DWRITE - WRITE SECTOR ROUTINE
*********************************
*
* CALLED BY: PRIMWR
* INPUT: A4 POINTS TO FCB
* OUTPUT: RETURN ZERO  IF NO ERROR;
*                ELSE D6 CONTAINS ANY DOS ERROR CODE
* REGISTERS USED: D5 - D7, A5 - A6 (ALL DESTROYED)
*                    A4 USED AND PRESERVED

DWRITE    MOVE.W SR,D5             SAVE CURRENT SR >>B<<
          OR.W #$0700,SR           TURN OFF INTERRUPTS >>B<<
          LEA FCBDAT(A4),A5        POINT A5 TO FCB DATA AREA >>B<<
          MOVE.L A4,D7             PRESERVE A4
* >>B<< ONE OR MORE LINES DELETED
          LEA STAREG,A6            POINT A6 TO STATUS REGISTER
          LEA DATREG,A4            POINT A4 TO DATA REG
* >>B<< ONE OR MORE LINES DELETED
          MOVE.B #$A4,COMREG       WRITE COMMAND
          BSR WAIT                 WAIT FOR FDC TO SETTLE

WRLOOP    MOVE.B (A6),D6           CHECK STATUS
          BTST.B #1,D6             DRQ?
          BNE.S WRBYTE             YES
          BTST.B #0,D6             BUSY?
          BNE.S WRLOOP             YES, SO WAIT
          BRA.S SDFINW             THEN EXIT
WRBYTE    MOVE.B (A5)+,(A4)        WRITE DATA BYTE
          BRA.S WRLOOP             REPEAT UNTIL DONE

SDFINW    JSR WNBUSY               WAIT FOR NOT BUSY
          BTST.B #4,D6             RNF ERROR?
          BEQ.S WRITEX             NO, SOMETHING ELSE?
          MOVE.L DSPTR,A6          YES, POINT TO DRIVE DATA BYTE
          ADD.B #1,(A6)            TRY NEXT SETTING
WRITEX    MOVE.W D5,SR             RESTORE INTERRUPTS
          AND.B #$5C,D6            NR, WP, RNF, CRC, OR LOST DATA? >>B<<
          MOVE.L D7,A4             RESTORE A4
          RTS                      AND RETURN

**************************************
* DVERIF - VERIFY SECTOR JUST WRITTEN
**************************************
*
* CALLED BY: PRIMWR
* INPUT: (ASSUMES DWRITE JUST SET EVERYTHING UP)
* OUTPUT: RETURN ZERO  IF NO ERROR;
*                ELSE D6 CONTAINS ANY DOS ERROR CODE
* REGISTERS USED: D6 (DESTROYED)


DVERIF    MOVE.W SR,D5             SAVE CURRENT SR >>B<<
          OR.W #$0700,SR           TURN OFF INTERRUPTS >>B<<
          MOVE.B #$80,COMREG       READ COMMAND >>B<< >>F<<
          BSR WNBUSY               WAIT FOR NOT BUSY
          MOVE.W D5,SR             RESTORE INTERRUPTS
          AND.B #$18,D6            NR, RNF, OR CRC (NOT LOST DATA!) >>B<<
          RTS                      AND RETURN

************************************************
* CHKRDY - CHECK IF DRIVE SPEC BY FCB IS READY
************************************************
*
* CALLED BY: FCS20
* INPUT: A4 POINTS TO FCB, FCBDRV(A4) IS DRIVE NUMBER
* OUTPUT: RETURN ZERO AND CLC IF NO ERROR;
*                NONZERO AND ERROR $80 IN D6 IF NOT READY
* REGISTERS USED: D6 AND A6 (NEED NOT RESTORE)


CHKRDY    CLR.L D6
          MOVE.B FCBDRV(A4),D6     GET LOGICAL DRIVE NUMBER >>A<<
          LEA DRUSED,A6            POINT TO DRIVE USED TABLE
          BTST.B #4,0(A6,D6.L)     CHECK CONTROLLER TYPE >>A<<
          BEQ.S CHKNG
          CLR.L D6                 NO ERROR
          AND.B #$FE,CCR           CLEAR CARRY
          RTS                      RTS
CHKNG     MOVE.B #$80,D6           NOT READY BIT
          OR.B #$01,CCR            SET CARRY
          RTS

DRIVNO    DC.B 0 CURRENT DRIVE NUMBER
DENSTY    DC.B 0 0=SD, 02=DD
SIDE      DC.B 0 SIDEA=0, SIDEB=1
DUBSTE    DC.B 0 DOUBLE-STEP FLAG (0=SINGLE)
DSPTR     DC.L 0 POINTER TO ENTRY IN...
* IN THE FOLLOWING, BIT 0 = DENSITY, BIT 1 = DOUBLE-STEPPING
D0TABL    DC.B 0,0,0,0 TRACK 0 DENSITY TABLE
DSTABL    DC.B 0,0,0,0 DENSITY/DOUBLE-STEP TABLE
TRTABL    DC.B $FF,$FF,$FF,$FF TRACK TABLE
MLATCH    DC.B $FF COPY OF DLATCH     
* >>B<< ONE OR MORE LINES DELETED

*********************************************
**** --- PART 1C - HARD DISK DRIVERS --- ****
* THIS PART IS ENTIRELY NEW IN REV. >>B<<.  *
*********************************************

* EQUATES
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

******************************
*** HARD DISK READ ROUTINE ***
******************************

* HARDRD - READ A SECTOR FROM DISK INTO FCB POINTED TO BY A4

HARDRD    BSR.L LPCONV             CONVERT LOG TO PHYS TR-SEC
          BNE.L HDERR1
          MOVE.B #$20,WDCOMA       SEND READ COMMAND
          BSR.L CHBUSY             WAIT FOR COMPLETION
          BNE.L HDERR1
          LEA FCBDAT(A4),A6        POINT TO DATA AREA
          MOVE.W #63,D7            COUNTER = 256/4-1
HRDLOO    MOVE.L WDREAD,(A6)+      READ 4 BYTES
          DBRA D7,HRDLOO           REPEAT FOR 256 BYTES
          BSR.S CHBUSY             WAIT FOR COMPLETION
          BNE.L HDERR1
          MOVEM.L (A7)+,D3-D7/A3/A5/A6
          CLR.B WDSDHR             DESELECT DRIVE
          RTS                      EXIT WITH ZERO IF NO ERROR

*******************************
*** HARD DISK WRITE ROUTINE ***
*******************************

* HARDWR - WRITE A SECTOR TO DISK FROM FCB POINTED TO BY A4

HARDWR    TST.W FCBCTR(A4)         CHECK FOR TRACK 0 SECTOR 0
          BNE.S HARDW1             OK TO GO ON IF NOT
          MOVE.B #11,D6            TR 0 SEC 0 IS WRITE PROT
          BRA.L RWERR4             AND QUIT

HARDW1    BSR.L LPCONV             CONVERT LOG TO PHYS TR-SEC
          BNE.S HDERR1
          MOVE.B #32,WDWPRE        FIRST ASSUME PRECOMP AT CYL 128
          MOVE.B 14(A3),D7         PRECOMP CYL FROM WINTAB
          ADD.B #1,D7              CHECK FOR EMPTY $FF
          BEQ.S NOPREC             DON'T USE IF EMPTY
          SUB.B #1,D7              ELSE CORRECT IT
          MOVE.B D7,WDWPRE         AND GIVE TO WD1002
NOPREC    MOVE.B #$30,WDCOMA       SEND WRITE COMMAND
          BSR.S CHBUSY             WAIT FOR COMPLETION
          BNE.S HDERR1
          LEA FCBDAT(A4),A6        POINT TO DATA AREA
          MOVE.W #63,D7            COUNTER = 256/4-1
HWRLOO    MOVE.L (A6)+,WDWRIT      OUTPUT 4 BYTES
          DBRA D7,HWRLOO           REPEAT FOR 256 BYTES
          BSR.S CHBUSY             WAIT FOR COMPLETION
          BNE.S HDERR1
          MOVEM.L (A7)+,D3-D7/A3/A5/A6
          CLR.B WDSDHR             DESELECT DRIVE
          RTS                      EXIT WITH ZERO IF NO ERROR

****************************
*** CHECK HARD DISK BUSY ***
****************************

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

CHBUSY    MOVE.L #$200000,D7       TIMEOUT COUNTER
CHBUS1    SUB.L #1,D7              DROP TIMEOUT COUNT
          BEQ.S CHBER2             SOMETHING WRONG?
          TST.B WDSTAT             CHECK WD1002 STATUS
          BMI.S CHBUS1             WAIT UNTIL NOT BUSY
CHBERR    MOVE.B WDSTAT,D7         GET WD STATUS BYTE
          BTST.B #0,D7             CHECK ERROR BIT
          RTS
CHBER2    MOVE.B #1,D7             SET NON-ZERO FOR ERROR
          RTS

***********************************************
* ERROR PROCESSING FOR BOTH HARD READ AND WRITE
***********************************************

* TRANSLATE INTO SK*DOS ERROR CODES AND
* STORE IN FCB
HDERR1    MOVE.B #15,D6            BAD DR NUM CODE
          BTST #1,D7               (PUT IN BY LPCONV)
          BNE.S HDERR4
          MOVE.B #16,D6            NOT READY CODE
          BTST #6,D7
          BNE.S HDERR4
          MOVE.B #10,D6            WRITE FAULT ERROR
          BTST #5,D7
          BNE.S HDERR4
          MOVE.B WDERRO,D7         GET WD1002 ERROR CODE
          MOVE.B #09,D6            READ ERROR
HDERR4    CLR.B WDSDHR             DESELECT DRIVE
          MOVE.B D6,FCBERR(A4)     PUT INTO FCB
          MOVE.B D6,ERRTYP
          MOVEM.L (A7)+,D3-D7/A3/A5/A6
          RTS

***********************************
*** LOGICAL TO PHYSICAL CONVERT ***
***********************************

* LPCONV - CONVERT DRIVE, TRACK, AND SECTOR DATA FOUND IN FCB INTO
* THE PHYS DRIVE NUMBER, PHYSICAL TRACK, HEAD, AND SECTOR NUMBERS AND
* PUT INTO WD REGS, USING INFO IN APPROPRIATE WINTAB ENTRY

LPCONV    MOVE.B #1,WDSCNT         SECTOR COUNT = 1
          LEA WINTAB(PC),A3        POINT TO WINCHESTER TABLE
          CLR.L D3
          MOVE.B FCBPHY(A4),D3     PHYSICAL DRIVE NUMBER
          MOVE.B D3,D4             TEMP SAVE ALSO IN D4
          LSL.B #4,D3              E.G., CVT 21 T0 10
          LEA 0(A3,D3.W),A3         POINT A3 TO THAT ENTRY
          CMP.B (A3),D4            COMPARE WINTAB ENTRY
          BNE.S LPERR              ERROR IF WRONG DRIVE
          CLR.L D6
          MOVE.B FCBCTR(A4),D6     LOGICAL TRACK
          CLR.L D7
          MOVE.B 11(A3),D7         LOG SECT/TRACK
          ADD.W #1,D7              NUMBER PER TRACK
          MULU D7,D6               SECT BEFORE THIS TRACK
          CLR.L D7
          MOVE.B FCBCSE(A4),D7     LOG SECTOR
          ADD.W D7,D6              BLOCK NUMBER
          MOVE.W 4(A3),D7          SECT/CYL ON HARD DISK
          DIVU D7,D6               REMAINDER | TRACK NUMBER
          ADD.W 8(A3),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(A3),D7          SECTORS PER TRACK
          DIVU D7,D6               SECTOR | HEAD
          AND.B #$04,D4            DRV A=00, DRB=04
          LSL.B #1,D4              A=00, B=08
          ADD.B #$88,D4            A=$88, B=$90
          ADD.B D4,D6              COMBINE WITH HEAD NUM
          MOVE.B D6,WDSDHR         PUT INTO SDH REGISTER
          SWAP D6                  MOVE SECTOR RIGHT
          MOVE.B D6,WDSNUM         SECTOR NUMBER TO WD1002
          MOVE.B #0,D6             RETURN ZERO IF OK
          RTS

LPERR     MOVE.B #$02,D7           ERROR CODE FOR BAD DR NUM
          RTS

****************************************************
**** --- PART 1D - HARD DISK INITIALIZATION --- ****
* THIS PART IS ENTIRELY NEW IN REV. >>B<<.
****************************************************

* HARD DISK INITIALIZATION
* THIS SECTION FIRST CHECKS WHETHER THERE IS A DISK CONTROLLER,
* THEN DOES A RESTORE ON ONE OR TWO DRIVES,
* COPIES DATA FROM TRACK 0 SECTOR 0 OF 1 OR 2 DRIVES INTO WINTAB
* AND SETS THE FINAL STEP RATE FOR BOTH DRIVES.

HDCOLD    LEA WINTAB(PC),A5        POINT TO WINNIE TABLE
          MOVE.W #31,D5            COUNTER = 128/4 - 1
INITCL    MOVE.L #$FFFFFFFF,(A5)+  CLEAR WINTAB TO START OFF
          DBRA D5,INITCL
          MOVE.B #$A5,WDSNUM       TRY STORING INTO WD1002
          MOVE.L WDSNUM,D5         READ BACK
          CMP.L #$A5A5A5A5,D5      CHECK IT
          BNE.L INITRT             NO WD1002 THERE
          MOVE.B #$5A,WDSNUM       THEN TRY THE COMPLEMENT
          MOVE.L WDSNUM,D5         READ BACK
          CMP.L #$5A5A5A5A,D5      CHECK IT
          BNE.L INITRT             NO WD1002 THERE
          LEA WINTAB(PC),A5        POINT TO WIN TABLE A ENTRY
          MOVE.B #$88,D5           SDH CODE FOR DRIVE A
          BSR.S INITSU             READ IF POSSIBLE
          LEA WINTAB(PC),A5        POINT TO WIN TABLE A ENTRY
          MOVE.B #$20,D5           DRIVE A STARTS WITH 20
          BSR.L INITFX             FIX THE PHYSICAL DRIVE NUMBERS
          LEA WINTAB+64(PC),A5     POINT TO WIN TABLE B ENTRY
          MOVE.B #$90,D5           SDH CODE FOR DRIVE B
          BSR.S INITSU             READ IF POSSIBLE
          LEA WINTAB+64(PC),A5     POINT TO WIN TABLE B ENTRY
          MOVE.B #$24,D5           DRIVE B STARTS WITH 24
          BSR.L INITFX             FIX THE PHYSICAL DRIVE NUMBERS
* RESTORE BOTH DRIVES AND THEIR STEP SPEED
          LEA WINTAB(PC),A5        POINT TO WINNIE TABLE
          TST.B (A5)               IS THERE A DRIVE A?
          BMI.S HDWRTS             NO, QUIT
          MOVE.B #$88,WDSDHR       SELECT DRIVE A
          MOVE.B 1(A5),D5          GET STEPRATE FROM DISK
          ADD.B #$10,D5            MAKE INTO RESTORE
          MOVE.B D5,WDCOMA         GIVE NEW STEPRATE TO DRIVE
          BSR.L CHBUSY
          TST.B 64(A5)             IS THERE A DRIVE B?
          BMI.S HDWRTS             NO, QUIT
          MOVE.B #$90,WDSDHR       SELECT DRIVE B
          MOVE.B 65(A5),D5         GET STEPRATE FROM DISK
          ADD.B #$10,D5            MAKE INTO RESTORE
          MOVE.B D5,WDCOMA         GIVE NEW STEPRATE TO DRIVE
          BSR.L CHBUSY
HDWRTS    CLR.B WDSDHR             DESELECT DRIVE
          RTS

INITSU    MOVE.B D5,WDSDHR         ECC,SEC=256,DRIVE N,HEAD 0
          MOVE.B #32,WDWPRE        SET PRECOMP TO TRACK 128
          MOVE.B #1,WDSCNT         COUNT 1 SECTOR
          CLR.B WDSNUM             SECTOR NUMBER 0
          CLR.B WDCYLO             CYLINDER 0
          CLR.B WDCYHI             DITTO
          MOVE.B #$1F,WDCOMA       RESTORE AT 7.5 MSEC STEP
          BSR.L CHBUSY             WAIT FOR WD1002 NOT BUSY
          BNE.S INITRT             QUIT ON ERROR
          MOVE.B #$20,WDCOMA       TRY TO READ
          BSR.L CHBUSY
          BNE.S INITRT             QUIT ON ERROR
          MOVE.W #15,D5            64/4 - 1
INITLO    MOVE.L WDREAD,(A5)+      READ INTO TABLE
          DBRA D5,INITLO
INITRT    RTS                      THEN EXIT

* INITFX - FIXES PHYSICAL DRIVE NUMBERS IN WINTAB SO DRIVE A
* NUMBERS ARE 20-23, AND DRIVE B ARE 24-27 (THEY ARE 00-03 ON
* THE DISK ITSELF, SO DRIVES CAN BE SWITCHED)

INITFX    CMP.B #4,0(A5)           CHECK FOR ENTRY 0
          BCC.S INITF1             EMPTY
          ADD.B D5,0(A5)           FIX IT
          CMP.B #4,16(A5)          CHECK FOR ENTRY 1
          BCC.S INITF1             EMPTY
          ADD.B D5,16(A5)          FIX IT
          CMP.B #4,32(A5)          CHECK FOR ENTRY 2
          BCC.S INITF1             EMPTY
          ADD.B D5,32(A5)          FIX IT
          CMP.B #4,48(A5)          CHECK FOR ENTRY 3
          BCC.S INITF1             EMPTY
          ADD.B D5,48(A5)          FIX IT
INITF1    RTS

******************************************
**** --- PART 2 - CONSOLE DRIVERS --- ****
******************************************

* CONVENTIONS: D1-D5 AND A1-A5 MUST BE PRESERVED
*                  (EXCEPT WHEN D5 IS FOR INPUT)
*              OTHER REGISTERS ARE SCRATCH

* SYSTEM AND DUART PORT REFERENCES >>B<<
DSTARG    EQU  $E0003              DUART STATUS REGISTER >>B<<
DDATRG    EQU  $E0007              DUART DATA REGISTER >>B<<
ROM       EQU  $FFC000             START OF ROM >>B<<

******************************************
* SERIAL PORT INITIALIZATION ROUTINE
SERINI    RTS                      DONE BY MONITOR >>B<<

******************************************
* ERASE TYPEAHEAD BUFFER (ALL NEW >>G<<)
* THIS VERSION OF BIOS DOES NOT IMPLEMENT TYPEAHEAD, BUT
* IF IT DID, THEN HERE IT WOULD EMPTY OUT THE BUFFER AND
* ERASE ALL FLAGS. INCIDENTALLY, THE SERINI ROUTINE SHOULD
* ALSO CALL KILLTA IF USED.

KILLTA    RTS

****
* SERIAL INPUT PORT STATUS CHECK - VIA TYPEAHEAD >>G<<
* IF TYPEAHEAD WERE USED, THIS WOULD CHECK THE TYPEAHEAD
* BUFFER TO SEE IF THERE WERE ANY CHARACTERS IN IT. SEE THE
* MANUAL FOR DISCUSSION
*
*    INPUT: NONE
*    OUTPUT: RETURN ZERO IF NO CHARACTER READY,
*                   NON-ZERO IF CHARACTER IS THERE
*                   D5=1 TO SHOW 1 CHARACTER READY >>C<<
*    REGISTERS USED: NONE >>C<<

STATM     BTST #0,DSTARG           CHECK RX READY BIT
          BEQ.S STATRX             EXIT IF NONE THERE >>C<<
          MOVE.L #1,D5             ELSE RETURN COUNT=1 >>C<<
STATRX    RTS                      RETURN WITH ZERO IF NOTHING >>C<<

****
* SERIAL INPUT PORT STATUS CHECK - SINGLE CHAR >>G<<
* IF TYPEAHEAD IS USED, THIS CHECKS ONLY FOR THE PRESENCE OF
* THE LAST CHARACTER. IN OUR CASE, WE JUST SEND PROGRAM TO STATM
* ABOVE
*
*    INPUT: NONE
*    OUTPUT: RETURN ZERO IF NO CHARACTER READY,
*                   NON-ZERO IF CHARACTER IS THERE
*                   D5=1 TO SHOW 1 CHARACTER READY >>C<<
*    REGISTERS USED: NONE >>C<<

STAT      BRA.S STATM              JUST USE OTHER ROUTINE >>G<<

* OUTPUT PORT STATUS CHECK. >>C<<
*
*    INPUT: NONE >>C<<
*    OUTPUT: RETURN ZERO IF NOT READY >>C<<
*    REGISTERS USED: NONE >>C<<

OSTAT     BTST #2,DSTARG           CHECK TX READY BIT >>C<<
          RTS                      RETURN WITH ZERO IF NOTHING >>C<<

* OUTPUT CHARACTER IN D5 TO TERMINAL
*
*    INPUT: D5 HOLDS CHARACTER TO OUTPUT
*    OUTPUT: NONE
*    REGISTERS USED: NONE (MUST PRESERVE D5)

OUTEEE    BTST #2,DSTARG           CHECK TX READY BIT
          BEQ.S OUTEEE             NOT READY, WAIT
          MOVE.B D5,DDATRG         READY, OUTPUT CHARACTER >>B<<
          TST.B STAREG             IS MOTOR ON? (CHECKS WD1772) >>B<<
          BMI.S OUTRTS             YES, JUST EXIT >>B<<
          CLR.B DLATCH             NO, DESELECT DRIVE >>B<<
          CLR.B MLATCH             >>B<<
OUTRTS    RTS                      THEN RETURN >>B<<

* INPUT CHARACTER INTO D5 AND ECHO IT
* USES TYPEAHEAD ROUTINE IF AVAILABLE >>G<<
*    INPUT: NONE
*    OUTPUT: D5 HOLDS 7-BIT CHARACTER INPUT
*    REGISTERS USED: PRESERVED (EXCEPT D5 HOLDS CHAR)

INEEE     BSR.S KINPUM             GET THE CHARACTER >>G<<
          AND.L #$7F,D5            KEEP 7-BIT CHAR, CLEAR ALL ELSE
          TST.B INECHO             ECHO?
          BEQ.S INERTS             NO
          BSR.S OUTEEE             ECHO IT
INERTS    RTS                      AND RETURN

* KEYBOARD INPUT INTO D5 WITHOUT ECHO - WITH TYPEAHEAD >>G<<
* THIS ROUTINE WOULD INPUT VIA THE TYPEAHEAD BUFFER, IF PRESENT >>G<<
*
*    INPUT: NONE
*    OUTPUT: D5 HOLDS 8-BIT CHARACTER INPUT
*    REGISTERS USED: PRESERVED (EXCEPT D5 HOLDS CHAR)

KINPUM    TST.B STAREG             IS MOTOR ON? >>B<< >>G<<
          BMI.S KINPU1             YES, JUST EXIT >>B<<
          CLR.B DLATCH             NO, DESELECT DRIVE >>B<<
          CLR.B MLATCH             >>B<<
KINPU1    BSR.S STATM              CHECK KEYBOARD STATUS >>B<< >>G<<
          BEQ.S KINPUT             IF NOTHING IS THERE
          MOVE.B DDATRG,D5         GET KEYBOARD CHARACTER
          RTS                      AND RETURN

* KEYBOARD INPUT INTO D5 WITHOUT ECHO - WITHOUT TYPEAHEAD >>G<<
* IF TYPEAHEAD WERE AVAILABLE, THIS ROUTINE WOULD INPUT ONLY
* THE LAST CHARACTER. SEE CONFIGURATION MANUAL FOR DETAILS.
* SINCE NO TYPEAHEAD IMPLEMENTED IN THIS VERSION, USE OTHER
* ROUTINE
*
*    INPUT: NONE
*    OUTPUT: D5 HOLDS 8-BIT CHARACTER INPUT
*    REGISTERS USED: PRESERVED (EXCEPT D5 HOLDS CHAR)

KINPUT    BRA.S KINPUM             >>G<<


* RE-ENTER MONITOR WITHOUT RESET
* THIS COMMAND DOES NOT CHANGE EXCEPTION VECTORS >>B<<
*
*    INPUT: NONE
*    OUTPUT: NONE
*    REGISTERS USED: IREELEVANT >>E<<

MONITX    MOVE.L ROM+$BC,A5        MONITOR WARM-START ADDRESS
          MOVE.L ROM,A7            RESTART STACK POINTER
          JMP (A5)                 JUMP TO MONITOR START

* RESET MONITOR/SYSTEM AS IF RESET FROM SCRATCH >>B<<
* THIS COMMAND RESETS EXCEPTION VECTORS TO MONITOR'S, >>B<<
* ERASES BREAKPOINT TABLE, RESET BAUD RATE, ETC. >>B<<
*
*    INPUT: NONE >>B<<
*    OUTPUT: NONE >>B<<
*    REGISTERS USED: IRRELEVANT >>E<<

RESETX    MOVE.L ROM+$04,A5        MONITOR COLD-START ADDRESS >>B<<
          MOVE.L ROM,A7            RESTART STACK POINTER >>B<<
          JMP (A5)                 JUMP TO MONITOR START >>B<<

* TIMER ON, OFF, INIT
* ONE OR MORE LINES DELETED IN REV. >>B<<.
*
*    INPUT: NONE
*    OUTPUT: NONE
*    REGISTERS USED: NONE

TIMRTS    RTS                      RTS DO NOTHING

*****************************************
*** --- PART 3 - GET DATE ROUTINE --- ***
* THIS PART ENTIRELY NEW IN REV. >>A<<
*****************************************

* IF THE SYSTEM HAS A CLOCK/CALENDAR CHIP, THEN
* THIS ROUTINE WOULD GET THE DATE DURING BOOTING,
* AND PUT IT INTO THE MONTH, DAY, YEAR LOCATIONS.
* DO NOTHING OTHERWISE.
* THIS EXAMPLE SHOWS THE CODE FOR THE PTA-68K COMPUTER.

* THIS ROUTINE GETS THE DATE DURING BOOTING,
* AND PUTS IT INTO THE MONTH, DAY, YEAR LOCATIONS.
* PROGRAM DOES NOTHING IF THE CLOCK IS NOT SET PROPERLY.

* THE FOLLOWING TWO EQUATES REFER TO TWO JMP.L INSTRUCTIONS WHICH >>E<<
* EXIST IN SK*DOS SPECIFICALLY TO ALLOW THIS BIOS TO USE ASKDAT, A >>E<<
* ROUTINE WHICH ASKS FOR THE CURRENT DATE, AND PSTRNG, A ROUTINE >>E<<
* WHICH PRINTS A STRING, WITHOUT USING THE CUSTOMARY DC $AXXX >>E<<
* METHOD. >>E<<

ASKDAV    EQU DOSORG+$00B0         JMP.L INSTRUCTION TO ASKDAT >>E<<
PSTRNV    EQU DOSORG+$00B6         JMP.L INSTRUCTION TO PSTRNG >>E<<

CLOCKA    EQU $E0041               CLOCK CHIP'S ADDRESS REG
CLOCKD    EQU $E0043               CLOCK CHIP'S DATA REG

* GET THE TIME AND DATE AND CHECK THEM

INPDAT    MOVE.B #2,D0
          BSR.L READIT             GET MINUTES
          CMP.B #59,D0             CHECK IT >>B<<
          BHI.S NOGOOD             CLOCK NOT SET IF >59 MIN
          MOVE.B #4,D0
          BSR.L READIT             GET HOURS
* ONE OR MORE LINES DELETED IN REV. >>B<<.
          CMP.B #23,D0             CHECK IT >>B<<
          BHI.S NOGOOD             NG IF PAST 23 O'CLOCK >>B<<
          MOVE.B #6,D0
          BSR.S READIT             GET DAY OF WEEK >>E<<
          CMP.B #7,D0              CHECK IT
          BHI.S NOGOOD             NO 8-DAY WEEKS ALLOWED
          MOVE.B #7,D0
          BSR.S READIT             GET DAY OF MONTH >>E<<
          CMP.B #31,D0             CHECK IT >>B<<
          BHI.S NOGOOD             MAX 31 DAYS A MONTH
* ONE OR MORE LINES DELETED IN REV. >>B<<.
          MOVE.B D0,CDAY           GIVE IT TO SK*DOS
          MOVE.B #8,D0
          BSR.S READIT             GET MONTH >>E<<
          CMP.B #12,D0             CHECK IT >>B<<
          BHI.S NOGOOD             MAX 12 MONTHS A YEAR
* ONE OR MORE LINES DELETED IN REV. >>B<<.
          MOVE.B D0,CMONTH         GIVE IT DO SK*DOS
          MOVE.B #9,D0
          BSR.S READIT             GET THE YEAR >>E<<
          CMP.B #84,D0             CHECK IT >>B<<
          BCS.S NOGOOD             MUST BE 84 OR LATER
          CMP.B #99,D0             >>B<<
          BHI.S NOGOOD             ASSUME THIS CENTURY
* ONE OR MORE LINES DELETED IN REV. >>B<<.
          MOVE.B D0,CYEAR          GIVE IT TO SK*DOS
          RTS                      AND THEN CONTINUE SK*DOS

* ON INVALID DATE, GET IT FROM KEYBOARD

NOGOOD    LEA CLKMSG(PC),A4        SAY CLOCK IS NO GOOD
          JSR PSTRNV               ASK FOR DATE >>E<<
          JMP ASKDAV               GO USE REGULAR SK*DOS DATE ENTRY >>E<<
CLKMSG    DC.B $D,$A
          DC.B "CALENDAR/CLOCK NOT PROPERLY SET -",4

* GET DATA FROM 146818 CLOCK CHIP

READIT    MOVE.B D0,CLOCKA         GIVE ADDRESS TO CLOCK
          MOVE.B CLOCKD,D0         GET THE DATAGAIN
          RTS

* ONE OR MORE LINES DELETED IN REV. >>B<<.

*****************************************
*** --- PART 4 - GET TIME ROUTINE --- ***
* THIS PART ENTIRELY NEW IN REV. >>A<<
*****************************************

* OMIT PARTS 4A AND 4B IF THERE IS NO CLOCK/CALENDAR >>D<<

*************** PART 4 A ************************ >>D<<
* THIS ROUTINE IS CALLED EVERY TIME SK*DOS OPENS A FILE >>B<<
* FOR WRITING, READS THE TIME OF DAY FROM THE 146818 CLOCK >>B<<
* ON THE PT-68K BOARD, CONVERTS THE TIME INTO A >>B<<
* ONE-BYTE CODE, AND PUTS IT INTO D5 SO THAT >>B<<
* SK*DOS CAN PUT IT INTO THE DIRECTORY, NEXT TO THE DATE. >>B<<
* CAUTION - ALL REGISTERS MUST BE PRESERVED EXCEPT A5-A6,D5-D7. >>B<<
* LARGELY NEW IN >>B<<; SLIGHT LOGIC CHANGES IN REVISION >>F<<

* CHECK FOR VALID TIME ON CLOCK

* CHECK THAT YEAR IS 85 THRU 99

SETIME    MOVE.B #$0A,D5           CHECK IF OK TO READ
          BSR.S GETICD             GET UPD IN PROG BIT
          BMI.S SETIME             WAIT UNTIL IT IS ZERO
          MOVE.L #09,D5            YEAR ADDRESS
          BSR.S GETICD             GET DATA FROM CHIP
          CMP.B #85,D5
          BCS.S TIMENG             QUIT IF TIME IS NG
          CMP.B #99,D5
          BHI.S TIMENG             DITTO

* GET THE TIME
GETTIM    MOVE.B #02,D5
          BSR.S GETICD             GET MINUTE
          DIVU #6,D5               DIVIDE MINUTES BY 6
          MOVE.B D5,D7             SAVE MINUTES/6 IN D7
          MOVE.B #04,D5
          BSR.S GETICD             GET HOURS
          MULU #10,D5              HOURS * 10
          ADD.B D5,D7              HOURS*10 + MINUTES/6 IN D7
          BNE.S QUIT               IF NOT 00
          MOVE.B #$F0,D5           CHANGE 00 TO F0
QUIT      MOVE.B #$0A,D5           CHECK IF STILL OK TO READ
          BSR.S GETICD             GET UPD IN PROG BIT
          BMI.S GETTIM             REPEAT IF NOT ZERO
          MOVE.B D7,D5             THEN RESTORE TIME
          RTS                      RETURN

* IF TIME IS NG, RETURN 0
TIMENG    MOVE.L #0,D5
          RTS                      AND THEN QUIT

* GIVE ADDRESS TO CLOCK AND GET DATA
GETICD    MOVE.B D5,CLOCKA         GIVE IT ADDRESS
          MOVE.B CLOCKD,D5         GET DATA
          RTS                      AND RETURN

*************** PART 4 B ************************
* THIS ROUTINE IS USER-CALLABLE, AND RETURNS DATE IN D5
* AS WWMMDDYY, AND TIME IN D6 AS 00HHMMSS, WHERE WW IS THE
* DAY OF THE WEEK.
* CAUTION - ALL REGISTERS MUST BE PRESERVED EXCEPT A5-A6,D5-D7.

* CHECK FOR VALID TIME ON CLOCK

* CHECK THAT YEAR IS 85 THRU 99
GETDT     MOVE.B #$0A,D5           CHECK IF OK TO READ
          BSR.S GETICD             GET UPD IN PROG BIT
          BMI.S GETDT              WAIT UNTIL IT IS ZERO
          MOVE.L #09,D5            YEAR ADDRESS
          BSR.S GETICD             GET DATA FROM CHIP
          CMP.B #85,D5
          BCS.S GETDNG             QUIT IF TIME IS NG
          CMP.B #99,D5
          BHI.S GETDNG             DITTO

* GET THE TIME
GETDT1    MOVE.B #04,D5
          BSR.S GETICD             GET HOUR
          LSL.L #8,D5
          MOVE.B #02,D5
          BSR.S GETICD             GET MINUTE
          LSL.L #8,D5
          MOVE.B #00,D5
          BSR.S GETICD             GET SECOND
          MOVE.L D5,D6             AND INTO D6
          MOVE.B #06,D5
          BSR.S GETICD             GET DAY OF WEEK
          LSL.L #8,D5
          MOVE.B #08,D5
          BSR.S GETICD             GET MONTH
          LSL.L #8,D5
          MOVE.B #07,D5
          BSR.S GETICD             GET DAY
          LSL.L #8,D5
          MOVE.B #09,D5
          BSR.S GETICD             GET YEAR
          MOVE.B #$0A,CLOCKA       CHECK UIP BIT AGAIN
          MOVE.B CLOCKD,D7         GET REGISTER A
          BMI.S GETDT1             REPEAT ALL IF 1
          RTS                      RETURN

* IF TIME IS NG, RETURN 0
GETDNG    MOVE.L #0,D5
          MOVE.L #0,D6
          RTS                      AND THEN QUIT

*****************************************
**** --- PART 5 - OFFSET --- ****
*****************************************

* THE FOLLOWING SETS "OFFSET" ABOVE THESE DRIVERS

DRVEND    EQU  *                   THE END OF THESE DRIVERS
          ORG  OFFINI
          DC.L DRVEND              DRVEND AT OFFINI

*****************************************
**** --- PART 6 - VECTORS --- ****
*****************************************

* THE FOLLOWING VECTORS STEER SK*DOS TO THESE DRIVERS

*         OMIT IF NO CLOCK/CALENDAR >>D<<
          ORG GETDAT               >>A<<
          JMP.L INPDAT             GO TO DATE PATCH TO GET DATE >>A<<

*         OMIT IF NO CLOCK/CALENDAR >>D<<
          ORG INTIME               >>A<<
          JMP.L SETIME             GO TO TIME PATCH TO GET TIME >>A<<

          ORG DICOLD               >>B<<
          JMP.L HDCOLD             COLD INIT HARD DISK DRIVERS >>B<<

          ORG DIWARM               NOTHING NEEDED

          ORG DIREAD
          JMP PRIMRD               PRIMARY READ ROUTINE

          ORG DIWRIT
          JMP PRIMWR               PRIMARY WRITE ROUTINE

          ORG DICHEK
          JMP CHKRDY               PRIMARY DISK READY CHECK

          ORG DIMOFF               NOTHING NEEDED
* ONE OR MORE LINES DELETED IN REV. >>B<<.

          ORG DIREST
          JMP DREST                PRIMARY DISK RESTORE

          ORG DISEEK
          JMP DSEEK                PRIMARY DISK SEEK

          ORG SINITV
          JMP SERINI               SERIAL PORT INITIALIZATION ROUTINE

          ORG STATVE               WITH TYPEAHEAD >>G<<
          JMP STATM                CHECK KEYBOARD STATUS >>G<<

          ORG OUTCHV
          JMP OUTEEE               OUTPUT CHARACTER TO TERMINAL

          ORG INCHV
          JMP INEEE                KEYBOARD INPUT WITH ECHO

          ORG KINPUV               WITH TYPEAHEAD >>G<<
          JMP KINPUM               KEYBOARD INPUT WITHOUT ECHO >>G<<

          ORG OSTATV               >>C<<
          JMP OSTAT                CHECK OUTPUT STATUS >>C<<

          ORG MONITV
          JMP MONITX               RE-ENTER MONITOR

          ORG RESETV
          JMP RESETX               RESET MONITOR/SYSTEM

          ORG TIMINI
          JMP TIMRTS               TIMER INITIALIZE

          ORG TIMOFF
          JMP TIMRTS               TIMER OFF

          ORG TIMON
          JMP TIMRTS               TIMER ON

*         OMIT IF NO CLOCK/CALENDAR >>D<<
          ORG GETDTV               >>D<<
          JMP GETDT                GET DATE AND TIME >>D<<

* THE FOLLOWING THREE VECTORS ARE ONLY USED IF KEYBOARD >>G<<
*    TYPEAHEAD HAS BEEN IMPLEMENTED; OTHERWISE SKIP THEM
* CHECK KEYBOARD STATUS - 1 CHAR W/O TYPEAHEAD
*         ORG STATV1
*         JMP.L STAT
*
* INPUT KBD CHARACTER - 1 CHAR W/O TYPEAHEAD
*         ORG KINPV1
*         JMP.L KINPUT
*
* ERASE TYPEAHEAD BUFFER
*         ORG KILLV1
*         JMP.L KILLTA

*****************************************
**** --- PART 7 - STEPRATE -- **** >>B<<
*****************************************

          ORG STPRAT               >>B<<
          FCB 1,1,1,1              DEFAULT 1772 TO 6 MS >>B<<

          END
