; BASIC INPUT/OUTPUT OPERATING SYSTEM ; TARBELL ELECTRONICS ; 4-DRIVE VERSION OF 8-13-77 ; (NOTE THAT CP/M PRESENTLY ONLY SUPPORTS 2 DRIVES) ; ; THIS MODULE CONTAINS ALL THE INPUT/OUTPUT ; ROUTINES FOR THE CP/M SYSTEM, INCLUDING ; THE DISK ROUTINES. ; 0018 = MSIZE EQU 24 ;MEMORY SIZE. 00F8 = DCOM EQU 0F8H ;DISK COMMAND PORT. 00F8 = DSTAT EQU 0F8H ;DISK STATUS PORT. 00F9 = TRACK EQU 0F9H ;DISK TRACK COMMAND. 00FA = SECTP EQU 0FAH ;DISK SECTOR COMMAND. 00FB = DDATA EQU 0FBH ;DISK DATA PORT. 00FC = WAIT EQU 0FCH ;DISK WAIT COMMAND. 000A = RTCNT EQU 10 ;RETRY COUNT. 5A00 ORG MSIZE*1024-1536 ;THIS SETS FIRST ADR. 59F6 = TRK EQU $-10 ;ADDRESS OF TRACK NUMBER. 59F7 = SECT EQU TRK+1 ;ADDRESS OF SECTOR NUMBER. 59F8 = DMAADD EQU TRK+2 ;DMA ADDRESS. 59FA = DISKNO EQU TRK+4 ;ADDRESS OF DISK NUMBER. 1C00 = CBASE EQU (MSIZE-17)*1024 ;TEMPORARY CALCULATION. 4500 = CPMB EQU CBASE+2900H ;START OF CP/M SYSTEM. 4E06 = BDOS EQU CBASE+3206H ;START OF BDOS. 1500 = CPML EQU $-CPMB ;LENGTH OF CPM SYSTEM. 002A = NSECTS EQU CPML/128 ;NUMBER OF SECTORS IN CP/M. ; ; 5A00 C3335A JMP BOOT ;FROM COLD START LOADER. 5A03 C34B5A WBOOTE: JMP WBOOT ;FROM WARM START. 5A06 C3BE5A JMP CONST ;CHECK FOR CONSOLE CHAR READY. 5A09 C3C75A JMP CONIN ;READ CONSOLE CHARACTER. 5A0C C3D35A JMP CONOT ;WRITE CONSOLE CHARACTER. 5A0F C3995D JMP LIST ;WRITE LISTING CHAR. 5A12 C3A45D JMP PUNCH ;WRITE PUNCH CHAR. 5A15 C3AF5D JMP READER ;WRITE READER CHAR. 5A18 C3DE5A JMP HOME ;MOVE DISK TO TRACK ZERO. 5A1B C3085B JMP SELDSK ;SELECT DISK DRIVE. 5A1E C3505B JMP SETTRK ;SET TRACK NUMBER. 5A21 C3585B JMP SETSEC ;SET SECTOR NUMBER. 5A24 C35D5B JMP SETDMA ;SET DMA ADDRESS. 5A27 C3755B JMP READ ;READ SELECTED SECTOR. 5A2A C31A5C JMP WRITE ;WRITE SELECTED SECTOR. 5A2D C3635B JMP READN ;READ WITH NO HEAD LOAD. 5A30 C3065C JMP WRITEN ;WRITE WITH NO HEAD LOAD. ; ; 5A33 318000 BOOT: LXI SP,80H ;SET STACK POINTER. 5A36 21545D LXI H,SMSG ;PRINT OPENING MESSAGE. 5A39 CDAE5C CALL PMSG 5A3C CDC75A CALL CONIN ;READ # OF DISKS. 5A3F 4F MOV C,A ;ECHO THE CHAR. 5A40 CDD35A CALL CONOT 5A43 E60F ANI 0FH ;LOOK AT 4 LSB'S. 5A45 32C25D STA NODSKS ;SAVE IT. 5A48 C39C5A JMP GOCPM ; ; 5A4B 318000 WBOOT: LXI SP,80H ;SET STACK POINTER. 5A4E 3EF2 MVI A,0F2H ;SELECT DISK 0. 5A50 D3FC OUT WAIT 5A52 AF XRA A ;PUT ZEROES INTO 5A53 21BE5D LXI H,TRTAB ;TRACK TABLE. 5A56 77 MOV M,A 5A57 23 INX H 5A58 77 MOV M,A 5A59 23 INX H 5A5A 77 MOV M,A 5A5B 23 INX H 5A5C 77 MOV M,A 5A5D CDDE5A WBOOT1: CALL HOME ;MOVE TO TRACK ZERO. 5A60 C2905A JNZ RDERR ;IF ERROR, PRINT MESSAGE. 5A63 162A MVI D,NSECTS ;GET # SECTORS FOR CPM READ. 5A65 010200 LXI B,2 ;TRACK (B)=0, SECTOR (C)=2. 5A68 210045 LXI H,CPMB ;GET STARTING ADDRESS. 5A6B 78 RDBLK: MOV A,B ;GO TO TRACK IN B. 5A6C CD6E5C CALL SEEK 5A6F C2905A JNZ RDERR ;IF ERROR, PRINT MESSAGE. 5A72 79 MOV A,C ;READ STARTING AT SECTOR IN C. 5A73 CD805B CALL READ1 5A76 C2905A RBLK1 JNZ RDERR ;IF ERROR, PRINT MESSAGE. 5A79 15 DCR D ;DECREMENT SECTOR COUNT. 5A7A CA9C5A JZ GOCPM ;GO BACK TO CPM WHEN DONE. 5A7D 0C INR C ;INCREMENT SECTOR NUMBER. 5A7E 79 MOV A,C ;IF SECTOR NUMBER 5A7F FE1B CPI 27 ;IS NOT 27, 5A81 DA8A5A JC RBLK2 ;HOP OUT OF LOOP. 5A84 0E01 MVI C,1 ;OTHERWISE, RESET SECTOR=1 5A86 04 INR B ;INCREMENT TRACK NUMBER, 5A87 C36B5A JMP RDBLK ;AND READ NEXT TRACK. ; 5A8A CD6E5B RBLK2: CALL READ2 ;READ ANOTHER TRACK. 5A8D C3765A JMP RBLK1 ; 5A90 21145D RDERR: LXI H,BTMSG ;GET ADDRESS OF "BOOT ERROR". 5A93 CDAE5C CALL PMSG ;PRINT IT. 5A96 CDC75A CALL CONIN ;READ A CHAR FROM CONSOLE. 5A99 C34B5A JMP WBOOT ;DO A WARM BOOT. ; ; 5A9C AF GOCPM: XRA A ;SET DISK NUMBER = 0. 5A9D 32FA59 STA DISKNO 5AA0 3EC3 MVI A,0C3H ;PUT JUMP TO WARM BOOT 5AA2 320000 STA 0 ;ADDRESS AT ZERO. 5AA5 21035A LXI H,WBOOTE 5AA8 220100 SHLD 1 5AAB 320500 STA 5 5AAE 21064E LXI H,BDOS ;PUT JUMP TO BDOS 5AB1 220600 SHLD 6 ;AT 5. 5AB4 218000 LXI H,80H ;SET DEFAULT DMA ADDRS. 5AB7 22F859 SHLD DMAADD 5ABA 4C MOV C,H ;SELECT DISK 0 5ABB C30045 JMP CPMB ; ; CHECK CONSOLE INPUT STATUS. ; 5ABE DB00 CONST: IN 0 ;READ CONSOLE STATUS. 5AC0 E601 ANI 1 ;LOOK AT BIT 0. 5AC2 3E00 MVI A,0 ;SET A = 0. 5AC4 C0 RNZ ;RETURN IF NOT READY WITH A = 0. 5AC5 2F CMA ;IF READY, A = FF. 5AC6 C9 RET ; ; READ A CHARACTER FROM CONSOLE. ; 5AC7 DB00 CONIN: IN 0 ;READ CONSOLE STATUS. 5AC9 E601 ANI 1 ;IF NOT READY, 5ACB C2C75A JNZ CONIN ;KEEP WAITING. 5ACE DB01 IN 1 ;READ A CHARACTER. 5AD0 E67F ANI 7FH ;MAKE MOST SIG. BIT = 0. 5AD2 C9 RET ; ; WRITE A CHARACTER TO THE CONSOLE DEVICE. ; 5AD3 DB00 CONOT: IN 0 ;READ CONSOLE STATUS. 5AD5 E680 ANI 80H ;IF NOT READY, 5AD7 C2D35A JNZ CONOT ;KEEP WAITING. 5ADA 79 MOV A,C ;GET CHARACTER. 5ADB D301 OUT 1 ;PRINT IT. 5ADD C9 RET ; ; MOVE DISK TO TRACK ZERO. ; 5ADE 3ED0 HOME: MVI A,0D0H ;CLEAR ANY PENDING COMMAND 5AE0 D3F8 OUT DCOM 5AE2 DBF8 HOME1: IN DSTAT ;READ DISK STATUS. 5AE4 0F RRC 5AE5 DAE25A JC HOME1 ;WAIT FOR NOT BSY 5AE8 3E02 MVI A,2 ;10 MS STEP RATE. 5AEA D3F8 OUT DCOM ;ISSUE HOME COMMAND 5AEC DBFC IN WAIT ;WAIT FOR INTRQ 5AEE B7 ORA A 5AEF FAFE5A JM HERR ;ERROR IF DRQ. 5AF2 DBF8 IN DSTAT ;READ DISK STATUS. 5AF4 5F MOV E,A ;SAVE IN REGISTER E. 5AF5 E604 ANI 4 ;LOOK AT BIT 2. 5AF7 CAFE5A JZ HERR ;ERROR IF NOT TRK. 0 5AFA 7B MOV A,E ;GET STATUS BACK. 5AFB E691 ANI 91H ;MASK NON-ERROR BITS. 5AFD C8 RZ ;RETURN IF NO ERROR. 5AFE 212E5D HERR: LXI H,HEMSG ;PRINT "HOME ERROR". 5B01 CDAE5C CALL PMSG 5B04 3E01 MVI A,1 ;SET HARDWARE ERROR. 5B06 B7 ORA A 5B07 C9 RET ; ; SELECT DISK NUMBER. ; 5B08 79 SELDSK: MOV A,C ;GET NEW DISK NUMBER. 5B09 E603 ANI 3 ;ONLY LOOK AT 2 LSB'S. 5B0B 21FA59 LXI H,DISKNO ;GET ADR OF OLD DISK NO. 5B0E BE CMP M ;NEW=OLD? 5B0F C8 RZ ;IF SO, RETURN. 5B10 F5 PUSH A ;SAVE DISK NUMBER. 5B11 3AC25D LDA NODSKS ;GET NUMBER OF DISKS. 5B14 FE01 CPI 1 ;IF MORE THAN ONE DISK, 5B16 C22E5B JNZ SELMOR ;TAKE CARE OF IT. 5B19 214B5D LXI H,MNTMSG ;GET ADR OF MOUNT MESSAGE. 5B1C CDAE5C CALL PMSG ;PRINT "MOUNT ". 5B1F F1 POP A ;GET DISK NUMBER. 5B20 32FA59 STA DISKNO ;UPDATE OLD WITH NEW. 5B23 C641 ADI 'A' ;ADD ASCII FOR 'A'. 5B25 4F MOV C,A ;PUT INTO C. 5B26 CDD35A CALL CONOT ;PRINT IT. 5B29 CDC75A CALL CONIN ;READ A CARRIAGE RETURN. 5B2C AF XRA A ;SET A=0 FOR NO ERRO IND. 5B2D C9 RET ;RETURN FROM SELDSK. 5B2E F1 SELMOR: POP A ;RECOVER REGISTER A. 5B2F 5E MOV E,M ;PUT OLD DISK NO. IN D&E. 5B30 1600 MVI D,0 5B32 21BE5D LXI H,TRTAB ;GET ADDRESS OF TRACK TABLE. 5B35 19 DAD D ;ADD DISK NO. TO ADDRESS. 5B36 DBF9 IN TRACK ;READ 1771 TRACK REGISTER. 5B38 77 MOV M,A ;PUT INTO TABLE. 5B39 59 MOV E,C ;PUT NEW DISK NO. IN D&E. 5B3A 21BE5D LXI H,TRTAB ;GET ADDRESS OF TRACK TABLE. 5B3D 19 DAD D ;ADD DISK NO. TO ADDRESS. 5B3E 7E MOV A,M ;GET NEW TRACK NUMBER. 5B3F D3F9 OUT TRACK ;PUT INTO 1771 TRACK REG. 5B41 79 MOV A,C ;UPDATE OLD DISK NUMBER. 5B42 32FA59 STA DISKNO 5B45 2F CMA ;BITS INVERTED INTO LATCH. 5B46 87 ADD A ;PUT BITS 1&2 AT 4&5. 5B47 87 ADD A 5B48 87 ADD A 5B49 87 ADD A 5B4A F602 ORI 2 ;MAKE LATCH COMMAND. 5B4C D3FC DSK1: OUT WAIT ;SET THE LATCH WITH CODE. 5B4E AF XRA A ;SET A = 0. 5B4F C9 RET ;RETURN FROM SELDSK. ; ; SET TRACK NUMBER TO WHATEVER IS IN REGISTER C. ; ALSO PERFORM MOVE TO THE CORRECT TRACK (SEEK). ; 5B50 79 SETTRK: MOV A,C ;GET NEW TRACK NUMBER. 5B51 32F659 STA TRK ;UPDATE OLD WITH NEW. 5B54 CD6E5C CALL SEEK ;MOVE TO NEW TRACK. 5B57 C9 RET ;RETURN FROM SETTRK ROUTINE. ; ; SET DISK SECTOR NUMBER. ; 5B58 79 SETSEC: MOV A,C ;GET SECTOR NUMBER. 5B59 32F759 STA SECT ;PUT AT SECT # ADDRESS. 5B5C C9 RET ;RETURN FROM SETSEC. ; ; SET DISK DMA ADDRESS. ; 5B5D 60 SETDMA: MOV H,B ;MOVE B&C TO H&L. 5B5E 69 MOV L,C 5B5F 22F859 SHLD DMAADD ;PUT AT DMA ADR ADDRESS. 5B62 C9 RET ;RETURN FROM SETDMA. ; ; READ THE SECTOR AT SECT, FROM THE PRESENT TRACK. ; DO NO HEAD LOAD. USE STARTING ADR AT DMAADD. ; 5B63 3E0A READN: MVI A,RTCNT ;SET RETRY COUNT. 5B65 32C35D STA ERCNT 5B68 3AF759 LDA SECT ;GET SECTOR NUMBER 5B6B 2AF859 LHLD DMAADD ;AND STARTING ADDRESS. ; ; READ A SECTOR WITHOUT LOADING HEAD FIRST. ; 5B6E D3FA READ2: OUT SECTP ;SET SECTOR NUMBER INTO 1771. 5B70 3E88 MVI A,88H ;GET CODE FOR READ W/O HLD. 5B72 C3845B JMP READE ;READ A SECTOR. ; ; READ THE SECTOR AT SECT, FROM THE PRESENT TRACK. ; USE STARTING ADDRESS AT DMAADD. ; 5B75 3E0A READ: MVI A,RTCNT ;GET RETRY COUNT. 5B77 32C35D RRETRY: STA ERCNT ;STORE IN ERROR COUNTER. 5B7A 3AF759 LDA SECT ;GET SECTOR NUMBER. 5B7D 2AF859 LHLD DMAADD ;GET STARTING ADDRESS. 5B80 D3FA READ1: OUT SECTP ;SET SECTOR INTO 1771. 5B82 3E8C MVI A,8CH ;CODE FOR READ W/O HEAD LOAD. 5B84 D3F8 READE: OUT DCOM ;SEND COMMAND TO 1771. 5B86 DBFC RLOOP: IN WAIT ;WAIT FOR DRQ OR INTRQ 5B88 B7 ORA A ;SET FLAGS. 5B89 F2935B JP RDDONE ;DONE IF INTRQ 5B8C DBFB IN DDATA ;READ A DATA BYTE FROM DISK. 5B8E 77 MOV M,A ;PUT BYTE INTO MEMORY. 5B8F 23 INX H ;INCREMENT MEMORY POINTER. 5B90 C3865B JMP RLOOP ;KEEP READING. 5B93 DBF8 RDDONE: IN DSTAT ;READ DISK STATUS. 5B95 E69D ANI 9DH ;LOOK AT ERROR BITS. 5B97 C8 RZ ;RETURN IF NONE. 5B98 CDE35B CHECK: CALL ERCHK ;CHECK FOR SEEK ERROR. 5B9B 21BB5D LXI H,RECNT ;GET RD ERR COUNT ADDR. 5B9E 34 INR M ;ONE MORE ERROR. 5B9F 3AC35D LDA ERCNT ;GET ERROR COUNT. 5BA2 3D DCR A ;DECREMENT COUNT. 5BA3 C2775B JNZ RRETRY ;TRY TO READ AGAIN. 5BA6 21035D LXI H,RDMSG ;PRINT "READ ". 5BA9 CDAE5C CALL PMSG 5BAC 7A ERMSG: MOV A,D ;GET ERROR BITS. 5BAD E680 ANI 80H ;IF BIT 7 HIGH, 5BAF 21B95C LXI H,NRMSG ;"NOT READY". 5BB2 C4AE5C CNZ PMSG 5BB5 7A MOV A,D ;GET ERROR BITS. 5BB6 E610 ANI 10H ;IF BIT 4 IS HIGH, 5BB8 21C45C LXI H,RNMSG ;PRINT "RECORD NOT FOUND" 5BBB C4AE5C CNZ PMSG 5BBE 7A MOV A,D ;GET ERROR BITS. 5BBF E608 ANI 8H ;IF BIT 3 IS HIGH, 5BC1 21D65C LXI H,CRCMSG ;PRINT "CRC ERROR". 5BC4 C4AE5C CNZ PMSG 5BC7 7A MOV A,D ;GET ERROR BITS. 5BC8 E604 ANI 4H ;IF BIT 2 IS HIGH, 5BCA 21DB5C LXI H,LDMSG ;PRINT "LOST DATA". 5BCD C4AE5C CNZ PMSG 5BD0 7A MOV A,D ;GET ERROR BITS. 5BD1 E601 ANI 1 ;IF BIT 1 IS HIGH, 5BD3 21E65C LXI H,BSYMSG ;PRINT "BUSY". 5BD6 C4AE5C CNZ PMSG 5BD9 21FC5C LXI H,ERRMSG ;PRINT "ERROR." 5BDC CDAE5C CALL PMSG 5BDF 3E01 MVI A,1 ;SET FOR PERM ERR MSG. 5BE1 B7 ORA A ;SET FLAGS. 5BE2 C9 RET ; ; ERCHK - CHECK FOR RECORD NOT FOUND ERROR. ; 5BE3 57 ERCHK: MOV D,A ;SAVE ERROR BITS IN D. 5BE4 E610 ANI 10H ;IF RECORD NOT FOUND, 5BE6 C2EC5B JNZ CHKSK ;DO A CHECK ON SEEK. 5BE9 7A MOV A,D ;OTHERWISE RESTORE BITS 5BEA B7 ORA A ;SET FLAGS, 5BEB C9 RET ;AND RETURN. ;CHECK FOR SEEK TO CORRECT TRACK, ;AND CHANGE IF NECESSARY. 5BEC 3EC4 CHKSK: MVI A,0C4H ;SEND COMMAND TO 1771 5BEE D3F8 OUT DCOM ;TO READ ADDRESS. 5BF0 DBFC IN WAIT ;WAIT FOR DRQ OR INTRQ. 5BF2 DBFB IN DDATA ;READ THE TRACK ADDRESS. 5BF4 47 MOV B,A ;SAVE IN REGISTER B. 5BF5 DBFC CHKS2: IN WAIT ;WAIT FOR INTRQ. 5BF7 FAF55B JM CHKS2 ;NOT IF DRQ. 5BFA 78 MOV A,B ;UPDATE TRACK REGISTER. 5BFB D3F9 OUT TRACK 5BFD 3AF659 LDA TRK ;GET REQUIRED TRACK NO. 5C00 CD6E5C CALL SEEK ;MOVE THE HEAD TO IT. 5C03 7A MOV A,D ;GET ERROR BITS. 5C04 B7 CHKS3: ORA A ;SET FLAGS. 5C05 C9 RET ;RETURN FROM ERCHK. ; ; WRITE THE SECTOR AT SECT ONTO THE PRESENT TRACK. ; DO NOT LOAD HEAD FIRST, THOUGH. ; 5C06 3E0A WRITEN: MVI A,RTCNT ;SET RETRY COUNT. 5C08 32C35D STA ERCNT 5C0B 3AF759 LDA SECT ;GET SECTOR AND 5C0E 2AF859 LHLD DMAADD ;STARTING ADDRESS. 5C11 D3FA OUT SECTP ;SET SECTOR NUMBER INTO 1771. 5C13 3EA8 MVI A,0A8H ;GET CODE FOR WRITE W/O HLD. 5C15 D3F8 OUT DCOM ;SEND TO 1771. 5C17 C32B5C JMP WLOOP ;DO REST IN REGULAR ROUTINE. ; ; WRITE THE SECTOR AT SECT, ON THE PRESENT TRACK. ; USE STARTING ADDRESS AT DMAADD. ; 5C1A 3E0A WRITE: MVI A,RTCNT ;GET RETRY COUNT. 5C1C 32C35D WRETRY: STA ERCNT ;STORE IN ERROR COUNTER. 5C1F 3AF759 LDA SECT ;GET SECTOR NUMBER. 5C22 2AF859 LHLD DMAADD ;GET STARTING ADDRESS. 5C25 D3FA WRTTE1: OUT SECTP ;SET THE SECTOR INTO 1771. 5C27 3EAC MVI A,0ACH ;SET UP 1771 FOR WRITE. 5C29 D3F8 OUT DCOM 5C2B DBFC WLOOP: IN WAIT ;WAIT FOR READY. 5C2D B7 ORA A ;SET FLAGS. 5C2E F2385C JP WDONE ;HOP OUT WHEN DONE. 5C31 7E MOV A,M ;GET BYTE FROM MEMORY. 5C32 D3FB OUT DDATA ;WRITE IT ONTO DISK. 5C34 23 INX H ;INCREMENT MEMORY POINTER. 5C35 C32B5C JMP WLOOP ;KEEP WRITING. 5C38 DBF8 WDONE: IN DSTAT ;READ DISK STATUS. 5C3A E6FD ANI 0FDH ;LOOK AT THESE BITS. 5C3C C8 PROCER: RZ ;RETURN IF NO ERRORS. 5C3D 57 MOV D,A ;SAVE ERROR BITS IN D. 5C3E E610 ANI 10H ;LOOK AT BIT 4. 5C40 CA525C JZ WERR0 ;OK IF ZERO. 5C43 7A MOV A,D ;GET ERROR BITS. 5C44 CDE35B CALL ERCHK ;CHECK/CORRECT SEEK ERR. 5C47 21BC5D LXI H,WECNT ;GET ADR OF WRITE ERR CTR. 5C4A 34 INR M ;ONE MORE WRITE ERROR. 5C4B 3AC35D LDA ERCNT ;GET ERROR COUNT. 5C4E 3D DCR A ;DECREMENT COUNT. 5C4F C21C5C JNZ WRETRY ;TRY TO WRITE AGAIN. 5C52 210B5D WERR0: LXI H,WTMSG ;PRINT "WRITE ". 5C55 CDAE5C CALL PMSG 5C58 7A MOV A,D ;GET ERROR BITS. 5C59 E640 ANI 40H ;LOOK AT BIT 6. 5C5B 21EC5C LXI H,WPMSG ;PRINT "PROTECT ". 5C5E C4AE5C CNZ PMSG 5C61 7A MOV A,D ;GET ERROR BITS. 5C62 E620 ANI 20H ;LOOK AT BIT 5. 5C64 21F55C LXI H,WFMSG ;PRINT "FAULT ". 5C67 C4AE5C CNZ PMSG 5C6A 7A MOV A,D ;GET ERROR BITS. 5C6B C3AC5B JMP ERMSG ;DO COMMON MESSAGES. ; ; MOVE THE HEAD TO THE TRACK IN REGISTER A. ; 5C6E C5 SEEK: PUSH B ;SAVE B&C. 5C6F 47 MOV B,A ;SAVE A IN B. 5C70 3E0A MVI A,RTCNT ;GET RETRY COUNT. 5C72 32C35D SRETRY: STA ERCNT ;STORE IN ERROR COUNTER. 5C75 DBF9 IN TRACK ;READ PRESENT TRACK NO. 5C77 B8 CMP B ;SAME AS NEW TRACK NO.? 5C78 78 MOV A,B ;RESTORE A FROM B. 5C79 C1 POP B ;RESTORE B&C. 5C7A C8 RZ ;RETURN IF ALREADY THERE. 5C7B D3FB OUT DDATA ;TRACK TO DATA REGISTER. 5C7D DBF8 IN DSTAT ;READ DISK STATUS. 5C7F 0F RRC ;LOOK AT BIT 0. 5C80 DAA05C JC ERROR ;ERROR IF BUSY. 5C83 3E12 MVI A,12H ;SET FOR 10 MS STEP. 5C85 F604 ORI 4 ;VERIFY ON LAST TRACK. 5C87 D3F8 OUT DCOM ;ISSUE SEEK COMMAND 5C89 DBFC IN WAIT ;WAIT FOR INTRQ 5C8B B7 ORA A 5C8C FAA05C JM ERROR ;ERROR IF DRQ 5C8F DBF8 IN DSTAT 5C91 E691 ANI 91H 5C93 C8 RZ 5C94 21BD5D LXI H,SECNT ;GET ADR OF SEEK ERR CTR. 5C97 34 INR M ;ONE MORE SEEK ERROR. 5C98 E1 POP H ;RESTORE H&L. 5C99 3AC35D LDA ERCNT ;GET ERROR COUNT. 5C9C 3D DCR A ;DECREMENT COUNT. 5C9D C2725C JNZ SRETRY ;RETRY SEEK. 5CA0 21265D ERROR: LXI H,SKMSG ;PRINT "SEEK ". 5CA3 CDAE5C CALL PMSG 5CA6 DBF8 IN DSTAT ;READ DISK STATUS. 5CA8 E691 ANI 91H ;LOOK AT ERROR BITS. 5CAA 57 MOV D,A ;SAVE IN REGISTER D. 5CAB C3AC5B JMP ERMSG ;DO COMMON ERROR MESSAGES. ; ; 5CAE 7E PMSG: MOV A,M 5CAF B7 ORA A 5CB0 C8 RZ 5CB1 4F MOV C,A 5CB2 CDD35A CALL CONOT 5CB5 23 INX H 5CB6 C3AE5C JMP PMSG ; ; CBIOS MESSAGES ; 5CB9 4E4F542052NRMSG: DB 'NOT READY ',0 5CC4 5245434F52RNMSG: DB 'RECORD NOT FOUND ',0 5CD6 4352432000CRCMSG: DB 'CRC ',0 5CDB 4C4F535420LDMSG: DB 'LOST DATA ',0 5CE6 4255535920BSYMSG: DB 'BUSY ',0 5CEC 50524F5445WPMSG: DB 'PROTECT ',0 5CF5 4641554C54WFMSG: DB 'FAULT ',0 5CFC 4552524F52ERRMSG: DB 'ERROR.',0 5D03 0D0A524541RDMSG: DB 0DH,0AH,'READ ',0 5D0B 0D0A575249WTMSG: DB 0DH,0AH,'WRITE ',0 5D14 0D0A574152BTMSG: DB 0DH,0AH,'WARM BOOT ERROR',0 5D26 0D0A534545SKMSG: DB 0DH,0AH,'SEEK ',0 5D2E 0D0A484F4DHEMSG: DB 0DH,0AH,'HOME ',0 5D36 0D0A544845RDRMSG: DB 0DH,0AH,'THERE IS NO READER',0 5D4B 0D0A4D4F55MNTMSG: DB 0DH,0AH,'MOUNT ',0 5D54 0D0A544152SMSG: DB 0DH,0AH,'TARBELL 24K CPM V1.3 OF 8-13-77' 5D75 0D0A322D44 DB 0DH,0AH,'2-DRIVE VERSION' 5D86 0D0A484F57 DB 0DH,0AH,'HOW MANY DISKS? ',0 ; ; WRITE A CHARACTER ON LISTING DEVICE. ; 5D99 DB04 LIST: IN 4 ;READ LISTER STATUS. 5D9B E680 ANI 80H ;LOOK AT READY BIT. 5D9D C2995D JNZ LIST ;WAIT TILL READY. 5DA0 79 MOV A,C ;GET DATA BYTE. 5DA1 D305 OUT 5 ;PRINT IT. 5DA3 C9 RET ;RETURN FROM LIST. ; ; NORMALLY USED TO PUNCH PAPER TAPE, BUT IS ; NICE FOR AN INFINITE BIT BUCKET TO CHECK FILES. ; 5DA4 00 PUNCH: NOP ;SPACE FOR YOUR ROUTINE. 5DA5 00 NOP 5DA6 00 NOP 5DA7 00 NOP 5DA8 00 NOP 5DA9 00 NOP 5DAA 00 NOP 5DAB 00 NOP 5DAC 00 NOP 5DAD 00 NOP 5DAE C9 RET ;RETURN FROM PUNCH. ; ; NORMALLY USED TO READ PAPER TAPE. RETURNS ; MESSAGE "THERE IS NO READER" AND END-OF-FILE. ; 5DAF 21365D READER: LXI H,RDRMSG ;PRINT "THERE IS NO READER". 5DB2 CDAE5C CALL PMSG 5DB5 3E1A MVI A,1AH ;SET A=CTL-Z (EOF). 5DB7 00 NOP ;MORE SPACE FOR YOUR ROUTINE. 5DB8 00 NOP 5DB9 00 NOP 5DBA C9 RET ;RETURN FROM READER. ; ; ERROR COUNTS. THESE LOCATIONS KEEP TRACK OF THE ; NUMBER OF ERRORS THAT OCCUR DURING READ, WRITE, ; OR SEEK OPERATIONS. THEY ARE INITIALIZED ONLY ; WHEN A COLD-START IS PERFORMED BY THE BOOTSTRAP. ; 5DBB 00 RECNT: DB 0 ;READ ERROR COUNT. 5DBC 00 WECNT: DB 0 ;WRITE ERROR COUNT. 5DBD 00 SECNT: DB 0 ;SEEK ERROR COUNT. ; ; TRTAB - DISK TRACK TABLE - PRESENT POSITION OF ; HEADS FOR UP TO 4 DRIVES. ; 5DBE TRTAB: DS 4 ; 5DC2 NODSKS: DS 1 ;NUMBER OF DISKS. 5DC3 ERCNT: DS 1 ;ERROR COUNT FOR RETRIES. 5DC4 END