; THIS ROUTINE DOES THE ACTUAL SEEKING. SEEK: LD HL,TRKTAB ; CURRENT TRACK TABLE LD A,(HSTDSK) ; CURRENT DRIVE LD C,A ; MAKE IT AN INDEX INTO LD B,0 ; TRACK TABLE ADD HL,BC ; ADD IN INDEX LD A,(HL) ; PULL OUT THE TRACK FOR THIS DRIVE OUT (FDCTRK),A ; SEND IT TO THE CONTROLLER LD B,A ; SAVE FOR LATER LD A,(HSTTRK) ; GET THE SOUGHT-AFTER TRACK. LD (HL),A ; PLACE IT IN TRACK TABLE CP B ; SAME TRACK? RET Z ; YES, NO NEED TO SEEK OUT (FDCDAT),A ; AND GIVE IT TO THE CONTROLLER. LD A,SEECMD ; THIS IS THE SEEK COMMAND OUT (FDCCMD),A ; GIVE THE ORDER TO FDC ; NOW TEST FOR COMPLETION CALL WAIT ; WAIT UNTIL NOT BUSY AND SEEMSK ; AND OUT TRACK 0 BIT RET ; MAY HAVE FAILED ; THIS ROUTINE LOOPS UNTIL THE FDC IS ; IN A NON-BUSY STATE, OR UNTIL A NOT- ; READY CONDITION IS DETECTED. TIME-OUT ; FOR DRIVE BUSY OCCURS AT APPROX. ; 1.5 SECONDS AFTER COMMAND ; INITIATION. WAIT: LD A,15 ; WE MUST DELAY ABOUT WAIT10: DEC A ; 60 USECS. BEFORE READING JR NZ,WAIT10 ; THE STATUS. LD (TEMPBC),BC ; SAVE REGISTERS LD (TEMPDE),DE LD (TEMPHL),HL LD BC,0C000H ; TIME OUT FOR 1.25 SECONDS LD A,0 LD (JMPSW),A ; RESET THE FLAG FOR MESSAGE WAIT20: IN A,(FDCCMD) ; READ THE FDC STATUS--2.75 LD (ERFLAG),A ; SAVE IT FOR LATER--3.25 BIT FDCRDY,A ; IS THE DEVICE NOT READY?--2.00 JR NZ,WAIT50 ; YES, THIS IS AN ERROR--1.25 PUSH AF ; SAVE REGISTERS--2.75 LD A,(JMPSW) ; GET MESSAGE FLAG--3.25 CP 0 ; MESSAGE ALREADY SENT OUT?--1.75 JR NZ,WAIT30 ; YES, SKIP--1.75 DEC BC ; COUNT DOWN--1.50 LD A,B ; --2.25 OR C ; TIME OUT?--1.00 CALL Z,SIGMSG ; YES, PRINT MESSAGE--2.50 WAIT40: POP AF ; RESTORE REGISTERS--2.50 BIT FDCBSY,A ; ARE WE PROCESSING A COMMAND?--2.00 JR NZ,WAIT20 ; NO, RETURN ERROR CODE--3.00 LD (UNMSTA),A ; UNMASKED STATUS (FOR DEBUG) AND ERRMSK ; MASK OFF NON-ERROR BITS LD (ERFLAG),A ; SAVE STATUS FOR LATER WAIT50: LD HL,(TEMPHL) ; RESTORE REGISTERS LD DE,(TEMPDE) LD BC,(TEMPBC) RET WAIT30: CALL CONST ; CONSOLE STATUS CP 0 ; AVAILABLE INPUT? JR Z,WAIT40 ; NO, SKIP CALL CONIN ; GET CHARACTER CP 03H ; CONTROL-C? JR NZ,WAIT40 ; NO, LOOP BACK POP AF ; RESTORE REGISTERS LD HL,(TEMPHL) LD DE,(TEMPDE) LD BC,(TEMPBC) LD A,FRCCMD ; FORCE TERMINATE OUT (FDCCMD),A OUT (FDCCMD),A CALL RESDMA ; RESET DMA LD A,0 LD (DEFDSK),A ; SET DEFAULT DRIVE TO A JP WBOOT ; WARM-BOOT ; THIS ROUTINE PRINTS DOOR MESSAGE WHEN THERE IS AN ACCESS TO ; A DRIVE WITH DOOR OPENED SIGMSG: LD A,1 ; SET FLAG LD (JMPSW),A LD A,(HSTDSK) ; CURRENT DRIVE ADD A,41H ; MAKE IT ASCII LD (VDRIVE),A ; SAVE FOR LATER LD HL,RDYMSG ; PRINT DOOR MESSAGE CALL PRTMSG RET ; SELECT THE PROPER SIDE OF THE ; DISKETTE TO SEEK, DEPENDING ON ; THE LOGICAL SECTOR NO. IN HSTSEC. ; GO AHEAD AND SET THE FDC SECTOR ; REGISTER. SELSID: LD A,(FDDBYT) ; GET THE DRIVE SELECT LATCH IN MEMORY LD C,A ; HOLD IT IN C FOR A BIT. RES 2,C ; CHOOSE SIDE 0, FOR NOW. LD A,(HSTSEC) ; GET THE LOGICAL HOST SECTOR CP PSPT0 ; SECTOR >= THAN MAXIMUM SECTOR? JR C,SELS10 ; IF NOT THEN SELECT SIDE 0 SET 2,C ; CHOOSE SIDE 1. SUB PSPT0 ; DE-BIAS SECTOR NO. SELS10: INC A ; PHYSICAL SECTORS HAVE ORIGIN 1 OUT (FDCSEC),A ; SEND SECTOR TO CONTROLLER LD (TSEC),A ; SAVE FOR LATER LD A,C ; GET NEW SIDE. LD (FDDBYT),A ; RESTORE IT TO THE MEMORY IMAGE OUT (FDD),A ; AND LATCH RET ; ALL DONE. ; SELECT THE DRIVE IN HARDWARE. ; DRIVE TO BE SELECTED IS PASSED ; IN REGISTER A. SELDRV: LD (HL),A ; SAVE CURRENT DRIVE FOR LATER LD C,00010000B ; THIS IS THE MASK FOR DRIVE 0 SELD10: OR A ; HAVE WE GOT THE RIGHT MASK? JR Z,SELD20 ; YES. SLA C ; SHIFT DRIVE MASK OVER 1 BIT LEFT. DEC A ; DOWN THE COUNTER. JR SELD10 ; AND LOOP. SELD20: LD A,(FDDBYT) ; GET MEMORY IMAGE OF DRIVE LATCH AND 00001111B ; AND OFF CURRENT DRIVE SELECT BITS. OR C ; OUT WITH THE OLD, IN WITH THE NEW LD (FDDBYT),A ; RESTORE MEMORY IMAGE. OUT (FDD),A ; AND INFORM LATCH ABOUT NEW DRIVE. RET ; RESET THE DISK SUBSYSTEM BY RESTORING ; ALL THE HEADS TO TRACK 0. RESTORING ; DRIVES IN REVERSE ORDER ASSURES THAT ; DRIVE A WILL ALWAYS BE SELECTED UPON ; COMPLETION. RESDSK: LD A,00000010B ; INITIALIZE THE FDD LATCH, MOTOR ON LD (FDDBYT),A ; MEMORY IMAGE. OUT (FDD),A ; HARDWARE LATCH. LD B,MAXDRV ; INITIAL DRIVE NO. RESD10: LD A,B ; SELECT THE DRIVE LD (HSTDSK),A ; STORE IT IN HSTDSK LD HL,DRIVE CALL SELDRV CALL RESTOR ; RESTORE THE HEADS TO TRACK 0 DEC B ; DECREMENT DRIVE NO. JP P,RESD10 ; LOOP FOR NEXT DRIVE RET ; RESTORE THE HEADS ON THE CURRENTLY ; SELECTED DRIVE TO TRACK 0. THIS IS ; DONE AFTER EACH SEEK, READ, OR, WRITE ; FAILURE. ALSO AT WARM AND COLD BOOT. ; WE MUST RESET THE CURRENT TRACK FOR ; THIS DRIVE ALSO. RESTOR: LD A,(HSTDSK) ; GET THE CURRENT DRIVE LD HL,TRKTAB ; BASE ADDRESS OF CURRENT TRACK TABLE LD E,A LD D,0 ; MAKE DRIVE NO. AN INDEX. ADD HL,DE ; ADD IN INDEX. LD (HL),0 ; CLEAR CURRENT TRACK TO 0. LD A,RESCMD ; FDC RESTORE COMMAND OUT (FDCCMD),A ; SEND IT. CALL WAIT ; WAIT FOR COMPLETION RET ; RESET THE DMA SIX TIMES TOTAL RESDMA: PUSH BC ; DON'T DESTROY REGGIES LD B,6 ; COUNTER RDMA10: LD A,11000011B ; RESET THE DMA OUT (DMA),A ; SO THAT IT DOESN'T RUN ON. DJNZ RDMA10 ; LOOP FOR ANOTHER TIME POP BC ; RESTORE REGISTER PAIR RET ; ALL DONE ; MISCELANEOUS ROUTINES ; PRINT THE STRING POINTED TO BY HL ; AND TERMINATED BY NULL (0). PRTMSG: LD A,(HL) OR A RET Z ; ALL DONE LD C,A PUSH HL CALL CONOUT ; OUTPUT IT POP HL INC HL JR PRTMSG ; AND LOOP BACK ; GENERAL PORT INITIALIZATION ROUTINE ; ENTRY: HL -> PORT ADDRESS ; BYTE COUNT ; DATA ; | ; | PRTINI: LD C,(HL) ; GET PORT ADDRESS INC HL PRTENT: LD B,(HL) ; GET THE COUNT INC HL ; POINT TO FIRST DATA BYTE OTIR ; BLOCK OUTPUT RET ; ADDITIONAL HARWARE SYSTEM ; HARDWARE INITIALIZATION ; COMES NEXT. HDWINI: CALL RESDSK ; RESET THE DISK SUBSYSTEM LD HL,SIOTAB ; INITIALIZE SIO #1 FOR SERIAL PRINTER CALL PRTINI ; BAUD RATE IS SET UP IN PROM CODE ; BY READING THE DIP SWITCH ; INITIALIZE MODEM PORT LD C,CTCP0 ; CTC #0, FOR MODEM PORT LD A,CTCM0 ; CTC #0 CONTROL REGISTER OUT (C),A LD A,BAUD1 ; SET BAUD RATE (300) OUT (C),A LD HL,MODTAB ; INITIALIZE MODEM PORT CALL PRTINI ; INITIALIZE TIME AND DATE COUNTER LD C,CTCP3 LD A,10110101B ; INITIALIZE TIMER OUT (C),A LD A,156 ; PRESET TIMER COUNTER OUT (C),A LD HL,CTCI3 LD A,L AND 0FEH ; SET TIMER INTERRUPT VECTOR(LSB) OUT (CTCP0),A LD A,10H OUT (SIOBC0),A ; RESET EXT/STATUS LATCH COMMAND IN A,(SIOBC0) AND 20H ; CHECK CTS BIT LD A,24H ; CTS+TXMT READY JR Z,XMIT0 LD A,0FH ; ENABLE XON/XOFF TO CRT LD (SIGNON),A LD A,4 XMIT0: LD (CRTMSK),A ; CRTMSK = 4H(TXMT RDY) OR 24H(CTS+TXMT RDY) RET ; THIS ROUTINE TRANSFERS CONTROL TO ; THE I/O DRIVER INDICATED BY THE ; APPROPRIATE BITS IN IOBYTE (0003H). ; ENTRY: HL -> ; ; ; ; IODISP: POP HL ; GET DISPATCH TABLE POINTER PUSH BC ; SAVE PERTINENT REGISTERS PUSH DE LD A,(HL) ; DEVICE TYPE INC HL ; ADVANCE POINTER LD B,A ; SAVE DEVICE TYPE FOR LATER OR A ; WHICH DEVICE? LD A,(IOBYTE) ; RETREIVE CURRENT IOBYTE JR Z,IODI20 ; NO SHIFTING NEEDED IODI10: RRA ; ROTATE BYTE UNTIL DEVICE BITS DJNZ IODI10 ; ARE LINED UP WITH BIT 0 IODI20: AND 03H ; MASK OFF DON'T CARE BITS RLA ; FORM WORD OFFSET LD C,A ; FORM 16 BITS, B ALREADY 0 ADD HL,BC ; ADD IN BASE ADDRESS LD E,(HL) ; TRANSFER DISPATCH ADDRESS INC HL ; TO REGISTERS DE LD D,(HL) EX DE,HL ; RESULT INTO HL POP DE ; RESTORE REGISTERS POP BC JP (HL) ; OFF WE GO, INTO THE WILD BLUE YONDER! ; ; TIMER INTERRUPT SERVICE ROUTINE ; Keeps time and date. ; Provides capability to set and read time and date. ; Shuts off floppy disk motor after 30 sec of no access. ; TCOUNT: DI LD (TUSTACK),SP ; SAVE USER STACK LD SP,LSTACK ; SET STACK POINTER TO LOCAL PUSH AF PUSH HL LD HL,(MSECNT) INC HL LD (MSECNT),HL ; INCREMENT 16-BIT MS COUNTER ; ; LD A,10110111B ; INITIALIZE TIMER ; OUT (CTCP3),A ; LD A,156 ; PRESET TIMER COUNTER (1/100 SEC) ; OUT (CTCP3),A ; LD HL,CLOCK CALL TCOUN4 ; COUNT 1/100 SEC. JP NZ,TEXIT ; SKIP IF NOT OVERFLOW 99 (BCD) ; CALL FLOPOFF ; TURN OFF FLOPPY DISK? ; ; ELSE RESET PRECOUNTER AND ADD 1 TO SEC. ; CALL TCOUN1 CP 060H ; CHECK FOR SEC. OVERFLOW JP NZ,TEXIT ; SKIP IF NOT ; CALL TCOUN1 ; ADD 1 TO MINUTE COUNT CP 060H JR NZ,TEXIT ; SKIP IF NOT OVERFLOW ; ; ELSE RESET MINUTE COUNT AND ADD 1 TO HOUR ; CALL TCOUN1 CP 024H ; CHECK OVERFLOW JR NZ,TEXIT ; CALL TCOUN1 ; RESET HOUR TO 0 AND ADD 1 TO DATE COUNT CP 029H ; CHECK DATE = 29 JR C,TEXIT ; SKIP IF DATE < 29 ; CALL NC,CHKM28 ; IF DATE >= 29 THEN CHECK MONTH = FEB JR Z,TCOUN3 ; SKIP IF FEB 29TH ; LD A,(HL) ; CHECK DATE = 31 CP 031H CALL NC,CHKM30 ; IF DATE >= 30 THEN CHECK MONTH=4,6,9,11? JR Z,TCOUN3 ; SKIP IF MONTH = 4,6,9,11 ; LD A,(HL) CP 032H ; CHECK DATE = 32 JR C,TEXIT ; ; ADJUST MONTH AND RESET SET DATE = 1 ; TCOUN3: LD (HL),1 ; RESET DATE = 1 CALL TCOUN2 ; MONTH = MONTH + 1 CP 013H JR C,TEXIT ; SKIP IF MONTH < 13 LD (HL),1 ; RESET MONTH = 1 CALL TCOUN2 ; AND ADD 1 TO YEAR JR NZ,TEXIT ; SKIP IF LSB OF YEAR > 0 CALL TCOUN2 ; ELSE ADD 1 TO MSB OF YEAR COUNT TEXIT: POP HL POP AF LD SP,(TUSTACK) ; RESTORE USER STACK EI RETI TCOUN1: LD (HL),0 ; RESET BCD TO 0 TCOUN2: INC HL TCOUN4: LD A,(HL) ; ADD 1 TO NEXT COUNT ADD A,1 DAA LD (HL),A RET ; ; CHECK MONTH = 2 ; RETURN Z = 1 IF YES, ELSE Z = 0 ; CHKM28: INC HL LD A,(HL) DEC HL CP 2 RET ; ; CHECK MONTH = 4,6,9 OR 11 ; RETURN Z = 1, ELSE Z = 0 ; CHKM30: INC HL LD A,(HL) DEC HL CP 4 RET Z CP 6 RET Z CP 9 RET Z CP 011H RET ; ; DATE AND TIME INTERFACE ROUTINE ; ENTRY: READ CURRENT DATE AND TIME ; C-REG = 0 AND DE = DATE AND TIME BUFFER POINTER ; SET CURRENT DATE AND TIME ; C-REG = 1 AND DE = BUFFER POINTER ; RETURN: CURRENT DATE AND TIME IN USER BUFFER ; FORMAT: MM?DD?YYYY?HH?MM?SS?NN ; TOD: DEC C JR Z,SETOD ; SET CURRENT DATE AND TIME ; RDTOD: LD HL,MONTH CALL BCDASC ; CONVERT BCD TO ASCII AND SAVE INTO (DE) INC DE DEC HL ; ADDRESS DATE CALL BCDASC INC DE INC HL ; ADDRESS YEAR INC HL INC HL CALL BCDASC ; SAVE MSB OF YEAR DEC HL ; ADDRESS LSB OF YEAR CALL BCDASC ; SAVE LSB OF YEAR ; INC DE ; SKIP FILLER LD HL,HOUR CALL BCDASC ; SAVE HOUR INC DE DEC HL CALL BCDASC ; SAVE MINUTE INC DE DEC HL CALL BCDASC ; SAVE SECOND INC DE DEC HL CALL BCDASC ; SAVE 1/100 SEC LD A,(TINITF) ; SET A = INITIALIZE FLAG RET ; ; SET CURRENT DATE AND TIME ; SETOD: LD HL,MONTH CALL ASCBCD LD (HL),A ; SET MONTH INC DE DEC HL CALL ASCBCD LD (HL),A ; SET DATE INC DE LD HL,YEAR+1 CALL ASCBCD LD (HL),A ; SET YEAR MSB DEC HL CALL ASCBCD ; SET YEAR LSB LD (HL),A ; INC DE LD HL,HOUR CALL ASCBCD LD (HL),A ; SET HOUR DEC HL INC DE CALL ASCBCD LD (HL),A ; SET MINUTE DEC HL INC DE CALL ASCBCD LD (HL),A ; SET SECOND DEC HL XOR A LD (HL),A ; RESET 1/100 SEC COUNT TO 0 LD (TINITF),A ; SET DATE AND TIME INITIALIZE FLAG RET ; ; CONVERT 1 BYTE BCD TO 2 BYTES ASCII ; AND SAVE IT INTO (DE) ; BCDASC: LD A,(HL) RRA RRA RRA RRA CALL BCDAS1 LD A,(HL) BCDAS1: AND 0FH OR '0' LD (DE),A INC DE RET ; ; CONVERT 2 BYTE ASCII DIGIT TO 1 BYTE BCD ; ASCBCD: LD A,(DE) RLA RLA RLA RLA AND 0F0H LD C,A ; SAVE MSN TO C-REG INC DE LD A,(DE) AND 0FH ; GET LSN OR C ; PACK IT INC DE RET ; ; TURN FLOPPY DRIVES MOTOR OFF? ; FLOPOFF: LD A,(FDTIME) ; MOTOR OFF DISABLE OR A RET Z DEC A ; TIME = TIME - 1 LD (FDTIME),A RET NZ ; EXIT IF NOT TIMEOUT XOR A OUT (FDD),A ; ELSE RESET DRIVE SELECT AND TURN MOTOR OFF LD (MOTFLG),A ; SET MOTOR OFF INDICATION RET ; ; RETURN DE = ADDRESS OF INTERRUPT VECTOR TABLE ; FOR USER PROGRAM WANT TO USE 16-BIT COUNTER ; THAT INCREMENT AT EVERY 10 MS THEN ; DE-2 = LSB COUNT, DE-1 = MSB COUNT INTADD: LD DE,INTVEC ; SET DE=INTERRUPT TABLE ADDRESS RET ; THIS ROUTINE FILLS OUT THE DETAILED ERROR MESSAGE TABLE ; OBTAINING VARIABLE VALUES FROM CURRENT STATE. ; THEN CALLS PRTMSG ROUTINE WITH THE TABLE ADDRESS IN HL ERRPRT: LD A,(COMAND) ; CURRENT COMMAND CP 80H ; READ? JR NZ,WRMSG ; NO, SKIP LD HL,RMSG ; READ MESSAGE JR ERR10 WRMSG: LD HL,WMSG ; WRITE MESSAGE ERR10: LD DE,VCMD ; COMMAND MESSAGE ADDRESS IN TABLE LD BC,5 LDIR ; STORE IN TABLE LD A,(HSTDSK) ; CURRENT HOST DISK ADD A,41H ; MAKE IT ASCII LD HL,VDRV ; GET DRIVE TABLE ADDRESS LD (HL),A LD A,(HSTTRK) ; GET CURRENT TRACK NUMBER LD E,A LD D,0 LD HL,VTRK ; GET TRACK TABLE ADDRESS CALL CVD2 ; CONVERT IT DECIMAL, STORE IN TABLE LD A,(HSTSEC) ; CURRENT SECTOR NUMBER LD E,A LD D,0 LD HL,VSEC CALL CVD2 LD HL,VSTAT ; FDC STATUS TABLE ADDRESS LD A,(ERFLAG) ; GET STATUS CODE CALL FTAB ; CONVERT IT AS HEX ASCII, STORE IN TABLE LD HL,ERRMSG ; ERROR MESSAGE TABLE ADDRESS CALL PRTMSG RET ; THIS ROUTINE CONVERTS HEX CODE INTO ASCII AND FILL OUT THE TABLE FTAB: PUSH AF ; SAVE REGISTERS RRCA ; ROTATE RIGHT 4 TIMES RRCA RRCA RRCA CALL GHEX ; CONVERT HIGH ORDER 4 BITS TO ASCII LD (HL),A ; STORE INTO TABLE INC HL ; NEXT TABLE LOCATION POP AF ; RESTORE REGISTERS CALL GHEX LD (HL),A RET ; HEX INTO ASCII ROUTINE GHEX: AND 0FH ; STRIP HIGH 4 BITS CP 10 ; NUMERIC? JR NC,G10 ; YES, SKIP FOR ALPHA ADD A,'0' ; ADD 30 RET G10: ADD A,'A'-10 ; ADD 40 RET ; DECIMAL CONVERSION ROUTINE CVD2: LD BC,10 ; 2 DIGIT CONVERSION CALL CVD CVD1: LD BC,1 ; 1 DIGIT CONVERSION CALL CVD RET CVD: XOR A EX DE,HL ; SWAP DE(DATA) FOR HL(OUTPUT POINTER) CVDL: OR A ; CLEAR CARRY FLAG SBC HL,BC ; HL(DATA)-BC(POWER OF 10) JP M,CVDX ; IF RESULT=NEG, THEN EXIT INC A ; OTHERWISE, ADD 1 TO RESULT JR CVDL CVDX: ADD HL,BC ; ADD BACK LAST VALUE EX DE,HL ; SWAP BACK DE AND HL ADD A,'0' ; CONVERT RESULT TO ASCII LD (HL),A ; STORE IT IN OUTPUT AREA INC HL ; BUMP OUTPUT POINTER RET ; CARRIAGE RETURN, LINE FEED CRLF: LD C,0DH CALL CONOUT ; PRINT A CR LD C,0AH JP CONOUT ; PRINT A LF ; END OF 802FSUBS.MAC