Files
86-DOS-0.11/86DOS.ASM
T
Broken Pipe 4bdf7a2bd9 Added RDCPM and EDLIN, style fixes
Added the reconstructed source code of RDCPM.COM and EDLIN.COM, and changed the style of the other source files to match Tim Paterson's coding style.
2024-01-30 14:42:47 +00:00

2243 lines
33 KiB
NASM

; 86-DOS 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
ESCCH EQU 1BH
CANCEL EQU "X"-"@" ;Cancel with Ctrl-X
MAXCALL EQU 36
MAXCOM EQU 40
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
SAVEXIT EQU 10
; Field definition for FCBs
FNAME EQU 0 ;Drive code and name
EXTENT EQU 12
ENTPOS EQU 16 ;Position of entry in directory
DRVBP EQU 18 ;BP for SEARCH FIRST and SEARCH NEXT
FIRCLUS EQU 20 ;First cluster of file
LSTCLUS EQU 22 ;Last cluster accessed
FILSIZ EQU 24 ;Size of file in records
CLUSPOS EQU 26 ;Position of last cluster accessed
FLSFLG EQU 28 ;Flush flag
SIZCHG EQU 29 ;Size change flag
NR EQU 32 ;Next record
RR EQU 33 ;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.)
;
; The File Allocation Table uses a 12-bit entry for each allocation unit on
; the disk. These entries are packed, two for every three bytes. The contents
; of entry number N is found by 1) multiplying N by 1.5; 2) adding the result
; to the base address of the Allocation Table; 3) fetching the 16-bit word at
; this address; 4) If N was odd (so that N*1.5 was not an integer), shift the
; word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry number
; zero is used as an end-of-file trap in the OS. Entry 1 is reserved for
; future use. The first available allocation unit is assigned entry number
; two, and even though it is the first, is called cluster 2. Entries of 0FFFH
; are end of file marks; entries of zero are unallocated. Otherwise, the
; contents of a FAT entry is the number of the next cluster in the file.
; Field definition for Drive Parameter Block
DEVNUM EQU 0 ;I/O driver number
SECSIZ EQU 1 ;Size of physical sector in records
CLUSMSK EQU 2 ;Records/cluster - 1
CLUSSHFT EQU 3 ;Log2 of records/cluster
FIRFAT EQU 4 ;Starting record of FATs
FATSIZ EQU 6 ;Number of records occupied by FAT
FATCNT EQU 7 ;Number of FATs for this drive
FIRDIR EQU 8 ;Starting record of directory
DIRSIZ EQU 10 ;Number of records occupied by directory
FIRREC EQU 11 ;First record of first cluster
MAXCLUS EQU 13 ;Number of clusters on drive + 1
DIRTY EQU 15 ;Whether FAT is dirty
FAT EQU 16 ;Pointer to start of FAT
DPBSIZ EQU 18 ;Size of the structure in bytes
; BOIS entry point definitions
BIOSSEG EQU 40H
BIOSINIT EQU 0 ;Reserve room for jump to init code
BIOSSTAT EQU 3 ;Console input status check
BIOSIN EQU 6 ;Get console character
BIOSOUT EQU 9 ;Output console character
BIOSPRINT EQU 12 ;Output to printer
BIOSAUXIN EQU 15 ;Get byte from auxilliary
BIOSAUXOUT EQU 18 ;Output byte to auxilliary
BIOSREAD EQU 21 ;Disk read
BIOSWRITE EQU 24 ;Disk write
BIOSFLUSH EQU 27 ;Disk buffer flush
; Start of code
ORG 0
JMP DOSINIT
ESCTAB:
DB "SC" ;Copy one character from template
DB "VN" ;Skip over one character in template
DB "TA" ;Copy up to specified character
DB "WB" ;Skip up to specified character
DB "UH" ;Copy rest of template
DB "HH" ;Kill line with no change in template (Ctrl-X)
DB "RM" ;Cancel line and update template
DB "DD" ;Backspace (same as Ctrl-H)
DB "P@" ;Enter Insert mode
DB "QL" ;Exit Insert mode
DB 1BH,1BH ;Escape sequence to represent escape character
DB ESCCH,ESCCH
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:
CLI
CLD
MOV AX,CS
MOV ES,AX
LODB ;Get no. of drives & no. of I/O drivers
CBW
MOV CX,AX
SEG CS
MOV [NUMIO],AL
MOV DI,AX
SHL DI
MOV AH,DPBSIZ ;Size of DPB
MUL AX,AH
MOV BX,DRVTAB
ADD DI,BX ;Point to first DPB
ADD AX,DI
MOV BP,AX ;Point to first FAT
SEG CS
MOV [FATBASE],AX
PERDEV:
SEG CS
MOV [BX],DI ;Store DPB pointer to table entry
INC BX
INC BX
MOV AL,CH
STOB ;DEVNUM
LODW ;Get pointer to DPT
PUSH SI ;Save INITTAB pointer
MOV SI,AX ;Load DPT
MOVB ;SECSIZ
LODB
DEC AL
STOB ;CLUSMSK
CBW
FIGSHFT:
INC AH
SAR AL
JNZ FIGSHFT
MOV AL,AH
STOB ;CLUSSHFT
LODW
STOW ;FIRFAT
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
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
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 ;Next free segment
MOV [DMAADD],128
MOV [DMAADD+2],DX
MOV AX,[DRVTAB]
MOV [CURDRV],AX
MOV CX,DX ;Start scanning just after DOS
MOV BX,0FH
MEMSCAN:
INC CX
JZ SETEND
MOV DS,CX
MOV AL,[BX]
NOT AL
MOV [BX],AL
CMP AL,[BX]
NOT AL
MOV [BX],AL
JZ MEMSCAN
SETEND:
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
CLI
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,SSSAVE
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
CLD
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
; Standard Functions
DISPATCH 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 GETVER
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 GETDRV ;25
DW SETDMA
DW GETFATPT
DW GETFATPTDL
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
GETIO:
SETIO:
GETVER:
GETFATPTDL:
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,BADFAT
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
GETNAME:
; 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
; AX = Directory record number
; BX = Pointer into directory buffer
; [DIRBUF] has directory record with match
; [NAME1] has file name
; All other registers destroyed.
CALL MOVNAME
JC RET
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 GETNAME
JC ERRET
PUSH AX
PUSH BX
CALL LOADFAT
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 SKIPLET
MOV [DI],AL
SKIPLET:
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 [NUMIO],AL
JC RET
CBW
XCHG AX,BP
SHL BP
MOV BP,[BP+CURDRV]
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,"a"-1
JLE STOLET
AND AL,5FH ;Convert to upper case
STOLET:
CMP AL," "
JB RET
STOB
LOOP MOVCHK
RET
OPEN: ;System call 15
PUSH DX
PUSH DS
CALL GETNAME
OPENNAM:
POP ES
POP DI
JC ERRET
MOV AH,[BP+DEVNUM]
INC AH
SEG ES
MOV [DI],AH
SEG ES
MOV [DI+EXTENT],0
ADD DI,16
MOV CX,BX
SUB CX,DIRBUF
MOV AH,CL
STOW ;ENTPOS
MOV AX,BP
STOW ;DRVBP
LEA SI,[BX+11]
LODW
STOW ;FIRCLUS
STOW ;LSTCLUS
LODB
SHL AL
LODW
RCL AX
STOW ;FILSIZ
XOR AX,AX
STOW ;CLUSPOS
STOW ;FLSFLG, SIZCHG
LOADFAT:
TEST B,[BP+DIRTY],-1
JNZ RET
CALL FIGFAT
READFAT:
PUSH DX
PUSH CX
PUSH BX
PUSH AX
CALL DREAD
OR AL,AL
POP AX
POP BX
POP CX
POP DX
JNZ FATERR
SUB AL,[BP+FATCNT]
JZ RET
NEG AL
JP FATWRT
FATERR:
ADD DX,CX
DEC AL
JNZ READFAT
POP BP
MOV SI,ALLBAD
CALL HARDERR
JP LOADFAT
CLOSE: ;System call 16
MOV DI,DX
TEST B,[DI+FLSFLG],-1
JZ NOFLSH
PUSH DI
MOV BP,[DI+DRVBP]
MOV AL,[BP+DEVNUM]
CALL BIOSFLUSH,BIOSSEG
POP DI
NOFLSH:
TEST B,[DI+SIZCHG],-1
JZ OKRET
MOV DX,DI
PUSH DX
PUSH DS
CALL GETNAME
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+DIRTY],-1
JZ OKRET
FATWRT:
; Inputs:
; DS = CS
; BP = Base of drive parameter table
; Function:
; Write the FAT back to disk and reset FAT
; dirty flag.
; Outputs:
; AL = 0
; BP unchanged
; All other registers destroyed
MOV B,[BP+DIRTY],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+DIRTY],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 OPENNAM
DIRREAD:
; Inputs:
; DS = CS
; AL = Directory block number
; BP = Base of drive parameters
; Function:
; Read the directory block into DIRBUF.
; Outputs:
; AX,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.
; BP preserved. All other registers destroyed.
MOV AL,[BP+DEVNUM]
PUSH BP
PUSH BX
PUSH CX
PUSH DX
CALL BIOSREAD,BIOSSEG
POP DX
POP DI
POP BX
POP BP
JC DSKRDERR
XOR AL,AL
RET
DSKRDERR:
MOV SI,RDERR
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.
; BP preserved. All other registers destroyed.
MOV AL,[BP+DEVNUM]
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 DSKWRERR
XOR AL,AL
RET
DSKWRERR:
MOV SI,WRERR
CALL HARDERR
JP DWRITE
HARDERR:
SUB DI,CX
ADD DX,DI ;Next record to transfer
CALL RECTOBYT
ADD BX,DI ;Next location for transfer
CALL OUTMES
GETRESP:
CALL IN
OR AL,20H ;To lower-case
CMP AL,"a"
JZ ERROR
CMP AL,"r"
JZ RET
CMP AL,"i"
JZ IGNORE
CMP AL,"c"
JNZ GETRESP
POP AX
MOV AL,1
RET
IGNORE:
POP AX
MOV AL,0
RET
ABORT:
SEG CS
MOV DS,[TEMP]
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 NOBUF
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
; [RECCNT] = Record count
; [RECPOS] = Record position in file
; [FCB] = DX
; [NEXTADD] = Displacement of disk transfer within segment
; [DSKERR] = 0 (no errors yet)
; [NUMTRNS] = 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 [NUMTRNS],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
; 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,[NUMTRNS]
ADD AX,BX
SEG ES
CMP AX,[DI+FILSIZ]
JBE NOSZINC
SEG ES
MOV [DI+FILSIZ],AX
SEG ES
MOV B,[DI+SIZCHG],-1
NOSZINC:
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
ADDREC:
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 ADDREC
MOV DX,0FFFH
MOV B,[BP+DIRTY],-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+FLSFLG],-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 [NUMTRNS],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
; 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
; CX = max. no. of records that could be added to file
; ELSE
; Carry clear
; BX = First cluster allocated
; FAT is fully updated including dirty flag
; 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+DIRTY],-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 GETNAME
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 GETNAME
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,[CURDRV]
CALL LOADFAT
MOV BX,[BP+FAT]
MOV AL,[BP+CLUSMSK]
INC AL
MOV DX,[BP+MAXCLUS]
DEC DX
MOV B,[BP+DIRTY],-1
MOV [BXSAVE],BX
MOV [DXSAVE],DX
RET
GETDSKPT: ;System call 31
SEG CS
MOV [DSSAVE],CS
SEG CS
MOV BX,[CURDRV]
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,[DRVTAB]
MOV [CURDRV],AX
NOBUF:
MOV CL,[NUMIO]
MOV CH,0
MOV SI,DRVTAB
WRTFAT:
LODW
PUSH CX
PUSH SI
MOV BP,AX
CALL CHKFATWRT
POP SI
POP CX
LOOP WRTFAT
MOV AL,-1
CALL BIOSFLUSH,BIOSSEG
RET
GETDRV: ;System call 25
SEG CS
MOV BP,[CURDRV]
MOV AL,[BP+0]
RET
INUSE: ;System call 24
MOV AX,CS
MOV DS,AX
MOV CL,[NUMIO]
MOV CH,0
MOV SI,CX
SHL SI
ADD SI,CURDRV
MOV BX,0
STD
CHKUSE:
LODW
MOV BP,AX
TEST B,[BP+DIRTY],-1
JZ SETBIT
STC
SETBIT:
RCL BX
LOOP CHKUSE
MOV AL,BL
RET
SETRNDREC: ;System call 36
CALL GETREC
MOV [DI+RR],AX
MOV AL,0
JZ BIGRR
INC AL
BIGRR:
MOV [DI+RR+2],AL
RET
SELDSK: ;System call 14
MOV DH,0
MOV BX,DX
PUSH CS
POP DS
CMP BL,[NUMIO]
JGE RET
SHL BX
MOV AX,[BX+DRVTAB]
MOV [CURDRV],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,CANCEL
JZ KILNEW
CMP AL,27
JZ ESC
SAVCH:
CMP DH,DL
JNB 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
STD
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
CLD
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 ;Eat Cntrl-S
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:
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,[TEMP]
XOR SI,SI
MOV DI,SI
MOV CX,80H
REP
MOVW
SETMEM:
; Inputs:
; AX = Size of memory in paragraphs
; 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)
; 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,0FFFH
JBE HAVDIF
MOV CX,0FFFH
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
RECTOBYT:
SHL DI
SHL DI
SHL DI
SHL DI
SHL DI
SHL DI
SHL DI
RET
;***** DATA AREA *****
BADFAT DB 13,10,"Bad FAT",13,10,"$"
ALLBAD DB 13,10,"All FATs on disk are bad",13,10,"$"
RDERR DB 13,10,"Disk read error",13,10,"$"
WRERR 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
NUMIO DS 1 ;Number of disk tables
NAME1 DS 11 ;File name buffer
NAME2 DS 11 ;File name buffer
DMAADD DS 4 ;User's disk transfer address (disp/seg)
TEMP DS 2
DSKERR DS 1
FCB DS 2 ;Address of user FCB
RECPOS DS 2
NEXTADD DS 2
RECCNT DS 2
CLUSNUM DS 2
NUMTRNS DS 2
DS 50
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
SSSAVE DS 2
SPSAVE DS 2
CURDRV DS 2
DRVTAB: ;Address of start of DPBs