TITLE 'CBIOS 48K FOR CP/M 2.2' PAGE 56 ; CP/M BASIC INPUT/OUTPUT OPERATING SYSTEM (BIOS) ; TARBELL ELECTRONICS ; 2.2 VERSION OF 12-5-79 ; MODIFIED BY RICHARD L BERG ; 10-25-80 ; ; THIS BIOS MODULE IS THE CPM V2.2 ; CBIOS. THIS BIOS READS SINGLE DENSITY ; DISK.. TRACK 0 = SINGLE DENSITY (IBM COMPATABLE) ; TRACKS 1 - 76 SINGLE DENSITY 52 SECTORS. ; ; 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. TRUE EQU 0FFFFH ;DEFINE VALUE OF TRUE. FALSE EQU NOT TRUE ;DEFINE VALUE OF FALSE. ;*************************************************** ;*** THIS BEGINS THE AREA WHICH REQUIRES CHANGES *** ;*** FOR DIFFERENT CONSOLE I/O SYSTEMS *** ;*************************************************** MSIZE EQU 56 ;MEMORY SIZE IN KBYTES. NDISK EQU 2 ;DEFINES THE NUMBER DRIVES IN SYSTEM. CDATA EQU 0 ;USED TO CLEAR CONSOLE STATUS. HLAB EQU 0 ;8 FOR HD LD AT BEG OF SEEK. STPRAT EQU 2 ;RATE 1=6MS, 2=10MS, 3=20MS. ;******************************************************* ;*** THIS IS THE END OF THE AREA WHICH NORMALLY NEED *** ;*** BE CHANGED FOR MOST CONSOLE I/O SYSTEMS *** ;******************************************************* RDYLO EQU TRUE ;STATUS READY WHEN LOW. RDYHI EQU NOT RDYLO DISK EQU 0F8H ;DISK BASE ADDRESS. DCOM EQU DISK ;DISK COMMAND PORT. DSTAT EQU DISK ;DISK STATUS PORT. TRACK EQU DISK+1 ;DISK TRACK PORT. SECTP EQU DISK+2 ;DISK SECTOR PORT. DDATA EQU DISK+3 ;DISK DATA PORT. WAIT EQU DISK+4 ;DISK WAIT PORT. DCONT EQU DISK+4 ;DISK CONTROL PORT. RTCNT EQU 10 ;RETRY COUNT. IOBYTE EQU 3 ;ADDRESS OF I/O BYTE. CBASE EQU (MSIZE-20)*1024 ;BIAS FOR LARGER THAN 20K. CPMB EQU CBASE+3400H ;START OF CPM 2.2 BDOS EQU CPMB+806H ;START OF BDOS 2.2. BIOS EQU CPMB+1600H ;START OF CBIOS IO. CDISK EQU 4 ;LOCATION 4 IS CURRENT DISK. NSECTS EQU 17 ;NUMBER OF SECTORS IN IT. CR EQU 0DH LF EQU 0AH ORG CPMB+16 ; SMSG: DB 0DH,0AH,0DH,'SBMS/K6HIJ',0AH,0DH DB MSIZE/10+'0',MSIZE MOD 10+'0' DB 'K CP/M V2.2 of 10-25-80',0 ; ; BOOT ; THIS SECTION IS EXECUTED WHENEVER RESET AND RUN ; IS PUSHED, AFTER THE COLDSTART LOADER READS IN ; THE CPM SYSTEM. ; BOOT: LXI SP,80H ;SET STACK POINTER. JMP BOOTF ;FINISH BOOT. ORG BIOS-64 ;HIDE REST OF BOOT HERE. BOOTF: XRA A ;CLEAR SCRATCH AREA. STA CDISK ;SELECT DRIVE ZERO STA LATCH ;SET LATCH FOR DRIVE A. LXI H,IOBYTE ;POINT TO IOBYTE. MVI M,80H ;SET UP IOBYTE. MVI B,ENDZ-STARTZ ;GET LENGTH OF ZERO AREA. LXI H,STARTZ ;GET SCRATCH ADDRESS. BOOTL: MOV M,A ;PUT ZERO IN MEMORY. INX H ;INCREMENT POINTER. DCR B ;DECREMENT COUNTER. JNZ BOOTL ;LOOP TILL DONE. IN CDATA ;CLEAR CONSOLE STATUS. LXI H,SMSG ;POINT TO SIGN ON. PMSG1: MOV A,M ;GET A BYTE OF THE MESSAGE INX H ;BUMP MEMORY POINTER. ORA A ;IS IT A ZERO? JZ GOCPM ;YES, WE ARE DONE, JMP TO CPM. MOV C,A ;NOPE, PRINT MORE MESSAGE. CALL CONOT ;USE THE CONOT ROUTINE. JMP PMSG1 ;AND LOOP TILL DONE. ORG BIOS ;START OF CBIOS STRUCTURE. ; ; 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. ; DMAENT: JMP BOOT ;FROM SBOOT LOADER,CHANGED FOR DMA. WBOOTE: JMP WBOOT ;FROM WARM BOOT. JMP @CONST ;CHECK CONSOLE KB STATUS. JMP @CONIN ;READ CONSOLE CHARACTER. JMP @CONOT ;WRITE CONSOLE CHARACTER. JMP @LIST ;WRITE LISTING CHAR. JMP @PUNCH ;WRITE PUNCH CHAR. JMP @READER ;READ READER CHAR. JMP HOME ;MOVE DISK TO TRACK ZERO. JMP SELDSK ;SELECT DISK DRIVE. JMP SETTRK ;SEEK TO TRACK IN REG A. JMP SETSEC ;SET SECTOR NUMBER. JMP SETDMA ;SET DISK STARTING ADR. JMP READ ;READ SELECTED SECTOR. JMP WRITE ;WRITE SELECTED SECTOR. JMP @PRSTAT ;LIST STATUS CHECK. JMP SECTRAN ;SECTOR TRANSLATE ROUTINE. ; THIS SECTION DEFINES THE THE DISK PARAMETERS ; NOTE: ; IF YOU HAVE THE MACRO ASSEMBLER (MAC) FROM ; DIGITAL RESEARCH, YOU MAY ELIMINATE THIS SECTION ; STARTING AT **AA** TO **BB** AND USE THE MACRO ; FILE "DISKDEF" TO CUSTOM TAILOR YOUR SYSTEM TO ; ALLOW DIFFERENT TYPES OF DRIVES OR MORE THAN 4 ; DRIVES. ; ;**AA** ; DPBASE EQU $ ;BASE OF DISK PARAMETER BLOCK DPE0: DW XLT0,0000H ;TRANSLATE TABLE DW 0000H,0000H ;SCRATCH AREA DW DIRBUF,SDTAB+2 ;DIR BUFF, PARM BLOCK DW CSV0,ALV0 ;CHECK, ALLOC VECTORS ; DPE1: DW XLT1,0000H DW 0000H,0000H DW DIRBUF,DPB1 DW CSV1,ALV1 ; ;THE FOLLOWING DESCRIBES THE DISK PHYSICAL ;NATURE, SUCH AS SECTORS/TRACK,DIRECTORY SIZE. ;THE FOLLOWING TABLE DEFINES A SINGLE DENSITY DRIVE. ; SDTAB: EQU $ ;ONE OF 4 DISK PARM. BLOCKS DW XLT0 ;USE SINGLE DENSITY TRANSLATE TAB. DW 26 ;SECTORS/TRACK DB 3 ;BLOCK SHIFT DB 7 ;BLOCK MASK DB 0 ;EXTNT MASK DW 242 ;DISK SIZE - 1 DW 63 ;DIRECTORY MAX. DB 192 ;ALLOC0 DB 0 ;ALLOC1 DW 16 ;CHECK SIZE DW 2 ;NUMBER OF SYSTEM TRACKS ; ;SECTOR TRANSLATION TABLE ; XLT0 EQU $ ;START OF TRANS. TABLE DB 1,7,13,19,25 DB 5,11,17,23,3 DB 9,15,21,2,8 DB 14,20,26,6,12 DB 18,24,4,10,16,22 ; DPB1 EQU SDTAB+2 ;EQUIVALENT PARAMETERS XLT1 EQU XLT0 ;SAME TRANSLATE TABLE ; ;**BB** ; ; ; WARM-BOOT: READ ALL OF CPM BACK IN ; EXCEPT BIOS, THEN JUMP TO CCP. ; WBOOT: LXI SP,80H ;SET STACK POINTER. LDA CDISK ;SAVE DISK NUMBER. STA TEMP MVI C,0 ;SELECT DISK 0. CALL SELDSK CALL HOME ;MOVE TO TRACK ZERO. JNZ RDERR1 ;IF ERROR, PRINT MESSAGE. MVI D,NSECTS ;GET # SECTORS FOR CPM READ. LXI B,2 ;TRACK (B)=0, SECTOR (C)=2. LXI H,CPMB ;GET STARTING ADDRESS. RDBLK: MOV A,B ;GOTO TRACK IN B. CALL SEEK JNZ RDERR1 ;IF ERROR, PRINT MESSAGE. MOV A,C ;READ STARTING AT SECTOR IN C. CALL READ1 RBLK1: JNZ RDERR1 ;IF ERROR, PRINT MESSAGE. DCR D ;DECREMENT SECTOR COUNT. JZ ALDON ;ALL DONE WHEN ZERO. INR C ;INCREMENT SECTOR NUMBER. MOV A,C ;IF SECTOR NUMBER CPI 27 ; IS NOT 27, JC RBLK2 ; HOP OUT OF LOOP. MVI C,1 ;OTHERWISE, RESET SECTOR=1 INR B ; INCREMENT TRACK NUMBER, JMP RDBLK ; AND READ NEXT TRACK. ALDON: LDA TEMP ;RESTORE DISK NUMBER. STA CDISK JMP GOCPM ;GO BACK TO CPM. RBLK2: CALL READ2 ;READ ANOTHER TRACK. JMP RBLK1 GOCPM: ; ; SET UP JUMPS INTO CP/M IN LOWER MEMORY. ; MVI A,0C3H ;PUT JMP TO WBOOT STA 0 ;ADR AT ZERO. LXI H,WBOOTE SHLD 1 STA 5 LXI H,BDOS ;PUT JUMP TO BDOS SHLD 6 ;AT ADR 5,6,7. LXI H,80H ;SET DEFAULT DMA ADR. SHLD DMAADD LDA CDISK ;GET DISK NUMBER TO MOV C,A ;PASS TO CCP IN C. JMP CPMB ;JUMP TO CCP. ; ; SELECT DISK NUMBER ACCORDING TO REGISTER C. ; SELDSK: LXI H,0 ;SET UP FOR ERROR CODE MOV A,C ;GET NEW DRIVE. CPI NDISK ;CALLING UNDEFINED DRIVE ? RNC ;IF NO CY, H,L TELLS CPM YES. STA CDISK ;WE ARE OK, SAVE NEW DISK NUMB. LXI H,DISKNO ;GET OLD DRIVE NUMBER. SELMOR: MOV A,M ;GET OLD DISK NUMBER. MOV E,A ;PUT OLD DISK NO. IN D&E. MVI D,0 LXI H,TRTAB ;GET ADDRESS OF TRACK TABLE. PUSH H ;SAVE ADDRESS OF TRTAB. DAD D ;ADD DISK NO. TO ADDRESS. IN TRACK ;READ 1771 TRACK REGISTER. MOV M,A ;PUT INTO TABLE. MOV A,C ;GET NEW DISK NUMBER. MOV E,A ;PUT NEW DISK NO. IN D&E. POP H ;RESTORE ADDRESS OF TRTAB. DAD D ;ADD DISK NO. TO ADDRESS. MOV A,M ;GET NEW TRACK NUMBER. OUT TRACK ;PUT INTO 1771 TRACK REG. SELD1: MOV A,C ;UPDATE OLD DISK NUMBER. STA DISKNO CMA ADD A ;PUT BITS 1&2 AT 4&5. ADD A ADD A ADD A ORI 2 STA LATCH ;SAVE NEW LATCH CODE. ; ;SELECT DRIVE AS A FUNCTION OF H,L ; PARINDX:LHLD DISKNO ;LOAD DISK NUMBER AND ZERO BYTE LXI D,DPBASE ;POINT TO DISK PARM START. DAD H ;*2 DAD H ; *4 DAD H ; *8 DAD H ; *16 DAD D ;COMPUTE INDEX FOR THE DRIVE XRA A ;SET A = 0. RET ;RETURN FROM SELDSK. ; ; MOVE DISK TO TRACK ZERO. ; HOME: MVI C,0 ;SEEK TO TRACK ZERO. MVI A,0D0H ;RESTORE COMMAND OUT DCOM ;TELL CONTROLLER. ; ; SET TRACK NUMBER TO WHATEVER IS IN REGISTER C. ; ALSO PERFORM MOVE TO THE CORRECT TRACK (SEEK). ; SETTRK: PUSH H ;SAVE H&L. LHLD LATCH ;GET NEW & OLD LATCH. MOV A,L ;GET NEW LATCH. OUT DCONT ;SELECT DRIVE NOW. STA CLATCH ;REMEMBER CURRENT LATCH. CMP H ;IS NEW SAME AS OLD? MVI A,0FFH ;IF NOT, SET FLAG = FF. JNZ SFLAG CMA ;IF NEW = OLD, FLAG = 0. SFLAG: STA HLSF ;SET HEAD-LOAD/SELECT FLAG. POP H ;RESTORE H&L. MOV A,C ;GET NEW TRACK NUMBER. STA TRK ;UPDATE OLD WITH NEW. ; ; MOVE THE HEAD TO THE TRACK IN REGISTER A. ; SEEK: PUSH B ;SAVE B&C. MOV B,A ;SAVE DESTINATION TRACK. MVI A,RTCNT ;GET RETRY COUNT. STA SERCNT ;STORE IN ERROR COUNTER. PUSH PSW SRETRY: POP PSW IN TRACK ;READ PRESENT TRACK NO. CMP B ;SAME AS NEW TRACK NO.? JNZ NOTHR ;JUMP IF NOT THERE. THERE: POP B ;RESTORE B&C. RET ;RETURN FROM SEEK. NOTHR: ;DELAY LOOP TO ALLOW TUNNEL ;ERASE TO END DURING WRITE. ; MVI A,0D0H ;COUNT = 208 BUSY1: DCR A ;LOOP JNZ BUSY1 ; TILL = ZER0 MOV A,B ;RESTORE A FROM B. OUT DDATA ;TRACK TO DATA REGISTER. BUSY: IN DSTAT ;READ DISK STATUS. RRC ;LOOK AT BIT 0. JC BUSY ;WAIT TILL NOT BUSY. MVI A,14H+STPRAT+HLAB ;GET STEP RATE, DO OUT DCOM ;SEEK WITH VERIFY. IN WAIT ;WAIT FOR INTRQ. IN DSTAT ;READ STATUS. ANI 98H ;LOOK AT BITS. JZ THERE ;OK IF ZERO. PUSH PSW LDA SERCNT ;GET ERROR COUNT. DCR A ;DECREMENT COUNT. JZ DABRT STA SERCNT JMP SRETRY DABRT: POP PSW CALL TP1ERR POP B DABRT1: LXI D,DABORT CALL PRINT JMP ABORT TP1ERR: RLC PUSH PSW LXI D,MSG1 CC PRINT POP PSW RLC PUSH PSW LXI D,MSG2 CC PRINT POP PSW RLC PUSH PSW LXI D,MSG3 CC PRINT POP PSW RLC PUSH PSW LXI D,MSG6 CC PRINT POP PSW RLC PUSH PSW LXI D,MSG4 CC PRINT POP PSW RLC PUSH PSW LXI D,MSG5 CC PRINT POP PSW RET ; ; SET DISK SECTOR NUMBER. ; SETSEC: MOV A,C ;GET SECTOR NUMBER. STA SECT ;PUT AT SECT # ADDRESS. RET ;RETURN FROM SETSEC. ; ;TRANSLATE THE SECTOR GIVEN B,C ;USING THE TRANSLATE TABLE ;GIVEN BY D,E ; SECTRAN: XCHG ;H,L = TRANS DAD B ;H,L = TRANS (SECTOR) MOV L,M ;L = TRANS (SECTOR) MVI H,0 ;CLEAR REG H RET ;H,L = TRANSLATED SECTOR ; ; SET DISK DMA ADDRESS. ; SETDMA: MOV H,B ;MOVE B&C TO H&L. MOV L,C SHLD DMAADD ;PUT AT DMA ADR ADDRESS. RET ;RETURN FROM SETDMA. ; ; HDLD - GET HEAD-LOAD BIT IF REQUIRED. ; HDLD: LDA HLSF ;GET HEAD-LOAD FLAG. ORA A ;IS A = ZERO? JZ HDLD1 ;HOP IF SO. CMA ;SET A = 0. STA HLSF ;SET FLAG = 0 IF NOT. HDLDY: MVI A,4 ;SET BIT TO LOAD HEAD. RET ;RETURN FROM HDLD. HDLD1: IN DSTAT ;READ 1771 STATUS. ANI 20H ;LOOK AT HL BIT. JZ HDLDY ;LOAD IF NOT LOADED. XRA A ;OTHERWISE, A=0. RET ;RETURN FROM HDLD. ; READ A SECTOR WITHOUT LOADING HEAD FIRST. ; READ1: OUT SECTP ;SET SECTOR NUMBER INTO 1771. MVI A,8CH ;GET CODE FOR READ W/O HLD. JMP READE ;READ A SECTOR. READ2: OUT SECTP MVI A,88H JMP READE ; ; READ THE SECTOR AT SECT, FROM THE PRESENT TRACK. ; USE STARTING ADDRESS AT DMAADD. ; READ: MVI A,RTCNT ;GET RETRY COUNT. RRETRY: ;STOR IN ERROR CTR. CALL DSKSET ADI 88H READE: OUT DCOM ;SEND COMMAND TO 1771. RLOOP: IN WAIT ;WAIT FOR DRQ OR INTRQ. ORA A ;SET FLAGS. JP RDDONE ;DONE IF INTRQ. IN DDATA ;READ A DATA BYTE FROM DISK. MOV M,A ;PUT BYTE INTO MEMORY. INX H ;INCREMENT MEMORY POINTER. JMP RLOOP ;KEEP READING. RDDONE: IN DSTAT ;READ DISK STATUS. ANI 9CH ;LOOK AT ERROR BITS. RZ ;RETURN IF NONE. CALL ERCHK ;CHECK FOR SEEK ERROR. LDA ERCNT ;GET ERROR COUNT. DCR A ;DECREMENT COUNT. JNZ RRETRY ;TRY TO READ AGAIN. JMP DABRT1 RDERR: RLC PUSH PSW LXI D,MSG1 CC PRINT POP PSW RLC RLC RLC PUSH PSW LXI D,MSG7 CC PRINT POP PSW RLC PUSH PSW LXI D,MSG4 CC PRINT POP PSW RLC PUSH PSW LXI D,MSG5 CC PRINT POP PSW RET RDERR1: MVI C,'B' CALL CONOT JMP 0E000H PRINT PUSH H MVI C,09 CALL BDOS POP H RET ABORT: MVI A,10 STA ERCNT STA SERCNT MVI A,1 JMP WBOOT ; ; ERCHK - CHECK FOR RECORD NOT FOUND ERROR. ; ERCHK: MOV D,A ;SAVE ERROR BITS ON STACK. ANI 10H ;IF RECORD NOT FOUND, JNZ CHKSK ;DO A CHECK ON SEEK. MOV A,D ;RESTORE ERROR BITS. ORA A RET ;AND RETURN. ;CHECK FOR SEEK TO CORRECT TRACK, ;AND CHANGE IF NECESSARY. CHKSK: MVI A,0C4H ;SEND COMMAND TO 1771 OUT DCOM ;TO READ ADDRESS. IN WAIT ;WAIT FOR DRQ OR INTRQ. IN DDATA ;READ THE TRACK ADDRESS. MOV B,A ;SAVE IN REGISTER B. CHKS2: IN WAIT ;WAIT FOR INTRQ. ORA A JP CHKS3 ;NOT IF DRQ. IN DDATA ;READ ANOTHER BYTE. JMP CHKS2 ;DO IT AGAIN. CHKS3: IN DSTAT ;READ DISK STATUS. ANI 09CH JZ CHKS4 ;READ ADR OK IF 0. PUSH D CALL RDERR CALL HOME ;OTHERWISE, HOME FIRST. POP D JMP CHKS5 CHKS4: MOV A,B ;UPDATE TRACK REGISTER. OUT TRACK CHKS5: LDA TRK ;GET REQUIRED TRACK NO. CALL SEEK ;MOVE THE HEAD TO IT. MOV A,D ORA A RET ; ;DISK SET UP ROUTINE. ;THIS ROUTINE IS COMMON TO ;BOTH THE READ AND WRITE ;ROUTINES. ; DSKSET: STA ERCNT ;STORE IN ERROR CTR. MVI A,0D0H ;CAUSE INTERRUPT. OUT DCOM XTHL ;SOME XTHL ; DELAY LHLD DMAADD ;GET STARTING ADDR. LDA SECT ;GET SECTOR NUMBER. OUT SECTP ;SET SECTOR INTO 1771. JMP HDLD ;GET HEAD-LOAD BIT? ; ; WRITE THE SECTOR AT SECT, ON THE PRESENT TRACK. ; USE STARTING ADDRESS AT DMAADD. ; WRITE: MVI A,RTCNT ;GET RETRY COUNT. WRETRY: CALL DSKSET ;SET UP DISK. ADI 0A8H ;ADD CODE TOR WRITE. WRITE2: OUT DCOM WLOOP: IN WAIT ;WAIT FOR READY. ORA A ;SET FLAGS. JP WDONE ;HOP OUT WHEN DONE. MOV A,M ;GET BYTE FROM MEM. OUT DDATA ;WRITE ONTO DISK. INX H ;INCREMENT MEM PTR. JMP WLOOP ;KEEP WRITING. WDONE: IN DSTAT ;READ DISK STATUS. ANI 0E4H ;LOOK AT THESE BITS. RZ ;RETURN IF NO ERR. CALL ERCHK ;CHECK/CORRECT SEEK ERR. CALL TP1ERR LDA ERCNT ;GET ERROR COUNT. DCR A ;DECREMENT COUNT. JNZ WRETRY ;TRY TO WRITE AGAIN. JMP DABRT1 ;NOTE: AS THERE ARE ONLY SIX (6) SECTORS ;AVAILABLE FOR CBIOS ON THE SECOND SYSTEM TRACK (1), ;THE LAST ADDRESS BEFORE THIS POINT SHOULD BE NO ;GREATER THAN THE CBIOS STARTING ADDRESS + 037F (HEX). ;THIS WILL NORMALLY BE XD7F (HEX). ; ; BIOS SCRATCH AREA. ; MSG1: DB CR,LF,'DRIVE NOT READY.','$' MSG2: DB CR,LF,'DISK WRITE PROTECTED.','$' MSG3: DB CR,LF,'WRITE FAULT.','$' MSG4: DB CR,LF,'CRC ERROR, BAD FORMAT.','$' MSG5: DB CR,LF,'LOST DATA.','$' MSG6: DB CR,LF,'DISK SEEK ERROR.','$' MSG7: DB CR,LF,'NOT FOUND.','$' DABORT: DB CR,LF,'DISK TRANSFER ABORTED','$' DMAADD: DW 0000H ;DISK TRANSFER ADDRESS. ; ; THE NEXT SEVERAL BYTES, BETWEEN STARTZ AND ; ENDZ, ARE SET TO ZERO AT COLD BOOT TIME. ; STARTZ: TRK: DB 0 ;CURRENT TRACK NUMBER. SECT: DB 1 ;CURRENT SECTOR NUMBER. DISKNO: DB 0 ;DISK NUMBER DB 0 PDISK: DB 0 ; SPECIAL FLAGS. HLSF: DB 0 ;HEAD-LOAD SELECT FLAG. LFCNT: DB 0 ;PAGING LINE-FEED COUNT. ; ; TRTAB - DISK TRACK TABLE - PRESENT POSITION OF ; HEADS FOR UP TO 4 DRIVES. ; TRTAB: DB 00 DB 00 ENDZ: ;END OF ZEROED AREA. ERCNT: DS 1 ;ERROR COUNT FOR RETRIES. SERCNT: DS 1 ;SEEK RETRY COUNTER. TEMP: DS 1 ;TEMPORARY STORAGE. LATCH: DS 1 ;NEW CODE FOR LATCH. CLATCH: DS 1 ;CURRENT CODE IN LATCH. BEGDAT EQU $ DIRBUF: DS 128 ;DIRECTORY BUFFER ALV0: DS 31 CSV0: DS 24 ALV1: DS 31 CSV1: DS 24 ALV2: DS 31 CSV2: DS 24 ALV3: DS 31 CSV3: DS 24 ENDDAT EQU $ DATSIZ EQU $-BEGDAT ;TOTAL SIZE OF DISK PARM STORAGE. TITLE 'ROM BASED I/O-IOBYTE-MODEM-PRINTER' ; BASIC INPUT/OUTPUT OPERATING SYSTEM ; IOBYTE PRINTER SYSTEM IN ROM ; MODIFIED BY RICHARD L BERG ; MAY 14,1980 ; ; THIS MODULE CONTAINS ALL THE INPUT/OUTPUT ; ROUTINES FOR THE CP/M SYSTEM. ; TTYS EQU 0 ;TTY STATUS PORT. TTYC EQU 0 ;TTY COMMAND PORT. TTYD EQU 1 ;TTY DATA PORT. TTYDA EQU 01H ;TTY READY BIT. TTYBE EQU 80H ;TTY OUTPUT RDY BIT. CRTS EQU 12H ;CRT STATUS PORT. CRTC EQU 12H ;CRT CONTROL PORT CRTD EQU 13H ;CRT DATA PORT. CRTDA EQU 01H ;CRT READY BIT. CRTBE EQU 80H ;CRT OUTPUT RDY BIT. PTRS EQU 2 ;PAPER TAPE STATUS PORT PTRDA EQU 01H ;PTR READY BIT. PTRD EQU 3 ;PTR DATA PORT. PTPS EQU 0 ;PTP STATUS PORT PTPBE EQU 80H ;PTP OUTPUT RDY BIT. PTPD EQU 1 ;PTP DATA PORT. LPTS EQU 10H ;LINE PRINTER STATUS PORT LPTBE EQU 0C0H ;LINE PRINTER OUTPUT RDY BIT. LPTD EQU 11H ;LINE PRINTER DATA PORT. IOBYT EQU 0003H ;I/O CONTROL BYTE ROM EQU 0FC00H ;START OF ROM I/O SYSTEM ; ; 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. ; ORG ROM @CONST JMP CONST ;CHECK FOR TTY CHAR READY. @CONIN JMP CONIN ;READ TTY CHARACTER. @CONOT JMP CONOT ;WRITE TTY CHARACTER. @LIST JMP LIST ;WRITE LISTING CHAR. @PUNCH JMP PUNCH ;WRITE PUNCH CHAR. @READER JMP READER ;READ READER CHAR. @PRSTAT JMP PRSTAT ;SAMPLE PRINTER STATUS @PMSG JMP PMSG ;PRINT MSG HANDLER. ;*********************************************** ; ; PERIPHERAL I/0 DRIVERS ; ;*********************************************** ; ; CONSOLE STATUS ; CONST: CALL CONS ;GET DEVICE STATUS MVI A,0 ;SET FLAGS RNZ ;ZERO IF NO CHAR AVAIL CMA ;FF IF CHAR OK RET CONS: LDA IOBYT ;GET IOBYT CALL IOCAL ;EXIT TO SELECTED ROUTINE DW TTYST ;TELETYPE STATUS ROUTINE DW CRTST ;CRT STATUS ROUTINE DW BATCH ;BATCH ROUTINE READER/LISTER DW TTYST ;USER-DEFINED STATUS ROUTINE ; ; CONSOLE INPUT ; CONIN: LDA IOBYT ;GET IOBYT CALL IOCAL ;EXIT TO SELECTED ROUTINE DW TTYIN ;TTY INPUT ROUTINE DW CRTIN ;CRT INPUT ROUTINE DW READER ;BATCH MODE DW UC1IN ;MODEM DRIVER ; ; CONSOLE OUTPUT ; CONOT: LDA IOBYT ;GET IOBYT CALL IOCAL ;EXIT TO SELECTED ROUTINE DW TTYOUT ;TTY OUTPUT ROUTINE DW CRTOUT ;CRT OUTPUT ROUTINE DW LIST ;BATCH MODE DW TTYOUT ;USER-DEFINED OUTPUT ROUTINE ; ; READER INPUT ; READER: LDA IOBYT ;GET IOBYT RRC ;SHIFT BITS RRC CALL IOCAL ;EXIT TO SELECTED ROUTINE DW TTYIN ;TTY INPUT ROUTINE DW PTRIN ;PAPER TAPE READER INPUT ROUTINE DW UR1IN ;MODEM INPUT ROUTINE DW UR2IN ;USER-DEFINED READER #2 ; ; PUNCH OUTPUT ; PUNCH: LDA IOBYT ;GET IOBYT RRC RRC ;SHIFT BITS RRC RRC CALL IOCAL ;EXIT TO SELECTED ROUTINE DW TTYOUT ;TTY OUTPUT ROUTINE DW PTPOUT ;PAPER TAPE PUNCH OUTPUT ROUTINE DW UP1OUT ;USER-DEFINED PUNCH #1 DW UP2OUT ;USER-DEFINED PUNCH #2 ; ; PRINTER STATUS ; PRSTAT: CALL PRS ;GET PRINTER STATUS MVI A,0 ;SET FLAGS RNZ ;ZERO IF NO CHAR AVAIL CMA ;FF IF CHAR OK RET PRS: LDA IOBYT ;GET IOBYT RLC ;SHIFT BITS RLC CALL IOCAL ;EXIT TO OUTPUT ROUTINE DW TTYST ;TELETYPE STATUS ROUTINE DW CRTST ;CRT STATUS ROUTINE DW PSTAT ;PRINTER STATUS ROUTINE DW UL1ST ;USER-DEFINED STATUS ROUTINE ; ; LISTING OUTPUT ; LIST: LDA IOBYT ;GET IOBYT RLC ;SHIFT BITS RLC CALL IOCAL ;EXIT TO SELECTED ROUTINE DW TTYOUT ;TTY OUTPUT ROUTINE DW CRTOUT ;CRT OUTPUT ROUTINE DW LPTOUT ;LINE PRINTER OUTPUT ROUTINE DW UL1OUT ;USER-DEFINED LIST OUTPUT ROUTINE ;******************************************************** ; ; I/O DISPATCHER ; ;******************************************************** IOCAL: RLC ;SHIFT BITS ANI 06H ;MASK BITS XTHL ;SAVE HL, GET TABLE ADDRESS PUSH D ;SAVE DE MOV E,A ;GET SELECTION VALUE IN A MVI D,0 DAD D ;CALCULATE TABLE ENTRY ADDRESS MOV A,M ;GET TABLE ENTRY INX H MOV H,M MOV L,A ;INTO HL POP D ;RESTORE DE XTHL ;PUT EXIT ADDR ON STACK, RESTORE RET ;EXIT TO ROUTINE ;**************************************************** ; ; PHYSICAL I/O ROUTINES ; ;**************************************************** TTYST: IN TTYS ;READ TTY STATUS ANI TTYDA ;TSET FOR TTY DATA AVAIL. RET ;EXIT WITH ZERO IF NOT AVAIL TTYIN: CALL TTYST ;TEST FOR CAR AVAIL JNZ TTYIN ;NOT YET, WAIT IN TTYD ;GET DATA ANI 7FH ;STRIP PARITY RET TTYOUT: IN TTYS ;GET TTY STATUS ANI TTYBE ;TEST FOR XMIT BUFFER EMPTY JNZ TTYOUT ;WAIT TIL READY MOV A,C ;GET OUTPUT CHAR OUT TTYD ;OUTPUT CHAR RET CRTST: IN CRTS ANI CRTDA ;TEST FOR TTY DATA AVAIL. RET CRTIN: CALL CRTST ;TEST FOR CHAR AVAIL JNZ CRTIN ;NOT YET, WAIT IN CRTD ;GET DATA ANI 7FH ;STRIP PARITY RET CRTOUT: IN CRTS ;GET CRT STATUS ANI CRTBE ;TEST FOR XMIT BUFFER EMPTY JNZ CRTOUT ;WAIT TIL READY MOV A,C ;GET OUTPUT CHAR OUT CRTD ;OUTPUT CHAR RET PTRIN: IN PTRS ;GET PTR STATUS ANI PTRDA ;TEST FOR PTR DATA AVAIL. JNZ PTRIN ;NOT YET, WAIT IN PTRD ;GET DATA ANI 7FH ;STRIP PARITY MOV C,A CALL CONOT ;WRITE IT TO CONCOLE RET PTPOUT: IN PTPS ;GET PTP STATUS ANI PTPBE ;TEST FOR XMIT BUFFER EMPTY JNZ PTPOUT ;WAIT TIL READY MOV A,C ;GET OUTPUT CHAR OUT PTPD ;OUTPUT CHAR RET PSTAT: IN LPTS ;GET LPT STATUS ANI LPTBE ;TEST FOR BUFFER EMPTY RET ;EXIT WITH ZERO IF NOT AVAIL LPTOUT: CALL PSTAT ;TEST FOR CAR AVAIL JNZ LPTOUT ;WAIT TIL READY MOV A,C ;GET OUTPUT CHAR OUT LPTD ;OUTPUT CHAR RET ; MODEM DRIVER TO USE CP/M ; AS A TIME-SHARE TERMINAL UC1IN: CALL TTYST ;CHARACTER ON CONSOLE? JNZ UC1A ;NO-CHECK MODEM CALL TTYIN ;YES-GET IT RET ;RETURN UC1A CALL CRTST ;CHARACTER ON MODEM? JNZ UC1IN ;NO-LOOP BACK CALL CRTIN ;YES-GET IT MOV C,A ;GET READY TO OUTPUT CALL TTYOUT ;PRINT ON CONSOLE JMP UC1IN ;CHECK FOR MORE UC1ST: LXI H,RDRMSG CALL PMSG MVI A,1AH ;SET A=CTL-Z (EOF) RET UC1OUT: JMP UC1ST ; MODEM DRIVER TO TRANSFER INFORMATION ; FROM MODEM TO CP/M DISK FILE ; ECHOS TO SYSTEM CONSOLE ; ECHOS ANYTHEING TYPED ON SYSTEM CONSOLE ; TO THE MODEM EXEPT A CONTROL Z ; WHICH IS SENT TO CP/M UR1IN: CALL CRTST ;CHARACTER ON MODEM? JNZ UR1A ;NO-CHECK CONSOLE CALL CRTIN ;YES-GET IT CPI 0 ;IS IT A NULL? JZ UR1IN ;YES-FORGET IT CPI 07FH ;IS IT A RUBOUT? JZ UR1IN ;YES-FORGET IT MOV C,A ;GET READY TO OUTPUT CALL TTYOUT ;PRINT ON CONSOLE MOV A,C ;KEEP CP/M STRAIGHT RET ;RETURN UR1A: CALL TTYST ;CHARACTER ON CONSOLE? JNZ UR1IN ;NO-CHECK MODEM CALL TTYIN ;YES-GET IT CPI 01AH ;IS IT A CONTROL Z? RZ ;YES-RETURN MOV C,A ;NO-GET READY TO OUTPUT CALL TTYOUT ;PRINT ON SYSTEM CONSOLE CALL CRTOUT ;TRANSMIT OVER MODEM JMP UR1IN ;DO IT ALL AGAIN UR2IN: JMP UC1ST UP1OUT: JMP UC1ST UP2OUT: JMP UC1ST UL1OUT: JMP UC1ST UL1ST: JMP UC1ST BATCH JMP UC1ST ; ; PRINT THE MESSAGE AT H&L UNTIL A ZERO. ; PMSG: MOV A,M ;GET A CHARACTER. ORA A ;IF IT'S ZERO, RZ ;RETURN. MOV C,A ;OTHERWISE, CALL CONOT ;PRINT IT. INX H ;INCREMENT H&L, JMP PMSG ;AND GET ANOTHER. RDRMSG: DB CR,LF,'USER-DEFINED NOT AVAILABLE',0 END