home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
ENTERPRS
/
CPM
/
UTILS
/
S
/
ZEN2.LBR
/
BIOS88.A86
< prev
next >
Wrap
Text File
|
2000-06-30
|
67KB
|
3,558 lines
TITLE 'CP/M-85 BIOS (8088 CODE PORTION) 10 MAR 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
WAIT EQU TRUE
;*** EQUATES
;
INCLUDE ZMEMMAP.LIB
INCLUDE ASCII.LIB
INCLUDE DEF6821.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 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
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
;
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
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 <CR>
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 <ETX>/<ACK> PROTOCOL
OSCIO2:
TEST CIOF1[BX],CIOEAH ;Q. USING <ETX>/<ACK> HANDSHAHKING
JZ OSCIO3 ; BR IF NOT
TEST CIOF2[BX],CIOW4A ;Q. WAITING FOR <ACK>
JNZ OSCIO2A ; BR IF YES
MOV AL,CIOECTR[BX] ;Q. TIME TO SEND <ETX>
CMP AL,CIOECNT[BX]
JB OSCIO4 ; BR IF NOT
MOV CIOECTR[BX],0 ;REINITIALIZE COUNTER
MOV AL,ETX ;SEND <ETX>
CALL CIOOD[BX]
OR CIOF2[BX],CIOW4A ;SHOW WAITING FOR <ACK>
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. <ACK>
JNE OSCIO8 ; BR IF NOT
AND CIOF2[BX],0FFH-CIOW4A ;SHOW NOT WAITING FOR <ACK>
JMPS OSCIO4
; HANDLE <DC1>/<DC3> PROTOCOL
OSCIO3:
TEST CIOF1[BX],CIODCH ;Q. USING <DC1>/<DC3> 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. <DC1>
JNE OSCIO3B ; BR IF NOT
AND CIOF2[BX],0FFH-CIOW4D ;SHOW NOT WAITING FOR <DC1>
JMPS OSCIO4
OSCIO3B:
CMP AL,DC3 ;Q. <DC3>
JNE OSCIO3C ; BR IF NOT
OR CIOF2[BX],CIOW4D ;SHOW WAITING FOR <DC1>
JMPS OSCIO8
OSCIO3C:
TEST CIOF2[BX],CIOW4D ;Q. WAITING FOR <DC1>
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:
CALL OSCIO ;WAIT UNTIL READY
TEST AL,AL
JZ ODCIO
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. <ESC>
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
MOV KEYCNT,0 ;INIT BUFFER HANDLING VALUES
LEA BX,KEYBUF
MOV KEYPUT,BX
MOV KEYGET,BX
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
;* 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
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
;NO LIGHT PEN HANDLER AT THIS TIME
;* 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 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
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 <CTL-C> TO ABORT, <RETURN> 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
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
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