Files
86-DOS-0.11/86DOS.A86
T
Yufeng Gao c7b866b40d General cleanup
Clean up of various source files. The CHESS program is not fully cleaned up yet.
2026-01-25 22:26:55 +10:00

2259 lines
32 KiB
Plaintext

; QDOS High-performance operating system for the 8086 version 0.11
; by Tim Paterson
; Interrupt Entry Points:
; INTBASE: ABORT
; INTBASE+4: COMMAND
; INTBASE+8: BASE EXIT ADDRESS
; INTBASE+C: CONTROL-C ABORT
; INTBASE+10H: FATAL ERROR ABORT
; INTBASE+14H: BIOS DISK READ
; INTBASE+18H: BIOS DISK WRITE
; INTBASE+40H: Long jump to CALL entry point
MAXCALL:EQU 36
MAXCOM: EQU 40
ESCCH: EQU 1BH
INTBASE:EQU 80H
INTTAB: EQU 20H
ENTRYPOINTSEG: EQU 0CH
ENTRYPOINT: EQU INTBASE+40H
CONTC: EQU INTTAB+3
EXIT: EQU INTBASE+8
LONGJUMP:EQU 0EAH
LONGCALL:EQU 9AH
MAXDIF: EQU 0FFFH
SAVEXIT:EQU 10
; Field definition for FCBs
ORG 0
DS 12 ;Drive code and name
EXTENT: DS 4
ENTPOS: DS 2 ;Position of entry in directory
DRVBP: DS 2 ;BP for SEARCH FIRST and SEARCH NEXT
FIRCLUS:DS 2 ;First cluster of file
LSTCLUS:DS 2 ;Last cluster accessed
FILSIZ: DS 2 ;Size of file in records
CLUSPOS:DS 2 ;Position of last cluster accessed
DIRTYFIL:DS 1 ;File has been written to if <>0
SIZCHG: DS 1 ;Directory needs update if <>0
ORG 32
NR: DS 1 ;Next record
RR: DS 3 ;Random record
; Description of 16-byte directory entry (same as returned by SEARCH FIRST
; and SEARCH NEXT, functions 17 and 18).
;
; Location bytes Description
;
; 0 11 File name and extension ( 0E5H if empty)
; 11 2 First allocation unit ( < 4080 )
; 13 3 File size, in bytes (LSB first, 24 bits max.)
; Field definition for Drive Parameter Block
ORG 0
DRVNUM: DS 1 ;Drive number
SECSIZ: DS 1 ;Size of physical sector in records
CLUSMSK:DS 1 ;Records/cluster - 1
CLUSSHFT:DS 1 ;Log2 of records/cluster
FIRFAT: DS 2 ;Starting record of FATs
FATSIZ: DS 1 ;Number of records occupied by FAT
FATCNT: DS 1 ;Number of FATs for this drive
FIRDIR: DS 2 ;Starting record of directory
DIRSIZ: DS 1 ;Number of records occupied by directory
FIRREC: DS 2 ;First record of first cluster
MAXCLUS:DS 2 ;Number of clusters on drive + 1
DIRTYFAT:DS 1 ;-1=FAT has been changed
FAT: DS 2 ;Start of FAT
DPBSIZ: EQU $
; BIOS entry point defintions
BIOSSEG: EQU 40H
ORG 0
DS 3
BIOSSTAT: DS 3
BIOSIN: DS 3
BIOSOUT: DS 3
BIOSPRINT: DS 3
BIOSAUXIN: DS 3
BIOSAUXOUT: DS 3
BIOSREAD: DS 3
BIOSWRITE: DS 3
BIOSFLUSH: DS 3
; Start of code
ORG 0
PUT 100H
JMP DOSINIT
ESCTAB:
DB "SC" ;Copy one char
DB "VN" ;Skip one char
DB "TA" ;Copy to char
DB "WB" ;Skip to char
DB "UH" ;Copy line
DB "HH" ;Kill line (no change in template)
DB "RM" ;Reedit line (new template)
DB "DD" ;Backspace
DB "P@" ;Enter insert mode
DB "QL" ;Exit insert mode
DB ESCCH,ESCCH ;Escape character
DB ESCCH,ESCCH ;End of table
ESCTABLEN:EQU $-ESCTAB
HEADER: DB 13,10,"86-DOS version 0.11"
DB 13,10
DB "Copyright 1980 Seattle Computer Products, Inc.",13,10,"$"
DOSINIT:
DI
UP
MOV AX,CS
MOV ES,AX
LODB
CBW
MOV CX,AX
SEG CS
MOV [NUMDRV],AL
MOV DI,AX
SHL DI
MOV AH,DPBSIZ
MUL AX,AH
MOV BX,DRVTAB
ADD DI,BX
ADD AX,DI
MOV BP,AX
SEG CS
MOV [FATBASE],AX
PERDEV:
SEG CS
MOV [BX],DI
INC BX
INC BX
MOV AL,CH
STOB ;DRVNUM
LODW ;Pointer to DPT
PUSH SI
MOV SI,AX
MOVB ;SECSIZ
LODB
DEC AL
STOB ;CLUSMSK
CBW
FIGSHFT:
INC AH
SAR AL
JNZ FIGSHFT
MOV AL,AH
STOB ;CLUSSHFT
LODW
STOW ;FIRFAT (= number of reserved records)
MOV DX,AX
LODB
STOB ;FATSIZ
MOV AH,AL
PUSH AX
LODB
STOB ;FATCNT
MUL AX,AH
ADD AX,DX
STOW ;FIRDIR
MOV DX,AX
LODB
STOB ;DIRSIZ
CBW
ADD AX,DX
STOW ;FIRREC
POP DX
LODW
INC AX
STOW ;MAXCLUS
XOR AL,AL
STOB
POP SI ;Restore pointer to init. table
LODW ;Allocation table displacement
SEG CS
ADD AX,[FATBASE]
STOW ;FAT
MOV DL,0
SHR DX ;FAT size in bytes
ADD AX,DX
CMP AX,BP ;Bigger than already allocated
JBE SMFAT
MOV BP,AX
SMFAT:
INC CH ;Next I/O device number
DEC CL
JNZ PERDEV
ADD BP,15 ;True start of free space
MOV CL,4
SHR BP,CL ;First free segment
XOR AX,AX
MOV DS,AX
MOV ES,AX
MOV DI,INTBASE
MOV AX,QUIT
STOW ;Set abort address--displacement
MOV AX,CS
MOV B,[ENTRYPOINT],LONGJUMP
MOV [ENTRYPOINT+1],ENTRY
MOV [ENTRYPOINT+3],CS
STOW
STOW
STOW
MOV [INTBASE+4],COMMAND
MOV DI,INTBASE+14H
MOV AX,BIOSREAD
STOW
MOV AX,BIOSSEG
STOW
STOW ;Add 2 to DI
STOW
MOV [INTBASE+18H],BIOSWRITE
MOV DX,CS
MOV DS,DX
ADD DX,BP
MOV [DMAADD],80H
MOV [DMAADD+2],DX
MOV AX,[DRVTAB]
MOV [CURDRVPT],AX
MOV CX,DX
MOV BX,0FH
MEMSCAN:
INC CX
JZ HAVMEM
MOV DS,CX
MOV AL,[BX]
NOT AL
MOV [BX],AL
CMP AL,[BX]
NOT AL
MOV [BX],AL
JZ MEMSCAN
HAVMEM:
SEG CS
MOV [ENDMEM],CX
XOR CX,CX
MOV DS,CX
MOV [EXIT],100H
MOV [EXIT+2],DX
MOV [INTBASE+0CH],100H
MOV [INTBASE+0EH],DX
CALL SETMEM
MOV SI,HEADER
CALL OUTMES
RET L
QUIT:
MOV AH,0
JP SAVREGS
COMMAND: ;Interrupt call entry point
CMP AH,MAXCOM
JBE SAVREGS
BADCALL:
MOV AL,0
IRET: IRET
ENTRY: ;System call entry point and dispatcher
POP AX ;IP from the long call at 5
POP AX ;Segment from the long call at 5
SEG CS
POP [TEMP] ;IP from the CALL 5
PUSHF ;Start re-ordering the stack
DI
PUSH AX ;Save segment
SEG CS
PUSH [TEMP] ;Stack now ordered as if INT had been used
CMP CL,MAXCALL ;This entry point doesn't get as many calls
JA BADCALL
MOV AH,CL
SAVREGS:
SEG CS
MOV [SPSAVE],SP
SEG CS
MOV [SSSAVE],SS
INC SP
INC SP
SEG CS
POP [TEMP]
MOV SP,CS
MOV SS,SP
MOV SP,STACK
PUSH ES
PUSH DS
PUSH BP
PUSH DI
PUSH SI
PUSH DX
PUSH CX
PUSH BX
PUSH AX
MOV BL,AH
MOV BH,0
SHL BX
UP
SEG CS
CALL [BX+DISPATCH]
SEG CS
MOV [AXSAVE],AL
POP AX
POP BX
POP CX
POP DX
POP SI
POP DI
POP BP
POP DS
POP ES
POP SS
SEG CS
MOV SP,[SPSAVE]
IRET
DISPATCH:
; Standard Functions
DW ABORT ;0
DW CONIN
DW CONOUT
DW READER
DW PUNCH
DW LIST ;5
DW RAWIO
DW GETIO
DW SETIO
DW PRTBUF
DW BUFIN ;10
DW CONSTAT
DW VERSION
DW DSKRESET
DW SELDSK
DW OPEN ;15
DW CLOSE
DW SRCHFRST
DW SRCHNXT
DW DELETE
DW SEQRD ;20
DW SEQWRT
DW CREATE
DW RENAME
DW INUSE
DW CURDRV ;25
DW SETDMA
DW GETFATPT
DW WRTPROT
DW GETRDONLY
DW SETATTRIB ;30
DW GETDSKPT
DW USERCODE
DW RNDRD
DW RNDWRT
DW FILESIZE ;35
DW SETRNDREC
; Extended Functions
DW SETVECT
DW NEWBASE
DW BLKRD
DW BLKWRT ;40
VERSION:
GETIO:
SETIO:
WRTPROT:
GETRDONLY:
SETATTRIB:
USERCODE:
MOV AL,0
RET
READER:
CALL BIOSAUXIN,BIOSSEG
RET
PUNCH:
MOV AL,DL
CALL BIOSAUXOUT,BIOSSEG
RET
UNPACK:
; Inputs:
; DS = CS
; BX = Cluster number
; BP = Base of drive parameters
; SI = Pointer to drive FAT
; Outputs:
; DI = Contents of FAT for given cluster
; Zero set means DI=0 (free cluster)
; No other registers affected. Fatal error if cluster too big.
CMP BX,[BP+MAXCLUS]
JA HURTFAT
LEA DI,[SI+BX]
SHR BX
MOV DI,[DI+BX]
JNC HAVCLUS
SHR DI
SHR DI
SHR DI
SHR DI
STC
HAVCLUS:
RCL BX
AND DI,0FFFH
RET
HURTFAT:
MOV SI,BADMES
CALL OUTMES
JMP ERROR
PACK:
; Inputs:
; DS = CS
; BX = Cluster number
; DX = Data
; SI = Pointer to drive FAT
; Outputs:
; The data is stored in the FAT at the given cluster.
; BX,DX,DI all destroyed
; No other registers affected
MOV DI,BX
SHR BX
ADD BX,SI
ADD BX,DI
SHR DI
MOV DI,[BX]
JNC ALIGNED
SHL DX
SHL DX
SHL DX
SHL DX
AND DI,0FH
JP PACKIN
ALIGNED:
AND DI,0F000H
PACKIN:
OR DI,DX
MOV [BX],DI
RET
GETFILE:
; Inputs:
; DS,DX point to FCB
; Function:
; Find file name in disk directory. First byte is
; drive number (0=current disk). "?" matches any
; character.
; Outputs:
; Carry set if file not found
; ELSE
; BP = Base of drive parameters
; DS = CS
; ES = CS
; AL = Directory record number
; BX = Pointer into directory buffer
; SI = Pointer to First Cluster field in directory entry
; [DIRBUF] has directory record with match
; [NAME1] has file name
; All other registers destroyed.
CALL MOVNAME
JC RET ;Bad file name?
FINDNAME:
MOV AX,CS
MOV DS,AX
MOV AL,0
RDIRREC:
PUSH AX
CALL DIRREAD
POP AX
MOV BX,DIRBUF-16
CONTSRCH:
CALL NEXTENT
JZ RET
NDIRREC:
INC AL ;Next directory record
CMP AL,[BP+DIRSIZ]
JB RDIRREC
STC
RET
NEXTENT:
ADD BX,16
CMP BX,DIRBUF+127
JA RET
CMP B,[BX],0E5H
JZ NEXTENT
MOV SI,BX
MOV DI,NAME1
MOV CX,11
WILDCRD:
REPE
CMPB
JZ RET
CMP B,[DI-1],"?"
JZ WILDCRD
JP NEXTENT
DELETE: ; System call 19
CALL GETFILE
JC ERRET
PUSH AX
PUSH BX
CALL FATREAD
POP BX
DELFILE:
MOV B,[BX],0E5H
PUSH BX
MOV BX,[BX+11]
MOV SI,[BP+FAT]
OR BX,BX
JZ DELNXT
CMP BX,[BP+MAXCLUS]
JA DELNXT
CALL RELEASE
DELNXT:
POP BX
CALL NEXTENT
JZ DELFILE
POP AX
PUSH AX
CALL DIRWRITE
POP AX
CALL NDIRREC
PUSH AX
JNC DELFILE
POP AX
CALL FATWRT
XOR AL,AL
RET
RENAME: ;System call 23
CALL MOVNAME
JC ERRET
ADD SI,5
MOV DI,NAME2
CALL LODNAME
CALL FINDNAME
JC ERRET
SAVDREC:
MOV AH,AL
RENFIL:
MOV DI,BX
MOV SI,NAME2
MOV CX,11
NEWNAM:
LODB
CMP AL,"?"
JZ NOCHG
MOV [DI],AL
NOCHG:
INC DI
LOOP NEWNAM
CALL NEXTENT
JZ RENFIL
MOV AL,AH
PUSH AX
CALL DIRWRITE
POP AX
CALL NDIRREC
JNC SAVDREC ;New record read, save current number
XOR AL,AL
RET
ERRET:
MOV AL,-1
RET
MOVNAME:
; Inputs:
; DS, DX point to FCB
; Outputs:
; ES = CS
; If file name OK:
; BP has base of driver parameters
; [NAME1] has name in upper case
; All registers except DX destroyed
; Carry set if bad file name or drive
MOV AX,CS
MOV ES,AX
MOV DI,NAME1
MOV SI,DX
LODB
SEG ES
CMP [NUMDRV],AL
JC RET
CBW
XCHG AX,BP
SHL BP
MOV BP,[BP+CURDRVPT]
LODNAME:
; This entry point copies a file name from DS,SI
; to ES,DI converting to upper case.
MOV CX,11
MOVCHK:
LODB
AND AL,7FH
CMP AL,60H
JLE CASEOK
AND AL,5FH
CASEOK:
CMP AL,20H
JC RET
STOB
LOOP MOVCHK
RET
OPEN: ;System call 15
PUSH DX
PUSH DS
CALL GETFILE
DOOPEN:
; Enter here to perform OPEN on file already found
; in directory. DS=ES=CS, BX points to directory
; entry in DIRBUF, and the top of the stack has the
; address and segment of the FCB to be opened. This
; entry point is used by CREATE.
POP ES
POP DI
JC ERRET
MOV AH,[BP+DRVNUM]
INC AH
SEG ES
MOV [DI],AH
SEG ES
MOV [DI+EXTENT],0 ;Set extent field to 0
ADD DI,16 ;Point to entry pos. field
MOV CX,BX
SUB CX,DIRBUF
MOV AH,CL
STOW ;directory location
MOV AX,BP
STOW ;pointer to driver parameters
LEA SI,[BX+11]
LODW ;Get starting cluster
STOW ; first cluster
STOW ; last cluster accessed
LODB
SHL AL
LODW
RCL AX
STOW ; size of file in records
XOR AX,AX
STOW ; position of last cluster
STOW ; file not dirty
FATREAD:
TEST B,[BP+DIRTYFAT],-1
JNZ RET
CALL FIGFAT
NEXTFAT:
PUSH DX
PUSH CX
PUSH BX
PUSH AX
CALL DREAD
OR AL,AL
POP AX
POP BX
POP CX
POP DX
JNZ BADFAT
SUB AL,[BP+FATCNT]
JZ RET
NEG AL
;{Insert error code here. AL=number of bad fats.
;Since one good FAT was read, should include option
;to rewrite all FATs.}
JP FATWRT
BADFAT:
ADD DX,CX
DEC AL
JNZ NEXTFAT
POP BP
;{Insert error code here. All FATs on drive are bad.}
MOV SI,BADFATMES
CALL HARDERR
JP FATREAD
CLOSE: ;System call 16
MOV DI,DX
TEST B,[DI+DIRTYFIL],-1
JZ NOFLSH
PUSH DI
MOV BP,[DI+DRVBP]
MOV AL,[BP+DRVNUM]
CALL BIOSFLUSH,BIOSSEG
POP DI
NOFLSH:
TEST B,[DI+SIZCHG],-1
JZ OKRET
MOV DX,DI
PUSH DX
PUSH DS
CALL GETFILE
POP ES
POP DI
JC BADCLOSE
MOV CX,BX
SUB CX,DIRBUF
MOV AH,CL
SEG ES
CMP AX,[DI+ENTPOS]
JNZ BADCLOSE
SEG ES
MOV CX,[DI+FIRCLUS]
MOV [BX+11],CX
SEG ES
MOV DX,[DI+FILSIZ]
SHR DX
MOV [BX+14],DX
MOV DL,0
RCR DL
MOV [BX+13],DL
CALL DIRWRITE
CHKFATWRT:
; Do FATWRT only if FAT is dirty
TEST B,[BP+DIRTYFAT],-1
JZ OKRET
FATWRT:
; Inputs:
; DS = CS
; BP = Base of drive parameter table
; Function:
; Write the FAT back to disk and reset FAT
; dirty bit.
; Outputs:
; AL = 0
; BP unchanged
; All other registers destroyed
MOV B,[BP+DIRTYFAT],0
CALL FIGFAT
EACHFAT:
PUSH DX
PUSH CX
PUSH BX
PUSH AX
CALL DWRITE
POP AX
POP BX
POP CX
POP DX
ADD DX,CX
DEC AL
JNZ EACHFAT
OKRET:
MOV AL,0
RET
BADCLOSE:
MOV B,[BP+DIRTYFAT],0
MOV AL,-1
RET
FIGFAT:
; Loads registers with values needed to read or
; write a FAT.
MOV AL,[BP+FATCNT]
MOV BX,[BP+FAT]
MOV CL,[BP+FATSIZ] ;No. of records occupied by FAT
MOV CH,0
MOV DX,[BP+FIRFAT] ;Record number of start of FATs
RET
DIRCOMP:
; Prepare registers for directory read or write
CBW
ADD AX,[BP+FIRDIR]
MOV DX,AX
MOV BX,DIRBUF
MOV CX,1
RET
CREATE: ;System call 22
CALL MOVNAME
JC ERRET3
MOV DI,NAME1
MOV CX,11
MOV AL,"?"
REPNE
SCAB
JZ ERRET3
PUSH DX
PUSH DS
MOV AX,CS
MOV DS,AX
XOR AX,AX
RDIRREC2:
PUSH AX
CALL DIRREAD
POP AX
MOV DI,DIRBUF-16
MOV CX,8
FNDFRE:
ADD DI,16
CMP B,[DI],0E5H
LOOPNE FNDFRE
JZ FREESPOT
INC AL
CMP AL,[BP+DIRSIZ]
JC RDIRREC2
POP DS
POP DX
ERRET3:
MOV AL,-1
RET
FREESPOT:
MOV BX,DI
MOV SI,NAME1
MOV CX,5
MOVB
REP
MOVW
XCHG AL,AH
MOV CL,5
REP
STOB
XCHG AL,AH
PUSH AX
PUSH BX
CALL DIRWRITE
POP BX
POP AX
JMP DOOPEN
DIRREAD:
; Inputs:
; DS = CS
; AL = Directory block number
; BP = Base of drive parameters
; Function:
; Read the directory block into DIRBUF.
; Outputs:
; BP unchanged
; All other registers destroyed.
CALL DIRCOMP
DREAD:
; Inputs:
; BX,DS = Transfer address
; CX = Number of records
; DX = Absolute record number
; BP = Base of drive parameters
; Function:
; Calls BIOS to perform disk read. If BIOS reports
; errors, will call HARDERR for further action.
; Outputs:
; AL = 0 if no error, otherwise non-zero
; BP preserved. All other registers destroyed.
MOV AL,[BP+DRVNUM]
PUSH BP
PUSH BX
PUSH CX
PUSH DX
CALL BIOSREAD,BIOSSEG
POP DX
POP DI
POP BX
POP BP
JC HARDREAD
XOR AL,AL
RET
HARDREAD:
MOV SI,RDERRMES
CALL HARDERR
JP DREAD
DIRWRITE:
; Inputs:
; DS = CS
; AL = Directory block number
; BP = Base of drive parameters
; Function:
; Write the directory block into DIRBUF.
; Outputs:
; BP unchanged
; All other registers destroyed.
CALL DIRCOMP
DWRITE:
; Inputs:
; BX,DS = Transfer address
; CX = Number of records
; DX = Absolute record number
; BP = Base of drive parameters
; Function:
; Calls BIOS to perform disk write. If BIOS reports
; errors, will call HARDERR for further action.
; Outputs:
; AL = 0 if no error, otherwise non-zero
; BP preserved. All other registers destroyed.
MOV AL,[BP+DRVNUM]
MOV AH,0
CMP DX,[BP+FIRREC]
RCR AH
PUSH BP
PUSH BX
PUSH CX
PUSH DX
CALL BIOSWRITE,BIOSSEG
POP DX
POP DI
POP BX
POP BP
JC HARDWRITE
XOR AL,AL
RET
HARDWRITE:
MOV SI,WRTERRMES
CALL HARDERR
JP DWRITE
HARDERR:
SUB DI,CX
ADD DX,DI
CALL SHFTDI7
ADD BX,DI
CALL OUTMES
GETINSTR:
CALL IN
OR AL,20H
CMP AL,"a"
JZ ERROR
CMP AL,"r"
JZ RET
CMP AL,"i"
JZ IGNORE
CMP AL,"c"
JNZ GETINSTR
POP AX
MOV AL,1
RET
IGNORE:
POP AX
MOV AL,0
RET
ABORT:
SEG CS
MOV DS,[CSLOC]
XOR AX,AX
MOV ES,AX
MOV SI,SAVEXIT
MOV DI,EXIT
MOVW
MOVW
MOVW
MOVW
ERROR:
MOV SP,BPSAVE
MOV AX,CS
MOV DS,AX
MOV ES,AX
CALL WRTFATS
XOR AX,AX
MOV DS,AX
MOV SI,EXIT
MOV DI,EXITHOLD
MOVW
MOVW
POP BP
POP ES
POP ES
POP DS
POP SS
MOV SP,[SPSAVE]
MOV DS,[DSSAVE]
SEG CS
JMP L,[EXITHOLD]
SEQRD: ;System call 20
CALL GETREC
MOV CX,1
CALL LOAD
JCXZ SETNREX
INC AX
JP SETNREX
SEQWRT: ;System call 21
CALL GETREC
MOV CX,1
CALL STORE
JCXZ SETNREX
INC AX
JP SETNREX
RNDRD: ;System call 33
MOV CX,1
MOV DI,DX
MOV AX,[DI+RR]
CALL LOAD
JP FINRND
RNDWRT: ;System call 34
MOV CX,1
MOV DI,DX
MOV AX,[DI+RR]
CALL STORE
JP FINRND
BLKRD: ;System call 39
MOV DI,DX
MOV AX,[DI+RR]
CALL LOAD
JP FINBLK
BLKWRT: ;System call 40
MOV DI,DX
MOV AX,[DI+RR]
CALL STORE
FINBLK:
MOV [CXSAVE],CX
JCXZ FINRND
INC AX
FINRND:
SEG ES
MOV [DI+RR],AX
SETNREX:
MOV CX,AX
AND AL,7FH
SEG ES
MOV [DI+NR],AL
AND CL,80H
ROL CX
XCHG CL,CH
SEG ES
MOV [DI+EXTENT],CX
MOV AL,[DSKERR]
RET
SETUP:
; Inputs:
; DS:DI point to FCB
; AX = Record position in file of disk transfer
; CX = Record count
; Outputs:
; DS = CS
; ES:DI point to FCB
; CX = No. of records to transfer
; BP = Base of drive parameters
; SI = FAT pointer
; [RECCNT] = Record count
; [RECPOS] = Record position in file
; [FCB] = DX
; [NEXTADD] = Displacement of disk transfer within segment
; [DSKERR] = 0 (no errors yet)
; [TRANS] = 0 (No transfers yet)
; If SETUP detects no records will be transfered, it returns 1 level up
; with CX = 0.
MOV BP,[DI+DRVBP]
MOV BX,DS
MOV ES,BX
MOV BX,CS
MOV DS,BX
MOV [RECPOS],AX
MOV [FCB],DX
MOV BX,[DMAADD]
MOV [NEXTADD],BX
MOV B,[DSKERR],0
MOV [TRANS],0
MOV SI,[BP+FAT]
ADD BX,7FH ;See if there is any space left
JC SEGEND
AND BL,80H
NEG BX ;These instructions divide by 128
ROL BX
XCHG BL,BH
JNZ CHKMAX
MOV BH,2 ;All 512 records OK
CHKMAX:
CMP CX,BX
JBE SAVCNT
MOV CX,BX
MOV B,[DSKERR],2 ;Flag that trimming took place
SAVCNT:
MOV [RECCNT],CX
RET
SEGEND:
MOV B,[DSKERR],2
MOV CX,0
POP BX
RET
FNDCLUS:
; Inputs:
; DS = CS
; CX = No. of clusters to skip
; BP = Base of drive parameters
; SI = FAT pointer
; ES:DI point to FCB
; Outputs:
; BX = Last cluster skipped to
; CX = No. of clusters remaining (0 unless EOF)
; DX = Position of last cluster
; DI destroyed. No other registers affected.
SEG ES
MOV BX,[DI+LSTCLUS]
SEG ES
MOV DX,[DI+CLUSPOS]
OR BX,BX
JZ NOCLUS
SUB CX,DX
JNB FINDIT
ADD CX,DX
XOR DX,DX
SEG ES
MOV BX,[DI+FIRCLUS]
FINDIT:
JCXZ RET
SKPCLP:
CALL UNPACK
CMP DI,0FFFH
JZ RET
XCHG BX,DI
INC DX
LOOP SKPCLP
RET
NOCLUS:
INC CX
DEC DX
RET
LOAD:
; Inputs:
; DS:DI point to FCB
; AX = Position in file to read
; CX = No. of records to read
; Outputs:
; AX = Position of last record read
; CX = No. of records read
; ES:DI point to FCB
; LSTCLUS, CLUSPOS fields in FCB set
CALL SETUP
SEG ES
MOV BX,[DI+FILSIZ]
SUB BX,AX
JBE WRTERRJ
CMP BX,CX
JNB ENUF
MOV B,[DSKERR],1
MOV [RECCNT],BX
ENUF:
MOV CL,[BP+CLUSSHFT]
SHR AX,CL
MOV CX,AX
CALL FNDCLUS
OR CX,CX
JNZ WRTERR
MOV DL,[RECPOS]
AND DL,[BP+CLUSMSK]
MOV CX,[RECCNT]
RDLP:
CALL OPTIMIZE
PUSH DI
PUSH AX
PUSH DS
MOV DS,[DMAADD+2]
CALL DREAD
POP DS
POP CX
POP BX
JCXZ SETFCB
MOV DL,0
CMP BX,0FFFH
JNZ RDLP
MOV B,[DSKERR],1
SETFCB:
MOV AX,[CLUSNUM]
MOV DI,[FCB]
SEG ES
MOV [DI+LSTCLUS],AX
MOV AX,[RECPOS]
MOV BX,[TRANS]
ADD AX,BX
SEG ES
CMP AX,[DI+FILSIZ]
JBE SAMSIZ
SEG ES
MOV [DI+FILSIZ],AX
SEG ES
MOV B,[DI+SIZCHG],-1
SAMSIZ:
DEC AX
MOV DX,AX
MOV CL,[BP+CLUSSHFT]
SHR DX,CL
SEG ES
MOV [DI+CLUSPOS],DX
MOV CX,BX
RET
WRTERRJ:JP WRTERR
HAVSTART:
MOV CX,AX
PUSH BX
CALL FNDCLUS
JCXZ WRCLUS
CALL ALLOCATE
POP BX
JNC NOSKIP
WRTERR:
MOV B,[DSKERR],1
LVDSK:
MOV AX,[RECPOS]
XOR CX,CX
MOV DI,[FCB]
RET
WRTEOF:
MOV CL,[BP+CLUSSHFT]
SHR AX,CL
MOV CX,AX
CALL FNDCLUS
OR CX,CX
JNZ LVDSK
MOV DX,0FFFH
MOV B,[BP+DIRTYFAT],-1
MOV DI,[FCB]
MOV AX,[RECPOS]
SEG ES
MOV [DI+FILSIZ],AX
SEG ES
MOV B,[DI+SIZCHG],-1
XOR CX,CX
RET
STORE:
; Inputs:
; DS:DI point to FCB
; AX = Position in file of disk transfer
; CX = Record count
; Outputs:
; AX = Position of last record written
; CX = No. of records written
; ES:DI point to FCB
; LSTCLUS, CLUSPOS fields in FCB set
CALL SETUP
JCXZ WRTEOF
MOV BX,CX
ADD BX,AX
DEC BX
MOV CL,[BP+CLUSSHFT]
SHR AX,CL
SHR BX,CL
MOV CX,AX
MOV AX,BX
CALL FNDCLUS
SUB AX,DX ;Last cluster minus current cluster
JCXZ HAVSTART ;See if no more data
PUSH CX ;No. of clusters of first
MOV CX,AX
CALL ALLOCATE
POP CX
JC WRTERR
DEC CX
JZ NOSKIP
CALL SKPCLP
PUSH BX
WRCLUS:
POP BX
NOSKIP:
MOV DL,[RECPOS]
AND DL,[BP+CLUSMSK]
MOV CX,[RECCNT]
WRTLP:
CALL OPTIMIZE
PUSH DI
PUSH AX
PUSH DS
MOV DS,[DMAADD+2]
CALL DWRITE
POP DS
POP CX
POP BX
MOV DL,0
OR CX,CX
JNZ WRTLP
CALL SETFCB
SEG ES
MOV B,[DI+DIRTYFIL],-1
RET
OPTIMIZE:
; Inputs:
; DS = CS
; BX = Physical cluster
; CX = No. of records
; DL = record within cluster
; BP = Base of drives parameters
; [NEXTADD] = transfer address
; Outputs:
; AX = No. of records remaining
; BX = Transfer address
; CX = No. or records to be transferred
; DX = Physical record address
; DI = Next cluster
; [CLUSNUM] = Last cluster accessed
; [NEXTADD] updated
; BP unchanged. Note that segment of transfer not set.
PUSH DX
PUSH BX
MOV AL,[BP+CLUSMSK]
INC AL ;Number of records per cluster
MOV AH,AL
SUB AL,DL ;AL = Number of records left in first cluster
MOV DX,CX
MOV SI,[BP+FAT]
MOV CX,0
OPTCLUS:
;AL has number of records available in current cluster
;AH has number of records available in next cluster
;BX has current physical cluster
;CX has number of sequential records found so far
;DX has number of records left to transfer
;SI has FAT pointer
CALL UNPACK
ADD CL,AL
ADC CH,0
CMP CX,DX
JAE BLKDON
MOV AL,AH
INC BX
CMP DI,BX
JZ OPTCLUS
DEC BX
FINCLUS:
MOV [CLUSNUM],BX ;Last cluster accessed
SUB DX,CX ;Number of records still needed
MOV AX,DX
MOV BX,CX
XCHG BL,BH
ROR BX
MOV SI,[NEXTADD]
ADD BX,SI ;Adjust by size of transfer
MOV [NEXTADD],BX
ADD [TRANS],CX
POP DX
POP BX
PUSH CX
MOV CL,[BP+CLUSSHFT]
DEC DX
DEC DX
SHL DX,CL
OR DL,BL
ADD DX,[BP+FIRREC]
POP CX
MOV BX,SI
RET
BLKDON:
MOV CX,DX ;Make the total equal to the request
JP FINCLUS
GETREC:
; Inputs:
; DS:DX point to FCB
; Outputs:
; AX = Record number determined by EXTENT and NR fields
; DS:DI point to FCB
; BX destroyed. No other registers affected.
MOV DI,DX
MOV AL,[DI+NR]
MOV BX,[DI+EXTENT]
SHL AL
SHR BX
RCR AL
MOV AH,BL
RET
ALLOCATE:
; Inputs:
; DS = CS
; ES = Segment of FCB
; BX = Last cluster of file (0 if null file)
; CX = No. of clusters to allocate
; DX = Position of cluster BX
; BP = Base of drive parameters
; SI = FAT pointer
; [FCB] = Displacement of FCB within segment
; Outputs:
; IF insufficient space
; THEN
; Carry set
; ELSE
; Carry clear
; BX = First cluster allocated
; FAT is fully updated including dirty bit
; FIRCLUS field of FCB set if file was null
; SI,BP unchanged. All other registers destroyed.
PUSH BX
MOV AX,BX
ALLOC:
MOV DX,BX
FINDFRE:
INC BX
CMP BX,[BP+MAXCLUS]
JL TRYOUT
CMP AX,1
JG TRYIN
POP BX
MOV DX,0FFFH
CALL RELBLKS
OR [SI],0FFFH
STC
RET
TRYOUT:
CALL UNPACK
JZ HAVFRE
TRYIN:
DEC AX
JLE FINDFRE
XCHG AX,BX
CALL UNPACK
JZ HAVFRE
XCHG AX,BX
JP FINDFRE
HAVFRE:
XCHG BX,DX
MOV AX,DX
CALL PACK
MOV BX,AX
LOOP ALLOC
MOV DX,0FFFH
CALL PACK
MOV B,[BP+DIRTYFAT],-1
POP BX
CALL UNPACK
XCHG BX,DI
OR DI,DI
JNZ RET
MOV DI,[FCB]
SEG ES
MOV [DI+FIRCLUS],BX
OR [SI],0FFFH
RET
RELEASE:
; Inputs:
; DS = CS
; BX = Cluster in file
; SI = FAT pointer
; BP = Base of drive parameters
; Function:
; Frees cluster chain starting with [BX]
; AX,BX,DX,DI all destroyed. Other registers unchanged.
XOR DX,DX
RELBLKS:
; Enter here with DX=0FFFH to put an end-of-file mark
; in the first cluster and free the rest in the chain.
CALL UNPACK
JZ RET
MOV AX,DI
CALL PACK
CMP AX,0FFFH
MOV BX,AX
JNZ RELEASE
RET
GETEOF:
; Inputs:
; BX = Cluster in a file
; SI = Base of drive FAT
; DS = CS
; Outputs:
; BX = Last cluster in the file
; DI destroyed. No other registers affected.
CALL UNPACK
CMP DI,0FFFH
JZ RET
MOV BX,DI
JP GETEOF
SRCHFRST: ;System call 17
CALL GETFILE
SAVPLCE:
; Search-for-next enters here to save place and report
; findings.
JC KILLSRCH
MOV [SRCHDON],AL
MOV [PDIR],BX
MOV [SRCHBP],BP
;Information in directory entry must be copied into the first
; 16 bytes starting at the disk transfer address.
MOV SI,BX
LES DI,[DMAADD]
MOV CX,8
REP
MOVW
MOV AL,0
RET
KILLSRCH:
MOV AL,-1
MOV [SRCHDON],AL
RET
SRCHNXT: ;System call 18
MOV AX,CS
MOV ES,AX
MOV DS,AX
MOV AL,[SRCHDON]
CMP AL,-1
JZ RET
MOV BX,[PDIR]
MOV BP,[SRCHBP]
CALL CONTSRCH
JP SAVPLCE
FILESIZE: ;System call 35
PUSH DI
PUSH DX
CALL GETFILE
POP DI
POP ES
MOV AL,-1
JC RET
ADD DI,33 ;Write size in RR field
LEA SI,[BX+13]
LODB
SHL AL
LODW
RCL AX ;Round to nearest record
STOW
MOV AL,0
RCL AL
STOB
RET
SETDMA: ;System call 26
SEG CS
MOV [DMAADD],DX
SEG CS
MOV [DMAADD+2],DS
RET
GETFATPT: ;System call 27
MOV AX,CS
MOV DS,AX
MOV [DSSAVE],CS
MOV BP,[CURDRVPT]
CALL FATREAD
MOV BX,[BP+FAT]
MOV AL,[BP+CLUSMSK]
INC AL
MOV DX,[BP+MAXCLUS]
DEC DX
MOV B,[BP+DIRTYFAT],-1
MOV [BXSAVE],BX
MOV [DXSAVE],DX
RET
GETDSKPT: ;System call 31
SEG CS
MOV [DSSAVE],CS
SEG CS
MOV BX,[CURDRVPT]
SEG CS
MOV [BXSAVE],BX
RET
DSKRESET: ;System call 13
SEG CS
MOV [DMAADD+2],DS
MOV AX,CS
MOV DS,AX
MOV [DMAADD],80H
MOV AX,[CURDRVPT+2]
MOV [CURDRVPT],AX
WRTFATS:
; DS=CS. Writes back all dirty FATs. All registers destroyed.
MOV CL,[NUMDRV]
MOV CH,0
MOV SI,CURDRVPT+2
WRTFAT:
LODW
PUSH CX
PUSH SI
MOV BP,AX
CALL CHKFATWRT
POP SI
POP CX
LOOP WRTFAT
MOV AL,-1
CALL BIOSFLUSH,BIOSSEG
RET
CURDRV: ;System call 25
SEG CS
MOV BP,[CURDRVPT]
MOV AL,[BP+DRVNUM]
RET
INUSE: ;System call 24
MOV AX,CS
MOV DS,AX
MOV CL,[NUMDRV]
MOV CH,0
MOV SI,CX
SHL SI
ADD SI,CURDRVPT
MOV BX,0
DOWN
CHKUSE:
LODW
MOV BP,AX
TEST B,[BP+DIRTYFAT],-1
JZ SETBIT
STC
SETBIT:
RCL BX
LOOP CHKUSE
MOV AL,BL
RET
SETRNDREC: ;System call 36
CALL GETREC
MOV [DI+33],AX
MOV AL,0
JZ BIGRR
INC AL
BIGRR:
MOV [DI+35],AL
RET
SELDSK: ;System call 14
MOV DH,0
MOV BX,DX
PUSH CS
POP DS
CMP BL,[NUMDRV]
JGE RET
SHL BX
MOV AX,[BX+CURDRVPT+2]
MOV [CURDRVPT],AX
RET
BUFIN: ;System call 10
MOV AX,CS
MOV ES,AX
MOV SI,DX
MOV CH,0
LODW
OR AL,AL
JZ RET
MOV BL,AH
MOV BH,CH
CMP AL,BL
JBE NOEDIT
CMP B,[BX+SI],0DH
JZ EDITON
NOEDIT:
MOV BL,CH
EDITON:
MOV DL,AL
DEC DX
NEWLIN:
SEG CS
MOV AL,[CARPOS]
SEG CS
MOV [STARTPOS],AL
PUSH SI
MOV DI,INBUF
MOV AH,CH
MOV BH,CH
MOV DH,CH
GETCH:
CALL IN
CMP AL,7FH
JZ BACKSP
CMP AL,8
JZ BACKSP
CMP AL,13
JZ ENDLIN
CMP AL,10
JZ PHYCRLF
CMP AL,"X"-"@"
JZ KILNEW
CMP AL,ESCCH
JZ ESC
SAVCH:
CMP DH,DL
JAE GETCH
STOB
INC DH
CALL OUT
OR AH,AH
JNZ GETCH
CMP BH,BL
JAE GETCH
INC SI
INC BH
JP GETCH
ESC:
CALL IN
MOV CL,ESCTABLEN
PUSH DI
MOV DI,ESCTAB
REPNE
SCAB
POP DI
AND CL,0FEH
MOV BP,CX
JMP [BP+ESCFUNC]
ENDLIN:
STOB
CALL OUT
POP DI
MOV [DI-1],DH
INC DH
COPYNEW:
MOV BP,ES
MOV BX,DS
MOV ES,BX
MOV DS,BP
MOV SI,INBUF
MOV CL,DH
REP
MOVB
RET
CRLF:
MOV AL,13
CALL OUT
MOV AL,10
JMP OUT
PHYCRLF:
CALL CRLF
JP GETCH
KILNEW:
MOV AL,"\"
CALL OUT
POP SI
PUTNEW:
CALL CRLF
JMP NEWLIN
BACKSP:
OR DH,DH
JZ OLDBAK
CALL BACKUP
SEG ES
MOV AL,[DI]
CMP AL," "
JAE OLDBAK
CMP AL,9
JZ BAKTAB
CALL BACKMES
OLDBAK:
OR AH,AH
JNZ GETCH1
OR BH,BH
JZ GETCH1
DEC BH
DEC SI
GETCH1:
JMP GETCH
BAKTAB:
PUSH DI
DEC DI
DOWN
MOV CL,DH
MOV AL," "
PUSH BX
MOV BL,7
JCXZ FIGTAB
FNDPOS:
SCAB
JNA CHKCNT
SEG ES
CMP B,[DI+1],9
JZ HAVTAB
DEC BL
CHKCNT:
LOOP FNDPOS
FIGTAB:
SEG CS
SUB BL,[STARTPOS]
HAVTAB:
SUB BL,DH
ADD CL,BL
AND CL,7
UP
POP BX
POP DI
JZ OLDBAK
TABBAK:
CALL BACKMES
LOOP TABBAK
JP OLDBAK
BACKUP:
DEC DH
DEC DI
BACKMES:
MOV AL,8
CALL OUT
MOV AL," "
CALL OUTCH
MOV AL,8
JMP OUTCH
TWOESC:
MOV AL,ESCCH
JMP SAVCH
COPYLIN:
MOV CL,BL
SUB CL,BH
JP COPYEACH
COPYSTR:
CALL FINDOLD
JP COPYEACH
COPYONE:
MOV CL,1
COPYEACH:
CMP DH,DL
JZ GETCH2
CMP BH,BL
JZ GETCH2
LODB
STOB
CALL OUT
INC BH
INC DH
LOOP COPYEACH
GETCH2:
JMP GETCH
SKIPONE:
CMP BH,BL
JZ GETCH2
INC BH
INC SI
JMP GETCH
SKIPSTR:
CALL FINDOLD
ADD SI,CX
ADD BH,CL
JMP GETCH
FINDOLD:
CALL IN
MOV CL,BL
SUB CL,BH
JZ NOTFND
DEC CX
JZ NOTFND
PUSH ES
PUSH DS
POP ES
PUSH DI
MOV DI,SI
INC DI
REPNE
SCAB
POP DI
POP ES
JNZ NOTFND
NOT CL
ADD CL,BL
SUB CL,BH
RET
NOTFND:
POP BP
JMP GETCH
REEDIT:
MOV AL,"@"
CALL OUT
POP DI
PUSH DI
PUSH ES
PUSH DS
CALL COPYNEW
POP DS
POP ES
POP SI
MOV BL,DH
JMP PUTNEW
ENTERINS:
MOV AH,-1
JMP GETCH
EXITINS:
MOV AH,0
JMP GETCH
ESCFUNC:
DW GETCH
DW TWOESC
DW EXITINS
DW ENTERINS
DW BACKSP
DW REEDIT
DW KILNEW
DW COPYLIN
DW SKIPSTR
DW COPYSTR
DW SKIPONE
DW COPYONE
CONOUT: ;System call 2
MOV AL,DL
OUT:
CMP AL,20H
JB CTRLOUT
CMP AL,7FH
JZ OUTCH
SEG CS
INC B,[CARPOS]
OUTCH:
CALL BIOSOUT,BIOSSEG
SEG CS
TEST B,[PFLAG],-1
JZ STATCHK
CALL BIOSPRINT,BIOSSEG
STATCHK:
CALL BIOSSTAT,BIOSSEG
JZ RET
INCHK:
CALL BIOSIN,BIOSSEG
CMP AL,'S'-'@'
JNZ NOSTOP
CALL BIOSIN,BIOSSEG
NOSTOP:
CMP AL,'P'-'@'
JZ PRINTON
CMP AL,'N'-'@'
JZ PRINTOFF
CMP AL,'C'-'@'
JNZ RET
INT CONTC ;Execute user Ctrl-C handler
RET
PRINTON:
SEG CS
MOV B,[PFLAG],1
RET
PRINTOFF:
SEG CS
MOV B,[PFLAG],0
RET
CTRLOUT:
CMP AL,10
JZ OUTCH
CMP AL,13
JZ ZERPOS
CMP AL,8
JZ BACKPOS
CMP AL,9
JZ TAB
PUSH AX
MOV AL,"^"
CALL OUT
POP AX
OR AL,40H
JP OUT
ZERPOS:
SEG CS
MOV B,[CARPOS],0
JP OUTCH
BACKPOS:
SEG CS
DEC B,[CARPOS]
JP OUTCH
TAB:
MOV AL,0
SEG CS
XCHG AL,[CARPOS]
OR AL,0F8H
NEG AL
PUSH CX
MOV CL,AL
MOV CH,0
TABLP:
MOV AL," "
CALL OUTCH
LOOP TABLP
POP CX
RET
CONSTAT: ;System call 11
CALL BIOSSTAT,BIOSSEG
JZ RET
OR AL,-1
RET
CONIN: ;System call 1
CALL INCHK
PUSH AX
CALL OUT
POP AX
RET
IN: ;Internal input routine
CALL INCHK
JZ IN
RET
RAWIO: ;System call 6
MOV AL,DL
CMP AL,-1
JNZ RAWOUT
CALL BIOSSTAT,BIOSSEG
JZ RET
CALL BIOSIN,BIOSSEG
RET
RAWOUT:
CALL BIOSOUT,BIOSSEG
RET
LIST: ;System call 5
MOV AL,DL
CALL BIOSPRINT,BIOSSEG
RET
PRTBUF: ;System call 9
MOV SI,DX
OUTSTR:
LODB
CMP AL,"$"
JZ RET
CALL OUT
JP OUTSTR
OUTMES: ;String output for internal messages
SEG CS
LODB
CMP AL,"$"
JZ RET
CALL OUT
JP OUTMES
SETVECT: ; Interrupt call 37
XOR BX,BX
MOV ES,BX
MOV BL,AL
SHL BX
SHL BX
SEG ES
MOV [BX],DX
SEG ES
MOV [BX+2],DS
RET
NEWBASE: ; Interrupt call 38
MOV ES,DX
SEG CS
MOV DS,[CSLOC]
XOR SI,SI
MOV DI,SI
MOV CX,80H
REP
MOVW
SETMEM:
; Inputs:
; DX = Segment
; Function:
; Completely prepares a program base at the
; specified segment.
; Outputs:
; DS = DX
; ES = DX
; [0] has INT 20H
; [2] = First unavailable segment ([ENDMEM])
; [5] to [9] form a long call to the entry point
; [10] to [13] have exit address (from INT 22H)
; [14] to [17] have ctrl-C exit address (from INT 23H)
; AX,DX,BP unchanged. All other registers destroyed.
XOR CX,CX
MOV DS,CX
MOV ES,DX
MOV SI,EXIT
MOV DI,SAVEXIT
MOVW
MOVW
MOVW
MOVW
SEG CS
MOV CX,[ENDMEM]
SEG ES
MOV [2],CX
SUB CX,DX
CMP CX,MAXDIF
JBE HAVDIF
MOV CX,MAXDIF
HAVDIF:
MOV BX,ENTRYPOINTSEG
SUB BX,CX
SHL CX
SHL CX
SHL CX
SHL CX
MOV DS,DX
MOV [6],CX
MOV [8],BX
MOV [0],20CDH ;"INT INTTAB"
MOV B,[5],LONGCALL
RET
SHFTDI7:
SHL DI
SHL DI
SHL DI
SHL DI
SHL DI
SHL DI
SHL DI
RET
;***** DATA AREA *****
BADMES: DB 13,10,"Bad FAT",13,10,"$"
BADFATMES:DB 13,10,"All FATs on disk are bad",13,10,"$"
RDERRMES:DB 13,10,"Disk read error",13,10,"$"
WRTERRMES:DB 13,10,"Disk write error",13,10,"$"
CARPOS: DB 0
STARTPOS:DB 0
PFLAG: DB 0
SRCHDON:DB -1
PDIR: DS 2
SRCHBP: DS 2
EXITHOLD:DS 4
ENDMEM: DS 2
FATBASE:DS 2
INBUF: DS 255
DIRBUF: DS 128
NUMDRV: DS 1 ;Number of drives
NAME1: DS 11 ;File name buffer
NAME2: DS 11
DMAADD: DS 4 ;User's disk transfer address (disp/seg)
TEMP:
CSLOC: DS 2
DSKERR: DS 1
FCB: DS 2 ;Address of user FCB
RECPOS: DS 2
NEXTADD:DS 2
RECCNT: DS 2
CLUSNUM:DS 2
TRANS: DS 2
DS 50 ;Stack space
AXSAVE: DS 2
BXSAVE: DS 2
CXSAVE: DS 2
DXSAVE: DS 2
SISAVE: DS 2
DISAVE: DS 2
BPSAVE: DS 2
DSSAVE: DS 2
ESSAVE: DS 2
STACK:
SSSAVE: DS 2
SPSAVE: DS 2
CURDRVPT:DS 2
DRVTAB: ;Address of start of DPBs