TITLE 'CP/M-85 BIOS (8088 CODE PORTION) 23 SEP 83' ;*** ; ; THIS IS THE 8088 CODED PORTION OF THE BIOS FOR CP/M-85. ; IT RESIDES IN THE FILE 'BIOS88.SYS'. ; FALSE EQU 0 TRUE EQU NOT FALSE ASM86 EQU TRUE EXPER EQU FALSE REL0 EQU 0 ;*** EQUATES ; INCLUDE ZMEMMAP.LIB INCLUDE ASCII.LIB INCLUDE DEF6821.LIB INCLUDE DEF6845.LIB INCLUDE DEF8253.LIB INCLUDE DEF8259A.LIB INCLUDE EP2DEF.LIB INCLUDE SBCDEF.LIB INCLUDE TIMERDEF.LIB INCLUDE Z207DEF.LIB INCLUDE Z217DEF.LIB INCLUDE ZINT.LIB INCLUDE ZMTR100.LIB INCLUDE ZPORTS.LIB INCLUDE ZVIDEO.LIB INCLUDE ZGDPDEF.LIB INCLUDE ZKEYBD.LIB ;** MISCELLANEOUS EQUATES ; INCLUDE EXTRAOPS.LIB ;* DEVICE DRIVER ENTRY JUMP VECTOR OFFSETS ; DDSEL EQU 0 ;SELECT DDRDT EQU 3 ;READ TRACK DDWRT EQU 6 ;WRITE TRACK DDMNT EQU 9 ;MOUNT DDFMT EQU 12 ;FORMAT DDWPC EQU 15 ;WRITE PROTECT CHECK ;* DISK OPERATIONS IN PROGRESS FLAGS ; DSKOPS EQU 00000001B ;1ST TIME AFTER WARM BOOT SELECTION DSKOPR EQU 00000010B ;READ DSKOPW EQU 00000100B ;WRITE DSKOPRA EQU 00001000B ;READ ADDRESS HEADER DSKOPF EQU 00010000B ;FORMAT DSKOPWP EQU 00100000B ;WRITE PROTECT CHECK DSKOPI EQU 01000000B ;INIT DSKOPRD EQU 10000000B ;READY ;* DISK BUFFER HANDLING DEFINITIONS ; DSEG BUFCNT EQU 4 ;NUMBER OF BUFFERS ; BUFFER HEADER INFO ORG 0 BUFHDR RB 0 BUFFWD RW 1 ;FORWARD CHAIN POINTER BUFBAK RW 1 ;BACKWARD CHAIN POINTER BUFDRV RB 1 ;DRIVE # BUFPDRV RB 1 ;MAPPED DRIVE # (PHYSICAL TABLE #) BUFDPE RW 1 ;ADDRESS OF DPE BUFTRK RW 1 ;TRACK # BUFWRF RB 1 ;BUFFER DIRTY FLAG BUFSECF RW 1 ;ADDRESS OF DIRTY SECTOR FLAGS BUFERR RB 1 ;TRACK ERROR FLAG BUFERRF RW 1 ;ADDRESS OF SECTOR ERROR FLAGS BUFBUF RW 1 ;ADDRESS OF BUFFER AREA BUFHDRL EQU OFFSET $ - OFFSET BUFHDR ;LENGTH OF BUFFER HEADER INFO EJECT ;*** EQUATES FOR INFO IN EXTRA SEGMENT ; ESEG BIAS EQU 0 INCLUDE CPM85SYS.LIB INCLUDE CIOTABLE.LIB INCLUDE BIOSDEF.LIB INCLUDE ZDPEDEF.LIB INCLUDE LABDEF.LIB ORG 0B0EH ;! KBCHAR RB 0 ;BDOS 1 CHAR TYPE AHEAD BUFFER ;! EJECT ;*** COLD BOOT ENTRY ; CSEG ORG BIOS88 CBOOTE: CLI ;INSURE I'M NOT DISTURBED ; INITIALIZE PARITY GENERATION PUSH DS PUSH ES MOV AL,ZMCLPZ+ZRM2 ;TURN OFF PARITY CHECKING OUT ZMCL,AL OUT 098H,AL OUT 099H,AL OUT 09AH,AL OUT 09BH,AL OUT 09CH,AL OUT 09DH,AL OUT 09EH,AL OUT 09FH,AL XOR AX,AX ;START AT SEGMENT 0 MEMIL: MOV DS,AX ;SET UP SEGMENT REGISTERS MOV ES,AX MOV AX,.0 ;GET FIRST WORD MOV BX,AX ;SAVE A COPY INC AX ;BUMP VALUE INC WORD PTR .0 ;BUMP MEMORY CMP AX,.0 ;Q. ARE THEY THE SAME JNE MEMIC ; BR IF NOT MOV .0,BX ;RESTORE VALUE XOR SI,SI ;SET UP REGS FOR MOVE XOR DI,DI MOV CX,08000H ;GET NUMBER OF WORDS TO MOVE REP MOVSW ;MOVE WORDS ONTO THEMSELVES MEMIC: MOV AX,DS ;POINT TO NEXT SEGMENT ADD AX,01000H JNZ MEMIL ; LOOP IF NO WRAP AROUND POP ES POP DS MOV AL,ZMCLPK+ZMCLPZ+ZRM2 ;TURN ON PARITY CHECKING OUT ZMCL,AL OUT 098H,AL OUT 099H,AL OUT 09AH,AL OUT 09BH,AL OUT 09CH,AL OUT 09DH,AL OUT 09EH,AL OUT 09FH,AL ; INITIALIZE ALL VECTORS (EXCEPT WHERE MONITOR DATA SEGMENT INFO ; IS) TO POINT TO WILD INTERRUPT HANDLER MOV BX,OFFSET INTWILD ;INITIALIZE VECTORS FOR WILD INTERRUPT MOV .0,BX MOV .2,CS MOV SI,0 MOV DI,4 MOV CX,(256-2)*4/2 CLD REP MOVSW ; INITIALIZE SOFTWARE INTERRUPT VECTORS MOV BX,OFFSET INTDIV0 ;DIVIDE BY ZERO MOV .0,BX MOV .2,CS MOV BX,OFFSET INTSWAP ;SWAP PROCESSORS MOV .SWAPVEC,BX MOV .SWAPVEC+2,CS ; INITIALIZE HARDWARE INTERRUPT VECTORS LEA SI,HINTVO MOV DI,ZINTMT*4 MOV CX,18 CLD INHV: MOVSW ADD DI,2 LOOP INHV ; INITIALIZE MASTER 8259A MOV AL,ICW1OP+ICW1LT+ICW1ADI+ICW1I4 OUT Z8259AM+ICW1,AL ;LEVEL TRIGGERED, ADI OF 4 MOV AL,ZINTMT OUT Z8259AM+ICW2,AL ;BASE TRAP VECTOR MOV AL,1 SHL ZINTSLV OUT Z8259AM+ICW3,AL ;INDICATE SLAVE IR LINE MOV AL,ICW4SFN+ICW4UPM OUT Z8259AM+ICW4,AL ;SPECIAL FULLY NESTED, 8086 PROCESSOR MOV AL,0FFH-(1 SHL ZINTKD)-(1 SHL ZINTTIM)-(1 SHL ZINTEI) OUT Z8259AM+OCW1,AL ;ENABLE ONLY DESIRED IR LINES ; INITIALIZE SLAVE 8259A MOV AL,ICW1OP+ICW1LT+ICW1ADI+ICW1I4 OUT Z8259AS+ICW1,AL ;LEVEL TRIGGERED, ADI OF 4 MOV AL,ZINTST OUT Z8259AS+ICW2,AL ;BASE TRAP VECTOR MOV AL,ZINTSLV OUT Z8259AS+ICW3,AL ;SLAVE ID MOV AL,ICW4UPM OUT Z8259AS+ICW4,AL ;8086 PROCESSOR MOV AL,0FFH OUT Z8259AS+OCW1,AL ;DISABLE ALL IR LINES ; MOVE ROM MONITOR DATA AREA TO BANK 0 PUSH DS MOV SI,0 ;GET SOURCE ADDRESS FOR MOVE MOV AX,.MTRDSEG MOV OMDSEG,AX MOV DS,AX MOV DI,B88DAT ;GET DESTINATION ADDRESS FOR MOVE MOV CX,MTRDSZ ;GET BYTE COUNT CMP CX,BIOS88-B88DAT ;Q. LARGER THAN ALLOCATED SPACE JBE MVMTRDA ; BR IF NOT POP DS ;MEMORY MAP LAYOUT ONLY ALLOWS LEA SI,MTRMSG ; A MAXIMUM MONITOR DATA AREA CALL PMSG ; SIZE JMP SYSHLT MVMTRDA: CLD ;SET FORWARD DIRECTION REP MOVSB ;DO MOVE MOV AX,B88DAT/16 ;POINT TO NEW LOCATION OF DATA AREA MOV DS,AX MOV MTRDXMTC,MTRSKBD ;INITIALIZE KEYBOARD HANDLER MOV MTRDXMTC+2,MTRSEG ; TO USE MY QUEUE MOV MTRSXMTC,OFFSET PUTKEY MOV MTRSXMTC+2,CS POP DS MOV WORD PTR .MTRDSEG,B88DAT/16 ;UPDATE MONITOR DSEG SLOT ; NOW SETUP CP/M-85 SYSTEM IN BANK 1 MOV AX,64/16*1024 ;FROM NOW ON EXTRA SEGMENT MOV ES,AX ; WILL POINT TO BANK 1 MOV BANK1,AX ;SAVE VALUE MOV AL,1 ;SET HIGH ADDR LATCH TO BANK 1 FOR 8085 OUT ZHAL,AL MOV SI,BLDRP0 ;MOVE PAGE ZERO MOV DI,0 MOV CX,256/2 CLD REP MOVSW MOV SI,BBIOS ;MOVE CCP, BDOS, & BIOS SUB SI,CCPL+BDOSL MOV CCPORG1,SI MOV DI,SI MOV CX,SI NEG CX INC CX SHR CX,1 CLD REP MOVSW MOV BX,BBIOS ;SET DEFAULT I/O BYTE MOV AL,DEFIOB[BX] MOV IOBYTE,AL ; MOVE CP/M CCP & BDOS AGAINST TOP OF BANK 0 ; TO PROVIDE MORE ROOM FOR DISK BUFFERS MOV SI,CCPORG1 ADD SI,CCPL+BDOSL-1 MOV DI,0FFFFH MOV CX,CCPL+BDOSL PUSH ES MOV AX,DS MOV ES,AX STD REP MOVSB POP ES INC DI MOV CCPORG0,DI ; CALL ALTCHR ;HANDLE ALTERNATE CHARACTER FONTS ; INITIALIZE CHARACTER I/O PORTS CALL INCRT ;CRT: CALL INSERA ;SERIAL PORT A CALL INSERB ;SERIAL PORT B CALL INPPRT ;LIGHTPEN, VSYNC , & PARALLEL PRINTER CALL INDUMMY ;DUMMY I/O MOV LPENHF,0 ;INDICATE NO LIGHT PEN HIT ; CALL INTIM ;INITIALIZE TIMER MOV COMWHO,ZPSPPS8 ;INDICATE WHICH PROCESSOR HAS CONTROL STI ;ALLOW INTERRUPTS NOW ; INITIALIZE HOST BUFFERING SCHEME CMP CCPORG0,B88END ;Q. ENOUGH MEMORY JNB CBINBUF ; BR IF YES LEA SI,BUFMSG ; OTHERWISE PRINT ERROR MESSAGE CALL PMSG JMP SYSHLT CBINBUF: CALL INBUF ;INIT BUFFERING ; INITIALIZE LOGICAL DRIVE TO PHYSICAL DRIVE MAP PUSH ES MOV ES,.MTRDSEG ;GET ADDRESS OF MONITOR DATA AREA MOV AL,ES: MTRBI ;GET BOOT DEVICE INDEX # CMP ES: MTRBI,2 ;Q. Z217 BOOTED POP ES JNE CBINDRV1 ; BR IF NOT CALL IN217 CALL IN207 JMPS PSIGNON CBINDRV1: CALL IN207 CALL IN217 ; PRINT SIGNON MESSAGE PSIGNON: LEA SI,SIGNON CALL PMSG ; INT SWISWAP ;SWAP TO 8085 PROCESSOR EJECT ;** WARM BOOT ENTRY ; ; MOVE 'CCP' AND 'BDOS' FROM BANK 0 TO BANK 1. ; THIS REPLACES THE NEED TO READ THE DISK ON WARM BOOT. ; WBOOTE: CALL CLRBUFA ;CLEAR ALL HOST BUFFERS MOV SI,CCPORG0 ;SOURCE ADDR OF CCP & BDOS IN BANK 0 MOV DI,CCPORG1 ;DESTINATION ADDR IN BANK 1 MOV CX,(CCPL+BDOSL)/2 ;WORD COUNT CLD ;SET DIRECTION FORWARD REP MOVSW RET ;** CONSOLE STATUS ENTRY ; ; ENTRY: NONE ; EXIT: (AL),'COMRA'=STATUS ; 0=NO CHARACTER AVAILABLE , 0FFH=CHARACTER AVAILABLE ; USES: ALL ; CONSTE: MOV AL,IOBYTE ;GET IOBYTE VALUE SHL AL,1 ;ADJUST VALUE CALL GETCIO ;GET APPROPRIATE CIO TABLE ENTRY DW SERATBL DW CRTTBL DW 0 DW SERBTBL TEST BX,BX ;Q. SPECIAL CASE BAT: JNZ CONSTE1 ; BR IF NOT MOV AL,IOBYTE ;GET IOBYTE VALUE SHR AL,1 ;ADJUST VALUE CALL GETCIO ;GET APPROPRIATE CIO TABLE ENTRY DW SERATBL DW DUMMYTBL DW SERBTBL DW CRTTBL CONSTE1: CALL ISCIO ;CALL CIO HANDLER MOV COMRA,AL ;PUT STATUS IN COM REGION RET ;** CONSOLE INPUT ENTRY ; ; ENTRY: NONE ; EXIT: (AL),'COMRA'=CHARACTER READ FROM CONSOLE ; USES: ALL ; CONINE: MOV AL,IOBYTE ;GET IOBYTE VALUE SHL AL,1 ;ADJUST VALUE CALL GETCIO ;GET APPROPRIATE CIO TABLE ENTRY DW SERATBL DW CRTTBL DW 0 DW SERBTBL TEST BX,BX ;Q. SPECIAL CASE BAT: JZ RDRINE ; BR IF YES CALL IDCIO ;CALL CIO HANDLER MOV COMRA,AL ;PUT CHARACTER IN COM REGION RET ;** CONSOLE OUTPUT ENTRY ; ; ENTRY: 'COMRC'=CHARACTER TO BE OUTPUT ; EXIT: NONE ; USES: ALL ; CONOUTE: MOV AL,IOBYTE ;GET IOBYTE VALUE SHL AL,1 ;ADJUST VALUE MOV CL,COMRC ;GET CHARACTER CALL GETCIO ;GET APPROPRIATE CIO TABLE ENTRY DW SERATBL DW CRTTBL DW 0 DW SERBTBL TEST BX,BX ;Q. SPECIAL CASE BAT: JZ LSTOUTE ; BR IF YES JMP ODCIO ;RETURN VIA CIO HANDLER ;** LIST OUTPUT ENTRY ; ; ENTRY: 'COMRC'=CHARACTER TO BE OUTPUT ; EXIT: NONE ; USES: ALL ; LSTOUTE: MOV AL,IOBYTE ;GET IOBYTE VALUE MOV CL,5 ;ADJUST VALUE SHR AL,CL MOV CL,COMRC ;GET CHARACTER CALL GETCIO ;GET APPROPRIATE CIO TABLE ENTRY DW SERATBL DW CRTTBL DW PPRTTBL DW SERBTBL JMP ODCIO ;RETURN VIA CIO HANDLER ;** PUNCH OUTPUT ENTRY ; ; ENTRY: 'COMRC'=CHARACTER TO BE OUTPUT ; EXIT: NONE ; USES: ALL ; PUNOUTE: MOV AL,IOBYTE ;GET IOBYTE VALUE MOV CL,3 ;ADJUST VALUE SHR AL,CL MOV CL,COMRC ;GET CHARACTER CALL GETCIO ;GET APPROPRIATE CIO TABLE ENTRY DW SERATBL DW DUMMYTBL DW SERBTBL DW CRTTBL JMP ODCIO ;RETURN VIA CIO HANDLER ;** READER INPUT ENTRY ; ; ENTRY: NONE ; EXIT: (AL),'COMRA'=CHARACTER READ ; USES: ALL ; RDRINE: MOV AL,IOBYTE ;GET IOBYTE VALUE SHR AL,1 ;ADJUST VALUE CALL GETCIO ;GET APPROPRIATE CIO TABLE ENTRY DW SERATBL DW DUMMYTBL DW SERBTBL DW CRTTBL CALL IDCIO ;CALL CIO HANDLER MOV COMRA,AL ;PUT CHARACTER IN COM REGION RET ;** HOME HEAD ENTRY ; ; ENTRY: NONE ; EXIT: NONE ; USES: ALL ; HOMEE: CALL CHKDBD ;Q. ANY DIRTY BUFFERS FOR REQ DRIVE TEST AL,AL JNZ HOMEE1 ; BR IF YES CALL CLRBUFD ;FORCE PHYSICAL I/O HOMEE1: MOV AX,0 ;SET REQUESTED TRACK # = 0 JMP SETTRKE1 ;JOIN SET TRACK CODE ;** SET DISK DRIVE ENTRY ; ; ENTRY: 'COMRC'=REQUESTED DRIVE ; 'COMRE'=LSB INDICATES 1ST TIME SINCE WARM BOOT SELECT ; 0=1ST TIME , 1=SUBSEQUENT TIMES ; 'COMRHL'=ADDRESS OF XLATE TABLE ADDRESSES ; EXIT: 'COMRHL'=RESULTS ; 0=ERROR , NOT 0=NO ERROR ; USES: ALL ; SETDSKE: MOV AL,COMRC ;GET REQUESTED DRIVE # MOV REQDRV,AL ;SAVE IT MOV BX,BBIOS ;CHECK IF IN RANGE CMP AL,NDISKS[BX] JAE SETDSKE5 ; BR IF NOT CBW ;CONVERT LOGICAL DRIVE # TO MOV BX,AX ; PHYSICAL DRIVE # MOV AL,BDMAP[BX] MOV PHYDRV,AL MOV BL,DPEL ;COMPUTE ADDRESS OF DPE MUL BL ADD AX,OFFSET DPEBASE ADD AX,BBIOS MOV PHYDPE,AX ;SAVE IT TEST COMRE,1 ;CHECK IF 1ST LOGIN JNZ SETDSKE9 ; BR IF NOT CALL CLRBUFD ;CLEAR HOST BUFFERS FOR THIS DRIVE MOV PREREAD,0 ;INDICATE DON'T DO PREREAD CALL SETUP ;GET A BUFFER TO USE CMP BUFERR[BX],0 ;Q. ABORT JNE SETDSKEA ; BR IF YES MOV AX,COMRHL ;GET ADDRESS OF XLATE TABLE ADDRESSES MOV XLATES,AX MOV AL,DDSEL ;CALL DEVICE DRIVER TO DO SELECT CALL DRVR CALL CLRBUFD ;GIVE BACK BUFFER CMP PHYDPE,0 ;Q. ERROR JNE SETDSKE9 ; BR IF NO ERROR RETURN BY DRIVER ; ERROR DURING SETDSK SETDSKE5: MOV AL,REQDRV ;CHECK IF REQUESTED DRIVE CMP AL,DFTDRV ; WAS TO BE DEFAULT DRIVE JNE SETDSKE6 ; BR IF NOT MOV DFTDRV,0 ;FORCE DEFAULT DRIVE TO 'A:' SETDSKE6: MOV PHYDPE,0 ;INDICATE ERROR (ADDR OF DPE = 0) ; RETURN ADDRESS OF DPE TO CALLER SETDSKE9: MOV AX,PHYDPE MOV COMRHL,AX RET ; ERROR DURING SETUP SETDSKEA: CALL CLRBUFD ;GIVE BACK BUFFER JMPS SETDSKE5 ;** SET TRACK ENTRY ; ; ENTRY: 'COMRBC'=TRACK # ; EXIT: NONE ; USES: ALL ; SETTRKE: MOV AX,COMRBC ;GET TRACK # SETTRKE1: MOV REQTRK,AX ;SAVE AS REQUESTED CP/M TRACK # RET ;** SET SECTOR ENTRY ; ; ENTRY: 'COMRBC'=SECTOR # (IN RANGE 1 TO SPT) ; EXIT: NONE ; USES: ALL ; ; *** NOTE *** ; IT IS ASSUMED ON ENTRY THAT THE SECTOR NUMBER IS IN THE RANGE 1 TO ; 'CP/M SECTORS PER TRACK'. THEREFORE, ONLY THE VALUE PASSED ; IN REGISTER C IS USED. ; INTERNALLY THE BIOS WANTS SECTOR NUMBERS IN THE RANGE ; 0 TO SPT-1. THEREFORE, BEFORE SAVING THE SECTOR NUMBER, ; IT IS DECREMENTED. ; SETSECE: MOV AL,COMRC ;GET SECTOR # DEC AL ;PUT INTO RANGE 0 TO SPT-1 XOR AH,AH ;ZERO HIGH ORDER BYTE MOV REQSEC,AX ;SAVE AS REQUESTED CP/M SECTOR # RET ;** SET DMA ENTRY ; ; ENTRY: 'COMRBC'=DMA POINTER ; EXIT: NONE ; USES: ALL ; SETDMAE: MOV AX,COMRBC ;GET DMA POINTER MOV DMAPTR,AX ;SAVE AS DMA POINTER RET ;** READ CP/M SECTOR ENTRY ; ; ENTRY: NONE ; EXIT: 'COMRA'=ERROR STATUS ; 0=NO ERROR , 1=ERROR ; USES: ALL ; READE: MOV PREREAD,1 ;DO PREREAD CALL SETUP ;CALL R/W COMMON SETUP ROUTINE CMP BUFERR[BX],0 ;Q. ERROR DURING SETUP JNE READE1 ; BR IF YES ; HOST BUFFER CONTAINS REQUESTED CP/M SECTOR. ; COPY IT TO USER BUFFER. MOV SI,BUFBUF[BX] ;COMPUTE START OF REQ CP/M SECTOR ADD SI,AX ; IN HOST BUFFER MOV DI,DMAPTR ;GET DMA POINTER REP MOVSW ;MOVE DATA FROM HOST TO USER BUFFER ; CALL CPSEC ;INDICATE ERROR STATUS OR DSKOP,DSKOPR CALL ABTIGN AND DSKOP,NOT DSKOPR READE1: MOV AL,BUFERR[BX] MOV COMRA,AL RET ;** WRITE CP/M SECTOR ENTRY ; ; ENTRY: 'COMRC'=TYPE OF WRITE ; 0=NORMAL WRITE ; 1=WRITE TO A DIRECTORY SECTOR ; 2=1ST WRITE TO A SECTOR IN AN UNALLOCATED BLOCK ; EXIT: 'COMRA'=ERROR STATUS ; 0=NO ERROR , 1=ERROR ; USES: ALL ; WRITEE: MOV PREREAD,1 ;DO PREREAD CALL SETUP ;CALL R/W COMMON SETUP ROUTINE CMP BUFERR[BX],0 ;Q. ERROR DURING SETUP JNE WRITEE5 ; BR IF YES ; HOST BUFFER CONTAINS TRACK FOR REQUESTED CP/M SECTOR. ; COPY THE SECTOR FROM USER BUFFER TO HOST BUFFER. MOV SI,DMAPTR ;GET DMA POINTER MOV DI,BUFBUF[BX] ;COMPUTE START OF REQ CP/M SECTOR ADD DI,AX ; IN HOST BUFFER CALL EXDSES ;EXCHANGE DS AND ES REP MOVSW ;MOVE DATA FROM USER TO HOST BUFFER CALL EXDSES ;RESTORE DS AND ES ; MARK PHYSICAL SECTOR AND HOST WRITE BUFFER AS DIRTY CALL CPSEC ;MARK WHICH HOST WRITE BUFFER MOV DI,BUFSECF[BX] ADD DI,PHYSEC MOV BYTE PTR [DI],1 ; PHYSICAL SECTOR IS DIRTY MOV BUFWRF[BX],1 ;INDICATE HOST BUFFER IS DIRTY ; CHECK FOR ABORT IF ERROR ON PREREAD CALL CPSEC OR DSKOP,DSKOPR CALL ABTIGN AND DSKOP,NOT DSKOPR CMP BUFERR[BX],0 JNE WRITEE5 ; IF TYPE OF WRITE IS A DIRECTORY WRITE, ; THEN FLUSH ALL HOST BUFFERS FOR REQUESTED DRIVE. MOV AL,COMRC ;CHECK TYPE OF WRITE CMP AL,BWRDIR JNE WRITEE5 ; BR IF NOT DIRECTORY WRITE CALL FLUSHD ;FLUSH BUFFERS JMPS WRITEE6 ; WRITEE5: MOV AL,BUFERR[BX] ;INDICATE ERROR STATUS WRITEE6: MOV COMRA,AL RET ;** CHECK LIST DEVICE STATUS ENTRY ; ; ENTRY: NONE ; EXIT: (AL),'COMRA'=STATUS ; 0=NOT READY , 0FFH=READY ; USES: ALL ; LSTSTE: MOV AL,IOBYTE ;GET IOBYTE VALUE MOV CL,5 ;ADJUST VALUE SHR AL,CL CALL GETCIO ;GET APPROPRIATE CIO TABLE ENTRY DW SERATBL DW CRTTBL DW PPRTTBL DW SERBTBL CALL OSCIO ;CALL CIO HANDLER MOV COMRA,AL ;PUT STATUS IN COM REGION RET ;** SECTOR TRANSLATE ENTRY ; ; ENTRY: 'COMRBC'=LOGICAL SECTOR NUMBER (IN RANGE 0 TO SPT-1) ; 'COMRDE'=ADDRESS OF SECTOR TABLE ; EXIT: 'COMRHL'=TRANSLATED CP/M SECTOR NUMBER (IN RANGE 1 TO SPT) ; USES: ALL ; SECTRNE: MOV BX,COMRBC MOV SI,COMRDE TEST SI,SI JZ SECTRNE1 MOV BL,ES:[BX+SI] XOR BH,BH JMPS SECTRNE2 SECTRNE1: INC BX SECTRNE2: MOV COMRHL,BX RET ;** FORMAT - FORMAT ENTRY ; ; ENTRY: 'COMRC'=VERIFY FLAG (0=NO , 1=YES) ; EXIT: 'COMRA'=STATUS BYTE ; USES: ALL ; FORMATE: CALL CLRBUFD ;CLEAR HOST BUFFERS FOR THIS DRIVE MOV PREREAD,0 ;DON'T PREREAD CALL SETUP ;GET A BUFFER TO USE MOV AL,0FFH CMP BUFERR[BX],0 ;Q. ERROR DURING SETUP JNE FORMATE1 ; BR IF YES MOV AL,COMRC ;GET VERIFY FLAG MOV FVFLG,AL MOV AL,DDFMT ;CALL DEVICE DRIVER TO DO FORMAT CALL DRVR XOR AL,AL ;ASSUME NO ERROR STATUS CMP BUFERR[BX],0 ;Q. ERROR JE FORMATE1 ; BR IF NOT MOV AL,ERRTYP ;GET ERROR STATUS BYTE FORMATE1: MOV COMRA,AL ;PLACE STATUS BYTE INTO COM REGION CALL CLRBUFD ;GIVE BACK BUFFER RET ;** READ TRACK ENTRY ; ; ENTRY: NONE ; EXIT: 'COMRA'=ERROR STATUS ; 0=NO ERROR , 1=ERROR ; USES: ALL ; RDTRKE: MOV PREREAD,0 ;INDICATE NO PREREAD CALL SETUP ;CALL R/W COMMON SETUP ROUTINE CMP BUFERR[BX],0 ;Q. ERROR DURING SETUP JNE RDTRKE1 ; BR IF YES MOV AL,DDRDT ;FORCE PHYSICAL READ OF TRACK CALL DRVR ; HOST BUFFER CONTAINS REQUESTED CP/M TRACK. ; COPY IT TO USER BUFFER. MOV SI,BUFDPE[BX] ;COMPUTE # BYTES TO COPY MOV SI,DPEDPB[SI] MOV AX,DPBSPT[SI] MOV CL,7 SHL AX,CL MOV CX,AX MOV SI,BUFBUF[BX] ;GET START OF HOST BUFFER MOV DI,DMAPTR ;GET DMA POINTER REP MOVSB ;MOVE DATA FROM HOST TO USER BUFFER ; RDTRKE1: MOV AL,BUFERR[BX] ;INDICATE ERROR STATUS MOV COMRA,AL RET ;** WRITE TRACK ENTRY ; ; ENTRY: NONE ; EXIT: 'COMRA'=ERROR STATUS ; 0=NO ERROR , 1=ERROR ; USES: ALL ; WRTRKE: MOV PREREAD,0 ;INDICATE NO PREREAD CALL SETUP ;CALL R/W COMMON SETUP ROUTINE CMP BUFERR[BX],0 ;Q. ERROR DURING SETUP JNE WRTRKE3 ; BR IF YES ; COPY THE TRACK FROM USER BUFFER TO HOST BUFFER MOV SI,BUFDPE[BX] ;COMPUTE # BYTES MOV SI,DPEDPB[SI] MOV AX,DPBSPT[SI] PUSH AX MOV CL,7 SHL AX,CL MOV CX,AX MOV SI,DMAPTR ;GET DMA POINTER MOV DI,BUFBUF[BX] ;GET START OF HOST BUFFER CALL EXDSES ;EXCHANGE DS AND ES REP MOVSB ;MOVE DATA FROM USER TO HOST BUFFER CALL EXDSES ;RESTORE DS AND ES ; MARK PHYSICAL SECTORS AND HOST BUFFER AS DIRTY POP AX ;COMPUTE # PHYSICAL SECTORS PER TRACK MOV DI,BUFDPE[BX] CMP REQTRK,0 JNE WRTRKE1 TEST DPEFLAG[DI],DPET0SD JZ WRTRKE1 MOV AL,26 JMPS WRTRKE2 WRTRKE1: DIV DPERPS[DI] WRTRKE2: CBW MOV CX,AX MOV AL,1 ;SET DIRTY SECTOR FLAGS MOV DI,BUFSECF[BX] CLD CALL EXDSES REP STOSB CALL EXDSES MOV BUFWRF[BX],1 ;INDICATE HOST BUFFER IS DIRTY ; CALL FLUSH ;FLUSH BUFFER WRTRKE3: MOV AL,BUFERR[BX] ;INDICATE ERROR STATUS MOV COMRA,AL RET ;** WRITE PROTECT CHECK ; ; ENTRY: NONE ; EXIT: 'COMRA'=STATUS (0=R/W , 1=R/O) ; USES: ALL ; WPCE: LEA BX,DMYHDR ;USE DUMMY BUFFER HEADER MOV AL,REQDRV MOV BUFDRV[BX],AL MOV AL,PHYDRV MOV BUFPDRV[BX],AL MOV AX,PHYDPE MOV BUFDPE[BX],AX MOV AL,DDWPC ;CALL DEVICE DRIVER TO DO CHECK CALL DRVR MOV AL,BUFERR[BX] ;GET RETURN VALUE MOV COMRA,AL RET ;** PEEK 8088 MEMORY FUNCTION ; ; ENTRY: 'COMRDE'=OFFSET ; 'COMRHL'=SEGMENT ; EXIT: 'COMRA'=VALUE ; USES: ALL ; PEEKE: MOV BX,COMRDE PUSH ES MOV ES,COMRHL MOV AL,ES:[BX] POP ES MOV COMRA,AL RET ;** POKE 8088 MEMORY FUNCTION ; ; ENTRY: 'COMRC'=VALUE ; 'COMRDE'=OFFSET ; 'COMRHL'=SEGMENT ; EXIT: NONE ; USES: ALL ; POKEE: MOV AL,COMRC MOV BX,COMRDE PUSH ES MOV ES,COMRHL MOV ES:[BX],AL POP ES RET EJECT ;*** DISK BUFFER HANDLING ROUTINES ; ;** SETUP -- COMMON R/W ROUTINE SETUP CODE ; ; ENTRY: 'REQDRV'=REQUESTED DRIVE # ; 'PHYDPE'=ADDRESS OF DPE FOR REQUESTED DRIVE ; 'REQTRK'=REQUESTED TRACK # ; EXIT: HOST BUFFER CONTAINS REQUESTED TRACK ; (BX)=ADDRESS OF BUFFER HEADER INFO ; (AX)=DISPLACEMENT OF REQUESTED CP/M SECTOR INTO HOST BUFFER ; (CX)=128/2=64 ; DIRECTION FLAG CLEARED TO FORWARD DIRECTION ; USES: AX,CX,DI ; ; *** NOTE *** ; ; IF A 1ST TIME SELECT OPERATION IS IN PROGRESS, THEN NO PHYSICAL ; READ IS DONE. IN THIS CASE, THIS ROUTINE ONLY SERVES TO ; AQUIRE A FREE BUFFER TO BE USED BY THE DEVICE SELECTION ; ROUTINES FOR THEIR OWN PURPOSES. ; SETUP: CALL FNDBUF ;Q. REQUESTED TRACK IN ANY HOST BUFFERS MOV BUFERR[BX],0 ;CLEAR ERROR FLAG JNC SETUP1 ; BR IF YES CALL FLUSH ;FLUSH LEAST RECENTLY USED HOST BUFFER CMP BUFERR[BX],0 ;Q. ERROR DURING FLUSH JNE SETUP2 ; BR IF YES ; SET BUFFER HEADER INFO FOR REQUESTED TRACK MOV AL,REQDRV ;DRIVE # MOV BUFDRV[BX],AL MOV AL,PHYDRV ;MAPPED DRIVE # (PHYSICAL TABLE #) MOV BUFPDRV[BX],AL MOV AX,PHYDPE ;ADDRESS OF DPE MOV BUFDPE[BX],AX MOV AX,REQTRK ;TRACK # MOV BUFTRK[BX],AX ; CLEAR ERROR SECTOR FLAGS XOR AL,AL MOV DI,BUFERRF[BX] MOV CX,ERRFLGL CALL EXDSES REP STOSB CALL EXDSES ; CMP PREREAD,0 ;Q. SHOULD I DO PREREAD JE SETUP2 ; BR IF NO MOV AL,DDRDT ;DO PHYSICAL READ AND FILL HOST BUFFER CALL DRVR ; REQUESTED TRACK IS IN A HOST BUFFER. ; SET MOVE VALUES. SETUP1: MOV AX,REQSEC ;CALCULATE DISPLACEMENT MOV CL,7 SHL AX,CL MOV CX,64 ;WORD COUNT CLD ;CLEAR FOR FORWARD DIRECTION MOV BUFERR[BX],0 ;INSURE ERROR FLAG IS CLEARED SETUP2: RET ;** FNDBUF -- FIND HOST BUFFER TO USE ; ; ENTRY: 'REQDRV'=DRIVE # ; 'REQTRK'=TRACK # ; EXIT: PSW/C=STATUS ; 0=REQUESTED TRACK IS IN HOST BUFFER TO BE USED. ; HEADER INFO FOR BUFFER IS ON TOP OF BUFFER STACK ; 1=NOT FOUND. ; HEADER INFO FOR THE LEAST RECENTLY USED BUFFER ; IS PLACED ON TOP OF BUFFER STACK SO IT CAN BE ; FLUSHED AND THEN USED ; USES: AL,BX,DX ; FNDBUF: MOV AL,REQDRV ;REQUESTED DRIVE # MOV DX,REQTRK ;REQUESTED TRACK # MOV BX,FSTBUF ;INIT POINTER FNDBUF1: TEST BX,BX ;Q. NO MORE BUFFER HEADERS JZ FNDBUF3 ; BR IF NOT CMP AL,BUFDRV[BX] ;Q. MATCH ON REQUESTED DRIVE JNE FNDBUF2 ; BR IF NOT CMP DX,BUFTRK[BX] ;Q. MATCH ON REQUESTED TRACK JE FNDBUF4 ; BR IF YES FNDBUF2: MOV BX,BUFFWD[BX] ;FOLLOW CHAIN TO NEXT INFO ELEMENT JMPS FNDBUF1 FNDBUF3: MOV BX,LSTBUF ;POINT TO LAST ELEMENT STC ;INDICATE NOT FOUND FNDBUF4: PUSHF ;SAVE FOUND STATUS CALL PSHBUF ;PLACE BUFFER TO BE USED ON TOP OF STACK POPF ;RESTORE FOUND STATUS RET ;** INBUF -- INITIALIZE BUFFER HEADERS ; ; ENTRY: NONE ; EXIT: NONE ; USES: BX,CX,SI,DI ; INBUF: MOV FSTBUF,0 ;INIT 1ST ELEMENT POINTER MOV LSTBUF,0 ;INIT LAST ELEMENT POINTER MOV CX,BUFCNT ;# OF BUFFERS LEA BX,HEADER ;START OF HEADER AREA LEA SI,SECFLG ;START OF DIRTY SECTOR FLAG AREA LEA DX,ERRFLG ;START OF SECTOR ERROR FLAG AREA LEA DI,BUFFER ;START OF BUFFER AREA INBUF1: MOV BUFSECF[BX],SI ;INIT ADDRESS OF DIRTY SECTOR FLAG AREA MOV BUFERRF[BX],DX ;INIT ADDRESS OF SECTOR ERROR FLAG AREA MOV BUFBUF[BX],DI ;INIT ADDRESS OF BUFFER AREA PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI PUSH BX MOV DI,0 ;INSERT HEADER AT END CALL INSBUF POP BX CALL CLRBUF ;CLEAR BUFFER HEADER POP DI POP SI POP DX POP CX POP BX ADD BX,BUFHDRL ;BUMP POINTERS ADD SI,SECFLGL ADD DX,ERRFLGL ADD DI,BUFFERL LOOP INBUF1 ;LOOP FOR # OF BUFFERS RET ;** CLRBUFA - CLEAR ALL HOST BUFFER HEADERS ; ; ENTRY: NONE ; EXIT: NONE ; USES: BX ; CLRBUFA: MOV BX,FSTBUF ;GET POINTER TO FIRST HEADER IN CHAIN CLRBUFA1: TEST BX,BX ;Q. AT END OF CHAIN JZ CLRBUFA2 ; BR IF YES CALL CLRBUF ;CLEAR THIS BUFFER HEADER MOV BX,BUFFWD[BX] ;CHAIN TO NEXT HEADER JMPS CLRBUFA1 CLRBUFA2: RET ;** CLRBUFD - CLEAR ALL HOST BUFFER HEADERS FOR REQUESTED DRIVE ; ; ENTRY: 'REQDRV'=REQUESTED DRIVE # ; EXIT: NONE ; USES: AX,BX ; CLRBUFD: MOV BX,FSTBUF ;POINT TO 1ST HEADER ELEMENT CLRBUFD1: TEST BX,BX ;Q. ANY MORE BUFFERS JZ CLRBUFD3 ; BR IF NOT MOV AL,REQDRV ;Q. BUFFER FOR REQUESTED DRIVE CMP AL,BUFDRV[BX] JE CLRBUFD2 ; BR IF YES MOV BX,BUFFWD[BX] ;SKIP TO NEXT ENTRY JMPS CLRBUFD1 CLRBUFD2: CALL CLRBUF ;CLEAR BUFFER MOV AX,BUFFWD[BX] ;REMEMBER WHO SHOULD BE NEXT PUSH AX CALL POPBUF ;POP BUFFER STACK POP BX ;GET NEXT ENTRY JMPS CLRBUFD1 CLRBUFD3: RET ;** CHKDBD -- CHECK FOR ANY DIRTY BUFFERS FOR REQUESTED DRIVE ; ; ENTRY: 'REQDRV'=REQUESTED DRIVE # ; EXIT: (AL)=STATUS 0=NO DIRTY BUFFERS , 1=DIRTY BUFFER(S) ; USES: AX,BX ; CHKDBD: XOR AH,AH ;ZERO WORK REG MOV AL,REQDRV ;GET REQUESTED DRIVE # MOV BX,FSTBUF ;START OF BUFFER HEADERS CHKDBD1: TEST BX,BX ;Q. ANY MORE BUFFERS JZ CHKDBD3 ; BR IF NOT CMP AL,BUFDRV[BX] ;Q. BUFFER FOR REQUESTED DRIVE JNE CHKDBD2 ; BR IF NOT OR AH,BUFWRF[BX] ;ACCUMULATE DIRTY FLAGS CHKDBD2: MOV BX,BUFFWD[BX] ;SKIP TO NEXT ENTRY JMPS CHKDBD1 CHKDBD3: MOV AL,AH ;MOVE RESULT TO (AL) RET ;** FLUSHD -- FLUSH ALL BUFFERS FOR REQUESTED DRIVE ; ; ENTRY: 'REQDRV'=REQUESTED DRIVE # ; EXIT: (AL)=ERROR STATUS (0=OK , 1=ABORT) ; USES: AL,BX ; FLUSHD: MOV FLDERR,0 ;CLEAR ERROR FLAG MOV BX,FSTBUF ;START OF BUFFER HEADERS FLUSHD1: TEST BX,BX ;Q. ANY MORE BUFFERS JZ FLUSHD3 ; BR IF NOT MOV AL,REQDRV ;Q. BUFFER FOR REQUESTED DRIVE CMP AL,BUFDRV[BX] JNE FLUSHD2 ; BR IF NOT MOV AL,FLDERR ;PROPAGATE ABORT STATUS OR BUFERR[BX],AL CALL FLUSH ;FLUSH BUFFER MOV AL,BUFERR[BX] ;ACCUMULATE ERROR STATUS OR FLDERR,AL FLUSHD2: MOV BX,BUFFWD[BX] ;FOLLOW CHAIN TO NEXT ELEMENT JMPS FLUSHD1 FLUSHD3: MOV AL,FLDERR ;GET ERROR STATUS RET ;* CLRBUF -- CLEAR BUFFER HEADER ; ; ENTRY: (BX)=POINTER TO BUFFER HEADER INFO ; EXIT: NONE ; USES: AL,CX,SI,DI ; ; *** NOTE *** ; ; IF A BUFFER WAS NOT FLUSHED BEFORE BEING CLEARED AND ; IF IT WAS DIRTY, THEN THE DATA IS LOST. ; CLRBUF: MOV BUFDRV[BX],-1 ;CLEAR DRIVE # MOV BUFWRF[BX],0 ;CLEAR DIRTY BUFFER FLAG XOR AL,AL ;CLEAR DIRTY SECTOR FLAGS MOV DI,BUFSECF[BX] MOV CX,SECFLGL CLD CALL EXDSES REP STOSB CALL EXDSES RET ;* FLUSH -- FLUSH BUFFER WHOSE HEADER INFO IS ON TOP OF THE STACK ; ; ENTRY: (BX)=POINTER TO BUFFER HEADER INFO ; EXIT: NONE ; USES: NONE ; FLUSH: TEST BUFWRF[BX],1 ;CHECK IF HOST BUFFER IS DIRTY JZ FLUSH1 ; BR IF NOT MOV AL,DDWRT ;GO WRITE TRACK CALL DRVR MOV BUFWRF[BX],0 ;INDICATE HOST WRITE BUFFER IS CLEAN FLUSH1: RET ;* PSHBUF -- PUSH DOWN BUFFER HEADER INFO STACK AND PLACE COPY ; OF HEADER INFO OF BUFFER TO BE USED ON TOP OF STACK. ; ; ENTRY: (BX)=ADDRESS OF HEADER INFO FOR HOST BUFFER TO BE USED ; EXIT: NONE ; USES: DI ; PSHBUF: CMP BX,FSTBUF ;Q. ALREADY ON TOP OF STACK JE PSHBUF1 ; BR IF YES CALL DELBUF ;REMOVE FROM STACK MOV DI,FSTBUF ;REINSERT ON TOP OF STACK CALL INSBUF PSHBUF1: RET ;* POPBUF -- POP UP BUFFER HEADER INFO STACK AND COPY ; HEADER INFO FOR BUFFER USED TO BOTTOM OF STACK. ; ; ENTRY: (BX)=ADDRESS OF HEADER INFO FOR HOST BUFFER TO BE USED ; EXIT: NONE ; USES: DI ; POPBUF: CMP BX,LSTBUF ;Q. ALREADY BOTTOM OF STACK JE POPBUF1 ; BR IF YES CALL DELBUF ;REMOVE FROM CURRENT POSITION MOV DI,0 ;REINSERT AT BOTTOM OF STACK CALL INSBUF POPBUF1: RET ;* DELBUF -- DELETE ELEMENT FROM BUFFER STACK ; ; ENTRY: (BX)=POINTER TO ELEMENT TO BE DELETED ; EXIT: NONE ; USES: SI,DI ; DELBUF: MOV DI,BUFFWD[BX] ;GET POINTER TO NEXT ELEMENT MOV SI,BUFBAK[BX] ;GET POINTER TO PREVIOUS ELEMENT TEST SI,SI ;Q. FIRST ELEMENT JNZ DELBUF1 ; BR IF NOT MOV FSTBUF,DI ;SET NEXT ELEMENT AS FIRST ELEMENT JMPS DELBUF2 DELBUF1: MOV BUFFWD[SI],DI ;CHAIN PREVIOUS ELEMENT TO NEXT ELEMENT DELBUF2: TEST DI,DI ;Q. LAST ELEMENT JNZ DELBUF3 ; BR IF NOT MOV LSTBUF,SI ;SET PREVIOUS ELEMENT AS LAST ELEMENT JMPS DELBUF4 DELBUF3: MOV BUFBAK[DI],SI ;CHAIN NEXT ELEMENT TO PREVIOUS ELEMENT DELBUF4: RET ;* INSBUF -- INSERT BUFFER HEADER INFO INTO STACK ; ; ENTRY: (BX)=ADDRESS OF ELEMENT TO BE INSERTED ; (DI)=ADDRESS OF ELEMENT TO BE INSERTED IN FRONT OF ; EXIT: NONE ; USES: SI ; ; *** NOTE *** ; ; IF (DI)=0 THEN INSERTION IS DONE AFTER LAST ELEMENT ; INSBUF: TEST DI,DI ;Q. INSERT AT END JNZ INSBUF3 ; BR IF NO ; INSERT AFTER LAST ELEMENT MOV SI,LSTBUF ;GET POINTER TO LAST ELEMENT TEST SI,SI ;Q. ANY ELEMENTS JNZ INSBUF1 ; BR IF YES MOV FSTBUF,BX ;SET ELEMENT AS FIRST ELEMENT JMPS INSBUF2 INSBUF1: MOV BUFFWD[SI],BX ;CHAIN LAST ELEMENT TO ELEMENT INSBUF2: MOV BUFFWD[BX],0 ;SET ELEMENT'S FORWARD POINTER MOV BUFBAK[BX],SI ;CHAIN ELEMENT TO LAST ELEMENT MOV LSTBUF,BX ;SET ELEMENT AS LAST ELEMENT RET ; INSERT IN FRONT OF ELEMENT POINTED TO BY (DI) INSBUF3: MOV SI,BUFBAK[DI] ;GET POINTER TO PREVIOUS ELEMENT TEST SI,SI ;Q. ANY PREVIOUS ELEMENT JNZ INSBUF4 ; BR IF YES MOV FSTBUF,BX ;SET ELEMENT AS FIRST ELEMENT JMPS INSBUF5 INSBUF4: MOV BUFFWD[SI],BX ;CHAIN PREVIOUS ELEMENT TO ELEMENT INSBUF5: MOV BUFBAK[BX],SI ;CHAIN ELEMENT TO PREVIOUS ELEMENT MOV BUFBAK[DI],BX ;CHAIN NEXT ELEMENT TO ELEMENT MOV BUFFWD[BX],DI ;CHAIN ELEMENT TO NEXT ELEMENT RET EJECT ;** DRVR - DISK DRIVER DISPATCHER ; ; ENTRY: (AL)=ENTRY JUMP VECTOR OFFSET ; (BX)=ADDRESS OF BUFFER HEADER INFO ; EXIT: NONE ; USES: AX,CL,SI,DI ; DRVR: PUSH AX MOV LSIO,0 ;CLEAR LOGICAL SECTOR I/O FLAG ;* INSURE CORRECT DISK IS INSERTED IN REQUESTED DRIVE MOV SI,BUFDPE[BX] ;GET ADDRESS OF REQUESTED DRIVE'S DPE MOV AL,DPEFLAG[SI] ;NOT ALL DEVICES ARE PERMITTED AND AL,DPETYPE ; IMAGINARY DRIVES CMP AL,DPEZ217 JNE DRVR0 ; BR IF NOT Z217 MOV LSIO,1 ;INDICATE LOGICAL I/O DEVICE JMPS DRVR5 DRVR0: TEST DPEFLG2[SI],DPEIMG ;Q. IMAGINARY DRIVE JZ DRVR1 ; BR IF NOT MOV AL,DPELUN[SI] ;POINT TO CORRESPONDING REAL DRIVE AND AL,DPEREAL MOV AH,DPEL MUL AH ADD AX,OFFSET DPEBASE ADD AX,BBIOS MOV SI,AX DRVR1: MOV AL,DPELUN[SI] ;GET LOGICAL/MOUNTED VALUE MOV AH,AL ;SAVE IT AND AL,DPEMNT ;MASK FOR MOUNTED VALUE CMP AL,BUFPDRV[BX] ;Q. MOUNTED EQUAL REQUESTED JE DRVR5 ; BR IF YES AND AH,DPELOG ;UPDATE MOUNTED VALUE OR AH,BUFPDRV[BX] ; TO REFLECT WHICH DISK IS MOUNTED MOV DPELUN[SI],AH ; IN REAL UNIT ; PRINT MESSAGE AND REQUEST THAT DISK BE INSERTED INTO DRIVE MOV AL,BUFDRV[BX] ;PLACE REQUESTED DRIVE NAME INTO MSG ADD AL,'A' MOV MNMSGA,AL MOV CL,4 ;PLACE REAL DRIVE NAME INTO MESSAGE SHR AH,CL ADD AH,'A' MOV MNMSGB,AH PUSH BX LEA SI,MNMSG ;PRINT MESSAGE CALL PMSG DRVR3: CALL GETCHR ;WAIT FOR CMP AL,CR JE DRVR4 MOV COMRC,BELL CALL CONOUTE JMPS DRVR3 DRVR4: LEA SI,CRLF CALL PMSG POP BX MOV AL,DDMNT ;CALL DEVICE DRIVER TO MOUNT DISK CALL DRVR6 ;* DISPATCH TO DEVICE DRIVER DRVR5: POP AX ;RESTORE ENTRY JUMP VECTOR OFFSET DRVR6: MOV AH,0 MOV DI,AX MOV SI,BUFDPE[BX] ;FETCH DEVICE TYPE MOV AL,DPEFLAG[SI] MOV CL,5 SHR AL,CL CBW ;ADJUST FOR DISPATCH TABLE ENTRY LENGTH SHL AX,1 MOV SI,AX MOV SI,DRVRTBL[SI] ;GET OFFSET OF START OF DEVICE DRIVER CMP SI,0 ;Q. DUMMY DRIVER JE DRVR7 ; BR IF YES ADD SI,DI ;ADD ENTRY JUMP VECTOR OFFSET JMP SI ;GOTO DEVICE DRIVER DRVR7: RET EJECT INCLUDE Z207DRVR.LIB EJECT INCLUDE Z217DRVR.LIB EJECT INCLUDE TIMEDRVR.LIB EJECT ;*** GENERAL PURPOSE CHARACTER I/O HANDLER ; ;* GETCIO - GET APPROPRIATE CIO TABLE ENTRY ; ; ENTRY: (AL)='IOBYTE' SHIFTED SO BITS 1-2 CONTAIN THE PERTINENT VALUE ; ((SP))=START OF ADDRESS OFFSET TABLE ; EXIT: (BX)=ADDRESS OF CIO TABLE ENTRY ; USES: AX,BX ; ; *** NOTE *** ; THE TABLE CONSISTS OF 4 DW STATEMENTS, WHICH EQUALS 8 BYTES ; GETCIO: AND AX,06H ;MASK FOR ONLY BITS 1-2 POP BX ;GET START OF TABLE ADD AX,BX ;MOVE POINTER TO APPROPRIATE ENTRY ADD BX,8 ;MODIFY RETURN ADDRESS TO SKIP PUSH BX ; AROUND TABLE MOV BX,AX MOV BX,CS: WORD PTR [BX] ;GET VALUE IN TABLE TEST BX,BX ;Q. SPECIAL CASE JZ GETCIO1 ; BR IF YES ADD BX,BBIOS ;ADJUST FOR WHERE BIOS IS IN MEMORY GETCIO1: RET ;* CLRCIO - CLEAR CIO TABLE FLAGS/VALUES ; ; ENTRY: (BX)=ADDRESS OF CIO TABLE ENTRY ; EXIT: NONE ; USES: NONE ; CLRCIO: AND CIOF2[BX],NOT (CIOW4A+CIOW4D) MOV CIOECTR[BX],0 MOV CIONCTR[BX],0 RET ;* ISCIO - INPUT STATUS ; ; ENTRY: (BX)=ADDRESS OF CIO TABLE ENTRY ; EXIT: (AL)=STATUS ; 0=NO CHARACTER AVAILBLE , 0FFH=CHARACTER AVAILBLE ; USES: AL ; ISCIO: CALL CIOIS[BX] ;INPUT STATUS BYTE FROM DEVICE AND AL,CIOIM[BX] ;USE INPUT READY MASK XOR AL,CIOIPM[BX] ;ADJUST FOR POLARITY CMP AL,CIOIM[BX] ;CHECK IF READY MOV AL,0FFH ; ASSUME READY JE ISCIO1 ; BR IF READY XOR AL,AL ; OTHERWISE SHOW NOT READY ISCIO1: RET ;* IDCIO - INPUT DATA ; ; ENTRY: (BX)=ADDRESS OF CIO TABLE ENTRY ; EXIT: (AL)=CHARACTER READ ; USES: AL ; IDCIO: CALL ISCIO ;WAIT FOR CHARACTER AVAILABLE TEST AL,AL JZ IDCIO CALL CIOID[BX] ;INPUT DATA TEST CIOF1[BX],CIOSPI ;Q. STRIP PARITY JZ IDCIO1 ; BR IF NOT AND AL,07FH ; OTHERWISE STRIP PARITY IDCIO1: TEST CIOF1[BX],CIOMLI ;CHECK IF I SHOULD MAP LOWER CASE JZ IDCIO2 ; BR IF NOT CALL UPC ; OTHERWISE DO MAPPING IDCIO2: RET ;* OSCIO - OUTPUT STATUS ; ; ENTRY: (BX)=ADDRESS OF CIO TABLE ENTRY ; EXIT: (AL)=STATUS ; 0=NOT READY , 0FFH=READY ; USES: AL ; OSCIO: CALL CIOOS[BX] ;INPUT STATUS BYTE FROM DEVICE AND AL,CIOOM[BX] ;USE OUTPUT READY MASK XOR AL,CIOOPM[BX] ;ADJUST FOR POLARITY CMP AL,CIOOM[BX] ;CHECK IF READY ; JNE OSCIO8 ; BR IF BUSY JE $+5 JMP OSCIO8 ; HANDLE / PROTOCOL OSCIO2: TEST CIOF1[BX],CIOEAH ;Q. USING / HANDSHAHKING JZ OSCIO3 ; BR IF NOT TEST CIOF2[BX],CIOW4A ;Q. WAITING FOR JNZ OSCIO2A ; BR IF YES MOV AL,CIOECTR[BX] ;Q. TIME TO SEND CMP AL,CIOECNT[BX] JB OSCIO4 ; BR IF NOT MOV CIOECTR[BX],0 ;REINITIALIZE COUNTER MOV AL,ETX ;SEND CALL CIOOD[BX] OR CIOF2[BX],CIOW4A ;SHOW WAITING FOR JMP OSCIO8 ;JUMP TO BUSY EXIT OSCIO2A: CALL ISCIO ;CHECK INPUT STATUS TEST AL,AL ;Q. CHARACTER AVAILABLE JZ OSCIO8 ; BR IF NOT CALL CIOID[BX] ;INPUT CHARACTER AND AL,07FH ;STRIP PARITY BIT CMP AL,ACK ;Q. JNE OSCIO8 ; BR IF NOT AND CIOF2[BX],0FFH-CIOW4A ;SHOW NOT WAITING FOR JMPS OSCIO4 ; HANDLE / PROTOCOL OSCIO3: TEST CIOF1[BX],CIODCH ;Q. USING / HANDSHAKING JZ OSCIO4 ; BR IF NOT CALL ISCIO ;INPUT STATUS TEST AL,AL ;Q. CHARACTER AVAILABLE JZ OSCIO3C ; BR IF NOT CALL CIOID[BX] ;INPUT CHARACTER AND AL,07FH ;STRIP PARITY BIT OSCIO3A: CMP AL,DC1 ;Q. JNE OSCIO3B ; BR IF NOT AND CIOF2[BX],0FFH-CIOW4D ;SHOW NOT WAITING FOR JMPS OSCIO4 OSCIO3B: CMP AL,DC3 ;Q. JNE OSCIO3C ; BR IF NOT OR CIOF2[BX],CIOW4D ;SHOW WAITING FOR JMPS OSCIO8 OSCIO3C: TEST CIOF2[BX],CIOW4D ;Q. WAITING FOR JNZ OSCIO8 ; BR IF YES ; HANDLE SENDING NULLS OSCIO4: CMP CIONCTR[BX],0 ;Q. ANY NULLS LEFT TO SEND JE OSCIO9 ; BR IF NOT DEC CIONCTR[BX] ;DECREMENT NULL COUNTER MOV AL,NULL ;SEND ANOTHER NULL CALL CIOOD[BX] ; SHOW AS BUSY OSCIO8: XOR AL,AL RET ; SHOW AS READY OSCIO9: MOV AL,0FFH RET ;* ODCIO - OUTPUT DATA ; ; ENTRY: (CL)=CHARACTER ; (BX)=ADDRESS OF CIO TABLE ENTRY ; EXIT: NONE ; USES: AL ; ; *** NOTE *** ; ; THE DEVICE OUTPUT ROUTINE MUST NOT DESTROY REGISTER (CL) OR (BX). ; ODCIO: TEST CIOF1[BX],CIOFO ;Q. FAST I/O JZ ODCIO0 ; BR IF NOT MOV AL,CL JMP CIOOD[BX] ;DO OUTPUT ODCIO0: CALL OSCIO ;WAIT UNTIL READY TEST AL,AL JZ ODCIO0 MOV AL,CL TEST CIOF1[BX],CIOSPO ;Q. STRIP PARITY JZ ODCIO1 ; BR IF NOT AND AL,07FH ODCIO1: TEST CIOF1[BX],CIOMLO ;Q. MAP LOWER CASE ON OUTPUT JZ ODCIO2 ; BR IF NOT CALL UPC ; OTHERWISE DO MAPPING ODCIO2: CALL CIOOD[BX] ;OUTPUT CHARACTER CMP CL,CIONCHR[BX] ;Q. SHOULD I SEND NULLS JNE ODCIO3 ; BR IF NOT MOV AL,CIONCNT[BX] ;GET NUMBER OF NULLS TO BE SENT MOV CIONCTR[BX],AL ;PLACE IN NULL COUNTER ODCIO3: INC CIOECTR[BX] ;COUNT CHARACTER CMP CL,ESC ;Q. JNE ODCIO4 ; BR IF NOT MOV AL,CIOECNT[BX] ; IF YES - THEN INSURE SUB AL,3 ; ETX/ACK HANDSHAKING IS DELAYED CMP CIOECTR[BX],AL JB ODCIO4 MOV CIOECTR[BX],AL ODCIO4: RET EJECT ;*** DEVICE DRIVERS ; ;** CRT: (KEYBOARD/DISPLAY) ; ;* INCRT - INITIALIZATION ; ; ENTRY: NONE ; EXIT: NONE ; USES: BX ; INCRT: PUSHF ;INSURE INTERRUPTS ARE DISABLED CLI ; DURING INIT LEA BX,CRTTBL ;GET ADDRSS OF CIO TABLE ENTRY ADD BX,BBIOS CALL CLRCIO ;CLEAR CIO TABLE FLAGS MOV CIOIN[BX],OFFSET INCRT ;ADDRESS OF INIT ROUTINE MOV CIOIS[BX],OFFSET ISCRT ;ADDRESS OF INPUT INPUT STATUS BYTE MOV CIOID[BX],OFFSET IDCRT ;ADDRESS OF INPUT DATA BYTE MOV CIOOS[BX],OFFSET DUMMY ;ADDRESS OF INPUT OUTPUT STATUS BYTE MOV CIOOD[BX],OFFSET ODCRT ;ADDRESS OF OUTPUT DATA BYTE CALL FLCRT ;FLUSH TYPEAHEAD BUFFER POPF ;RESTORE INTERRUPT STATUS RET ;* FLCRT - FLUSH CRT: TYPE AHEAD BUFFER ; ; ENTRY: NONE ; EXIT: NONE ; USES: NONE ; FLCRT: PUSH AX PUSH BX PUSHF ;DISABLE INTERRUPTS CLI FLCRT1: IN AL,ZKEYBDS ;DISABLE KEYBOARD TEST AL,ZKEYIBF JNZ FLCRT1 MOV AL,ZKEYDK OUT ZKEYBDC,AL FLCRT2: IN AL,ZKEYBDS ;CLEAR FIFO TEST AL,ZKEYIBF JNZ FLCRT2 MOV AL,ZKEYCF OUT ZKEYBDC,AL FLCRT3: IN AL,ZKEYBDS ;CLEAR OUTPUT BUFFER TEST AL,ZKEYIBF JNZ FLCRT3 IN AL,ZKEYBDD CALL FLCRT9 ;FLUSH TYPE AHEAD BUFFER POPF ;RESTORE INTERRUPT STATUS PUSHF ;Q. INTERRUPTS ENABLED POP AX TEST AH,002H JZ FLCRT4 ; BR IF NOT MOV AX,250*250 ;WAIT IN CASE KEY WAS DEPRESSED CALL WDLY ; DURING FLUSH CALL WDLY FLCRT4: MOV AL,ZKEYEK ;RE-ENABLE KEYBOARD OUT ZKEYBDC,AL POP BX POP AX RET FLCRT9: MOV KEYCNT,0 ;INIT BUFFER HANDLING VALUES LEA BX,KEYBUF MOV KEYPUT,BX MOV KEYGET,BX RET ;* ISCRT - INPUT INPUT STATUS BYTE ; ; ENTRY: (BX)=ADDRESS OF CIO TABLE ENTRY ; EXIT: (AL)=STATUS ; 0=NO DATA AVAILABLE , 0FFH=DATA IN TYPE-AHEAD BUFFER ; USES: AL ; ISCRT: MOV AL,KEYCNT ;GET TYPE-AHEAD CHARACTER COUNT TEST AL,AL ;Q. ANY CHARACTERS AVAILABLE JZ ISCRT1 ; BR IF NOT MOV AL,0FFH ; INDICATE AVAILABLE ISCRT1: RET ;* IDCRT - GET DATA BYTE FROM TYPE-AHEAD BUFFER ; ; ENTRY: (BX)=ADDRESS OF CIO TABLE ENTRY ; EXIT: (AL)=DATA BYTE ; USES: AL ; IDCRT: CALL ISCRT ;Q. ANY AVAILABLE TEST AL,AL JZ IDCRT2 ; BR IF NOT PUSHF ;DISABLE INTERRUPTS WHILE FETCHING CLI ; CHARACTER PUSH BX MOV BX,KEYGET ;FETCH GET POINTER MOV AL,[BX] ;FETCH CHARACTER DEC KEYCNT ;DECREMENT CHARACTER COUNTER INC BX ;BUMP GET POINTER CMP BX,OFFSET KEYBUF + KEYBUFL ;Q. TIME TO WRAP POINTER JB IDCRT1 ; BR IF NOT LEA BX,KEYBUF ; WRAP POINTER TO BEGINNING IDCRT1: MOV KEYGET,BX ;SAVE UPDATED GET POINTER POP BX POPF IDCRT2: RET ;* ODCRT - OUTPUT DATA ; ; ENTRY: (AL)=CHARACTER ; (BX)=ADDRESS OF CIO TABLE ENTRY ; EXIT: NONE ; USES: NONE ; ODCRT: PUSHA CLD CALLFI MTRSCRT,MTRSEG ;CALL ROM MONITOR ROUTINE POPA RET ;* PUTKEY - PUT DATA BYTE INTO TYPE-AHEAD BUFFER ; ; ENTRY: (AL)=CHARACTER ; (CS)=CODE SEGMENT VALUE ; EXIT: NONE ; USES: (AL) ; ; THIS ROUTINE IS CALLED BY THE ROM MONITOR AT INTERRUPT TIME PUTKEY: PUSH BX CMP CS:KEYCNT,KEYBUFL ;Q. BUFFER FULL JB PUTKEY2 ; BR IF NOT PUTKEY1: IN AL,ZKEYBDS ;SEND BEEP TO INDICATE BUFFER FULL TEST AL,ZKEYIBF JNZ PUTKEY1 MOV AL,ZKEYBEP OUT ZKEYBDC,AL JMPS PUTKEY4 PUTKEY2: MOV BX,CS:KEYPUT ;GET PUT POINTER MOV CS:[BX],AL ;PUT CHARACTER INTO BUFFER INC CS:KEYCNT ;BUMP CHARACTER COUNTER INC BX ;BUMP PUT POINTER CMP BX,OFFSET KEYBUF + KEYBUFL ;Q. TIME TO WRAP POINTER JB PUTKEY3 ; BR IF NOT LEA BX,CS:KEYBUF ; WRAP POINTER TO BEGINNING PUTKEY3: MOV CS:KEYPUT,BX ;SAVE UPDATED PUT POINTER PUTKEY4: POP BX RETF ;** SERIAL PORT A DEVICE DRIVER ; ;* INSERA - INITIALIZATION ; ; ENTRY: NONE ; EXIT: NONE ; USES: BX ; INSERA: PUSHF ;INSURE INTERRUPTS ARE DISABLED CLI ; DURING INIT LEA BX,SERATBL ;GET ADDRESS OF CIO ENTRY ADD BX,BBIOS CALL CLRCIO ;CLEAR CIO TABLE FLAGS MOV CIOIN[BX],OFFSET INSERA ;ADDRESS OF INIT ROUTINE MOV CIOIS[BX],OFFSET IS2661 ;ADDRESS OF INPUT INPUT STATUS ROUTINE MOV CIOID[BX],OFFSET ID2661 ;ADDRESS OF INPUT DATA ROUTINE MOV CIOOS[BX],OFFSET IS2661 ;ADDRESS OF INPUT OUTPUT STATUS ROUTINE MOV CIOOD[BX],OFFSET OD2661 ;ADDRESS OF OUTPUT DATA ROUTINE CALL IN2661 ;CALL DEVICE INIT ROUTINE POPF ;RESTORE INTERRUPT STATUS RET ;** SERIAL PORT B DEVICE DRIVER ; ;* INSERB - INITIALIZATION ; ; ENTRY: NONE ; EXIT: NONE ; USES: BX ; INSERB: PUSHF ;INSURE INTERRUPTS ARE DISABLED CLI ; DURING INIT LEA BX,SERBTBL ;GET ADDRESS OF CIO ENTRY ADD BX,BBIOS CALL CLRCIO ;CLEAR CIO TABLE FLAGS MOV CIOIN[BX],OFFSET INSERB ;ADDRESS OF INIT ROUTINE MOV CIOIS[BX],OFFSET IS2661 ;ADDRESS OF INPUT INPUT STATUS ROUTINE MOV CIOID[BX],OFFSET ID2661 ;ADDRESS OF INPUT DATA ROUTINE MOV CIOOS[BX],OFFSET IS2661 ;ADDRESS OF INPUT OUTPUT STATUS ROUTINE MOV CIOOD[BX],OFFSET OD2661 ;ADDRESS OF OUTPUT DATA ROUTINE CALL IN2661 ;CALL DEVICE INIT ROUTINE POPF ;RESTORE INTERRUPT STATUS RET ;** 2661 COMMON DEVICE DRIVER ROUTINES ; ;* IS2661 - INPUT INPUT/OUTPUT STATUS BYTE ; ; ENTRY: (BX)=ADDRESS OF CIO ENTRY ; EXIT: (AL)=STATUS BYTE ; USES: AL,DX ; IS2661: XOR DH,DH ;GET STATUS PORT # MOV DL,CIOBP[BX] ADD DX,EPSTAT IN AL,DX ;GET STATUS RET ;* ID2661 - INPUT DATA BYTE ; ; ENTRY: (BX)=ADDRESS OF CIO ENTRY ; EXIT: (AL)=DATA BYTE ; USES: AL,DX ; ID2661: XOR DH,DH ;GET DATA PORT # MOV DL,CIOBP[BX] ADD DX,EPDATA IN AL,DX ;INPUT DATA RET ;* OD2661 - OUTPUT DATA BYTE ; ; ENTRY: (AL)=DATA BYTE ; (BX)=ADDRESS OF CIO ENTRY ; EXIT: NONE ; USES: DX ; OD2661: XOR DH,DH ;GET DATA PORT # MOV DL,CIOBP[BX] ADD DX,EPDATA OUT DX,AL ;OUTPUT DATA RET ;* IN2661 - INITIALIZE ; ; ENTRY: (BX)=ADDRESS OF CIO ENTRY ; EXIT: NONE ; USES: AL,DX ; IN2661: PUSH CX XOR CH,CH ;GET BASE PORT # MOV CL,CIOBP[BX] XOR AL,AL ;SHUT DOWN 2661 MOV DX,EPCMD ADD DX,CX OUT DX,AL IN AL,DX ;RESET MODE REGISTER POINTER MOV AL,CIOVAL1[BX] ;SET MODE REGISTER 1 MOV DX,EPMODE ADD DX,CX OUT DX,AL MOV AL,CIOVAL2[BX] ;SET MODE REGISTER 2 OR AL,BYTE PTR CIOBR[BX] OUT DX,AL MOV AL,CIOVAL3[BX] ;SET COMMAND REGISTER MOV DX,EPCMD ADD DX,CX OUT DX,AL MOV DX,EPDATA ;FLUSH INPUT BUFFER ADD DX,CX IN AL,DX IN AL,DX POP CX RET ;** PARALLEL PRINTER DRIVER ; ;* INPPRT - INITIALIZE PARALLEL PRINTER PORT ; ; ENTRY: NONE ; EXIT: NONE ; USES: AL,BX ; INPPRT: PUSHF ;INSURE INTERRUPTS ARE DISABLED CLI ; DURING INIT LEA BX,PPRTTBL ;GET ADDRESS OF CIO ENTRY ADD BX,BBIOS CALL CLRCIO ;CLEAR CIO TABLE FLAGS MOV CIOIN[BX],OFFSET INPPRT ;ADDR OF INIT ROUTINE MOV CIOIS[BX],OFFSET DUMMY ;ADDR OF INPUT INPUT STATUS ROUTINE MOV CIOID[BX],OFFSET IDDUMMY ;ADDR OF INPUT DATA ROUTINE MOV CIOOS[BX],OFFSET OSPPRT ;ADDR OF INPUT OUTPUT STATUS ROUTINE MOV CIOOD[BX],OFFSET ODPPRT ;ADDR OF OUTPUT DATA ROUTINE ; DO PORT A FIRST XOR AL,AL ;ACCESS DATA DIRECTION REG OUT GDPCTLA,AL OUT GDPDDRA,AL ;SET ALL BITS AS INPUTS MOV AL,PIADDAC ;ACCESS PERIPHERAL DATA REG OUT GDPCTLA,AL MOV AL,CIOVAL1[BX] ;SET OUTPUT LATCHES OUT GDPDATA,AL XOR AL,AL ;ACCESS DATA DIRECTION REG OUT GDPCTLA,AL MOV AL,CIOVAL2[BX] ;SET DATA DIRECTION REG OUT GDPDDRA,AL MOV AL,CIOVAL3[BX] ;SET CONTROL PORT VALUE OUT GDPCTLA,AL IN AL,GDPDATA ;CLEAR ANY PENDING INTERRUPTS IN AL,ZDIPSW ;FIRE E-CLOCK MOV AL,CIOVAL1[BX] ;CLEAR LPEN & VSYNC STROBE FLIP-FLOPS AND AL,NOT (LPENSE+VSYNCE) OUT GDPDATA,AL OR AL,LPENSE+VSYNCE OUT GDPDATA,AL ; DO PORT B NEXT XOR AL,AL ;ACCESS DATA DIRECTION REG OUT GDPCTLB,AL OUT GDPDDRB,AL ;SET ALL BITS AS INPUTS MOV AL,PIADDAC ;ACCESS PERIPHERAL DATA REG OUT GDPCTLB,AL MOV AL,CIOVAL4[BX] ;SET OUTPUT LATCHES OUT GDPDATB,AL XOR AL,AL ;ACCESS DATA DIRECTION REG OUT GDPCTLB,AL MOV AL,CIOVAL5[BX] ;SET DATA DIRECTION REG OUT GDPDDRB,AL MOV AL,CIOVAL6[BX] ;SET CONTROL PORT VALUE OUT GDPCTLB,AL IN AL,GDPDATB ;CLEAR ANY PENDING INTERRUPTS IN AL,ZDIPSW ;FIRE E-CLOCK POPF ;RESTORE INTERRUPT STATUS RET ;* OSPPRT - INPUT OUTPUT STATUS BYTE ; ; ENTRY: (BX)=ADDRESS OF CIO TABLE ENTRY ; EXIT: (AL)=STATUS BYTE ; USES: AL ; OSPPRT: IN AL,GDPDATB ;INPUT STATUS RET ;* ODPPRT - OUTPUT DATA BYTE ; ; ENTRY: (AL)=DATA ; (BX)=ADDRESS OF CIO TABLE ENTRY ; EXIT: NONE ; USES: AH ; ODPPRT: PUSHF ;DISABLE INTERRUPTS WHILE PLAYING CLI ; WITH PORTS MOV AH,AL ;SAVE (AL) OUT GDPDATB,AL ;PLACE PORT B DATA IN OUTPUT LATCH AND AL,PPRTM10 ;MASK FOR PORT A DATA OR AL,CIOVAL1[BX] ;OR IN NON-ASSERTED VALUES FOR OTHER ; PORT A OUTPUT BITS OUT GDPDATA,AL ;PLACE PORT A DATA IN OUTPUT LATCH AND AL,0FFH-PPRTSTB ;GENERATE STROBE OUT GDPDATA,AL OR AL,PPRTSTB OUT GDPDATA,AL MOV AL,AH ;RESTORE (AL) POPF ;RESTORE INTERRUPT STATUS RET ;** DUMMY DEVICE DRIVER ; ;* INDUMMY - INITIALIZATION ; ; ENTRY: NONE ; EXIT: NONE ; USES: BX ; INDUMMY: LEA BX,DUMMYTBL ;GET ADDRESS OF CIO TABLE ENTRY ADD BX,BBIOS CALL CLRCIO ;CLEAR CIO TABLE FLAGS MOV CIOIN[BX],OFFSET INDUMMY ;ADDRESS OF INIT ROUTINE MOV CIOIS[BX],OFFSET DUMMY ;ADDRESS OF INPUT INPUT STATUS BYTE MOV CIOID[BX],OFFSET IDDUMMY ;ADDRESS OF INPUT DATA ROUTINE MOV CIOOS[BX],OFFSET DUMMY ;ADDRESS OF INPUT OUTPUT STATUS BYTE MOV CIOOD[BX],OFFSET DUMMY ;ADDRESS OF OUTPUT DATA ROUTINE RET ;* DUMMY - DUMMY I/O (NOP) ; ; ENTRY: NONE ; EXIT: (AL)=STATUS BYTE ; USES: AL ; DUMMY: RET ;NOP ;* IDDUMMY - INPUT DATA BYTE ; ; ENTRY: NONE ; EXIT: (AL)=DATA BYTE ; USES: AL ; IDDUMMY: MOV AL,CPMEOF ;ALWAYS CP/M ASCII END-OF-FILE RET EJECT ;*** INTERRUPT HANDLERS ; ;** INTDIV0 - DIVIDE BY 0 ; INTDIV0: PUSHA LEA SI,DIV0MSG ;PRINT MESSAGE AND DUMP CALL PMSG POPA JMP SYSDMP ;** INTPBE - PARITY OR BUSS ERROR HANDLER ; INTPBE: PUSHA LEA SI,PBEMSG ;PRINT MESSAGE AND DUMP CALL PMSG POPA JMP SYSDMP ;** INTLVK - LIGHTPEN, VSYNC, & KEYBOARD HANDLER ; INTLVK: PUSHA IN AL,GDPCTLA ;Q. INTERRUPT FROM PIA TEST AL,LPENSI+VSYNCI JZ INTKEY ; BR IF NOT MOV AH,AL ;SAVE STATUS ;* LIGHTPEN HANDLER TEST AH,LPENSI ;Q. LIGHTPEN STROBE INTERRUPT JZ INTV ; BR IF NOT IN AL,GDPDATA ;CLEAR INTERRUPT AND GET DATA TEST AL,LPEN ;Q. LIGHT PEN HIT INTERRUPT JZ INTV ; BR IF NOT PUSH AX MOV AL,CRTLPH ;GET LIGHT PEN ADDRESS MSB OUT ZCRTC+CRTREG,AL IN AL,ZCRTC+CRTDAT MOV BH,AL MOV AL,CRTLPL ;GET LIGHT PEN ADDRESS LSB OUT ZCRTC+CRTREG,AL IN AL,ZCRTC+CRTDAT MOV BL,AL ; BX = RELATIVE ADDRESS OF HIT, NOW GET REAL ADDRESS MOV AL,CRTSAH ;GET START ADDRESS MSB OUT ZCRTC+CRTREG,AL IN AL,ZCRTC+CRTDAT MOV AH,AL MOV AL,CRTSAL ;GET START ADDRESS LSB OUT ZCRTC+CRTREG,AL IN AL,ZCRTC+CRTDAT SUB BX,AX ;(BX)=RELATIVE HIT ADDRESS SUB BX,ZLPENEV ; SUBTRACT ERROR VALUE ; MOV LPENHF,1 ;INDICATE LIGHT PEN HIT MOV LPENPOS,BX ;STORE LIGHT PEN POSITION IN AL,ZLPEN ;READ LIGHT PEN HIT REGISTER MOV LPENHIT,AL ; STORE IT POP AX ;* VSYNC HANDLER INTV: TEST AH,VSYNCI ;Q. VSYNC INTERRUPT JZ INTV1 ; BR IF NOT IN AL,GDPDATA ;CLEAR INTERRUPT AND GET DATA TEST AL,VSYNC ;Q. VSYNC STILL PRESENT JZ INTV1 ; BR IF NOT CALLFI MTRTINT,MTRSEG ;CALLF ROM MONITOR ROUTINE ; CLEAR LIGHTPEN STROBE / VERTICAL SYNC INTERRUPTS AND RE-ARM FLIP-FLOPS INTV1: IN AL,GDPDATA ;READ PIA DATA AND AL,NOT (LPENSE+VSYNCE) ;CLEAR LIGHTPEN / VSYNC FLIP-FLOPS OUT GDPDATA,AL IN AL,ZDIPSW ;DUMMY I/O TO FIRE E-CLOCK IN AL,GDPDATA ;ENABLE LIGHTPEN / VSYNC FLIP-FLOPS OR AL,LPENSE+VSYNCE OUT GDPDATA,AL ;* INTKEY - KEYBOARD HANDLER INTKEY: MOV AX,CS ;GET DS MOV DS,AX IN AL,ZKEYBDS ;GET STATUS BYTE TEST AL,ZKEYOBF ;Q. CHARACTER AVAILABLE JZ INTKEY3 ; BR IF NOT IN AL,ZKEYBDD ;INPUT CHARACTER CMP AL,ZKEYBRK ;Q. KEY -- FLUSH TYPE AHEAD BUFS JNE INTKEY0 ; BR IF NOT CALL FLCRT9 ; FLUSH BIOS BUFFER MOV AL,IOBYTE ; IF CRT IS CON:, THEN ALSO AND AL,3 ; FLUSH BDOS 1 CHARACTER BUFFER CMP AL,1 JNE INTKEY3 MOV BX,CCPORG1 MOV KBCHAR[BX],0 JMPS INTKEY3 INTKEY0: CMP KEYCNT,KEYBUFF ;Q. KEY BUFFER ALREADY FULL JB INTKEY2 ; BR IF NOT FULL INTKEY1: IN AL,ZKEYBDS ;BUFFER FULL, SEND BEEP TEST AL,ZKEYIBF JNZ INTKEY1 MOV AL,ZKEYBEP OUT ZKEYBDC,AL JMPS INTKEY3 INTKEY2: CALLFI MTRDKBD,MTRSEG ;PASS CHARACTER TO ROM MONITOR HANDLER INTKEY3: POPA JMP INTX2 ;EXIT VIA COMMON IRET EXIT ;** INTSWAP - SWAP TO 8085 PROCESSOR ; INTSWAP: MOV COMWHO,ZPSPPS5+ZPSPI88 ;INDICATE 8085 WILL GET CONTROL JMP INTX3 ;GOTO TO INTERRUPT EXIT ROUTINE ;** INTWILD - WILD INTERRUPT ; INTWILD: PUSHA LEA SI,WILDMSG ;PRINT MESSAGE AND DUMP CALL PMSG POPA JMP SYSDMP ;** SYSDMP - DUMP REGISTERS AT INTERRUPT ; SYSDMP: PUSH DI LEA DI,DMPAX ;AX CALL HEXW POP AX ;DI LEA DI,DMPDI CALL HEXW POP AX ;PC LEA DI,DMPIP CALL HEXW POP AX ;CS LEA DI,DMPCS CALL HEXW POP AX ;FLAGS LEA DI,DMPFLG CALL HEXW MOV AX,DS ;DS LEA DI,DMPDS CALL HEXW MOV AX,ES ;ES LEA DI,DMPES CALL HEXW MOV AX,SS ;SS LEA DI,DMPSS CALL HEXW MOV AX,SP ;SP LEA DI,DMPSP CALL HEXW MOV AX,BX ;BX LEA DI,DMPBX CALL HEXW MOV AX,CX ;CX LEA DI,DMPCX CALL HEXW MOV AX,DX ;DX LEA DI,DMPDX CALL HEXW MOV AX,SI ;SI LEA DI,DMPSI CALL HEXW MOV AX,BP ;BP LEA DI,DMPBP CALL HEXW LEA SI,DMPMSG ;PRINT DUMP CALL PMSG ;** HALT SYSTEM ; SYSHLT: LEA SI,HLTMSG ;PRINT MESSAGE CALL PMSG CALLFI MTRTINT,MTRSEG ;CALLF ROM MONITOR TO INSURE SCROLLING CLI ;INSURE MACHINE HALTS HLT ;** INTX - INTERRUPT EXIT ROUTINES ; ; INTX1 - ENTERED WHEN HARDWARE SLAVE INTERRUPT ; INTX2 - ENTERED WHEN HARDWARE MASTER INTERRUPT ; INTX3 - ENTERED WHEN SOFTWARE INTERRUPT ; ; EXIT FOR HARDWARE SLAVE INTERRUPT INTX1: PUSH AX MOV AL,OCW2OP+OCW2EOI ;ISSUE NON-SPECIFIC EOI OUT Z8259AS+OCW2,AL MOV AL,OCW3OP+OCW3RIS ;READ ISR OUT Z8259AS+OCW3,AL IN AL,Z8259AS+OCW3 TEST AL,AL ;Q. ANY OTHER SLAVE INT'S IN SERVICE POP AX JNZ INTX3 ; BR IF YES - SKIP EOI TO MASTER ; EXIT FOR HARDWARE MASTER INTERRUPT INTX2: PUSH AX MOV AL,OCW2OP+OCW2EOI ;ISSUE NON-SPECIFIC EOI OUT Z8259AM+OCW2,AL POP AX ; EXIT FOR SOFTWARE INTERRUPTS INTX3: PUSH BP PUSH ES MOV ES,CS:BANK1 CMP COMWHO,ZPSPPS8 ;8088 PROCESSOR SHOULD GET CONTROL JE INTIRET ; BR IF YES MOV BP,SP ;MODIFY RETURN ADDRESS MOV 4[BP],OFFSET SWAP85 ; TO GOTO SWAP OUTPUT MOV 6[BP],CS ; INSTRUCTION MOV AL,COMWHO ;FETCH SWAP OUTPUT DATA VALUE ; INTIRET: POP ES POP BP IRET ;DO RETURN FROM INTERRUPT EJECT ;*** SUBROUTINES ; ;** ABTIGN - HANDLE ABORT/IGNORE ALTERNATIVE FOR HARD DISK ERRORS ; ; ENTRY: (BX)=ADDRESS OF BUFFER HEADER ; 'PHYSEC'=PHYSICAL SECTOR # ; EXIT: 'BUFERR[BX]'=ABORT STATUS (0=NO , 1=YES) ; USES: AX,SI,DI ; ABTIGN: TEST DSKOP,DSKOPS ;Q. ERROR DURING 1ST TIME SELECT JNZ ABTIGN2 ; BR IF YES MOV BUFERR[BX],0 ;ASSUME NO ERROR MOV DI,BUFERRF[BX] ;GET ERROR STATUS BYTE ADD DI,PHYSEC MOV AL,[DI] CMP AL,0 ;Q. ERROR JE ABTIGN2 ; BR IF NO ERROR PUSH BX PUSH DI CALL ERRRPT ;REPORT ERROR LEA SI,AIMSG CALL PMSG CALL GETCHR ;GET RESPONSE PUSH AX LEA SI,CRLF CALL PMSG POP AX POP DI POP BX CMP AL,CTLC ;Q. ABORT RESPONSE JNE ABTIGN1 ; BR IF NO MOV BUFERR[BX],1 ;INDICATE ABORT JMPS ABTIGN2 ABTIGN1: MOV BYTE PTR [DI],0 ;INDICATE IGNORE ERROR ABTIGN2: RET ;** ALTCHR -- HANDLE ALTERNATE CHARACTER FONTS ; ; ENTRY: ; EXIT: NONE ; USES: ALL ; ALTCHR: CMP BBIOS-2,0 ;Q. ALTERNATE CHARACTER SET REQUESTED ; JE ALTCHR9 ; BR IF NOT JNE $+5 JMP ALTCHR9 PUSH DS MOV DS,.MTRDSEG ;DS=>MONITOR DATA AREA CMP MTRFNTL,ALTFNTL ;Q. WILL ROM FONT TABLE FIT IN MY AREA JBE ALTCHR1 ; BR IF YES POP DS LEA SI,FNTMSG ;PRINT ERROR MESSAGE CALL PMSG JMP SYSHLT ; MOVE ROM FONT TABLE TO MY AREA ALTCHR1: CLD LEA DI,ALTFNT MOV CX,MTRFNTL MOV SI,MTRFONT MOV AX,MTRFONT+2 POP DS ;DS=>BIOS PUSH ES MOV ES,AX ;ES=>ROM FONT TABLE CALL EXDSES ;DS=>ROM FONT TABLE , ES=>BIOS REP MOVSB CALL EXDSES ;DS=>BIOS , ES=>ROM FONT TABLE ; MAKE CHANGES TO KEYBOARD MAP POP ES ;ES=>8085 BANK MOV SI,BBIOS-2 PUSH ES MOV ES,.MTRDSEG ;ES=>MONITOR DATA AREA ALTCHR2: LODSW CMP AX,0FFFFH JE ALTCHR3 MOV DI,AX AND DI,0FFH MOV ES: MTRKMAP[DI],AH JMPS ALTCHR2 ; MAKE CHANGES TO FONT TABLE ALTCHR3: MOV AX,DS MOV ES,AX ;ES=>BIOS ALTCHR4: LODSB CMP AL,0FFH JE ALTCHR5 MOV AH,9 MUL AH LEA DI,ALTFNT ADD DI,AX MOV CX,9 REP MOVSB JMPS ALTCHR4 ; MAKE CHANGES TO DISPLAY MAP ALTCHR5: MOV ES,.MTRDSEG ;ES=>MONITOR DATA AREA ALTCHR6: LODSW CMP AX,0FFFFH JE ALTCHR7 MOV DI,AX AND DI,0FFH MOV ES: MTRDMAP[DI],AH JMPS ALTCHR6 ; ALTCHR7: MOV ES: MTRFONT,OFFSET ALTFNT MOV ES: MTRFONT+2,DS ;UPDATE FONT TABLE VECTOR POP ES ;ES=>8085 BANK ALTCHR9: RET ;** CBTFIL - FILL THE LOGICAL TO PHYSICAL MAPPING TABLE FOR REAL DRIVES. ; THEN DO THE SAME FOR THE IMAGINARY DRIVES PLUS SET UP THE ; IMAGINARY'S LINK TO HIS CORRESPONDING REAL DRIVE. ; ; ENTRY: (CH)=# DRIVES ; (CL)=STARTING UNIT # ; (DH)=STARTING DRIVE MAP # ; 'CBIC'=NEXT LOGICAL DRIVE # TO BE ASSIGNED ; EXIT: 'CBIC' UPDATED ; USES: ALL ; CBTFIL: MOV CBTIA,0 ;INIT CBTIA CBTFIL1: PUSH CX PUSH DX MOV CBTFA,0 ;INDICATE REAL DRIVE CYCLE CALL CBTF ;HANDLE REAL DRIVES POP DX POP CX MOV CBTFA,1 ;INDICATE IMAGINARY CYCLE ;* THIS SECTION OF CODE IS RAN THROUGH TWICE. ; FIRST TIME IS FOR HANDLING THE REAL DRIVES. ; SECOND TIME IS FOR HANDLING THE IMAGINARY DRIVES. CBTF: MOV DL,CH ;COPY # OF DRIVES CBTF1: MOV AL,CL ;GET THIS DRIVES NUMBER MOD (# DRIVES) CBW DIV CH ADD AH,DH ;COMPUTE DISK ENTRY TABLE TO USE MOV CBIB,AH PUSH CX MOV AL,DPEL ;GET ADDRESS OF TABLE ENTRY MUL AH ADD AX,OFFSET DPEBASE ADD AX,BBIOS MOV BP,AX TEST DPEFLG2[BP],DPEIMG ;Q. IMAGINARY DRIVE JNZ CBTF3 ; BR IF YES ; HANDLE REAL DRIVE IS THIS IS REAL DRIVE CYCLE CMP CBTFA,0 ;Q. REAL DRIVE CYCLE JNE CBTF4 ; BR IF NOT CMP CBTIA,0 ;IF THIS IS 1ST REAL DRIVE ENCOUNTERED JNE CBTF25 ; THEN REMEMBER ITS TABLE ADDRESS MOV CBTIA,BP CBTF25: MOV CH,CBIC MOV CL,4 SHL CH,CL OR CH,CBIB MOV DPELUN[BP],CH ;PLACE LOGICAL/REAL IN DPELUN SLOT CALL CBTF6 ;MAP DRIVE JMPS CBTF4 ; HANDLE IMAGINARY DRIVE IF THIS IS THE IMAGINARY DRIVE CYCLE CBTF3: CMP CBTFA,0 ;Q. IMAGINARY DRIVE CYCLE JE CBTF4 ; BR IF NOT CMP CBTIA,0 ;Q. ANY REAL DRIVES FOR THIS DRIVE TYPE JNE CBTF31 ; BR IF YES MOV DPEFLAG[BP],DPENE ; OTHERWISE CHANGE DRIVE TYPE TO MOV BX,BBIOS ; NONEXISTANT DRIVE AND DECREMENT DEC NDISKS[BX] ; # CP/M DRIVES JMPS CBTF4 CBTF31: CALL CBTF6 ;MAP DRIVE MOV SI,CBTIA ;MOVE THE REAL DRIVE'S HEATH EXTENSIONS ADD SI,OFFSET DPEHTH ; INTO THIS IMAGINARY DRIVE'S TABLES MOV DI,BP ADD DI,OFFSET DPEHTH PUSH CX MOV CX,DPEHL PUSH DS MOV AX,ES MOV DS,AX CLD REP MOVSB POP DS POP CX OR DPEFLG2[BP],DPEIMG ;REMARK AS IMAGINARY DRIVE MOV CH,CBIC ;REENTER LOGICAL DRIVE # MOV CL,4 SHL CH,CL AND DPELUN[BP],DPEREAL OR DPELUN[BP],CH ; CBTF4: POP CX INC CL ;ROUND ROBIN TO NEXT DRIVE DEC DL ;COUNT THIS ONE AS DONE JZ $+5 JMP CBTF1 RET ;* PLACE MAPPED DRIVE # INTO MAP DRIVE TABLE ; 'CBIB'=MAPPED DRIVE # CBTF6: LEA BX,BDMAP ;CALCULATE MAP TABLE ENTRY ADDRESS MOV AL,CBIC CBW ADD BX,AX MOV AL,CBIB MOV ES: [BX],AL ;PLACE MAPPED DRIVE # THERE INC CBIC ;BUMP VALUE NEXT LOGICAL DRIVE # RET ;** CHKLAB - CHECK CHECKSUM OF LABEL ; ; ENTRY: (SI)=ADDRESS OF LABEL ; EXIT: PSW/Z=STATUS ; 0=BAD CHECKSUM , 1=GOOD CHECKSUM ; USES: AL,CX,SI ; CHKLAB: XOR AL,AL ;ZERO ACCUMULATOR MOV CX,LABLEN ;COUNT CHKLAB1: ADD AL,[SI] ;ADD VALUES INC SI LOOP CHKLAB1 INC AL ;INC CHECKSUM VALUE AND SET/RESET PSW/Z RET ;** CPSEC - CALCULATE PHYSICAL SECTOR ; ; ENTRY: 'REQSEC'=REQUESTED CP/M SECTOR # ; (BX)=ADDRESS OF BUFFER HEADER ; EXIT: (AX),'PHYSEC'=PHYSICAL SECTOR # ; USES: AX,DI ; CPSEC: MOV AX,REQSEC MOV DI,BUFDPE[BX] CMP REQTRK,0 JNE CPSEC1 TEST DPEFLAG[DI],DPET0SD JNZ CPSEC2 CPSEC1: DIV DPERPS[DI] CBW CPSEC2: MOV PHYSEC,AX RET ;** DISPATCHER ; SWAP85: OUT ZPSP,AL ;OUTPUT SWAP VALUE TO SWAP PORT JMPS DISPATCH ;FLUSH PIPELINE DISPATCH: XOR BH,BH MOV BL,COMFUNC ;GET BIOS FUNCTION # CMP BX,TABLEL ;CHECK RANGE JA SWAP851 ; BR IF OUT OF RANGE SHL BX,1 CALL TABLE[BX] ;CALL APPROPRIATE HANDLER SWAP851: INT SWISWAP ;SWAP TO 8085 PROCESSOR ; UNUSED DISPATCH ENTRY UNUSED: RET ;** ERRRPT - REPORT DISK ERRORS ; ; ENTRY: (AL)=ERROR STATUS BYTE ; (BX)=ADDRESS OF BUFFER HEADER INFO ; 'PHYTRK'=TRACK # ; 'PHYSEC'=SECTOR # ; 'PHYSID','PHYSIDN'=SIDE INFO ; 'LSIO'=FLAG INDICATING LOGICAL SECTOR I/O RATHER THAN ; TRACK/SIDE/SECTOR ; EXIT: NONE ; USES: CX,SI,DI ; ERRRPT: TEST DSKOP,DSKOPS ;Q. ERROR DURING 1ST TIME SELECT ; JNZ ERRRPT4 ; BR IF YES JZ $+5 JMP ERRRPT4 PUSH AX LEA DI,ERRMSG6 ;STATUS BYTE CALL HEXB PUSH ES ;'READ' OR 'WRITE' ERROR MOV AX,DS MOV ES,AX LEA SI,RDEMSG TEST DSKOP,NOT (DSKOPR+DSKOPRA) JZ ERRRPT1 LEA SI,WREMSG ERRRPT1: LEA DI,ERRMSG1 MOV CX,5 CLD REP MOVSB POP ES MOV AL,BUFDRV[BX] ;DRIVE NAME ADD AL,'A' MOV ERRMSG2,AL PUSH BX ;PRINT ERROR MSG SO FAR LEA SI,ERRMSG CALL PMSG POP BX CMP LSIO,1 ;Q. LOGICAL SECTOR I/O DEVICE JE ERRRPT2A ; BR IF YES MOV AX,PHYTRK ;TRACK # LEA DI,ERRMSG3 CALL HEXW XOR AL,AL ;SIDE # MOV DI,BUFDPE[BX] TEST DPEFLAG[DI],DPE2S JZ ERRRPT2 MOV AL,PHYSIDN ERRRPT2: LEA DI,ERRMSG4 CALL HEXN PUSH BX ;AGAIN PRINT ERROR MSG SO FAR LEA SI,ERRMSG7 CALL PMSG POP BX ERRRPT2A: TEST DSKOP,DSKOPR+DSKOPW ;SECTOR # JZ ERRRPT3 MOV AX,PHYSEC INC AX CMP LSIO,1 JNE ERRRPT2B ADD AX,PHYTRK DEC AX ERRRPT2B: LEA DI,ERRMSG5 CALL HEXW PUSH BX ;AGAIN PRINT ERROR MSG SO FAR LEA SI,ERRMSG8 CALL PMSG POP BX ERRRPT3: PUSH BX LEA SI,CRLF CALL PMSG POP BX POP AX ERRRPT4: RET ;** EXDSES -- EXCHANGE DS AND ES ; EXDSES: PUSH DS PUSH ES POP DS POP ES RET ;** GETCHR - GET CHARACTER FROM CON: (FLUSHING TYPEAHEAD BUFFER ; BEFORE HAND IF NECESSARY ; ; ENTRY: NONE ; EXIT: (AL)=CHARACTER ; USES: AL ; GETCHR: MOV AL,IOBYTE ;GET IOBYTE AND AL,003H ;Q. CON:=CRT: CMP AL,1 JNE GETCHR1 ; BR IF NOT CALL FLCRT ;FLUSH CRT: TYPE AHEAD BUFFER GETCHR1: JMP CONINE ;RETURN VIA 'CONINE' ;** HEXW, HEXB, HEXN - CONVERT HEX VALUES TO ASCII ; ; HEXW - WORD ; ENTRY: (AX)=HEX VALUE ; ; HEXB - BYTE ; ENTRY: (AL)=HEX VALUE ; ; HEXN - LOW ORDER NIBBLE ; ENTRY: (AL)=HEX VALUE ; ; ENTRY: (DI)=ADDRESS OF START OF OUTPUT AREA TO RECEIVE ASCII ; EXIT: NONE ; USES: AX,DI ; HEXW: XCHG AL,AH CALL HEXB MOV AL,AH HEXB: PUSH AX SHR AL,1 SHR AL,1 SHR AL,1 SHR AL,1 CALL HEXN POP AX HEXN: AND AL,00FH ADD AL,090H DAA ADC AL,040H DAA MOV [DI],AL INC DI RET ;** PMSG -- PRINT MESSAGE ON CONSOLE ; ; ENTRY: (SI)=ADDRESS OF MESSAGE ENDING WITH 'CPMEOM' CHARACTER ; THE 'CPMEOM' CHARACTER IS NOT PRINTED ; EXIT: NONE ; USES: ALL ; PMSG: LODSB CMP AL,CPMEOM JZ PMSG1 MOV COMRC,AL CALL CONOUTE JMPS PMSG PMSG1: RET ;** UPC - TRANSLATE (AL) TO UPPERCASE ; ; ENTRY: (AL)=CHARACTER ; EXIT: (AL)=TRANSLATED CHARACTER ; USES: AL ; UPC: CMP AL,'a' ;CHECK IF LOWER CASE JB UPC1 CMP AL,'z' JA UPC1 ; BR IF NOT AND AL,05FH ;TRANSLATE TO UPPERCASE UPC1: RET EJECT ;*** DATA STORAGE ; X EQU OFFSET $ DSEG ORG X MTRMSG RB 0 ;ROM MONITOR DATA AREA TOO LARGE DB CR,LF,'MONITOR ROM DATA AREA IS TOO LARGE',CPMEOM FNTMSG RB 0 ;ROM FONT TABLE TOO LARGE DB CR,LF,'MONITOR ROM FONT TABLE IS LARGER THAN BIOS ' DB 'FONT TABLE AREA',CPMEOM BUFMSG RB 0 ;NOT ENOUGH MEMORY FOR DISK BUFFERS DB CR,LF,'NOT ENOUGH MEMORY FOR DISK BUFFERS',CPMEOM SIGNON RB 0 ;SIGNON MESSAGE DB CR,LF,LF DB 'CP/M-85 VERSION 2.2' IF EXPER DB 'x' ENDIF IF NOT EXPER DB '.' ENDIF DB BVERSN/100+'0',(BVERSN MOD 100)/10+'0',(BVERSN MOD 10)+'0' IF BREVSN NE ' ' DB BREVSN ENDIF DB ' ' DB BMO/10+'0',(BMO MOD 10)+'0','/' DB BDY/10+'0',(BDY MOD 10)+'0','/' DB BYR/10+'0',(BYR MOD 10)+'0' DB CR,LF,LF,CPMEOM MNMSG RB 0 ;MOUNT MESSAGE DB CR,LF,'PUT DISK ' MNMSGA DB '? IN DRIVE ' MNMSGB DB '?: AND PRESS RETURN',CPMEOM ERRMSG RB 0 ;HARD DISK ERROR MESSAGE DB CR,LF,LF,'HARD ' ERRMSG1 DB '????? ERROR ON DRIVE ' ERRMSG2 DB '?: STATUS ' ERRMSG6 DB '??',CPMEOM ERRMSG7 DB ' TRACK ' ERRMSG3 DB '???? SIDE ' ERRMSG4 DB '?',CPMEOM ERRMSG8 DB ' SECTOR ' ERRMSG5 DB '????',CPMEOM RDEMSG DB 'READ ' WREMSG DB 'WRITE' AIMSG DB 'PRESS TO ABORT, TO IGNORE: ',CPMEOM CRLF RB 0 DB CR,LF,CPMEOM TIMERRM RB 0 ;TIMER BROKE MSG DB BELL,CR,LF,'THE TIMER IS BROKE',CR,LF,CPMEOM DIV0MSG RB 0 ;DIVIDE BY 0 ERROR MESSAGE DB CR,LF,LF,'DIVIDE BY ZERO INTERRUPT',CR,LF,LF,CPMEOM PBEMSG RB 0 ;PARITY OR BUSS ERROR MESSAGE DB CR,LF,LF,'ERROR - MEMORY PARITY OR BUSS',CR,LF,LF,CPMEOM WILDMSG RB 0 ;WILD INTERRUPT MESSAGE DB CR,LF,LF,'WILD INTERRUPT',CR,LF,LF,CPMEOM DMPMSG RB 0 ;REGISTER DUMP DB 'F =' DMPFLG DB '???? IP=' DMPIP DB '???? CS=' DMPCS DB '???? DS=' DMPDS DB '???? ES=' DMPES DB '???? SS=' DMPSS DB '???? SP=' DMPSP DB '????',CR,LF,'AX=' DMPAX DB '???? BX=' DMPBX DB '???? CX=' DMPCX DB '???? DX=' DMPDX DB '???? DI=' DMPDI DB '???? SI=' DMPSI DB '???? BP=' DMPBP DB '????',CPMEOM HLTMSG RB 0 ;SYSTEM HALT MESSAGE DB CR,LF,LF,'SYSTEM HALT',CR,LF,LF,CPMEOM HINTVO RW 0 ;HARDWARE INTERRUPT VECTOR OFFSET TABLE DW OFFSET INTPBE ; MASTER 0 DW OFFSET INTWILD ; MASTER 1 DW OFFSET INTTIM ; MASTER 2 DW OFFSET INTWILD ; MASTER 3 DW OFFSET INTWILD ; MASTER 4 DW OFFSET INTWILD ; MASTER 5 DW OFFSET INTLVK ; MASTER 6 DW OFFSET INTWILD ; MASTER 7 DW OFFSET INTWILD ; SLAVE 0 DW OFFSET INTWILD ; SLAVE 1 DW OFFSET INTWILD ; SLAVE 2 DW OFFSET INTWILD ; SLAVE 3 DW OFFSET INTWILD ; SLAVE 4 DW OFFSET INTWILD ; SLAVE 5 DW OFFSET INTWILD ; SLAVE 6 DW OFFSET INTWILD ; SLAVE 7 DW OFFSET INTX2 ; MASTER EXIT ROUTINE DW OFFSET INTX1 ; SLAVE EXIT ROUTINE DRVRTBL RW 0 ;DEVICE DRIVER DISPATCH TABLE DW 0 ; NON-EXISTANT DW OFFSET DRVR207 ; Z207 DW OFFSET DRVR217 ; Z217 DW 0 DW 0 DW 0 DW 0 DW 0 TABLE RW 0 ;DISPATCH TABLE DW OFFSET UNUSED ; COLD BOOT DW OFFSET WBOOTE ; WARM BOOT DW OFFSET CONSTE ; CONSOLE STATUS DW OFFSET CONINE ; CONSOLE INPUT DW OFFSET CONOUTE ; CONSOLE OUTPUT DW OFFSET LSTOUTE ; LIST OUTPUT DW OFFSET PUNOUTE ; PUNCH OUTPUT DW OFFSET RDRINE ; READER INPUT DW OFFSET HOMEE ; HOME HEAD DW OFFSET SETDSKE ; SET DISK DRIVE DW OFFSET SETTRKE ; SET TRACK DW OFFSET SETSECE ; SET SECTOR DW OFFSET SETDMAE ; SET DMA DW OFFSET READE ; READ CP/M SECTOR DW OFFSET WRITEE ; WRITE CP/M SECTOR DW OFFSET LSTSTE ; LIST STATUS DW OFFSET SECTRNE ; SECTOR TRANSLATE DW OFFSET FORMATE ; FORMAT DW OFFSET RDTRKE ; READ TRACK DW OFFSET WRTRKE ; WRITE TRACK DW OFFSET WPCE ; WRITE PROTECT CHECK DW OFFSET CLRBUFD ; CLEAR BUFFERS FOR DRIVE DW OFFSET PEEKE ; PEEK 8088 MEMORY FUNCTION DW OFFSET POKEE ; POKE 8088 MEMORY FUNCTION TABLEL EQU (OFFSET $ - OFFSET TABLE)/2 CBIC DB 0 ;LOGICAL DRIVE # (DRIVE TABLE FILL) DSKOP DB 0 ;DISK OPERATIONS IN PROGRESS DEVCTL DB 0 ;1797 DEVICE CONTROL REGISTER SIDE207 DB FDFSS1 ;1797 SIDE SELECT VALUE LAST USED ; Z207 8" DRIVE TABLES TBL207 RW 0 DW Z2071S ;SINGLE DENSITY / SINGLE SIDED / 128 DW 0 ;SINGLE DENSITY / SINGLE SIDED / 256 DW 0 ;SINGLE DENSITY / SINGLE SIDED / 512 DW 0 ;SINGLE DENSITY / SINGLE SIDED /1024 DW Z2072S ;SINGLE DENSITY / DOUBLE SIDED / 128 DW 0 ;SINGLE DENSITY / DOUBLE SIDED / 256 DW 0 ;SINGLE DENSITY / DOUBLE SIDED / 512 DW 0 ;SINGLE DENSITY / DOUBLE SIDED /1024 DW 0 ;DOUBLE DENSITY / SINGLE SIDED / 128 DW Z2071D1 ;DOUBLE DENSITY / SINGLE SIDED / 256 DW 0 ;DOUBLE DENSITY / SINGLE SIDED / 512 DW Z2071D2 ;DOUBLE DENSITY / SINGLE SIDED /1024 DW 0 ;DOUBLE DENSITY / DOUBLE SIDED / 128 DW Z2072D1 ;DOUBLE DENSITY / DOUBLE SIDED / 256 DW 0 ;DOUBLE DENSITY / DOUBLE SIDED / 512 DW Z2072D2 ;DOUBLE DENSITY / DOUBLE SIDED /1024 Z2071S DB 1,1,8 ;SINGLE DENSITY / SINGLE SIDED / 128 DW 26 DB 3,7,0 DW 242,63 DB 0C0H,0 DW 16,2 Z2072S DB 1,1,16 ;SINGLE DENSITY / DOUBLE SIDED / 128 DW 26 DB 4,15,1 DW 246,127 DB 0C0H,0 DW 32,2 Z2071D1 DB 2,2,16 ;DOUBLE DENSITY / SINGLE SIDED / 256 DW 52 DB 4,15,0 DW 242,127 DB 0C0H,0 DW 32,2 Z2071D2 DB 0,8,16 ;DOUBLE DENSITY / SINGLE SIDED /1024 DW 64 DB 4,15,0 DW 299,127 DB 0C0H,0 DW 32,2 Z2072D1 DB 2,2,16 ;DOUBLE DENSITY / DOUBLE SIDED / 256 DW 52 DB 4,15,0 DW 493,255 DB 0F0H,0 DW 64,2 Z2072D2 DB 0,8,16 ;DOUBLE DENSITY / DOUBLE SIDED /1024 DW 64 DB 4,15,0 DW 607,255 DB 0F0H,0 DW 64,2 ; PATCH RB 128 ;PATCH AREA ; BANK1 RW 1 ;SEGMENT ADDRESS FOR BANK 1 CCPORG0 RW 1 ;CP/M-85 CCP ORIGIN IN BANK 0 COPY CCPORG1 RW 1 ;CP/M-85 CCP ORIGIN IN BANK 1 CBTFA RB 1 ;DRIVE TABLE FILL CYCLE INDICATOR CBTIA RW 1 ;ADDRESS OF REAL DRIVE DPE CBIB RB 1 ;MAPPED DRIVE # DMAPTR RW 1 ;DMA ADDRESS FVFLG RB 1 ;FORMAT VERIFY FLAG HSTPTR RW 1 ;HOST BUFFER POINTER LSIO RB 1 ;LOGICAL SECTOR I/O FLAG PHYDRV RB 1 ;PHYSICAL DRIVE # PHYDPE RW 1 ;PHYSICAL DPE PHYSID RB 1 ;PHYSICAL SIDE PHYSIDN RB 1 ;PHYSICAL SIDE NUMBER PHYTRK RW 1 ;PHYSICAL TRACK PHYSEC RW 1 ;PHYSICAL SECTOR REQDRV RB 1 ;REQUESTED DRIVE REQTRK RW 1 ;REQUESTED TRACK REQSEC RW 1 ;REQUESTED SECTOR SECCNT RB 1 ;PHYSICAL SECTORS PER TRACK SEC1ST RB 1 ;1ST SECTOR # FOR OPERATION COUNT RW 1 ;BYTES PER PHYSICAL SECTOR RETRIES RB 1 ;I/O RETRY COUNTER HLDDLYF RB 1 ;1797 DELAY FLAG ERRTYP RB 1 ;ERROR TYPE (STATUS BYTE) XLATES RW 1 ;ADDRESS OF XLATE TABLE ADDRESSES RDABUF RB FDRAL ;READ ADDRESS BUFFER #1 RDABUF2 RB FDRAL ;READ ADDRESS BUFFER #2 OMDSEG RW 1 ;ORIGINAL MONITOR DATA SEGMENT VALUE PREREAD RB 1 ;DO PREREAD FLAG FLDERR RB 1 ;FLUSH DRIVE ERROR ACCUMULATOR PTICCNT RW 1 ;PREVIOUS TIMER 1 COUNT ; KEYBOARD TYPE-AHEAD BUFFER KEYCNT RB 1 ;CHARACTER COUNT KEYPUT RW 1 ;PUT POINTER KEYGET RW 1 ;GET POINTER KEYBUF RB 80 ;BUFFER KEYBUFL EQU OFFSET $ - OFFSET KEYBUF ;BUFFER SIZE KEYBUFF EQU KEYBUFL-10 ;KEYBOARD BUFFER FULL VALUE ; ALTERNATE CHARACTER FONT TABLE ALTFNTL EQU (256-32)*9 ;LENGTH ALTFNT RB ALTFNTL ;AREA IF OFFSET $ GE BLDRP0 %: BIOS88 TOO LARGE ENDIF ; DISK BUFFER AND BUFFER HANDLING STORAGE FSTBUF RW 1 ;POINTER TO FIRST ELEMENT LSTBUF RW 1 ;POINTER TO LAST ELEMENT DMYHDR RB BUFHDRL ;DUMMY BUFFER HEADER HEADER RB BUFCNT*BUFHDRL ;DISK BUFFER HEADER INFO STACK SECFLGL EQU 26 SECFLG RB BUFCNT*SECFLGL ;DIRTY SECTOR FLAGS (1=DIRTY) ERRFLGL EQU 26 ERRFLG RB BUFCNT*ERRFLGL ;SECTOR ERROR FLAGS BUFFERL EQU 9*1024 BUFFER RB BUFCNT*BUFFERL ;BUFFER AREAS B88END EQU OFFSET $ END