Initial import of the transcribed source code from Tim Paterson's DOS listings. Co-authored-by: RichCini <rich.cini@gmail.com>
3622 lines
59 KiB
NASM
3622 lines
59 KiB
NASM
; 86-DOS High-performance operating system for the 8086 version 1.00 04/28/81
|
|
; by Tim Paterson
|
|
|
|
; ****************** Revision History *************************
|
|
; >> EVERY change must noted below!! <<
|
|
;
|
|
; 0.34 12/29/80 General release, updating all past customers
|
|
; 0.42 02/25/81 32-byte directory entries added
|
|
; 0.56 03/23/81 Variable record and sector sizes
|
|
; 0.60 03/27/81 Ctrl-C exit changes, including register save on user stack
|
|
; 0.74 04/15/81 Recognize I/O devices with file names
|
|
; 0.75 04/17/81 Improve and correct buffer handling
|
|
; 0.76 04/23/81 Correct directory size when not 2^N entries
|
|
; 0.80 04/27/81 Add console input without echo, Functions 7 & 8
|
|
; 1.00 04/28/81 Renumber for general release
|
|
;
|
|
; *************************************************************
|
|
|
|
; Use the switch below to generate code to accept the old 16-byte
|
|
; directory entry as well as the new 32-byte entry.
|
|
|
|
SMALLDIR: EQU 1 ;1 to enable, 0 to disable
|
|
|
|
|
|
; Turn on switch below to allow testing disk code with DEBUG. It sets
|
|
; up a different stack for disk I/O (functions > 11) than that used for
|
|
; character I/O which effectively makes the DOS re-entrant.
|
|
|
|
DSKTEST: EQU 0 ;1 to enable, 0 to disable
|
|
|
|
|
|
; 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 41
|
|
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 2
|
|
RECSIZ: DS 2 ;Size of record (user settable)
|
|
FILSIZ: DS 4 ;Size of file in bytes
|
|
FDATE: DS 2 ;Date of last writing
|
|
FILDIRBLK:DS 2 ;Location in directory
|
|
FIRCLUS:DS 2 ;First cluster of file
|
|
LSTCLUS:DS 2 ;Last cluster accessed
|
|
CLUSPOS:DS 2 ;Position of last cluster accessed
|
|
DIRTYFIL:DS 1 ;File has been written to if <>0
|
|
ORG 32
|
|
NR: DS 1 ;Next record
|
|
RR: DS 3 ;Random record
|
|
|
|
|
|
; Description of 32-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 13 Zero field (for expansion)
|
|
; 24 2 Date. Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980
|
|
; 26 2 First allocation unit ( < 4080 )
|
|
; 28 4 File size, in bytes (LSB first, 30 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 and as a flag for directory
|
|
; entry size (if SMALLDIR selected). 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 greater than 0FF8H 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
|
|
|
|
ORG 0
|
|
DRVNUM: DS 1 ;Drive number
|
|
SECSIZ: DS 2 ;Size of physical sector in bytes
|
|
CLUSMSK:DS 1 ;Sectors/cluster - 1
|
|
CLUSSHFT:DS 1 ;Log2 of sectors/cluster
|
|
FIRFAT: DS 2 ;Starting record of FATs
|
|
FATCNT: DS 1 ;Number of FATs for this drive
|
|
MAXENT: DS 2 ;Number of directory entries
|
|
DIRSEC: ;Number of dir. sectors (init temporary)
|
|
FIRREC: DS 2 ;First sector of first cluster
|
|
DSKSIZ: ;Size of disk (temp used during init only)
|
|
MAXCLUS:DS 2 ;Number of clusters on drive + 1
|
|
FATSIZ: DS 1 ;Number of records occupied by FAT
|
|
FIRDIR: DS 2 ;Starting record of directory
|
|
|
|
IF SMALLDIR
|
|
FIRREC1:DS 2 ;First data sector with 16-byte dir. entries
|
|
MAXCLUS1:DS 2 ;No. of clusters + 1 with 16-byte dir. entries
|
|
FIRREC2:DS 2 ;First data sector with 32-byte dir. entries
|
|
MAXCLUS2:DS 2 ;No. of clusters + 1 with 32-byte dir entries
|
|
ENDIF
|
|
|
|
DIRTYFAT:DS 1 ;1=FAT has been changed, -1=never been read
|
|
FAT: ;Start of FAT
|
|
DIRSIZ: ;-1=small dir. entry, else large
|
|
|
|
|
|
; 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
|
|
BIOSDSKCHG: DS 3
|
|
|
|
|
|
; Location of user registers relative user stack pointer
|
|
|
|
ORG 0
|
|
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
|
|
IPSAVE: DS 2
|
|
CSSAVE: DS 2
|
|
FSAVE: DS 2
|
|
|
|
|
|
; 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 1.00"
|
|
|
|
IF DSKTEST
|
|
DB "D"
|
|
ENDIF
|
|
|
|
DB 13,10
|
|
DB "Copyright 1980,81 Seattle Computer Products, Inc.",13,10,"$"
|
|
|
|
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:
|
|
PUSH ES
|
|
PUSH DS
|
|
PUSH BP
|
|
PUSH DI
|
|
PUSH SI
|
|
PUSH DX
|
|
PUSH CX
|
|
PUSH BX
|
|
PUSH AX
|
|
|
|
IF DSKTEST
|
|
SEG CS
|
|
MOV AX,[SPSAVE]
|
|
SEG CS
|
|
MOV [NSP],AX
|
|
SEG CS
|
|
MOV AX,[SSSAVE]
|
|
SEG CS
|
|
MOV [NSS],AX
|
|
POP AX
|
|
PUSH AX
|
|
ENDIF
|
|
|
|
SEG CS
|
|
MOV [SPSAVE],SP
|
|
SEG CS
|
|
MOV [SSSAVE],SS
|
|
MOV BP,SP
|
|
MOV BX,[BP+CSSAVE]
|
|
SEG CS
|
|
MOV [CSLOC],BX
|
|
MOV SP,CS
|
|
MOV SS,SP
|
|
MOV SP,STACK
|
|
EI ;Stack OK now
|
|
SEG CS
|
|
MOV [FUNC],AH
|
|
MOV BL,AH
|
|
MOV BH,0
|
|
SHL BX
|
|
UP
|
|
|
|
IF DSKTEST
|
|
CMP AH,12
|
|
JL SAMSTK
|
|
MOV SP,TESTSTK
|
|
SAMSTK:
|
|
ENDIF
|
|
|
|
SEG CS
|
|
CALL [BX+DISPATCH]
|
|
LEAVE:
|
|
DI
|
|
SEG CS
|
|
MOV SP,[SPSAVE]
|
|
SEG CS
|
|
MOV SS,[SSSAVE]
|
|
MOV BP,SP
|
|
MOV [BP+AXSAVE],AL
|
|
|
|
IF DSKTEST
|
|
SEG CS
|
|
MOV AX,[NSP]
|
|
SEG CS
|
|
MOV [SPSAVE],AX
|
|
SEG CS
|
|
MOV AX,[NSS]
|
|
SEG CS
|
|
MOV [SSSAVE],AX
|
|
ENDIF
|
|
|
|
POP AX
|
|
POP BX
|
|
POP CX
|
|
POP DX
|
|
POP SI
|
|
POP DI
|
|
POP BP
|
|
POP DS
|
|
POP ES
|
|
IRET
|
|
|
|
DISPATCH:
|
|
; Standard Functions
|
|
DW ABORT ;0
|
|
DW CONIN
|
|
DW CONOUT
|
|
DW READER
|
|
DW PUNCH
|
|
DW LIST ;5
|
|
DW RAWIO
|
|
DW RAWINP
|
|
DW IN
|
|
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
|
|
DW MAKEFCB
|
|
|
|
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
|
|
|
|
IOCHK:
|
|
MOV CX,5 ;Check rest of name but not extension
|
|
CMP B,[DI],":"
|
|
JNZ NOCOL
|
|
INC DI ;Skip over colon
|
|
DEC CX
|
|
NOCOL:
|
|
MOV AL," "
|
|
REPE
|
|
SCAB ;Make sure rest of name is blanks
|
|
JNZ FILSRCH
|
|
DEC BL
|
|
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
|
|
; 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 SI,IONAME ;List of I/O devices with file names
|
|
MOV BX,0FF04H ;BL = number of devices
|
|
LOOKIO:
|
|
MOV DI,NAME1
|
|
MOV CX,3 ;All device names are 3 letters
|
|
REPE
|
|
CMPB ;Check for name in list
|
|
JZ IOCHK ;If first 3 letters OK, check the rest
|
|
ADD SI,CX ;Point to next device name
|
|
DEC BL
|
|
JNZ LOOKIO
|
|
FILSRCH: ;Not a device name
|
|
CALL STARTSRCH
|
|
CONTSRCH:
|
|
CALL GETENTRY
|
|
JC RET
|
|
SRCH:
|
|
CMP B,[BX],0E5H
|
|
JZ NEXTENT
|
|
MOV SI,BX
|
|
MOV DI,NAME1
|
|
MOV CX,11
|
|
WILDCRD:
|
|
REPE
|
|
CMPB
|
|
JZ FOUND
|
|
CMP B,[DI-1],"?"
|
|
JZ WILDCRD
|
|
NEXTENT:
|
|
CALL NEXTENTRY
|
|
JNC SRCH
|
|
RET
|
|
|
|
FOUND:
|
|
IF SMALLDIR
|
|
CMP B,[BP+DIRSIZ],-1
|
|
JZ RET
|
|
ENDIF
|
|
|
|
ADD SI,15
|
|
RET
|
|
|
|
|
|
GETENTRY:
|
|
|
|
; Inputs:
|
|
; [LASTENT] has previously searched directory entry
|
|
; Function:
|
|
; Locates next sequential directory entry in preparation for search
|
|
; Outputs:
|
|
; Carry set if none
|
|
; ELSE
|
|
; AL = Current directory block
|
|
; BX = Pointer to next directory entry in [DIRBUF]
|
|
; DX = Pointer to first byte after end of DIRBUF
|
|
; [LASTENT] = New directory entry number
|
|
|
|
MOV AX,[LASTENT]
|
|
INC AX ;Start with next entry
|
|
CMP AX,[BP+MAXENT]
|
|
JAE NONE
|
|
MOV [LASTENT],AX
|
|
MOV CL,4
|
|
SHL AX,CL
|
|
XOR DX,DX
|
|
|
|
IF SMALLDIR
|
|
CMP B,[BP+DIRSIZ],-1
|
|
JZ SMALENT1
|
|
ENDIF
|
|
|
|
SHL AX
|
|
RCL DX ;Account for overflow in last shift
|
|
SMALENT1:
|
|
MOV BX,[BP+SECSIZ]
|
|
AND BL,255-31 ;Must be multiple of 32
|
|
DIV AX,BX
|
|
MOV BX,DX ;Position within sector
|
|
MOV AH,[BP+DRVNUM] ;AL=Directory sector no.
|
|
CMP AX,[DIRBUFID]
|
|
JZ HAVDIRBUF
|
|
PUSH BX
|
|
CALL DIRREAD
|
|
POP BX
|
|
HAVDIRBUF:
|
|
MOV DX,DIRBUF
|
|
ADD BX,DX
|
|
ADD DX,[BP+SECSIZ]
|
|
RET
|
|
|
|
NEXTENTRY:
|
|
|
|
; Inputs:
|
|
; Same as outputs of GETENTRY, above
|
|
; Function:
|
|
; Update AL, BX, and [LASTENT] for next directory entry.
|
|
; Carry set if no more.
|
|
|
|
MOV DI,[LASTENT]
|
|
INC DI
|
|
CMP DI,[BP+MAXENT]
|
|
JAE NONE
|
|
MOV [LASTENT],DI
|
|
ADD BX,32
|
|
|
|
IF SMALLDIR
|
|
CMP B,[BP+DIRSIZ],-1
|
|
JNZ BIGENT3
|
|
SUB BX,16
|
|
BIGENT3:
|
|
ENDIF
|
|
|
|
CMP BX,DX
|
|
JB HAVIT
|
|
INC AL ;Next directory sector
|
|
PUSH DX ;Save limit
|
|
CALL DIRREAD
|
|
POP DX
|
|
MOV BX,DIRBUF
|
|
HAVIT:
|
|
CLC
|
|
RET
|
|
|
|
NONE:
|
|
CALL CHKDIRWRITE
|
|
STC
|
|
RET
|
|
|
|
|
|
DELETE: ; System call 19
|
|
CALL GETFILE
|
|
JC ERRET
|
|
CMP BH,-1 ;Check if device name
|
|
JZ ERRET ;Can't delete I/O devices
|
|
DELFILE:
|
|
MOV B,[DIRTYDIR],-1
|
|
MOV B,[BX],0E5H
|
|
MOV BX,[SI]
|
|
LEA SI,[BP+FAT]
|
|
OR BX,BX
|
|
JZ DELNXT
|
|
CMP BX,[BP+MAXCLUS]
|
|
JA DELNXT
|
|
CALL RELEASE
|
|
DELNXT:
|
|
CALL CONTSRCH
|
|
JNC DELFILE
|
|
CALL FATWRT
|
|
CALL CHKDIRWRITE
|
|
XOR AL,AL
|
|
RET
|
|
|
|
|
|
RENAME: ;System call 23
|
|
CALL MOVNAME
|
|
JC ERRET
|
|
CMP BH,-1 ;Check if I/O device name
|
|
JZ ERRET ;If so, can't rename it
|
|
ADD SI,5
|
|
MOV DI,NAME2
|
|
CALL LODNAME
|
|
CALL FINDNAME
|
|
JC ERRET
|
|
RENFIL:
|
|
MOV B,[DIRTYDIR],-1
|
|
MOV DI,BX
|
|
MOV SI,NAME2
|
|
MOV CX,11
|
|
NEWNAM:
|
|
LODB
|
|
CMP AL,"?"
|
|
JZ NOCHG
|
|
MOV [DI],AL
|
|
NOCHG:
|
|
INC DI
|
|
LOOP NEWNAM
|
|
CALL CONTSRCH
|
|
JNC RENFIL
|
|
CALL CHKDIRWRITE
|
|
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
|
|
CALL GETBP
|
|
JB RET
|
|
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
|
|
|
|
GETBP:
|
|
SEG CS
|
|
CMP [NUMDRV],AL
|
|
JC RET
|
|
CBW
|
|
XCHG BP,AX
|
|
SHL BP
|
|
MOV BP,[BP+CURDRVPT]
|
|
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, SI points to First Cluster field, 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
|
|
CMP BH,-1 ;Check if file is I/O device
|
|
JZ OPENDEV ;Special handler if so
|
|
MOV AL,[BP+DRVNUM]
|
|
INC AL
|
|
STOB
|
|
ADD DI,11 ;Point to extent field
|
|
XOR AX,AX
|
|
STOW ;Set extent field to 0
|
|
MOV AX,128 ;Default record size
|
|
STOW ;Set record size
|
|
LODW ;Get starting cluster
|
|
MOV DX,AX ;Save it for the moment
|
|
MOVW ;Transfer size to FCB
|
|
MOVW
|
|
MOV AX,[SI-8] ;Get date
|
|
|
|
IF SMALLDIR
|
|
CMP B,[BP+DIRSIZ],-1
|
|
JNZ BIGENT10
|
|
SEG ES
|
|
MOV [DI-1],0
|
|
XOR AX,AX ;Date not available in small entry
|
|
BIGENT10:
|
|
ENDIF
|
|
|
|
STOW ;Save date in FCB
|
|
MOV AX,[LASTENT]
|
|
STOW ;directory location
|
|
MOV AX,DX ;Restore starting cluster
|
|
STOW ; first cluster
|
|
STOW ; last cluster accessed
|
|
XOR AX,AX
|
|
STOW ; position of last cluster
|
|
STOB ; dirty flag
|
|
RET
|
|
|
|
OPENDEV:
|
|
SEG ES
|
|
MOV [DI+FILDIRBLK],BX ;Use dir. entry number as flag
|
|
XOR AL,AL
|
|
RET
|
|
|
|
|
|
STARTSRCH:
|
|
MOV [LASTENT],-1
|
|
FATREAD:
|
|
|
|
; Inputs:
|
|
; DS = CS
|
|
; BP = Base of drive parameters
|
|
; Function:
|
|
; If disk may have been changed, FAT is read in and buffers are
|
|
; flagged invalid. If not, no action is taken.
|
|
; Outputs:
|
|
; AL = 0
|
|
; BP unchanged
|
|
; All other registers destroyed
|
|
|
|
MOV AL,[BP+DRVNUM]
|
|
CALL BIOSDSKCHG,BIOSSEG ;See what BIOS has to say
|
|
MOV AL,[BP+DRVNUM]
|
|
OR AH,[BP+DIRTYFAT]
|
|
JS NEWDSK ;If either say new disk, then it's so
|
|
DEC AH ;Check for AH=1 (disk not changed)
|
|
JZ RET
|
|
MOV AH,1
|
|
CMP AX,[BUFDRVNO] ;Does buffer have dirty sector of this drive?
|
|
JZ RET ;If so, disk has not been changed
|
|
NEWDSK:
|
|
CMP AL,[BUFDRVNO] ;See if buffer is for this drive
|
|
JNZ BUFOK ;If not, don't touch it
|
|
MOV [BUFSECNO],0 ;Flag buffers invalid
|
|
MOV [BUFDRVNO],00FFH
|
|
BUFOK:
|
|
MOV [DIRBUFID],-1
|
|
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
|
|
|
|
IF SMALLDIR
|
|
MOV DL,AL
|
|
LEA SI,[BP+FIRREC1] ;FIRREC and MAXCLUS for 16-byte dir entries
|
|
CMP B,[BP+DIRSIZ],-1
|
|
JZ SETSIZ
|
|
ADD SI,4 ;FIRREC and MAXCLUS for 32-byte entries
|
|
SETSIZ:
|
|
LODW
|
|
MOV [BP+FIRREC],AX
|
|
LODW
|
|
MOV [BP+MAXCLUS],AX
|
|
MOV AL,DL
|
|
ENDIF
|
|
|
|
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.}
|
|
JMP 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
|
|
|
|
OKRET1:
|
|
MOV AL,0
|
|
RET
|
|
|
|
CLOSE: ;System call 16
|
|
MOV DI,DX
|
|
CMP B,[DI+FILDIRBLK],-1 ;Check for I/O device
|
|
JZ OKRET1 ;Can't close I/O device
|
|
TEST B,[DI+DIRTYFIL],-1
|
|
JZ OKRET1 ;If not written to, do nothing
|
|
MOV AL,[DI] ;Get drive number
|
|
CALL GETBP ;Get base of drive parameters
|
|
JC BADCLOSEJ
|
|
MOV AL,[BP+DRVNUM]
|
|
MOV AH,1 ;Look for dirty buffer
|
|
SEG CS
|
|
CMP AX,[BUFDRVNO]
|
|
JNZ FNDDIR
|
|
;Write back dirty buffer if on same drive
|
|
PUSH DX
|
|
PUSH DS
|
|
PUSH CS
|
|
POP DS
|
|
MOV B,[DIRTYBUF],0
|
|
MOV BX,[BUFFER]
|
|
MOV CX,1
|
|
MOV DX,[BUFSECNO]
|
|
CALL DWRITE
|
|
POP DS
|
|
POP DX
|
|
FNDDIR:
|
|
PUSH DX
|
|
PUSH DS
|
|
CALL GETFILE
|
|
POP ES
|
|
POP DI
|
|
BADCLOSEJ:
|
|
JC BADCLOSE
|
|
MOV AX,[LASTENT]
|
|
SEG ES
|
|
CMP AX,[DI+FILDIRBLK]
|
|
JNZ BADCLOSE
|
|
SEG ES
|
|
MOV CX,[DI+FIRCLUS]
|
|
MOV [SI],CX
|
|
SEG ES
|
|
MOV DX,[DI+FILSIZ]
|
|
MOV [SI+2],DX
|
|
SEG ES
|
|
MOV DX,[DI+FILSIZ+2]
|
|
|
|
IF SMALLDIR
|
|
CMP B,[BP+DIRSIZ],-1
|
|
JNZ BIGENT11
|
|
MOV [SI+4],DL
|
|
JP SMALLENT2
|
|
BIGENT11:
|
|
ENDIF
|
|
|
|
MOV [SI+4],DX
|
|
SEG ES
|
|
MOV DX,[DI+FDATE]
|
|
MOV [SI-2],DX
|
|
SMALLENT2:
|
|
CALL DIRWRITE
|
|
|
|
CHKFATWRT:
|
|
; Do FATWRT only if FAT is dirty
|
|
|
|
CMP B,[BP+DIRTYFAT],1
|
|
JNZ 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]
|
|
LEA 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
|
|
CALL FINDNAME
|
|
JNC EXISTENT
|
|
CALL STARTSRCH
|
|
CALL GETENTRY
|
|
LOOKFRE:
|
|
CMP B,[BX],0E5H
|
|
JZ FREESPOT
|
|
CALL NEXTENTRY
|
|
JNC LOOKFRE
|
|
POP DS
|
|
POP DX
|
|
ERRET3:
|
|
MOV AL,-1
|
|
RET
|
|
|
|
EXISTENT:
|
|
CMP BH,-1 ;Check if file is I/O device
|
|
JZ OPENJMP ;If so, no action
|
|
XOR CX,CX
|
|
MOV [SI+2],CX
|
|
MOV AX,[DATE]
|
|
|
|
IF SMALLDIR
|
|
MOV [SI+4],CL
|
|
CMP B,[BP+DIRSIZ],-1
|
|
JZ SMLENT
|
|
MOV [SI+5],CL
|
|
MOV [SI-2],AX
|
|
SMLENT:
|
|
ENDIF
|
|
|
|
IF 1-SMALLDIR
|
|
MOV [SI+4],CX
|
|
MOV [SI-2],AX
|
|
ENDIF
|
|
|
|
XCHG CX,[SI]
|
|
PUSH SI
|
|
PUSH BX
|
|
JCXZ WRTBACK
|
|
CMP CX,[BP+MAXCLUS]
|
|
JA WRTBACK
|
|
MOV BX,CX
|
|
LEA SI,[BP+FAT]
|
|
CALL RELEASE
|
|
CALL FATWRT
|
|
JP WRTBACK
|
|
|
|
FREESPOT:
|
|
MOV DI,BX
|
|
MOV SI,NAME1
|
|
MOV CX,5
|
|
MOVB
|
|
REP
|
|
MOVW
|
|
XOR AX,AX
|
|
|
|
IF SMALLDIR
|
|
CMP B,[BP+DIRSIZ],-1
|
|
JNZ BIGENT4
|
|
PUSH DI
|
|
MOV CL,5
|
|
JP SMALLENT
|
|
BIGENT4:
|
|
ENDIF
|
|
|
|
MOV CL,13
|
|
REP
|
|
STOB
|
|
MOV AX,[DATE]
|
|
STOW
|
|
XOR AX,AX
|
|
PUSH DI
|
|
MOV CL,6
|
|
SMALLENT:
|
|
REP
|
|
STOB
|
|
PUSH BX
|
|
WRTBACK:
|
|
CALL DIRWRITE
|
|
POP BX
|
|
POP SI
|
|
OPENJMP:
|
|
CLC ;Clear carry so OPEN won't fail
|
|
JMP DOOPEN
|
|
|
|
|
|
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.
|
|
|
|
PUSH AX
|
|
CALL CHKDIRWRITE
|
|
POP AX
|
|
PUSH AX
|
|
MOV AH,[BP+DRVNUM]
|
|
MOV [DIRBUFID],AX
|
|
CALL DIRCOMP
|
|
CALL DREAD
|
|
POP AX
|
|
RET
|
|
|
|
|
|
DREAD:
|
|
|
|
; Inputs:
|
|
; BX,DS = Transfer address
|
|
; CX = Number of sectors
|
|
; 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
|
|
|
|
|
|
CHKDIRWRITE:
|
|
TEST B,[DIRTYDIR],-1
|
|
JZ RET
|
|
|
|
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.
|
|
|
|
MOV B,[DIRTYDIR],0
|
|
MOV AL,[DIRBUFID]
|
|
CALL DIRCOMP
|
|
|
|
|
|
DWRITE:
|
|
|
|
; Inputs:
|
|
; BX,DS = Transfer address
|
|
; CX = Number of sectors
|
|
; 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]
|
|
WRTDRV:
|
|
PUSH AX
|
|
PUSH BP
|
|
PUSH BX
|
|
PUSH CX
|
|
PUSH DX
|
|
CALL BIOSWRITE,BIOSSEG
|
|
POP DX
|
|
POP DI
|
|
POP BX
|
|
POP BP
|
|
POP AX
|
|
JC HARDWRITE
|
|
XOR AL,AL
|
|
RET
|
|
HARDWRITE:
|
|
MOV SI,WRTERRMES
|
|
CALL HARDERR
|
|
JP WRTDRV
|
|
|
|
|
|
HARDERR:
|
|
SUB DI,CX
|
|
ADD DX,DI
|
|
CALL SHFTDI7
|
|
ADD BX,DI
|
|
MOV AH,AL ;Save drive number
|
|
CALL OUTMES
|
|
GETINSTR:
|
|
CALL IN
|
|
OR AL,20H
|
|
CMP AL,"a"
|
|
JZ ERROR
|
|
CMP AL,"r"
|
|
JZ RETRY
|
|
CMP AL,"i"
|
|
JZ IGNORE
|
|
CMP AL,"c"
|
|
JNZ GETINSTR
|
|
CONTINUE:
|
|
POP AX
|
|
MOV AL,1
|
|
RET
|
|
IGNORE:
|
|
POP AX
|
|
MOV AL,0
|
|
RET
|
|
RETRY:
|
|
MOV AL,AH ;Restore drive number
|
|
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 AX,CS
|
|
MOV DS,AX
|
|
MOV ES,AX
|
|
CALL WRTFATS
|
|
XOR AX,AX
|
|
DI
|
|
MOV SS,[SSSAVE]
|
|
MOV SP,[SPSAVE]
|
|
MOV DS,AX
|
|
MOV SI,EXIT
|
|
MOV DI,EXITHOLD
|
|
MOVW
|
|
MOVW
|
|
POP AX
|
|
POP BX
|
|
POP CX
|
|
POP DX
|
|
POP SI
|
|
POP DI
|
|
POP BP
|
|
POP DS
|
|
POP ES
|
|
EI ;Stack OK now
|
|
SEG CS
|
|
JMP L,[EXITHOLD]
|
|
|
|
|
|
SEQRD: ;System call 20
|
|
CALL GETREC
|
|
CALL LOAD
|
|
JP FINSEQ
|
|
|
|
SEQWRT: ;System call 21
|
|
CALL GETREC
|
|
CALL STORE
|
|
FINSEQ:
|
|
JCXZ SETNREX
|
|
ADD AX,1
|
|
ADC DX,0
|
|
JP SETNREX
|
|
|
|
RNDRD: ;System call 33
|
|
CALL GETRRPOS1
|
|
CALL LOAD
|
|
JP FINRND
|
|
|
|
RNDWRT: ;System call 34
|
|
CALL GETRRPOS1
|
|
CALL STORE
|
|
JP FINRND
|
|
|
|
BLKRD: ;System call 39
|
|
CALL GETRRPOS
|
|
CALL LOAD
|
|
JP FINBLK
|
|
|
|
BLKWRT: ;System call 40
|
|
CALL GETRRPOS
|
|
CALL STORE
|
|
FINBLK:
|
|
LDS SI,[SPSAVE]
|
|
MOV [SI+CXSAVE],CX
|
|
JCXZ FINRND
|
|
ADD AX,1
|
|
ADC DX,0
|
|
FINRND:
|
|
SEG ES
|
|
MOV [DI+RR],AX
|
|
SEG ES
|
|
MOV [DI+RR+2],DL
|
|
OR DH,DH
|
|
JZ SETNREX
|
|
SEG ES
|
|
MOV [DI+RR+3],DH ;Save 4 byte of RECPOS only if significant
|
|
SETNREX:
|
|
MOV CX,AX
|
|
AND AL,7FH
|
|
SEG ES
|
|
MOV [DI+NR],AL
|
|
AND CL,80H
|
|
SHL CX
|
|
RCL DX
|
|
MOV AL,CH
|
|
MOV AH,DL
|
|
SEG ES
|
|
MOV [DI+EXTENT],AX
|
|
SEG CS
|
|
MOV AL,[DSKERR]
|
|
RET
|
|
|
|
GETRRPOS1:
|
|
MOV CX,1
|
|
GETRRPOS:
|
|
MOV DI,DX
|
|
MOV AX,[DI+RR]
|
|
MOV DX,[DI+RR+2]
|
|
RET
|
|
|
|
NOFILERR:
|
|
XOR CX,CX
|
|
MOV B,[DSKERR],-2
|
|
POP BX
|
|
RET
|
|
|
|
SETUP:
|
|
|
|
; Inputs:
|
|
; DS:DI point to FCB
|
|
; DX:AX = Record position in file of disk transfer
|
|
; CX = Record count
|
|
; Outputs:
|
|
; DS = CS
|
|
; ES:DI point to FCB
|
|
; CX = No. of bytes to transfer
|
|
; BP = Base of drive parameters
|
|
; SI = FAT pointer
|
|
; [RECCNT] = Record count
|
|
; [RECPOS] = Record position in file
|
|
; [FCB] = DI
|
|
; [NEXTADD] = Displacement of disk transfer within segment
|
|
; [SECPOS] = Position of first sector
|
|
; [BYTPOS] = Byte position in file
|
|
; [BYTSECPOS] = Byte position in first sector
|
|
; [CLUSNUM] = First cluster
|
|
; [SECCLUSPOS] = Sector within first cluster
|
|
; [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.
|
|
|
|
PUSH AX
|
|
MOV AL,[DI]
|
|
MOV SI,[DI+RECSIZ]
|
|
OR SI,SI
|
|
JNZ HAVRECSIZ
|
|
MOV SI,128
|
|
MOV [DI+RECSIZ],SI
|
|
HAVRECSIZ:
|
|
MOV BX,DS
|
|
MOV ES,BX
|
|
MOV BX,CS
|
|
MOV DS,BX
|
|
CALL GETBP
|
|
POP AX
|
|
JC NOFILERR
|
|
CMP SI,64 ;Check if highest byte of RECPOS is significant
|
|
JB SMALREC
|
|
MOV DH,0 ;Ignore MSB if record >= 64 bytes
|
|
SMALREC:
|
|
MOV [RECCNT],CX
|
|
MOV [RECPOS],AX
|
|
MOV [RECPOS+2],DX
|
|
MOV [FCB],DI
|
|
MOV BX,[DMAADD]
|
|
MOV [NEXTADD],BX
|
|
MOV B,[DSKERR],0
|
|
MOV B,[TRANS],0
|
|
MOV BX,DX
|
|
MUL AX,SI
|
|
MOV [BYTPOS],AX
|
|
PUSH DX
|
|
MOV AX,BX
|
|
MUL AX,SI
|
|
POP BX
|
|
ADD AX,BX
|
|
ADC DX,0 ;Ripple carry
|
|
JNZ EOFERR
|
|
MOV [BYTPOS+2],AX
|
|
MOV DX,AX
|
|
MOV AX,[BYTPOS]
|
|
DIV AX,[BP+SECSIZ]
|
|
MOV [SECPOS],AX
|
|
MOV [BYTSECPOS],DX
|
|
MOV DX,AX
|
|
AND AL,[BP+CLUSMSK]
|
|
MOV [SECCLUSPOS],AL
|
|
MOV AX,CX ;Record count
|
|
MOV CL,[BP+CLUSSHFT]
|
|
SHR DX,CL
|
|
MOV [CLUSNUM],DX
|
|
MUL AX,SI ;Multiply by bytes per record
|
|
MOV CX,AX
|
|
ADD AX,[DMAADD] ;See if it will fit in one segment
|
|
ADC DX,0
|
|
JZ OK ;Must stay within 64K
|
|
MOV AX,[DMAADD]
|
|
NEG AX ;Amount of room left in segment
|
|
XOR DX,DX
|
|
DIV AX,SI ;How many records will fit?
|
|
MUL AX,SI ;Translate that back into bytes
|
|
MOV B,[DSKERR],2 ;Flag that trimming took place
|
|
MOV CX,AX
|
|
JCXZ NOROOM
|
|
OK:
|
|
LEA SI,[BP+FAT]
|
|
RET
|
|
|
|
EOFERR:
|
|
MOV B,[DSKERR],1
|
|
XOR CX,CX
|
|
NOROOM:
|
|
POP BX ;Kill return address
|
|
RET
|
|
|
|
BREAKDOWN:
|
|
|
|
;Inputs:
|
|
; DS = CS
|
|
; CX = Length of disk transfer in bytes
|
|
; BP = Base of drive parameters
|
|
; [BYTSECPOS] = Byte position witin first sector
|
|
;Outputs:
|
|
; [BYTCNT1] = Bytes to transfer in first sector
|
|
; [SECCNT] = No. of whole sectors to transfer
|
|
; [BYTCNT2] = Bytes to transfer in last sector
|
|
;AX, BX, DX destroyed. No other registers affected.
|
|
|
|
MOV AX,[BYTSECPOS]
|
|
MOV BX,CX
|
|
OR AX,AX
|
|
JZ SAVFIR ;Partial first sector?
|
|
SUB AX,[BP+SECSIZ]
|
|
NEG AX ;Max number of bytes left in first sector
|
|
SUB BX,AX ;Subtract from total length
|
|
JAE SAVFIR
|
|
ADD AX,BX ;Don't use all of the rest of the sector
|
|
XOR BX,BX ;And no bytes are left
|
|
SAVFIR:
|
|
MOV [BYTCNT1],AX
|
|
MOV AX,BX
|
|
XOR DX,DX
|
|
DIV AX,[BP+SECSIZ] ;How many whole sectors?
|
|
MOV [SECCNT],AX
|
|
MOV [BYTCNT2],DX ;Bytes remaining for last sector
|
|
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,0FF8H
|
|
JAE RET
|
|
XCHG BX,DI
|
|
INC DX
|
|
LOOP SKPCLP
|
|
RET
|
|
NOCLUS:
|
|
INC CX
|
|
DEC DX
|
|
RET
|
|
|
|
|
|
BUFSEC:
|
|
; Inputs:
|
|
; AL = 0 if buffer must be read, 1 if no pre-read needed
|
|
; BP = Base of drive parameters
|
|
; [CLUSNUM] = Physical cluster number
|
|
; [SECCLUSPOS] = Sector position of transfer within cluster
|
|
; [BYTCNT1] = Size of transfer
|
|
; Function:
|
|
; Insure specified sector is in buffer, flushing buffer before
|
|
; read if necessary.
|
|
; Outputs:
|
|
; SI = Pointer to buffer
|
|
; DI = Pointer to transfer address
|
|
; CX = Number of bytes
|
|
; [NEXTADD] updated
|
|
; [TRANS] set to indicate a transfer will occur
|
|
|
|
MOV DX,[CLUSNUM]
|
|
MOV BL,[SECCLUSPOS]
|
|
CALL FIGREC
|
|
OR AL,AL
|
|
JNZ SETBUF
|
|
CMP DX,[BUFSECNO]
|
|
JNZ GETSEC
|
|
MOV AL,[BUFDRVNO]
|
|
CMP AL,[BP+DRVNUM]
|
|
JZ FINBUF ;Already have it?
|
|
GETSEC:
|
|
TEST B,[DIRTYBUF],-1
|
|
JZ RDSEC
|
|
PUSH DX
|
|
MOV AL,[BUFDRVNO]
|
|
MOV BX,[BUFFER]
|
|
MOV CX,1
|
|
MOV DX,[BUFSECNO]
|
|
CALL WRTDRV
|
|
POP DX
|
|
RDSEC:
|
|
MOV BX,[BUFFER]
|
|
MOV CX,1
|
|
PUSH DX
|
|
CALL DREAD
|
|
POP DX
|
|
SETBUF:
|
|
MOV [BUFSECNO],DX
|
|
MOV AL,[BP+DRVNUM]
|
|
MOV AH,0
|
|
MOV [BUFDRVNO],AX
|
|
FINBUF:
|
|
MOV B,[TRANS],1 ;A transfer is taking place
|
|
MOV DI,[NEXTADD]
|
|
MOV SI,DI
|
|
MOV CX,[BYTCNT1]
|
|
ADD SI,CX
|
|
MOV [NEXTADD],SI
|
|
MOV SI,[BUFFER]
|
|
ADD SI,[BYTSECPOS]
|
|
RET
|
|
|
|
BUFRD:
|
|
XOR AL,AL ;Pre-read necessary
|
|
CALL BUFSEC
|
|
PUSH ES
|
|
MOV ES,[DMAADD+2]
|
|
SHR CX
|
|
JNC EVENRD
|
|
MOVB
|
|
EVENRD:
|
|
REP
|
|
MOVW
|
|
POP ES
|
|
RET
|
|
|
|
BUFWRT:
|
|
MOV AX,[SECPOS]
|
|
INC AX ;Set for next sector
|
|
MOV [SECPOS],AX
|
|
CMP AX,[VALSEC] ;Has sector been written before?
|
|
MOV AL,1
|
|
JA NOREAD ;Skip preread if SECPOS>VALSEC
|
|
MOV AL,0
|
|
NOREAD:
|
|
CALL BUFSEC
|
|
XCHG DI,SI
|
|
PUSH DS
|
|
PUSH ES
|
|
PUSH CS
|
|
POP ES
|
|
MOV DS,[DMAADD+2]
|
|
SHR CX
|
|
JNC EVENWRT
|
|
MOVB
|
|
EVENWRT:
|
|
REP
|
|
MOVW
|
|
POP ES
|
|
POP DS
|
|
MOV B,[DIRTYBUF],1
|
|
RET
|
|
|
|
NEXTSEC:
|
|
TEST B,[TRANS],-1
|
|
JZ CLRET
|
|
MOV AL,[SECCLUSPOS]
|
|
INC AL
|
|
CMP AL,[BP+CLUSMSK]
|
|
JBE SAVPOS
|
|
MOV BX,[CLUSNUM]
|
|
CMP BX,0FF8H
|
|
JAE NONEXT
|
|
LEA SI,[BP+FAT]
|
|
CALL UNPACK
|
|
MOV [CLUSNUM],DI
|
|
INC [LASTPOS]
|
|
MOV AL,0
|
|
SAVPOS:
|
|
MOV [SECCLUSPOS],AL
|
|
CLRET:
|
|
CLC
|
|
RET
|
|
NONEXT:
|
|
STC
|
|
RET
|
|
|
|
TRANBUF:
|
|
LODB
|
|
STOB
|
|
CMP AL,13 ;Check for carriage return
|
|
JNZ NORMCH
|
|
MOV [SI],10
|
|
NORMCH:
|
|
CMP AL,10
|
|
LOOPNZ TRANBUF
|
|
JNZ ENDRDCON
|
|
CALL OUT ;Transmit linefeed
|
|
XOR SI,SI
|
|
OR CX,CX
|
|
JNZ GETBUF
|
|
OR AL,1 ;Clear zero flag--not end of file
|
|
ENDRDCON:
|
|
MOV [CONTPOS],SI
|
|
ENDRDDEV:
|
|
MOV [NEXTADD],DI
|
|
POP ES
|
|
JNZ SETFCBJ ;Zero set if Ctrl-Z found in input
|
|
MOV DI,[FCB]
|
|
SEG ES
|
|
OR B,[DI+FILDIRBLK],80H ;Mark as no more data available
|
|
SETFCBJ:
|
|
JMP SETFCB
|
|
|
|
READDEV:
|
|
PUSH ES
|
|
LES DI,[DMAADD]
|
|
OR BL,BL
|
|
JZ READCON
|
|
DEC BL
|
|
JNZ ENDRDDEV
|
|
READAUX:
|
|
CALL BIOSAUXIN,BIOSSEG
|
|
STOB
|
|
CMP AL,1AH
|
|
LOOPNZ READAUX
|
|
JP ENDRDDEV
|
|
|
|
READCON:
|
|
PUSH CS
|
|
POP DS
|
|
MOV SI,[CONTPOS]
|
|
OR SI,SI
|
|
JNZ TRANBUF
|
|
CMP B,[CONBUF],128
|
|
JZ GETBUF
|
|
MOV [CONBUF],0FF80H ;Set up 128-byte buffer with no template
|
|
GETBUF:
|
|
PUSH CX
|
|
PUSH ES
|
|
PUSH DI
|
|
MOV DX,CONBUF
|
|
CALL BUFIN ;Get input buffer
|
|
POP DI
|
|
POP ES
|
|
POP CX
|
|
MOV SI,CONBUF+2
|
|
CMP B,[SI],1AH ;Check for Ctrl-Z in first character
|
|
JNZ TRANBUF
|
|
MOV AL,1AH
|
|
STOB
|
|
MOV AL,10
|
|
CALL OUT ;Send linefeed
|
|
XOR SI,SI
|
|
JP ENDRDCON
|
|
|
|
RDERR:
|
|
XOR CX,CX
|
|
JMP WRTERR
|
|
|
|
RDLASTJ:JMP RDLAST
|
|
|
|
LOAD:
|
|
|
|
; Inputs:
|
|
; DS:DI point to FCB
|
|
; DX:AX = Position in file to read
|
|
; CX = No. of records to read
|
|
; Outputs:
|
|
; DX:AX = Position of last record read
|
|
; CX = No. of bytes read
|
|
; ES:DI point to FCB
|
|
; LSTCLUS, CLUSPOS fields in FCB set
|
|
|
|
CALL SETUP
|
|
SEG ES
|
|
MOV BX,[DI+FILDIRBLK]
|
|
CMP BH,-1 ;Check for named device I/O
|
|
JZ READDEV
|
|
SEG ES
|
|
MOV AX,[DI+FILSIZ]
|
|
SEG ES
|
|
MOV BX,[DI+FILSIZ+2]
|
|
SUB AX,[BYTPOS]
|
|
SBC BX,[BYTPOS+2]
|
|
JB RDERR
|
|
JNZ ENUF
|
|
OR AX,AX
|
|
JZ RDERR
|
|
CMP AX,CX
|
|
JAE ENUF
|
|
MOV CX,AX
|
|
ENUF:
|
|
CALL BREAKDOWN
|
|
MOV CX,[CLUSNUM]
|
|
CALL FNDCLUS
|
|
OR CX,CX
|
|
JNZ RDERR
|
|
MOV [LASTPOS],DX
|
|
MOV [CLUSNUM],BX
|
|
CMP [BYTCNT1],0
|
|
JZ RDMID
|
|
CALL BUFRD
|
|
RDMID:
|
|
CMP [SECCNT],0
|
|
JZ RDLASTJ
|
|
CALL NEXTSEC
|
|
JC SETFCB
|
|
MOV B,[TRANS],1 ;A transfer is taking place
|
|
ONSEC:
|
|
MOV DL,[SECCLUSPOS]
|
|
MOV CX,[SECCNT]
|
|
MOV BX,[CLUSNUM]
|
|
RDLP:
|
|
CALL OPTIMIZE
|
|
PUSH DI
|
|
PUSH AX
|
|
PUSH DS
|
|
MOV DS,[DMAADD+2]
|
|
CALL DREAD
|
|
POP DS
|
|
POP CX
|
|
POP BX
|
|
JCXZ RDLAST
|
|
CMP BX,0FF8H
|
|
JAE SETFCB
|
|
MOV DL,0
|
|
INC [LASTPOS] ;We'll be using next cluster
|
|
JP RDLP
|
|
|
|
SETFCB:
|
|
MOV SI,[FCB]
|
|
MOV AX,[NEXTADD]
|
|
MOV DI,AX
|
|
SUB AX,[DMAADD] ;Number of bytes transfered
|
|
XOR DX,DX
|
|
SEG ES
|
|
MOV CX,[SI+RECSIZ]
|
|
DIV AX,CX ;Number of records
|
|
CMP AX,[RECCNT] ;Check if all records transferred
|
|
JZ FULLREC
|
|
MOV B,[DSKERR],1
|
|
OR DX,DX
|
|
JZ FULLREC ;If remainder 0, then full record transfered
|
|
MOV B,[DSKERR],3 ;Flag partial last record
|
|
SUB CX,DX ;Bytes left in last record
|
|
PUSH ES
|
|
MOV ES,[DMAADD+2]
|
|
XCHG AX,BX ;Save the record count temporarily
|
|
XOR AX,AX ;Fill with zeros
|
|
SHR CX
|
|
JNC EVENFIL
|
|
STOB
|
|
EVENFIL:
|
|
REP
|
|
STOW
|
|
XCHG AX,BX ;Restore record count to AX
|
|
POP ES
|
|
INC AX ;Add last (partial) record to total
|
|
FULLREC:
|
|
MOV CX,AX
|
|
MOV DI,SI ;ES:DI point to FCB
|
|
SETCLUS:
|
|
MOV AX,[CLUSNUM]
|
|
SEG ES
|
|
MOV [DI+LSTCLUS],AX
|
|
MOV AX,[LASTPOS]
|
|
SEG ES
|
|
MOV [DI+CLUSPOS],AX
|
|
ADDREC:
|
|
MOV AX,[RECPOS]
|
|
MOV DX,[RECPOS+2]
|
|
DEC CX
|
|
ADD AX,CX ;Update current record position
|
|
ADC DX,0
|
|
INC CX
|
|
RET
|
|
|
|
RDLAST:
|
|
MOV AX,[BYTCNT2]
|
|
OR AX,AX
|
|
JZ SETFCB
|
|
MOV [BYTCNT1],AX
|
|
CALL NEXTSEC
|
|
JC SETFCB
|
|
MOV [BYTSECPOS],0
|
|
CALL BUFRD
|
|
JP SETFCB
|
|
|
|
WRTDEV:
|
|
PUSH DS
|
|
LDS SI,[DMAADD]
|
|
AND BL,7FH
|
|
OR BL,BL
|
|
JZ WRTCON
|
|
DEC BL
|
|
JZ WRTAUX
|
|
WRTLST:
|
|
LODB
|
|
CMP AL,1AH
|
|
JZ ENDWRDEV
|
|
CALL BIOSPRINT,BIOSSEG
|
|
LOOP WRTLST
|
|
JP ENDWRDEV
|
|
|
|
WRTAUX:
|
|
LODB
|
|
CALL BIOSAUXOUT,BIOSSEG
|
|
CMP AL,1AH
|
|
LOOPNZ WRTAUX
|
|
JP ENDWRDEV
|
|
|
|
WRTCON:
|
|
LODB
|
|
CMP AL,1AH
|
|
JZ ENDWRDEV
|
|
CALL OUT
|
|
LOOP WRTCON
|
|
ENDWRDEV:
|
|
POP DS
|
|
MOV CX,[RECCNT]
|
|
MOV DI,[FCB]
|
|
JP ADDREC
|
|
|
|
HAVSTART:
|
|
MOV CX,AX
|
|
CALL SKPCLP
|
|
JCXZ DOWRTJ
|
|
CALL ALLOCATE
|
|
JNC DOWRTJ
|
|
WRTERR:
|
|
MOV B,[DSKERR],1
|
|
LVDSK:
|
|
MOV AX,[RECPOS]
|
|
MOV DX,[RECPOS+2]
|
|
MOV DI,[FCB]
|
|
RET
|
|
|
|
DOWRTJ: JMP DOWRT
|
|
|
|
WRTEOFJ:
|
|
JMP WRTEOF
|
|
|
|
STORE:
|
|
|
|
; Inputs:
|
|
; DS:DI point to FCB
|
|
; DX:AX = Position in file of disk transfer
|
|
; CX = Record count
|
|
; Outputs:
|
|
; DX:AX = Position of last record written
|
|
; CX = No. of records written
|
|
; ES:DI point to FCB
|
|
; LSTCLUS, CLUSPOS fields in FCB set
|
|
|
|
MOV B,[DI+DIRTYFIL],1
|
|
SEG CS
|
|
MOV BX,[DATE]
|
|
MOV [DI+FDATE],BX
|
|
CALL SETUP
|
|
SEG ES
|
|
MOV BX,[DI+FILDIRBLK]
|
|
CMP BH,-1
|
|
JZ WRTDEV
|
|
CALL BREAKDOWN
|
|
MOV AX,[BYTPOS]
|
|
MOV DX,[BYTPOS+2]
|
|
JCXZ WRTEOFJ
|
|
DEC CX
|
|
ADD AX,CX
|
|
ADC DX,0 ;AX:DX=last byte accessed
|
|
DIV AX,[BP+SECSIZ] ;AX=last sector accessed
|
|
MOV CL,[BP+CLUSSHFT]
|
|
SHR AX,CL ;Last cluster to be accessed
|
|
PUSH AX
|
|
SEG ES
|
|
MOV AX,[DI+FILSIZ]
|
|
SEG ES
|
|
MOV DX,[DI+FILSIZ]
|
|
DIV AX,[BP+SECSIZ]
|
|
OR DX,DX
|
|
JZ NORNDUP
|
|
INC AX ;Round up if any remainder
|
|
NORNDUP:
|
|
MOV [VALSEC],AX ;Number of sectors that have been written
|
|
POP AX
|
|
MOV CX,[CLUSNUM] ;First cluster accessed
|
|
CALL FNDCLUS
|
|
MOV [CLUSNUM],BX
|
|
MOV [LASTPOS],DX
|
|
SUB AX,DX ;Last cluster minus current cluster
|
|
JZ DOWRT ;If we have last clus, we must have first
|
|
JCXZ HAVSTART
|
|
PUSH CX ;No. of clusters short of first
|
|
MOV CX,AX
|
|
CALL ALLOCATE
|
|
POP AX
|
|
JC WRTERR
|
|
MOV CX,AX
|
|
MOV DX,[LASTPOS]
|
|
INC DX
|
|
DEC CX
|
|
JZ NOSKIP
|
|
CALL SKPCLP
|
|
NOSKIP:
|
|
MOV [CLUSNUM],BX
|
|
MOV [LASTPOS],DX
|
|
DOWRT:
|
|
CMP [BYTCNT1],0
|
|
JZ WRTMID
|
|
MOV BX,[CLUSNUM]
|
|
CALL BUFWRT
|
|
WRTMID:
|
|
MOV AX,[SECCNT]
|
|
OR AX,AX
|
|
JZ WRTLAST
|
|
ADD [SECPOS],AX
|
|
CALL NEXTSEC
|
|
MOV B,[TRANS],1 ;A transfer is taking place
|
|
MOV DL,[SECCLUSPOS]
|
|
MOV BX,[CLUSNUM]
|
|
MOV CX,[SECCNT]
|
|
WRTLP:
|
|
CALL OPTIMIZE
|
|
PUSH DI
|
|
PUSH AX
|
|
PUSH DS
|
|
MOV DS,[DMAADD+2]
|
|
CALL DWRITE
|
|
POP DS
|
|
POP CX
|
|
POP BX
|
|
JCXZ WRTLAST
|
|
MOV DL,0
|
|
INC [LASTPOS] ;We'll be using next cluster
|
|
JP WRTLP
|
|
WRTLAST:
|
|
MOV AX,[BYTCNT2]
|
|
OR AX,AX
|
|
JZ FINWRT
|
|
MOV [BYTCNT1],AX
|
|
CALL NEXTSEC
|
|
MOV [BYTSECPOS],0
|
|
CALL BUFWRT
|
|
FINWRT:
|
|
MOV AX,[NEXTADD]
|
|
SUB AX,[DMAADD]
|
|
ADD AX,[BYTPOS]
|
|
MOV DX,[BYTPOS+2]
|
|
ADC DX,0
|
|
MOV CX,DX
|
|
MOV DI,[FCB]
|
|
SEG ES
|
|
CMP AX,[DI+FILSIZ]
|
|
SEG ES
|
|
SBB CX,[DI+FILSIZ+2]
|
|
JB SAMSIZ
|
|
SEG ES
|
|
MOV [DI+FILSIZ],AX
|
|
SEG ES
|
|
MOV [DI+FILSIZ+2],DX
|
|
SAMSIZ:
|
|
MOV CX,[RECCNT]
|
|
JMP SETCLUS
|
|
|
|
|
|
WRTERRJ:JMP WRTERR
|
|
|
|
WRTEOF:
|
|
MOV CX,AX
|
|
OR CX,DX
|
|
JZ KILLFIL
|
|
SUB AX,1
|
|
SBC DX,0
|
|
DIV AX,[BP+SECSIZ]
|
|
MOV CL,[BP+CLUSSHFT]
|
|
SHR AX,CL
|
|
MOV CX,AX
|
|
CALL FNDCLUS
|
|
JCXZ RELFILE
|
|
CALL ALLOCATE
|
|
JC WRTERRJ
|
|
UPDATE:
|
|
MOV DI,[FCB]
|
|
MOV AX,[BYTPOS]
|
|
SEG ES
|
|
MOV [DI+FILSIZ],AX
|
|
MOV AX,[BYTPOS+2]
|
|
SEG ES
|
|
MOV [DI+FILSIZ+2],AX
|
|
XOR CX,CX
|
|
RET
|
|
|
|
RELFILE:
|
|
MOV DX,0FFFH
|
|
CALL RELBLKS
|
|
SETDIRT:
|
|
MOV B,[BP+DIRTYFAT],1
|
|
JP UPDATE
|
|
|
|
KILLFIL:
|
|
XOR BX,BX
|
|
SEG ES
|
|
XCHG BX,[DI+FIRCLUS]
|
|
OR BX,BX
|
|
JZ UPDATE
|
|
CALL RELEASE
|
|
JP SETDIRT
|
|
|
|
|
|
OPTIMIZE:
|
|
|
|
; Inputs:
|
|
; DS = CS
|
|
; BX = Physical cluster
|
|
; CX = No. of records
|
|
; DL = sector 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 sector 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 sectors per cluster
|
|
MOV AH,AL
|
|
SUB AL,DL ;AL = Number of sectors left in first cluster
|
|
MOV DX,CX
|
|
LEA SI,[BP+FAT]
|
|
MOV CX,0
|
|
OPTCLUS:
|
|
;AL has number of sectors available in current cluster
|
|
;AH has number of sectors available in next cluster
|
|
;BX has current physical cluster
|
|
;CX has number of sequential sectors found so far
|
|
;DX has number of sectors 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 sectors still needed
|
|
PUSH DX
|
|
MOV AX,CX
|
|
MUL AX,[BP+SECSIZ] ;Number of sectors times sector size
|
|
MOV SI,[NEXTADD]
|
|
ADD AX,SI ;Adjust by size of transfer
|
|
MOV [NEXTADD],AX
|
|
POP AX ;Number of sectors still needed
|
|
POP DX ;Starting cluster
|
|
SUB BX,DX ;Number of new clusters accessed
|
|
ADD [LASTPOS],BX
|
|
POP BX ;BL = sector postion within cluster
|
|
CALL FIGREC
|
|
MOV BX,SI
|
|
RET
|
|
BLKDON:
|
|
SUB CX,DX ;Number of sectors in cluster we don't want
|
|
SUB AH,CL ;Number of sectors in cluster we accepted
|
|
DEC AH ;Adjust to mean position within cluster
|
|
MOV [SECCLUSPOS],AH
|
|
MOV CX,DX ;Anyway, make the total equal to the request
|
|
JP FINCLUS
|
|
|
|
|
|
FIGREC:
|
|
|
|
;Inputs:
|
|
; DX = Physical cluster number
|
|
; BL = Sector postion within cluster
|
|
; BP = Base of drive parameters
|
|
;Outputs:
|
|
; DX = physical sector number
|
|
;No other registers affected.
|
|
|
|
PUSH CX
|
|
MOV CL,[BP+CLUSSHFT]
|
|
DEC DX
|
|
DEC DX
|
|
SHL DX,CL
|
|
OR DL,BL
|
|
ADD DX,[BP+FIRREC]
|
|
POP CX
|
|
RET
|
|
|
|
GETREC:
|
|
|
|
; Inputs:
|
|
; DS:DX point to FCB
|
|
; Outputs:
|
|
; CX = 1
|
|
; DX:AX = Record number determined by EXTENT and NR fields
|
|
; DS:DI point to FCB
|
|
; No other registers affected.
|
|
|
|
MOV DI,DX
|
|
MOV CX,1
|
|
MOV AL,[DI+NR]
|
|
MOV DX,[DI+EXTENT]
|
|
SHL AL
|
|
SHR DX
|
|
RCR AL
|
|
MOV AH,DL
|
|
MOV DL,DH
|
|
MOV DH,0
|
|
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 bit
|
|
; FIRCLUS field of FCB set if file was null
|
|
; SI,BP unchanged. All other registers destroyed.
|
|
|
|
PUSH [SI]
|
|
PUSH DX
|
|
PUSH CX
|
|
PUSH BX
|
|
MOV AX,BX
|
|
ALLOC:
|
|
MOV DX,BX
|
|
FINDFRE:
|
|
INC BX
|
|
CMP BX,[BP+MAXCLUS]
|
|
JLE TRYOUT
|
|
CMP AX,1
|
|
JG TRYIN
|
|
POP BX
|
|
MOV DX,0FFFH
|
|
CALL RELBLKS
|
|
POP AX ;No. of clusters requested
|
|
SUB AX,CX ;AX=No. of clusters allocated
|
|
POP DX
|
|
POP [SI]
|
|
INC DX ;Position of first cluster allocated
|
|
ADD AX,DX ;AX=max no. of cluster in file
|
|
MOV DL,[BP+CLUSMSK]
|
|
MOV DH,0
|
|
INC DX ;DX=records/cluster
|
|
MUL AX,DX ;AX=max no. of records in file
|
|
MOV CX,AX
|
|
SUB CX,[RECPOS] ;CX=max no. of records that could be written
|
|
JA MAXREC
|
|
XOR CX,CX ;If CX was negative, zero it
|
|
MAXREC:
|
|
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
|
|
POP CX ;Don't need this stuff since we're successful
|
|
POP DX
|
|
CALL UNPACK
|
|
POP [SI]
|
|
XCHG BX,DI
|
|
OR DI,DI
|
|
JNZ RET
|
|
MOV DI,[FCB]
|
|
SEG ES
|
|
MOV [DI+FIRCLUS],BX
|
|
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,0FF8H
|
|
MOV BX,AX
|
|
JB 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,0FF8H
|
|
JAE RET
|
|
MOV BX,DI
|
|
JP GETEOF
|
|
|
|
|
|
SRCHFRST: ;System call 17
|
|
PUSH DX
|
|
PUSH DS
|
|
CALL GETFILE
|
|
SAVPLCE:
|
|
; Search-for-next enters here to save place and report
|
|
; findings.
|
|
POP ES
|
|
POP DI
|
|
JC KILLSRCH
|
|
CMP BH,-1
|
|
JZ SRCHDEV
|
|
MOV AX,[LASTENT]
|
|
SEG ES
|
|
MOV [DI+FILDIRBLK],AX
|
|
;Information in directory entry must be copied into the first
|
|
; 33 bytes starting at the disk transfer address.
|
|
MOV SI,BX
|
|
LES DI,[DMAADD]
|
|
MOV AL,[BP+DRVNUM]
|
|
INC AL
|
|
STOB ;Set drive number
|
|
MOVB ;Copy first character of name
|
|
MOV CX,5
|
|
REP
|
|
MOVW ;Copy remaining 10 characters of name
|
|
XOR AX,AX
|
|
|
|
IF SMALLDIR
|
|
CMP B,[BP+DIRSIZ],-1
|
|
JNZ BIGENT5
|
|
STOB ;Zero out unused portion
|
|
MOV CX,7
|
|
REP
|
|
STOW ;Zero a total of 15 bytes
|
|
MOVW ;Copy first cluster pointer
|
|
MOVW ;Copy low word of length
|
|
MOVB ;Copy 3rd byte of length
|
|
STOB ;4th byte of length must be zero
|
|
RET
|
|
BIGENT5:
|
|
ENDIF
|
|
|
|
MOV CX,10
|
|
REP
|
|
MOVW
|
|
MOVB
|
|
RET
|
|
|
|
KILLSRCH:
|
|
SEG ES
|
|
KILLSRCH1:
|
|
MOV [DI+FILDIRBLK],-2
|
|
MOV AL,-1
|
|
RET
|
|
|
|
SRCHDEV:
|
|
SEG ES
|
|
MOV [DI+FILDIRBLK],BX
|
|
LES DI,[DMAADD]
|
|
XOR AX,AX
|
|
STOB ;Zero drive byte
|
|
SUB SI,3 ;Point to device name
|
|
MOVW
|
|
MOVB
|
|
MOV AX,2020H
|
|
MOV CX,4
|
|
REP
|
|
STOW ;Fill with 8 blanks
|
|
XOR AX,AX
|
|
MOV CX,10
|
|
REP
|
|
STOW
|
|
STOB
|
|
RET
|
|
|
|
SRCHNXT: ;System call 18
|
|
CALL MOVNAME
|
|
MOV DI,DX
|
|
JC KILLSRCH1
|
|
PUSH DX
|
|
PUSH DS
|
|
MOV AX,[DI+FILDIRBLK]
|
|
PUSH CS
|
|
POP DS
|
|
MOV [LASTENT],AX
|
|
CALL CONTSRCH
|
|
JMP SAVPLCE
|
|
|
|
|
|
FILESIZE: ;System call 35
|
|
PUSH DS
|
|
PUSH DX
|
|
CALL GETFILE
|
|
POP DI
|
|
POP ES
|
|
MOV AL,-1
|
|
JC RET
|
|
ADD DI,33 ;Write size in RR field
|
|
SEG ES
|
|
MOV CX,[DI-33+RECSIZ]
|
|
OR CX,CX
|
|
JNZ RECOK
|
|
MOV CX,128
|
|
RECOK:
|
|
XOR AX,AX
|
|
XOR DX,DX ;Intialize size to zero
|
|
CMP BH,-1 ;Check for named I/O device
|
|
JZ DEVSIZ
|
|
INC SI
|
|
INC SI ;Point to length field
|
|
MOV AX,[SI+2] ;Get high word of size
|
|
|
|
IF SMALLDIR
|
|
CMP B,[BP+DIRSIZ],-1
|
|
JNZ BIGSIZ
|
|
MOV AH,0
|
|
BIGSIZ:
|
|
ENDIF
|
|
|
|
DIV AX,CX
|
|
PUSH AX ;Save high part of result
|
|
LODW ;Get low word of size
|
|
DIV AX,CX
|
|
OR DX,DX ;Check for zero remainder
|
|
POP DX
|
|
JZ DEVSIZ
|
|
INC AX ;Round up for partial record
|
|
JNZ DEVSIZ ;Propagate carry?
|
|
INC DX
|
|
DEVSIZ:
|
|
STOW
|
|
MOV AX,DX
|
|
STOB
|
|
MOV AL,0
|
|
CMP CX,64
|
|
JAE RET ;Only 3-byte field if RECSIZ >= 64
|
|
SEG ES
|
|
MOV [DI],AH
|
|
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 BP,[CURDRVPT]
|
|
CALL FATREAD
|
|
LEA BX,[BP+FAT]
|
|
MOV AL,[BP+CLUSMSK]
|
|
INC AL
|
|
MOV DX,[BP+MAXCLUS]
|
|
DEC DX
|
|
MOV B,[BP+DIRTYFAT],1
|
|
MOV CX,[BP+SECSIZ]
|
|
LDS SI,[SPSAVE]
|
|
MOV [SI+BXSAVE],BX
|
|
MOV [SI+DXSAVE],DX
|
|
MOV [SI+CXSAVE],CX
|
|
MOV [SI+DSSAVE],CS
|
|
RET
|
|
|
|
|
|
GETDSKPT: ;System call 31
|
|
SEG CS
|
|
MOV BX,[CURDRVPT]
|
|
SEG CS
|
|
LDS SI,[SPSAVE]
|
|
MOV [SI+BXSAVE],BX
|
|
MOV [SI+DSSAVE],CS
|
|
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 AX,[BUFDRVNO]
|
|
OR AH,AH
|
|
JZ RET
|
|
CBW
|
|
MOV BX,AX
|
|
SHL BX
|
|
MOV BP,[BX+DRVTAB]
|
|
MOV B,[DIRTYBUF],0
|
|
MOV DX,[BUFSECNO]
|
|
MOV BX,BUFFER
|
|
MOV CX,1
|
|
JMP DWRITE
|
|
|
|
|
|
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
|
|
CMP B,[BP+DIRTYFAT],-1 ;Carry set if not equal
|
|
RCL BX
|
|
LOOP CHKUSE
|
|
MOV AL,BL
|
|
RET
|
|
|
|
|
|
SETRNDREC: ;System call 36
|
|
CALL GETREC
|
|
MOV [DI+33],AX
|
|
MOV [DI+35],DL
|
|
RET
|
|
|
|
|
|
SELDSK: ;System call 14
|
|
MOV DH,0
|
|
MOV BX,DX
|
|
PUSH CS
|
|
POP DS
|
|
MOV AL,[NUMDRV]
|
|
CMP BL,AL
|
|
JNB RET
|
|
SHL BX
|
|
MOV DX,[BX+CURDRVPT+2]
|
|
MOV [CURDRVPT],DX
|
|
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 BUFOUT
|
|
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
|
|
SEG CS ;To work in init
|
|
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
|
|
SEG CS
|
|
MOV AL,[STARTPOS]
|
|
CALL TAB
|
|
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 OUT
|
|
MOV AL,8
|
|
JMP OUT
|
|
|
|
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 BUFOUT
|
|
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
|
|
|
|
BUFOUT:
|
|
CMP AL," "
|
|
JAE OUT
|
|
CMP AL,9
|
|
JZ OUT
|
|
PUSH AX
|
|
MOV AL,"^"
|
|
CALL OUT
|
|
POP AX
|
|
OR AL,40H
|
|
JP OUT
|
|
|
|
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
|
|
; Ctrl-C handler.
|
|
; If function 9 or 10 was in progress, a backslash, CR, and LF are printed
|
|
; to show line is canceled. Then the user registers are restored and the
|
|
; user CTRL-C handler is executed. At this point the top of the stack has
|
|
; 1) the interrupt return address should the user CTRL-C handler wish to
|
|
; allow processing to continue; 2) the original interrupt return address
|
|
; to the code that performed the function call in the first place. If the
|
|
; user CTRL-C handler wishes to continue, it must leave all registers
|
|
; unchanged and IRET. The function that was interrupted will simply be
|
|
; repeated, except for console output (function 2), which has already output
|
|
; its character before the interrupt.
|
|
SEG CS
|
|
MOV AL,[FUNC] ;Get currently executing function
|
|
CMP AL,10 ;Check if buffered line input
|
|
JZ CANLIN
|
|
CMP AL,9 ;Check if buffered line output
|
|
JNZ RESTREG
|
|
CANLIN:
|
|
MOV AL,"\" ;Display cancel line symbol
|
|
CALL OUT
|
|
CALL CRLF
|
|
RESTREG:
|
|
DI ;Prepare to play with stack
|
|
SEG CS
|
|
MOV SS,[SSSAVE]
|
|
SEG CS
|
|
MOV SP,[SPSAVE] ;User stack now restored
|
|
POP AX
|
|
POP BX
|
|
POP CX
|
|
POP DX
|
|
POP SI
|
|
POP DI
|
|
POP BP
|
|
POP DS
|
|
POP ES ;User registers now restored
|
|
INT CONTC ;Execute user Ctrl-C handler
|
|
CMP AH,2 ;Check if function was console output
|
|
JZ SETAL
|
|
JMP COMMAND ;Repeat command otherwise
|
|
SETAL:
|
|
MOV AL,DL
|
|
IRET ;Return to user program
|
|
|
|
PRINTON:
|
|
SEG CS
|
|
MOV B,[PFLAG],1
|
|
RET
|
|
PRINTOFF:
|
|
SEG CS
|
|
MOV B,[PFLAG],0
|
|
RET
|
|
CTRLOUT:
|
|
CMP AL,13
|
|
JZ ZERPOS
|
|
CMP AL,8
|
|
JZ BACKPOS
|
|
CMP AL,9
|
|
JNZ OUTCHJ
|
|
SEG CS
|
|
MOV AL,[CARPOS]
|
|
OR AL,0F8H
|
|
NEG AL
|
|
TAB:
|
|
PUSH CX
|
|
MOV CL,AL
|
|
MOV CH,0
|
|
TABLP:
|
|
MOV AL," "
|
|
CALL OUT
|
|
LOOP TABLP
|
|
POP CX
|
|
RET
|
|
|
|
ZERPOS:
|
|
SEG CS
|
|
MOV B,[CARPOS],0
|
|
OUTCHJ: JMP OUTCH
|
|
|
|
BACKPOS:
|
|
SEG CS
|
|
DEC B,[CARPOS]
|
|
JMP OUTCH
|
|
|
|
|
|
CONSTAT: ;System call 11
|
|
CALL BIOSSTAT,BIOSSEG
|
|
JZ RET
|
|
OR AL,-1
|
|
RET
|
|
|
|
|
|
CONIN: ;System call 1
|
|
CALL IN
|
|
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
|
|
RAWINP: ;System call 7
|
|
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
|
|
|
|
|
|
MAKEFCB: ;Interrupt call 41
|
|
MOV DL,0 ;Flag--not ambiguous file name
|
|
OR AL,AL ;Scan off separators if not zero
|
|
JZ NOSCAN
|
|
SCAN:
|
|
CALL GETLET
|
|
JZ SCAN ;Get rid of leading separators (e.g., blanks)
|
|
DEC SI ;Point back to first non-separator
|
|
NOSCAN:
|
|
CMP B,[SI+1],":" ;Check for potential drive specifier
|
|
JNZ DEFAULT
|
|
CALL GETLET
|
|
SUB AL,"@" ;Convert drive letter to binary drive number
|
|
JZ NODRV ;Valid drive numbers are 1-15
|
|
INC SI
|
|
CMP AL,15
|
|
JBE HAVDRV
|
|
DEC SI
|
|
NODRV:
|
|
DEC SI ;Invalid drive specifier--back up pointer
|
|
DEFAULT:
|
|
XOR AL,AL
|
|
HAVDRV:
|
|
STOB ;Put drive specifier in first byte
|
|
MOV CX,8
|
|
CALL GETWORD ;Get 8-letter file name
|
|
CMP B,[SI],"."
|
|
JNZ NODOT
|
|
INC SI ;Skip over dot if present
|
|
NODOT:
|
|
MOV CX,3 ;Get 3-letter extension
|
|
CALL GETWORD
|
|
SEG CS
|
|
LDS BX,[SPSAVE]
|
|
MOV [BX+SISAVE],SI
|
|
XOR AX,AX
|
|
STOW
|
|
STOW
|
|
MOV AL,DL
|
|
RET
|
|
|
|
GETWORD:
|
|
CALL GETLET
|
|
JZ FILLNAM ;Exit if invalid character
|
|
CMP AL," "
|
|
JBE FILLNAM
|
|
CMP AL,"*" ;Check for ambiguous file specifier
|
|
JNZ NOSTAR
|
|
MOV AL,"?"
|
|
DEC CX
|
|
REP
|
|
STOB ;Fill rest of word with "?"
|
|
INC CX
|
|
NOSTAR:
|
|
STOB
|
|
CMP AL,"?"
|
|
JNZ NOTQ
|
|
MOV DL,1 ;Flag ambiguous file name
|
|
NOTQ:
|
|
LOOP GETWORD
|
|
INC SI ;Point to "termination" character
|
|
FILLNAM:
|
|
MOV AL," "
|
|
REP
|
|
STOB
|
|
DEC SI
|
|
RET
|
|
|
|
GETLET:
|
|
LODB
|
|
CMP AL,"a"
|
|
JB CHK
|
|
CMP AL,"z"
|
|
JA CHK
|
|
SUB AL,20H ;Convert to upper case
|
|
CHK:
|
|
CMP AL," "
|
|
JZ RET
|
|
CMP AL,"="
|
|
JZ RET
|
|
CMP AL,","
|
|
JZ RET
|
|
CMP AL,";"
|
|
JZ RET
|
|
CMP AL,"."
|
|
JZ RET
|
|
CMP AL,":"
|
|
JZ RET
|
|
CMP AL,9 ;Filter out TABs too
|
|
RET
|
|
|
|
|
|
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
|
|
|
|
|
|
; Default handler for division overflow trap
|
|
DIVOV:
|
|
XOR DX,DX ;Say no remainder
|
|
MOV AX,-1 ;But large quotient
|
|
IRET
|
|
|
|
|
|
;***** 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,"$"
|
|
IONAME: DB "PRN","LST","AUX","CON"
|
|
|
|
CARPOS: DB 0
|
|
STARTPOS:DB 0
|
|
PFLAG: DB 0
|
|
DIRTYDIR:DB 0 ;Dirty buffer flag
|
|
NUMDRV: DS 1 ;Number of drives
|
|
CONTPOS:DW 0
|
|
DMAADD: DW 80H ;User's disk transfer address (disp/seg)
|
|
DS 2
|
|
ENDMEM: DS 2
|
|
MAXSEC: DW 0
|
|
BUFFER: DS 2
|
|
BUFSECNO:DW 0
|
|
BUFDRVNO:DB -1
|
|
DIRTYBUF:DB 0
|
|
DIRBUFID:DW -1
|
|
DATE: DS 2
|
|
CURDRVPT:DS 2
|
|
DRVTAB: DS 30 ;Enough for 15 drives
|
|
INBUF: DS 15 ;Only the first part
|
|
|
|
; Init code overlaps with data area below
|
|
|
|
INITCODE:
|
|
|
|
DS 128-15 ;More of INBUF
|
|
CONBUF: DS 130 ;The rest of INBUF and console buffer
|
|
FUNC: DS 1 ;Currently executing function code
|
|
LASTENT:DS 2
|
|
EXITHOLD:DS 4
|
|
FATBASE:DS 2
|
|
NAME1: DS 11 ;File name buffer
|
|
NAME2: DS 11
|
|
TEMP:
|
|
CSLOC: DS 2
|
|
SPSAVE: DS 2
|
|
SSSAVE: DS 2
|
|
SECCLUSPOS:DS 1 ;Position of first sector within cluster
|
|
DSKERR: DS 1
|
|
TRANS: DS 1
|
|
|
|
ALIGN
|
|
FCB: DS 2 ;Address of user FCB
|
|
NEXTADD:DS 2
|
|
RECPOS: DS 4
|
|
RECCNT: DS 2
|
|
LASTPOS:DS 2
|
|
CLUSNUM:DS 2
|
|
SECPOS: DS 2 ;Position of first sector accessed
|
|
VALSEC: DS 2 ;Number of valid (previously written) sectors
|
|
BYTSECPOS:DS 2 ;Position of first byte within sector
|
|
BYTPOS: DS 4 ;Byte position in file of access
|
|
BYTCNT1:DS 2 ;No. of bytes in first sector
|
|
BYTCNT2:DS 2 ;No. of bytes in last sector
|
|
SECCNT: DS 2 ;No. of whole sectors
|
|
|
|
DS 60 ;Stack space
|
|
STACK:
|
|
|
|
IF DSKTEST
|
|
NSS: DS 2
|
|
NSP: DS 2
|
|
DS 60
|
|
TESTSTK:
|
|
ENDIF
|
|
|
|
DIRBUF:
|
|
|
|
;Init code below overlaps with data area above
|
|
|
|
ORG INITCODE
|
|
PUT $+100H
|
|
|
|
MOVFAT:
|
|
;This section of code is safe from being overwritten by block move
|
|
SEG ES
|
|
REP
|
|
MOVB
|
|
UP
|
|
FININIT:
|
|
CALL SETMEM ;Set up segment
|
|
RET L
|
|
|
|
DOSINIT:
|
|
DI
|
|
UP
|
|
PUSH CS
|
|
POP ES
|
|
LODB
|
|
SEG ES
|
|
MOV [NUMDRV],AL
|
|
MOV BX,DRVTAB
|
|
MOV DI,MEMSTRT
|
|
PERDRV:
|
|
SEG ES
|
|
MOV [BX],DI
|
|
MOV BP,DI
|
|
INC BX
|
|
INC BX
|
|
SEG ES
|
|
MOV AL,[DRVCNT]
|
|
STOB ;DRVNUM
|
|
LODW ;Pointer to DPT
|
|
PUSH SI
|
|
MOV SI,AX
|
|
LODW
|
|
STOW ;SECSIZ
|
|
MOV DX,AX
|
|
SEG ES
|
|
CMP AX,[MAXSEC]
|
|
JBE NOTMAX
|
|
SEG ES
|
|
MOV [MAXSEC],AX
|
|
NOTMAX:
|
|
LODB
|
|
DEC AL
|
|
STOB ;CLUSMSK
|
|
JZ HAVSHFT
|
|
CBW
|
|
FIGSHFT:
|
|
INC AH
|
|
SAR AL
|
|
JNZ FIGSHFT
|
|
MOV AL,AH
|
|
HAVSHFT:
|
|
STOB ;CLUSSHFT
|
|
MOVW ;FIRFAT (= number of reserved sectors)
|
|
MOVB ;FATCNT
|
|
MOVW ;MAXENT
|
|
MOV AX,DX ;SECSIZ again
|
|
MOV CL,5
|
|
SHR AX,CL
|
|
MOV CX,AX ;Directory entries per sector
|
|
DEC AX
|
|
SEG ES
|
|
ADD AX,[BP+MAXENT]
|
|
XOR DX,DX
|
|
DIV AX,CX
|
|
STOW ;DIRSEC (temporarily)
|
|
SHR AX ;Divide by two
|
|
ADC AX,0 ;Round up
|
|
SEG ES
|
|
MOV [SDIRSEC],AX ;Number of directory records for small entries
|
|
MOVW ;DSKSIZ (temporarily)
|
|
FNDFATSIZ:
|
|
MOV AL,1
|
|
MOV DX,1
|
|
GETFATSIZ:
|
|
PUSH DX
|
|
CALL FIGFATSIZ
|
|
POP DX
|
|
CMP AL,DL ;Compare newly computed FAT size with trial
|
|
JZ HAVFATSIZ ;Has sequence converged?
|
|
CMP AL,DH ;Compare with previous trial
|
|
MOV DH,DL
|
|
MOV DL,AL ;Shuffle trials
|
|
JNZ GETFATSIZ ;Continue iterations if not oscillating
|
|
SEG ES
|
|
DEC [BP+DSKSIZ] ;Damp those oscillations
|
|
JP FNDFATSIZ ;Try again
|
|
HAVFATSIZ:
|
|
STOB ;FATSIZ
|
|
SEG ES
|
|
MUL AL,[BP+FATCNT] ;Space occupied by all FATs
|
|
SEG ES
|
|
ADD AX,[BP+FIRFAT]
|
|
STOW ;FIRDIR
|
|
|
|
IF SMALLDIR-1
|
|
SEG ES
|
|
ADD AX,[BP+DIRSEC]
|
|
SEG ES
|
|
MOV [BP+FIRREC],AX ;Destroys DIRSEC
|
|
CALL FIGMAX
|
|
SEG ES
|
|
MOV [BP+MAXCLUS],CX
|
|
ENDIF
|
|
|
|
IF SMALLDIR
|
|
MOV DX,AX ;Save FIRDIR momentarily
|
|
SEG ES
|
|
ADD AX,[SDIRSEC] ;Add number of dir. sectors for 16-byte entry
|
|
STOW ;FIRREC1
|
|
XCHG AX,CX ;Previously computed MAXCLUS
|
|
STOW ;MAXCLUS1
|
|
XCHG DX,AX
|
|
SEG ES
|
|
ADD AX,[BP+DIRSEC] ;Add number of dir. sectores for 32-byte entry
|
|
STOW ;FIRREC2
|
|
CALL FIGMAX
|
|
XCHG AX,CX
|
|
STOW ;MAXCLUS2
|
|
ENDIF
|
|
|
|
MOV AX,0FFH
|
|
STOB ;DIRTYFAT
|
|
SEG ES
|
|
MOV AL,[BP+FATSIZ]
|
|
SEG ES
|
|
MUL AX,[BP+SECSIZ]
|
|
ADD DI,AX ;Allocate FAT
|
|
POP SI ;Restore pointer to init. table
|
|
SEG ES
|
|
MOV AL,[DRVCNT]
|
|
INC AL
|
|
SEG ES
|
|
MOV [DRVCNT],AL
|
|
SEG ES
|
|
CMP AL,[NUMDRV]
|
|
JAE CONTINIT
|
|
JMP PERDRV
|
|
CONTINIT:
|
|
LODW ;Max. buffer size
|
|
SEG ES
|
|
MOV BX,[MAXSEC]
|
|
MOV AX,DIRBUF
|
|
ADD AX,BX
|
|
SEG ES
|
|
MOV [BUFFER],AX ;Start of buffer
|
|
PUSH DI ;Save ending location
|
|
ADD DI,BX ;Allocate directory buffer
|
|
ADD DI,BX ;Allocate buffer space
|
|
ADD DI,ADJFAC+15 ;True start of free space
|
|
MOV CL,4
|
|
SHR DI,CL ;First free segment
|
|
MOV BP,DI
|
|
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],AX
|
|
MOV [0],DIVOV ;Set default divide trap address
|
|
MOV [2],AX
|
|
MOV CX,9
|
|
REP
|
|
STOW ;Set 5 segments (skip 2 between each)
|
|
MOV [INTBASE+4],COMMAND
|
|
MOV [INTBASE+12],IRET ;CTRL-C exit
|
|
MOV [INTBASE+16],IRET ;Fatal error exit
|
|
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 SI,HEADER
|
|
CALL OUTMES
|
|
PUSH CS
|
|
POP DS
|
|
PUSH CS
|
|
POP ES
|
|
PUSH DX
|
|
GETDAT:
|
|
MOV SI,DATMES
|
|
CALL OUTMES
|
|
MOV DX,DATBUF
|
|
CALL BUFIN
|
|
CALL CRLF
|
|
MOV SI,DATBUF+2
|
|
MOV DX,12
|
|
CALL MYD
|
|
JC GETDAT
|
|
MOV CL,5
|
|
SHL AX,CL
|
|
MOV [DATE],AX
|
|
MOV DX,31
|
|
CALL MYD
|
|
JC GETDAT
|
|
OR [DATE],AL
|
|
MOV DX,2100
|
|
CALL MYD
|
|
JC GETDAT
|
|
SUB AX,80
|
|
JC GETDAT
|
|
CMP AX,19
|
|
JBE SAVYR
|
|
SUB AX,1900
|
|
JC GETDAT
|
|
SAVYR:
|
|
SHL AL
|
|
OR [DATE+1],AL
|
|
;Move the FATs into position and adjust the drive pointer table
|
|
POP DX
|
|
POP SI
|
|
MOV AX,[MAXSEC]
|
|
SHL AX ;Allocate two buffers
|
|
ADD AX,ADJFAC
|
|
JZ FINJMP
|
|
MOV DI,DRVTAB
|
|
MOV CX,15
|
|
ADJLP:
|
|
ADD [DI],AX
|
|
INC DI
|
|
INC DI
|
|
LOOP ADJLP
|
|
MOV CX,SI
|
|
MOV SI,MEMSTRT ;Place to move FATs from
|
|
SUB CX,SI ;Total length of FATs
|
|
MOV DI,AX
|
|
ADD DI,SI ;Place to move FATs to
|
|
OR AX,AX
|
|
JS MOVJMP
|
|
DEC CX
|
|
ADD DI,CX
|
|
ADD SI,CX
|
|
INC CX
|
|
DOWN
|
|
MOVJMP:
|
|
JMP MOVFAT
|
|
FINJMP: JMP FININIT
|
|
|
|
FIGFATSIZ:
|
|
SEG ES
|
|
MUL AL,[BP+FATCNT]
|
|
SEG ES
|
|
ADD AX,[BP+FIRFAT]
|
|
SEG ES
|
|
ADD AX,[SDIRSEC] ;Use small dir. entry to figure FAT size
|
|
FIGMAX:
|
|
;AX has equivalent of FIRREC
|
|
SEG ES
|
|
SUB AX,[BP+DSKSIZ]
|
|
NEG AX
|
|
SEG ES
|
|
MOV CL,[BP+CLUSSHFT]
|
|
SHR AX,CL
|
|
INC AX
|
|
MOV CX,AX ;MAXCLUS
|
|
INC AX
|
|
MOV DX,AX
|
|
SHR DX
|
|
ADC AX,DX ;Size of FAT in bytes
|
|
SEG ES
|
|
MOV SI,[BP+SECSIZ]
|
|
ADD AX,SI
|
|
DEC AX
|
|
XOR DX,DX
|
|
DIV AX,SI
|
|
RET
|
|
|
|
MYD:
|
|
;SI points to input buffer. Get decimal number < DX and return it
|
|
;in AX. Carry set on error.
|
|
XOR BX,BX
|
|
MOV AH,0
|
|
GETDIG:
|
|
LODB
|
|
SUB AL,"0"
|
|
JC CHKRET
|
|
CMP AL,10
|
|
JNC CHKRET
|
|
SHL BX
|
|
MOV CX,BX
|
|
SHL BX
|
|
SHL BX
|
|
ADD BX,CX
|
|
ADD BX,AX
|
|
JP GETDIG
|
|
CHKRET:
|
|
MOV AX,BX
|
|
OR AX,AX
|
|
STC
|
|
JZ RET
|
|
CMP DX,AX
|
|
RET
|
|
|
|
DRVCNT: DB 0
|
|
|
|
DATMES: DB "Enter today's date (m-d-y): $"
|
|
DATBUF: DB 12,8,"04-28-81",13
|
|
DS 5
|
|
|
|
SDIRSEC:DS 2
|
|
|
|
MEMSTRT:
|
|
ADJFAC: EQU DIRBUF-MEMSTRT
|
|
|