; BASIC INPUT/OUTPUT OPERATING SYSTEM ; TARBELL ELECTRONICS ; 4-DRIVE VERSION OF 10-26-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. ; 0020 = MSIZE EQU 32 ;MEMORY SIZE. ; THIS SECTION DEFINES THE I/O PORTS AND ; STATUS BITS. BY SETTING THE PROPER VALUES ; FOR THE EQU STATEMENTS, THE I/O MAY BE ; AUTOMATICALLY RECONFIGURED TO FIT MOST ; SITUATIONS. THE TRUE AND FALSE ONES ; CONTROL CONDITIONAL ASSEMBLIES OF DIFFERENT ; SECTIONS OF I/O ROUTINES TO FIT DIFFERENT ; INTERFACE REQUIREMENTS. FFFF = TRUE EQU 0FFFFH ;DEFINE VALUE OF TRUE. 0000 = FALSE EQU NOT TRUE ;DEFINE VALUE OF FALSE. 0000 = STD EQU FALSE ;TRUE IF STANDARD I/O. 0000 = MSIO2 EQU FALSE ;TRUE IF MITS 2SIO. 0000 = ISIO2 EQU FALSE ;TRUE IF IMSAI SIO-2. FFFF = TUART EQU TRUE ;TRUE IF CROMEMCO TUART. FFFF = SIO2 EQU MSIO2 OR ISIO2 OR TUART 0000 = CSTAT EQU 0 ;CONSOLE STATUS PORT. 0000 = CCOM EQU 0 ;CONSOLE COMMAND PORT. 0001 = CDATA EQU 1 ;CONSOLE DATA PORT. IF STD ;IF STANDARD I/O, CKBR EQU 00000001B ;KEYBOARD READY BIT. CPTR EQU 10000000B ;CONS OUTPUT RDY BIT. ENDIF IF MSIO2 ;IF MITS 2SIO, CKBR EQU 00000001B ;KEYBOARD READY BIT. CPTR EQU 00000010B ;PRINT READY BIT. ENDIF IF ISIO2 ;IF IMSAI SIO-2, CKBR EQU 00000010B ;KEYBOARD READY BIT. CPTR EQU 00000001B ;PRINT READY BIT. ENDIF IF TUART ;IF CROMEMCO TUART, 0040 = CKBR EQU 01000000B ;KEYBOARD READY BIT. 0080 = CPTR EQU 10000000B ;PRINT READY BIT. ENDIF 0001 = CNULL EQU 1 ;CONSOLE NULL COUNT. 0050 = LSTAT EQU 50H ;LIST STATUS PORT. 0050 = LCOM EQU 50H ;LIST COMMAND PORT. 0051 = LDATA EQU 51H ;LIST DATA PORT. 0080 = LRBIT EQU CPTR ;LIST READY BIT. 000F = LNULL EQU 15 ;LIST NULL COUNT. 0000 = DUAL EQU FALSE ;TRUE IF DUAL DRIVE. 0000 = FAST EQU FALSE ;TRUE IF FAST SEEK. 00F8 = DISK EQU 0F8H ;DISK BASE ADDRESS. 00F8 = DCOM EQU DISK ;DISK COMMAND PORT. 00F8 = DSTAT EQU DISK ;DISK STATUS PORT. 00F9 = TRACK EQU DISK+1 ;DISK TRACK PORT. 00FA = SECTP EQU DISK+2 ;DISK SECTOR PORT. 00FB = DDATA EQU DISK+3 ;DISK DATA PORT. 00FC = WAIT EQU DISK+4 ;DISK WAIT PORT. 00FC = DCONT EQU DISK+4 ;DISK CONTROL PORT. 000A = RTCNT EQU 10 ;RETRY COUNT. 7A00 ORG MSIZE*1024-1536 ;FIRST ADDRESS. 79F6 = TRK EQU $-10 ;ADDRESS OF TRACK NO. 79F7 = SECT EQU TRK+1 ;ADDRESS OF SECTOR NO. 79F8 = DMAADD EQU TRK+2 ;DIRECT MEMORY ADDRESS. 79FA = DISKNO EQU TRK+4 ;ADDRESS OF DISK NO. 3C00 = CBASE EQU (MSIZE-17)*1024 ;TEMPORARY CALC. 6500 = CPMB EQU CBASE+2900H ;START OF CPM. 6E06 = BDOS EQU CBASE+3206H ;START OF BDOS. 1500 = CPML EQU $-CPMB ;LENGTH OF CPM SYSTEM-BIOS. 002A = NSECTS EQU CPML/128 ;NUMBER OF SECTORS IN IT. ; ; I/O JUMP VECTOR ; THIS IS WHERE CPM CALLS WHENEVER IT NEEDS ; TO DO ANY INPUT/OUTPUT OPERATION. ; USER PROGRAMS MAY USE THESE ENTRY POINTS ; ALSO, BUT NOTE THAT THE LOCATION OF THIS ; VECTOR CHANGES WITH THE MEMORY SIZE. ; 7A00 C3337A JMP BOOT ;FROM COLD START LOADER. 7A03 C3967A WBOOTE: JMP WBOOT ;FROM WARM BOOT. 7A06 C3EC7A JMP CONST ;CHECK CONSOLE KB STATUS. 7A09 C3F57A JMP CONIN ;READ CONSOLE CHARACTER. 7A0C C3017B JMP CONOT ;WRITE CONSOLE CHARACTER. 7A0F C3DF7D JMP LIST ;WRITE LISTING CHAR. 7A12 C3FF7D JMP PUNCH ;WRITE PUNCH CHAR. 7A15 C30A7E JMP READER ;READ READER CHAR. 7A18 C3217B JMP HOME ;MOVE DISK TO TRACK ZERO. 7A1B C3697B JMP SELDSK ;SELECT DISK DRIVE. 7A1E C3B17B JMP SETTRK ;SEEK TO TRACK IN REG A. 7A21 C3B97B JMP SETSEC ;SET SECTOR NUMBER. 7A24 C3BE7B JMP SETDMA ;SET DISK STARTING ADR. 7A27 C3D67B JMP READ ;READ SELECTED SECTOR. 7A2A C37B7C JMP WRITE ;WRITE SELECTED SECTOR. ; THESE ENTRY POINTS ADDED BY TARBELL ELECTRONICS. 7A2D C3C47B JMP READN ;READ WITH NO HEAD LOAD. 7A30 C3677C JMP WRITEN ;WRITE WITH NO HEAD LOAD. ; ; BOOT ; THIS SECTION IS EXECUTED WHENEVER RESET AND RUN ; IS PUSHED, AFTER THE COLDSTART LOADER READS IN ; THE CPM SYSTEM. ; 7A33 318000 BOOT: LXI SP,80H ;SET STACK POINTER. IF STD ;IF STANDARD I/O, NOP!NOP!NOP!NOP ;LEAVE SPACE FOR INIT. NOP!NOP!NOP!NOP NOP!NOP!NOP!NOP NOP!NOP!NOP!NOP ENDIF IF MSIO2 ;IF MITS 2SIO, MVI A,3 ;INITIALIZE 2SIO. OUT CCOM OUT LCOM MVI A,11H OUT CCOM OUT LCOM ENDIF IF ISIO2 ;IF IMSAI SIO2, MVI A,0AAH ;INITIALIZE SIO 2-2. OUT CCOM MVI A,40H OUT CCOM MVI A,0CEH OUT CCOM MVI A,37H OUT CCOM ENDIF IF TUART ;IF CROMEMCO TUART, 7A36 3E01 MVI A,1 ;SET A = 1. 7A38 D354 OUT 54H ;SELECT DEVICE A. 7A3A D352 OUT 52H ;RESET DEVICE B. 7A3C 218E7A LXI H,BAUDRS ;GET ADR OF BAUD RATE TABLE. 7A3F 3E11 MVI A,11H ;OCTUPLE THE CLOCK. 7A41 D302 IT1: OUT 02H ;& RESET CURRENT DEV. 7A43 7E MOV A,M ;GET BAUD RATE FROM TABLE. 7A44 D300 OUT 0 ;SET BAUD RATE. 7A46 CDF57A CALL CONIN ;READ KEYBOARD. 7A49 CDF57A CALL CONIN ;READ KEYBOARD AGAIN. 7A4C FE0D CPI 0DH ;IF NOT CARRIAGE-RETURN, 7A4E 3E01 MVI A,1 ;SLOW THE CLOCK. 7A50 C2417A JNZ IT1 ;UNTIL A CARRIAGE-RETURN. 7A53 3E04 MVI A,4 ;SET LIST RATE TO 300. 7A55 D350 OUT LCOM ENDIF 7A57 219A7D LXI H,SMSG ;PRINT OPENING MESSAGE. 7A5A CD097D CALL PMSG 7A5D CDF57A CALL CONIN ;READ # OF DISKS. 7A60 4F MOV C,A ;ECHO THE CHAR. 7A61 CD017B CALL CONOT 7A64 E607 ANI 7 ;LOOK AT 3 LSB'S. 7A66 321E7E STA NODSKS ;SAVE IT. 7A69 AF XRA A ;SET DISK NUMBER = 0. 7A6A 32FA79 STA DISKNO 7A6D 3EC3 GOCPM: MVI A,0C3H ;PUT JMP TO WBOOT 7A6F 320000 STA 0 ;ADR AT ZERO. 7A72 21037A LXI H,WBOOTE 7A75 220100 SHLD 1 7A78 320500 STA 5 7A7B 21066E LXI H,BDOS ;PUT JUMP TO BDOS 7A7E 220600 SHLD 6 ;AT ADR 5,6,7. 7A81 218000 LXI H,80H ;SET DEFAULT DMA ADR. 7A84 22F879 SHLD DMAADD 7A87 3AFA79 LDA DISKNO ;GET DISK NUMBER TO 7A8A 4F MOV C,A ;PASS TO CCP IN C. 7A8B C30065 JMP CPMB ;JUMP TO CCP. IF TUART ;IF CROMEMCO TUART, 7A8E 94CEA29288BAUDRS: DB 94H,0CEH,0A2H,92H,88H,84H,82H,1 ENDIF ; ; WARM-BOOT: READ ALL OF CPM BACK IN ; EXCEPT BIOS, THEN JUMP TO CCP. ; 7A96 318000 WBOOT: LXI SP,80H ;SET STACK POINTER. 7A99 3AFA79 LDA DISKNO ;SAVE DISK NUMBER. 7A9C 32217E STA TEMP 7A9F 0E00 MVI C,0 ;SELECT DISK ZERO. 7AA1 CD697B CALL SELDSK 7AA4 CD217B CALL HOME ;MOVE TO TRACK ZERO. 7AA7 C2E07A JNZ RDERR ;IF ERROR, PRINT MESSAGE. 7AAA 162A MVI D,NSECTS ;GET # SECTORS FOR CPM READ. 7AAC 010200 LXI B,2 ;TRACK (B)=0, SECTOR (C)=2. 7AAF 210065 LXI H,CPMB ;GET STARTING ADDRESS. 7AB2 78 RDBLK: MOV A,B ;GO TO TRACK IN B. 7AB3 CDC77C CALL SEEK 7AB6 C2E07A JNZ RDERR ;IF ERROR, PRINT MESSAGE. 7AB9 79 MOV A,C ;READ STARTING AT SECTOR IN C. 7ABA CDE17B CALL READ1 7ABD C2E07A RBLK1 JNZ RDERR ;IF ERROR, PRINT MESSAGE. 7AC0 15 DCR D ;DECREMENT SECTOR COUNT. 7AC1 CAD17A JZ ALDON ;ALL DONE WHEN ZERO. 7AC4 0C INR C ;INCREMENT SECTOR NUMBER. 7AC5 79 MOV A,C ;IF SECTOR NUMBER 7AC6 FE1B CPI 27 ;IS NOT 27, 7AC8 DADA7A JC RBLK2 ;HOP OUT OF LOOP. 7ACB 0E01 MVI C,1 ;OTHERWISE, RESET SECTOR=1 7ACD 04 INR B ;INCREMENT TRACK NUMBER, 7ACE C3B27A JMP RDBLK ;AND READ NEXT TRACK. 7AD1 3A217E ALDON: LDA TEMP ;RESTORE DISK NUMBER. 7AD4 32FA79 STA DISKNO 7AD7 C36D7A JMP GOCPM ;GO BACK TO CPM. ; 7ADA CDCF7B RBLK2: CALL READ2 ;READ ANOTHER TRACK. 7ADD C3BD7A JMP RBLK1 ; 7AE0 216F7D RDERR: LXI H,BTMSG ;GET ADDRESS OF "BOOT ERROR". 7AE3 CD097D CALL PMSG ;PRINT IT. 7AE6 CDF57A CALL CONIN ;READ A CHAR FROM CONSOLE. 7AE9 C3967A JMP WBOOT ;DO A WARM BOOT. ; ; CHECK CONSOLE INPUT STATUS. ; 7AEC DB00 CONST: IN CSTAT ;READ CONSOLE STATUS. 7AEE E640 ANI CKBR ;LOOK AT KB READY BIT. 7AF0 3E00 MVI A,0 ;SET A=0 FOR RETURN. IF STD ;IF STANDARD I/O, RNZ ;NOT READY WHEN NOT 0. ENDIF IF SIO2 ;IF MITS OR IMSAI, 7AF2 C8 RZ ;NOT READY WHEN ZERO. ENDIF 7AF3 2F CMA ;IF READY A=FF. 7AF4 C9 RET ;RETURN FROM CONST. ; ; READ A CHARACTER FROM CONSOLE. ; 7AF5 DB00 CONIN: IN CSTAT ;READ CONSOLE STATUS. 7AF7 E640 ANI CKBR ;IF NOT READY, IF STD ;IF STANDARD I/O, JNZ CONIN ;READY WHEN LOW. ENDIF IF SIO2 ;IF MITS OR IMSAI, 7AF9 CAF57A JZ CONIN ;READY WHEN HIGH. ENDIF 7AFC DB01 IN CDATA ;READ A CHARACTER. 7AFE E67F ANI 7FH ;MAKE MOST SIG. BIT = 0. 7B00 C9 RET ; ; WRITE A CHARACTER TO THE CONSOLE DEVICE. ; 7B01 3E0D CONOT: MVI A,0DH ;IF IT'S A CR, 7B03 B9 CMP C ;THEN HOP OUT 7B04 CA127B JZ CONUL ;TO NULL ROUTINE. 7B07 DB00 CONOT1: IN CSTAT ;READ CONSOLE STATUS. 7B09 E680 ANI CPTR ;IF NOT READY, IF STD ;IF STANDARD I/O, JNZ CONOT1 ;READY WHEN LOW. ENDIF IF SIO2 ;IF MITS OR IMSAI, 7B0B CA077B JZ CONOT1 ;READY WHEN HIGH. ENDIF 7B0E 79 MOV A,C ;GET CHARACTER. 7B0F D301 OUT CDATA ;PRINT IT. 7B11 C9 RET ;RETURN. 7B12 C5 CONUL: PUSH B ;SAVE B&C. 7B13 0601 MVI B,CNULL ;GET NULL COUNT. 7B15 CD077B CONUL1: CALL CONOT1 ;PRINT CR. 7B18 0E00 MVI C,0 ;GET NULL CHAR. 7B1A 05 DCR B ;DECREMENT COUNTER. 7B1B C2157B JNZ CONUL1 ;DO NEXT NULL. 7B1E C1 POP B ;RESTORE B&C. 7B1F 79 MOV A,C ;RESTORE A. 7B20 C9 RET ;RETURN. ; ; MOVE DISK TO TRACK ZERO. ; 7B21 3E0A HOME: MVI A,RTCNT ;GET RETRY COUNT. 7B23 321F7E HRETRY: STA ERCNT ;STORE IN ERROR CTR. 7B26 3ED0 MVI A,0D0H ;CLEAR ANY PENDING COMMAND. 7B28 D3F8 OUT DCOM 7B2A 3AFA79 LDA DISKNO ;GET DISK NUMBER. 7B2D 5F MOV E,A ;PUT IN D&E. 7B2E AF XRA A 7B2F 57 MOV D,A 7B30 211A7E LXI H,TRTAB ;GET ADR OF TRK TABLE. IF NOT DUAL ;IF NOT A DUAL DRIVE. 7B33 19 DAD D ;ADD DISK NUMBER. ENDIF 7B34 77 MOV M,A ;PUT ZERO INTO TABLE. 7B35 DBF8 HOME1: IN DSTAT ;READ DISK STATUS. 7B37 0F RRC ;LOOK AT LSB. 7B38 DA357B JC HOME1 ;WAIT FOR NOT BUSY. IF FAST ;IF FAST SEEK, LDA DISKNO ;GET DISK NUMBER. RLC ;SHIFT LEFT 4 BITS. RLC RLC RLC ANI 10H ;LOOK AT BIT 4. CMA ;INVERT. MOV E,A ;SAVE IT. ANI 0B2H ;SET PERSCI OUT DCONT ;RESTORE LINE. HLOOP: IN DSTAT ;LOOK AT STATUS ANI 4 ;BIT 2 (TRACK 0) JZ HLOOP ;AND WAIT TILL 1. MOV A,E ;RESTORE OLD BITS ANI 0F2H ;IN LATCH AND CLEAR OUT DCONT ;RESTORE LINE. ENDIF 7B3B 3E02 MVI A,2 ;10 MS STEP RATE. 7B3D D3F8 OUT DCOM ;ISSUE HOME COMMAND. 7B3F DBFC IN WAIT ;WAIT FOR INTRQ. 7B41 B7 ORA A ;SET FLAGS. 7B42 FA517B JM HERR ;ERROR IF DRQ. 7B45 DBF8 IN DSTAT ;READ DISK STATUS. 7B47 57 MOV D,A ;SAVE IN REGISTER D. 7B48 E604 ANI 4 ;LOOK AT BIT 2. 7B4A CA517B JZ HERR ;ERROR IF NOT TRK 0. 7B4D 7A MOV A,D ;GET STATUS BACK. 7B4E E691 ANI 91H ;MASK NON-ERROR BITS. 7B50 C8 RZ ;RETURN IF NO ERROR. 7B51 3A167E HERR: LDA HECNT ;GET TOTAL ERROR COUNT. 7B54 3C INR A ;ADD ONE. 7B55 32167E STA HECNT ;SAVE IT BACK. 7B58 3A1F7E LDA ERCNT ;GET THIS ERROR COUNT. 7B5B 3D DCR A ;DECREMENT COUNT. 7B5C C2237B JNZ HRETRY ;TRY TO HOME AGAIN. 7B5F 21897D LXI H,HEMSG ;PRINT "HOME ". 7B62 7A MOV A,D ;MASK NON-ERROR BITS. 7B63 E691 ANI 91H 7B65 57 MOV D,A 7B66 C30A7C JMP ERMSG ;DO COMMON ERROR MSGS. ; ; SELECT DISK NUMBER. ; 7B69 79 SELDSK: MOV A,C ;GET NEW DISK NUMBER. 7B6A E603 ANI 3 ;ONLY LOOK AT 2 LSB'S. 7B6C 21FA79 LXI H,DISKNO ;GET ADR OF OLD DISK NO. 7B6F BE CMP M ;NEW = OLD? 7B70 C8 RZ ;IF SO, RETURN. 7B71 F5 PUSH A ;SAVE DISK NUMBER. 7B72 3A1E7E LDA NODSKS ;GET NUMBER OF DISKS. 7B75 FE01 CPI 1 ;IF MORE THAN ONE DISK, 7B77 C28F7B JNZ SELMOR ;TAKE CARE OF IT. 7B7A 21917D LXI H,MNTMSG ;GET ADR OF MOUNT MESSAGE. 7B7D CD097D CALL PMSG ;PRINT "MOUNT ". 7B80 F1 POP A ;GET DISK NUMBER. 7B81 32FA79 STA DISKNO ;UPDATE OLD WITH NEW. 7B84 C641 ADI 'A' ;ADD ASCII FOR 'A'. 7B86 4F MOV C,A ;PUT INTO C. 7B87 CD017B CALL CONOT ;PRINT IT. 7B8A CDF57A CALL CONIN ;READ A CARRIAGE RETURN. 7B8D AF XRA A ;SET A=0 FOR NO ERRO IND. 7B8E C9 RET ;RETURN FROM SELDSK. 7B8F F1 SELMOR: POP A ;RECOVER REGISTER A. 7B90 5E MOV E,M ;PUT OLD DISK NO. IN D&E. 7B91 1600 MVI D,0 7B93 211A7E LXI H,TRTAB ;GET ADDRESS OF TRACK TABLE. IF NOT DUAL ;IF NOT A DUAL DRIVE, 7B96 19 DAD D ;ADD DISK NO. TO ADDRESS. ENDIF 7B97 DBF9 IN TRACK ;READ 1771 TRACK REGISTER. 7B99 77 MOV M,A ;PUT INTO TABLE. 7B9A 59 MOV E,C ;PUT NEW DISK NO. IN D&E. 7B9B 211A7E LXI H,TRTAB ;GET ADDRESS OF TRACK TABLE. IF NOT DUAL ;IF NOT A DUAL DRIVE, 7B9E 19 DAD D ;ADD DISK NO. TO ADDRESS. ENDIF 7B9F 7E MOV A,M ;GET NEW TRACK NUMBER. 7BA0 D3F9 OUT TRACK ;PUT INTO 1771 TRACK REG. 7BA2 79 MOV A,C ;UPDATE OLD DISK NUMBER. 7BA3 32FA79 STA DISKNO 7BA6 2F CMA ;BITS INVERTED INTO LATCH. 7BA7 87 ADD A ;PUT BITS 1&2 AT 4&5. 7BA8 87 ADD A 7BA9 87 ADD A 7BAA 87 ADD A 7BAB F602 ORI 2 ;MAKE LATCH COMMAND. 7BAD D3FC DSK1: OUT DCONT ;SET THE LATCH WITH CODE. 7BAF AF XRA A ;SET A = 0. 7BB0 C9 RET ;RETURN FROM SELDSK. ; ; SET TRACK NUMBER TO WHATEVER IS IN REGISTER C. ; ALSO PERFORM MOVE TO THE CORRECT TRACK (SEEK). ; 7BB1 79 SETTRK: MOV A,C ;GET NEW TRACK NUMBER. 7BB2 32F679 STA TRK ;UPDATE OLD WITH NEW. 7BB5 CDC77C CALL SEEK ;MOVE TO NEW TRACK. 7BB8 C9 RET ;RETURN FROM SETTRK ROUTINE. ; ; SET DISK SECTOR NUMBER. ; 7BB9 79 SETSEC: MOV A,C ;GET SECTOR NUMBER. 7BBA 32F779 STA SECT ;PUT AT SECT # ADDRESS. 7BBD C9 RET ;RETURN FROM SETSEC. ; ; SET DISK DMA ADDRESS. ; 7BBE 60 SETDMA: MOV H,B ;MOVE B&C TO H&L. 7BBF 69 MOV L,C 7BC0 22F879 SHLD DMAADD ;PUT AT DMA ADR ADDRESS. 7BC3 C9 RET ;RETURN FROM SETDMA. ; ; READ THE SECTOR AT SECT, FROM THE PRESENT TRACK. ; DO NO HEAD LOAD. USE STARTING ADR AT DMAADD. ; 7BC4 3E0A READN: MVI A,RTCNT ;SET RETRY COUNT. 7BC6 321F7E STA ERCNT 7BC9 3AF779 LDA SECT ;GET SECTOR NUMBER 7BCC 2AF879 LHLD DMAADD ;AND STARTING ADDRESS. ; ; READ A SECTOR WITHOUT LOADING HEAD FIRST. ; 7BCF D3FA READ2: OUT SECTP ;SET SECTOR NUMBER INTO 1771. 7BD1 3E88 MVI A,88H ;GET CODE FOR READ W/O HLD. 7BD3 C3E57B JMP READE ;READ A SECTOR. ; ; READ THE SECTOR AT SECT, FROM THE PRESENT TRACK. ; USE STARTING ADDRESS AT DMAADD. ; 7BD6 3E0A READ: MVI A,RTCNT ;GET RETRY COUNT. 7BD8 321F7E RRETRY: STA ERCNT ;STORE IN ERROR CTR. 7BDB 3AF779 LDA SECT ;GET SECTOR NUMBER. 7BDE 2AF879 LHLD DMAADD ;GET STARTING ADR. 7BE1 D3FA READ1: OUT SECTP ;SET SECTOR INTO 1771. 7BE3 3E8C MVI A,8CH ;CODE FOR READ W/O HD LD. 7BE5 D3F8 READE: OUT DCOM ;SEND COMMAND TO 1771. 7BE7 DBFC RLOOP: IN WAIT ;WAIT FOR DRQ OR INTRQ. 7BE9 B7 ORA A ;SET FLAGS. 7BEA F2F47B JP RDDONE ;DONE IF INTRQ. 7BED DBFB IN DDATA ;READ A DATA BYTE FROM DISK. 7BEF 77 MOV M,A ;PUT BYTE INTO MEMORY. 7BF0 23 INX H ;INCREMENT MEMORY POINTER. 7BF1 C3E77B JMP RLOOP ;KEEP READING. 7BF4 DBF8 RDDONE: IN DSTAT ;READ DISK STATUS. 7BF6 E69D ANI 9DH ;LOOK AT ERROR BITS. 7BF8 C8 RZ ;RETURN IF NONE. 7BF9 CD447C CHECK: CALL ERCHK ;CHECK FOR SEEK ERROR. 7BFC 21177E LXI H,RECNT ;GET RD ERR COUNT ADDR. 7BFF 34 INR M ;ONE MORE ERROR. 7C00 3A1F7E LDA ERCNT ;GET ERROR COUNT. 7C03 3D DCR A ;DECREMENT COUNT. 7C04 C2D87B JNZ RRETRY ;TRY TO READ AGAIN. 7C07 215E7D LXI H,RDMSG ;PRINT "READ ". 7C0A CD097D ERMSG: CALL PMSG ;PRINT ORIGIN MESSAGE. 7C0D 7A ERMSG1: MOV A,D ;GET ERROR BITS. 7C0E E680 ANI 80H ;IF BIT 7 HIGH, 7C10 21147D LXI H,NRMSG ;"NOT READY". 7C13 C4097D CNZ PMSG 7C16 7A MOV A,D ;GET ERROR BITS. 7C17 E610 ANI 10H ;IF BIT 4 IS HIGH, 7C19 211F7D LXI H,RNMSG ;PRINT "RECORD NOT FOUND" 7C1C C4097D CNZ PMSG 7C1F 7A MOV A,D ;GET ERROR BITS. 7C20 E608 ANI 8H ;IF BIT 3 IS HIGH, 7C22 21317D LXI H,CRCMSG ;PRINT "CRC ERROR". 7C25 C4097D CNZ PMSG 7C28 7A MOV A,D ;GET ERROR BITS. 7C29 E604 ANI 4H ;IF BIT 2 IS HIGH, 7C2B 21367D LXI H,LDMSG ;PRINT "LOST DATA". 7C2E C4097D CNZ PMSG 7C31 7A MOV A,D ;GET ERROR BITS. 7C32 E601 ANI 1 ;IF BIT 1 IS HIGH, 7C34 21417D LXI H,BSYMSG ;PRINT "BUSY". 7C37 C4097D CNZ PMSG 7C3A 21577D PERMSG: LXI H,ERRMSG ;PRINT "ERROR." 7C3D CD097D CALL PMSG 7C40 3E01 MVI A,1 ;SET FOR PERM ERR MSG. 7C42 B7 ORA A ;SET FLAGS. 7C43 C9 RET ; ; ERCHK - CHECK FOR RECORD NOT FOUND ERROR. ; 7C44 57 ERCHK: MOV D,A ;SAVE ERROR BITS IN D. 7C45 E610 ANI 10H ;IF RECORD NOT FOUND, 7C47 C24D7C JNZ CHKSK ;DO A CHECK ON SEEK. 7C4A 7A MOV A,D ;OTHERWISE RESTORE BITS 7C4B B7 ORA A ;SET FLAGS, 7C4C C9 RET ;AND RETURN. ;CHECK FOR SEEK TO CORRECT TRACK, ;AND CHANGE IF NECESSARY. 7C4D 3EC4 CHKSK: MVI A,0C4H ;SEND COMMAND TO 1771 7C4F D3F8 OUT DCOM ;TO READ ADDRESS. 7C51 DBFC IN WAIT ;WAIT FOR DRQ OR INTRQ. 7C53 DBFB IN DDATA ;READ THE TRACK ADDRESS. 7C55 47 MOV B,A ;SAVE IN REGISTER B. 7C56 DBFC CHKS2: IN WAIT ;WAIT FOR INTRQ. 7C58 FA567C JM CHKS2 ;NOT IF DRQ. 7C5B 78 MOV A,B ;UPDATE TRACK REGISTER. 7C5C D3F9 OUT TRACK 7C5E 3AF679 LDA TRK ;GET REQUIRED TRACK NO. 7C61 CDC77C CALL SEEK ;MOVE THE HEAD TO IT. 7C64 7A MOV A,D ;GET ERROR BITS. 7C65 B7 CHKS3: ORA A ;SET FLAGS. 7C66 C9 RET ;RETURN FROM ERCHK. ; ; WRITE THE SECTOR AT SECT ONTO THE PRESENT TRACK. ; DO NOT LOAD HEAD FIRST, THOUGH. ; 7C67 3E0A WRITEN: MVI A,RTCNT ;SET RETRY COUNT. 7C69 321F7E STA ERCNT 7C6C 3AF779 LDA SECT ;GET SECTOR AND 7C6F 2AF879 LHLD DMAADD ;STARTING ADDRESS. 7C72 D3FA OUT SECTP ;SET SECTOR NUMBER INTO 1771. 7C74 3EA8 MVI A,0A8H ;GET CODE FOR WRITE W/O HLD. 7C76 D3F8 OUT DCOM ;SEND TO 1771. 7C78 C38C7C JMP WLOOP ;DO REST IN REGULAR ROUTINE. ; ; WRITE THE SECTOR AT SECT, ON THE PRESENT TRACK. ; USE STARTING ADDRESS AT DMAADD. ; 7C7B 3E0A WRITE: MVI A,RTCNT ;GET RETRY COUNT. 7C7D 321F7E WRETRY: STA ERCNT ;STORE IN ERROR COUNTER. 7C80 3AF779 LDA SECT ;GET SECTOR NUMBER. 7C83 2AF879 LHLD DMAADD ;GET STARTING ADR. 7C86 D3FA WRITE1: OUT SECTP ;SET THE SECTOR INTO 1771. 7C88 3EAC MVI A,0ACH ;SET UP 1771 FOR WRITE. 7C8A D3F8 OUT DCOM 7C8C DBFC WLOOP: IN WAIT ;WAIT FOR READY. 7C8E B7 ORA A ;SET FLAGS. 7C8F F2997C JP WDONE ;HOP OUT WHEN DONE. 7C92 7E MOV A,M ;GET BYTE FROM MEM. 7C93 D3FB OUT DDATA ;WRITE ONTO DISK. 7C95 23 INX H ;INCREMENT MEM PTR. 7C96 C38C7C JMP WLOOP ;KEEP WRITING. 7C99 DBF8 WDONE: IN DSTAT ;READ DISK STATUS. 7C9B E6FD ANI 0FDH ;LOOK AT THESE BITS. 7C9D C8 PROCER: RZ ;RETURN IF NO ERR. 7C9E CD447C CALL ERCHK ;CHECK/CORRECT SEEK ERR. 7CA1 21187E LXI H,WECNT ;GET ADR OF WRITE ERR CTR. 7CA4 34 INR M ;ONE MORE WRITE ERROR. 7CA5 3A1F7E LDA ERCNT ;GET ERROR COUNT. 7CA8 3D DCR A ;DECREMENT COUNT. 7CA9 C27D7C JNZ WRETRY ;TRY TO WRITE AGAIN. 7CAC 21667D WERR0: LXI H,WTMSG ;PRINT "WRITE ". 7CAF CD097D CALL PMSG 7CB2 7A MOV A,D ;GET ERROR BITS. 7CB3 E640 ANI 40H ;LOOK AT BIT 6. 7CB5 21477D LXI H,WPMSG ;PRINT "PROTECT ". 7CB8 C4097D CNZ PMSG 7CBB 7A MOV A,D ;GET ERROR BITS. 7CBC E620 ANI 20H ;LOOK AT BIT 5. 7CBE 21507D LXI H,WFMSG ;PRINT "FAULT ". 7CC1 C4097D CNZ PMSG 7CC4 C30D7C JMP ERMSG1 ;DO COMMON MESSAGES. ; ; MOVE THE HEAD TO THE TRACK IN REGISTER A. ; 7CC7 C5 SEEK: PUSH B ;SAVE B&C. 7CC8 47 MOV B,A ;SAVE DESTINATION TRACK. 7CC9 3E0A MVI A,RTCNT ;GET RETRY COUNT. 7CCB 32207E SRETRY: STA SERCNT ;STORE IN ERROR COUNTER. 7CCE DBF9 IN TRACK ;READ PRESENT TRACK NO. 7CD0 4F MOV C,A ;SAVE IN C. 7CD1 79 MOV A,C ;DELAY. 7CD2 B8 CMP B ;SAME AS NEW TRACK NO.? 7CD3 78 MOV A,B ;RESTORE A FROM B. 7CD4 C2D97C JNZ NOTHR ;JUMP IF NOT THERE. 7CD7 C1 THERE: POP B ;RESTORE B&C. 7CD8 C9 RET ;RETURN FROM SEEK. NOTHR: IF NOT FAST ;IF NOT FAST SEEK, 7CD9 D3FB OUT DDATA ;TRACK TO DATA REGISTER. 7CDB DBF8 BUSY: IN DSTAT ;READ DISK STATUS. 7CDD 0F RRC ;LOOK AT BIT 0. 7CDE DADB7C JC BUSY ;WAIT TILL NOT BUSY. 7CE1 3E12 MVI A,12H ;SET FOR 10 MS STEP. 7CE3 F604 ORI 4 ;VERIFY ON LAST TRACK. 7CE5 D3F8 OUT DCOM ;ISSUE SEEK COMMAND. 7CE7 DBFC IN WAIT ;WAIT FOR INTRQ. 7CE9 DBF8 IN DSTAT ;READ STATUS. 7CEB E691 ANI 91H ;LOOK AT BITS. 7CED CAD77C JZ THERE ;OK IF ZERO. ENDIF IF FAST ;IF FAST SEEK, MVI A,40H ;IF CARRY = 1, JC SDIR ;STEP IN. MVI A,60H ;OTHERWISE, OUT. SDIR: OUT DCOM ;ISSUE STEP DIRECTION. MVI A,20 ;DELAY LOOP COUNT. DLOOP: DCR A ;DECREMENT COUNTER. JNZ DLOOP MOV A,C ;GET PRESENT TRACK. SUB B ;FIGURE TRACKS TO STEP. JP STEP ;IF NEGATIVE, CMA ;FIGURE THE INR A ;TWO'S COMPLEMENT. STEP: MOV C,A ;GET DIFFERENCE. MVI A,1 ;PERSCI STEP COMMAND. STEP1: OUT DCONT ;STEP PERSCI (E-14). DCR C ;COUNT THE STEP. JNZ STEP1 ;STEP UNTIL C = 0. IN WAIT ;CLEAR 1771. IN DSTAT MOV A,B ;GET DEST. TRACK. OUT TRACK ;UPDATE TRACK REG. LDA DISKNO ;GET DISK NUMBER. RLC!RLC!RLC!RLC ;SHIFT LEFT 4 BITS. ANI 10H ;LOOK AT BIT 4. CMA ;INVERT. MOV B,A ;SAVE IN B. ANI 72H ;MAKE COMMAND TO OUT DCONT ;SWITCH WAIT FOR IN WAIT ;SEEK COMPLETE. MOV A,B ;RESTORE ORIG. BITS. ANI 0F2H ;SWITCH WAIT BACK. OUT DCONT XRA A ;MAKE GOOD RETURN. POP B ;RESTORE B&C. RET ENDIF IF NOT FAST ;IF NOT FAST SEEK, 7CF0 E5 PUSH H ;SAVE H&L. 7CF1 21197E LXI H,SECNT ;GET ADR OF SEEK ERR CTR. 7CF4 34 INR M ;ONE MORE SEEK ERROR. 7CF5 E1 POP H ;RESTORE H&L. 7CF6 3A1F7E LDA ERCNT ;GET ERROR COUNT. 7CF9 3D DCR A ;DECREMENT COUNT. 7CFA C2CB7C JNZ SRETRY ;RETRY SEEK. 7CFD C1 POP B ;RESTORE B&C. 7CFE 21817D LXI H,SKMSG ;PRINT "SEEK ". 7D01 DBF8 IN DSTAT ;READ DISK STATUS. 7D03 E691 ANI 91H ;LOOK AT ERROR BITS. 7D05 57 MOV D,A ;PUT IN REG D. 7D06 C30A7C JMP ERMSG ;DO COMMON ERR MESSAGES. ENDIF ; ; PRINT THE MESSAGE AT H&L UNTIL A ZERO. ; 7D09 7E PMSG: MOV A,M ;GET A CHARACTER. 7D0A B7 ORA A ;IF IT'S ZERO, 7D0B C8 RZ ;RETURN. 7D0C 4F MOV C,A ;OTHERWISE, 7D0D CD017B CALL CONOT ;PRINT IT. 7D10 23 INX H ;INCREMENT H&L, 7D11 C3097D JMP PMSG ;AND GET ANOTHER. ; ; CBIOS MESSAGES ; 7D14 4E4F542052NRMSG: DB 'NOT READY ',0 7D1F 5245434F52RNMSG: DB 'RECORD NOT FOUND ',0 7D31 4352432000CRCMSG: DB 'CRC ',0 7D36 4C4F535420LDMSG: DB 'LOST DATA ',0 7D41 4255535920BSYMSG: DB 'BUSY ',0 7D47 50524F5445WPMSG: DB 'PROTECT ',0 7D50 4641554C54WFMSG: DB 'FAULT ',0 7D57 4552524F52ERRMSG: DB 'ERROR.',0 7D5E 0D0A524541RDMSG: DB 0DH,0AH,'READ ',0 7D66 0D0A575249WTMSG: DB 0DH,0AH,'WRITE ',0 7D6F 0D0A574152BTMSG: DB 0DH,0AH,'WARM BOOT ERROR',0 7D81 0D0A534545SKMSG: DB 0DH,0AH,'SEEK ',0 7D89 0D0A484F4DHEMSG: DB 0DH,0AH,'HOME ',0 7D91 0D0A4D4F55MNTMSG: DB 0DH,0AH,'MOUNT ',0 7D9A 0D0A544152SMSG: DB 0DH,0AH,'TARBELL ' 7DA4 3332 DB MSIZE/10+'0',MSIZE MOD 10 + '0' 7DA6 4B2043504D DB 'K CPM V1.3 OF 10-26-77' 7DBC 0D0A DB 0DH,0AH IF STD ;IF STANDARD I/O, DB 'STANDARD ' ENDIF IF MSIO2 ;IF MITS 2SIO, DB '2SIO ' ENDIF IF ISIO2 ;IF IMSAI SIO-2, DB 'SIO-2 ' ENDIF IF TUART ;IF TUART, 7DBE 5455415254 DB 'TUART ' ENDIF IF FAST ;IF FAST SEEK, DB 'FAST SEEK ' ENDIF IF DUAL ;IF DUAL DRIVE, DB 'DUAL ' ENDIF 7DC4 5645525349 DB 'VERSION.' 7DCC 0D0A484F57 DB 0DH,0AH,'HOW MANY DISKS? ',0 ; ; WRITE A CHARACTER ON LISTING DEVICE. ; 7DDF 3E0D LIST: MVI A,0DH ;IF IT'S A CR, 7DE1 B9 CMP C ;THEN HOP OUT TO 7DE2 CAF07D JZ LINUL ;NULL ROUTINE. 7DE5 DB50 LIST1: IN LSTAT ;READ LISTER STATUS. 7DE7 E680 ANI LRBIT ;LOOK AT READY BIT. IF STD ;IF STANDARD I/O, JNZ LIST1 ;READY WHEN LOW. ENDIF IF SIO2 ;IF MITS, IMSAI, CROM., 7DE9 CAE57D JZ LIST1 ;READY WHEN HIGH. ENDIF 7DEC 79 MOV A,C ;GET DATA BYTE. 7DED D351 OUT LDATA ;PRINT IT. 7DEF C9 RET ;RETURN FROM LIST. 7DF0 C5 LINUL: PUSH B ;SAVE B&C. 7DF1 060F MVI B,LNULL ;GET NULL COUNT. 7DF3 CDE57D LINUL1: CALL LIST1 ;PRINT (CR FIRST). 7DF6 0E00 MVI C,0 ;GET NULL CHAR. 7DF8 05 DCR B ;DECREMENT COUNTER. 7DF9 C2F37D JNZ LINUL1 ;DO NEXT NULL. 7DFC C1 POP B ;RESTORE B&C. 7DFD 79 MOV A,C ;RESTORE A. 7DFE C9 RET ;RETURN FROM LIST. ; ; NORMALLY USED TO PUNCH PAPER TAPE, BUT IS ; NICE FOR AN INFINITE BIT BUCKET TO CHECK FILES. ; 7DFF 00 PUNCH: NOP ;SPACE FOR YOUR ROUTINE. 7E00 00000000 NOP!NOP!NOP!NOP 7E04 00000000 NOP!NOP!NOP!NOP 7E08 00 NOP 7E09 C9 RET ;RETURN FROM PUNCH. ; ; NORMALLY USED TO READ PAPER TAPE. ; SET UP TO READ FROM CONSOLE IN STANDARD SYSTEM. ; 7E0A CDF57A READER: CALL CONIN ;READ FROM CONSOLE. 7E0D 00000000 NOP!NOP!NOP!NOP ;MORE SPACE FOR YOUR ROUTINE. 7E11 00000000 NOP!NOP!NOP!NOP 7E15 C9 RET ;RETURN FROM READER. ;NOTE: THE LAST ADDRESS BEFORE THIS POINT ; SHOULD BE NO GREATER THAN XE7F (HEX). ; ; 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. ; 7E16 00 HECNT: DB 0 ;HOME ERROR COUNT. 7E17 00 RECNT: DB 0 ;READ ERROR COUNT. 7E18 00 WECNT: DB 0 ;WRITE ERROR COUNT. 7E19 00 SECNT: DB 0 ;SEEK ERROR COUNT. ; ; TRTAB - DISK TRACK TABLE - PRESENT POSITION OF ; HEADS FOR UP TO 4 DRIVES. ; 7E1A TRTAB: DS 4 ; 7E1E NODSKS: DS 1 ;NUMBER OF DISKS. 7E1F ERCNT: DS 1 ;ERROR COUNT FOR RETRIES. 7E20 SERCNT: DS 1 ;SEEK RETRY COUNTER. 7E21 TEMP: DS 1 ;TEMPORARY STORAGE. 7E22 END