mirror of
https://github.com/microsoft/MS-DOS.git
synced 2024-12-01 10:05:48 +00:00
4031 lines
108 KiB
NASM
4031 lines
108 KiB
NASM
; 86-DOS High-performance operating system for the 8086 version 1.25
|
||
; 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
|
||
; 1.01 05/12/81 Fix bug in `STORE'
|
||
; 1.10 07/21/81 Fatal error trapping, NUL device, hidden files, date & time,
|
||
; RENAME fix, general cleanup
|
||
; 1.11 09/03/81 Don't set CURRENT BLOCK to 0 on open; fix SET FILE SIZE
|
||
; 1.12 10/09/81 Zero high half of CURRENT BLOCK after all (CP/M programs don't)
|
||
; 1.13 10/29/81 Fix classic "no write-through" error in buffer handling
|
||
; 1.20 12/31/81 Add time to FCB; separate FAT from DPT; Kill SMALLDIR;
|
||
; Add FLUSH and MAPDEV calls; allow disk mapping in DSKCHG;
|
||
; Lots of smaller improvements
|
||
; 1.21 01/06/82 HIGHMEM switch to run DOS in high memory
|
||
; 1.22 01/12/82 Add VERIFY system call to enable/disable verify after write
|
||
; 1.23 02/11/82 Add defaulting to parser; use variable escape character
|
||
; Don't zero extent field in IBM version (back to 1.01!)
|
||
; 1.24 03/01/82 Restore fcn. 27 to 1.0 level; add fcn. 28
|
||
; 1.25 03/03/82 Put marker (00) at end of directory to speed searches
|
||
;
|
||
; *************************************************************
|
||
|
||
|
||
; 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
|
||
|
||
IF IBM
|
||
ESCCH EQU 0
|
||
CANCEL EQU 1BH ;Cancel with ESC
|
||
TOGLINS EQU TRUE ;One key toggles insert mode
|
||
TOGLPRN EQU TRUE ;One key toggles printer echo
|
||
NUMDEV EQU 6 ;Include "COM1" as I/O device name
|
||
ZEROEXT EQU TRUE
|
||
ELSE
|
||
ESCCH EQU 1BH
|
||
CANCEL EQU "X"-"@" ;Cancel with Ctrl-X
|
||
TOGLINS EQU FALSE ;Separate keys for insert mode on and off
|
||
TOGLPRN EQU FALSE ;Separate keys for printer echo on and off
|
||
NUMDEV EQU 5 ;Number of I/O device names
|
||
ZEROEXT EQU FALSE
|
||
ENDIF
|
||
|
||
MAXCALL EQU 36
|
||
MAXCOM EQU 46
|
||
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
|
||
|
||
FCBLOCK STRUC
|
||
DB 12 DUP (?) ;Drive code and name
|
||
EXTENT DW ?
|
||
RECSIZ DW ? ;Size of record (user settable)
|
||
FILSIZ DW ? ;Size of file in bytes
|
||
DRVBP DW ? ;BP for SEARCH FIRST and SEARCH NEXT
|
||
FDATE DW ? ;Date of last writing
|
||
FTIME DW ? ;Time of last writing
|
||
DEVID DB ? ;Device ID number, bits 0-5
|
||
;bit 7=0 for file, bit 7=1 for I/O device
|
||
;If file, bit 6=0 if dirty
|
||
;If I/O device, bit 6=0 if EOF (input)
|
||
FIRCLUS DW ? ;First cluster of file
|
||
LSTCLUS DW ? ;Last cluster accessed
|
||
CLUSPOS DW ? ;Position of last cluster accessed
|
||
DB ? ;Forces NR to offset 32
|
||
NR DB ? ;Next record
|
||
RR DB 3 DUP (?) ;Random record
|
||
FCBLOCK ENDS
|
||
FILDIRENT = FILSIZ ;Used only by SEARCH FIRST and SEARCH NEXT
|
||
|
||
; 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 1 Attributes. Bits 1 or 2 make file hidden
|
||
; 12 10 Zero field (for expansion)
|
||
; 22 2 Time. Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour
|
||
; 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
|
||
|
||
DPBLOCK STRUC
|
||
DEVNUM DB ? ;I/O driver number
|
||
DRVNUM DB ? ;Physical Unit number
|
||
SECSIZ DW ? ;Size of physical sector in bytes
|
||
CLUSMSK DB ? ;Sectors/cluster - 1
|
||
CLUSSHFT DB ? ;Log2 of sectors/cluster
|
||
FIRFAT DW ? ;Starting record of FATs
|
||
FATCNT DB ? ;Number of FATs for this drive
|
||
MAXENT DW ? ;Number of directory entries
|
||
FIRREC DW ? ;First sector of first cluster
|
||
MAXCLUS DW ? ;Number of clusters on drive + 1
|
||
FATSIZ DB ? ;Number of records occupied by FAT
|
||
FIRDIR DW ? ;Starting record of directory
|
||
FAT DW ? ;Pointer to start of FAT
|
||
DPBLOCK ENDS
|
||
|
||
DPBSIZ EQU 20 ;Size of the structure in bytes
|
||
DIRSEC = FIRREC ;Number of dir. sectors (init temporary)
|
||
DSKSIZ = MAXCLUS ;Size of disk (temp used during init only)
|
||
|
||
;The following are all of the segments used
|
||
;They are declared in the order that they should be placed in the executable
|
||
|
||
CODE SEGMENT
|
||
CODE ENDS
|
||
|
||
CONSTANTS SEGMENT BYTE
|
||
CONSTANTS ENDS
|
||
|
||
DATA SEGMENT WORD
|
||
DATA ENDS
|
||
|
||
DOSGROUP GROUP CODE,CONSTANTS,DATA
|
||
|
||
SEGBIOS SEGMENT
|
||
SEGBIOS ENDS
|
||
|
||
|
||
; BOIS entry point definitions
|
||
|
||
IF IBM
|
||
BIOSSEG EQU 60H
|
||
ENDIF
|
||
IF NOT IBM
|
||
BIOSSEG EQU 40H
|
||
ENDIF
|
||
|
||
SEGBIOS SEGMENT AT BIOSSEG
|
||
ORG 0
|
||
DB 3 DUP (?) ;Reserve room for jump to init code
|
||
BIOSSTAT DB 3 DUP (?) ;Console input status check
|
||
BIOSIN DB 3 DUP (?) ;Get console character
|
||
BIOSOUT DB 3 DUP (?) ;Output console character
|
||
BIOSPRINT DB 3 DUP (?) ;Output to printer
|
||
BIOSAUXIN DB 3 DUP (?) ;Get byte from auxilliary
|
||
BIOSAUXOUT DB 3 DUP (?) ;Output byte to auxilliary
|
||
BIOSREAD DB 3 DUP (?) ;Disk read
|
||
BIOSWRITE DB 3 DUP (?) ;Disk write
|
||
BIOSDSKCHG DB 3 DUP (?) ;Dsik-change status
|
||
BIOSSETDATE DB 3 DUP (?) ;Set date
|
||
BIOSSETTIME DB 3 DUP (?) ;Set time
|
||
BIOSGETTIME DB 3 DUP (?) ;Get time and date
|
||
BIOSFLUSH DB 3 DUP (?) ;Clear console input buffer
|
||
BIOSMAPDEV DB 3 DUP (?) ;Dynamic disk table mapper
|
||
|
||
SEGBIOS ENDS
|
||
; Location of user registers relative user stack pointer
|
||
|
||
STKPTRS STRUC
|
||
AXSAVE DW ?
|
||
BXSAVE DW ?
|
||
CXSAVE DW ?
|
||
DXSAVE DW ?
|
||
SISAVE DW ?
|
||
DISAVE DW ?
|
||
BPSAVE DW ?
|
||
DSSAVE DW ?
|
||
ESSAVE DW ?
|
||
IPSAVE DW ?
|
||
CSSAVE DW ?
|
||
FSAVE DW ?
|
||
STKPTRS ENDS
|
||
|
||
; Start of code
|
||
|
||
CODE SEGMENT
|
||
ASSUME CS:DOSGROUP,DS:DOSGROUP,ES:DOSGROUP,SS:DOSGROUP
|
||
|
||
ORG 0
|
||
CODSTRT EQU $
|
||
JMP DOSINIT
|
||
|
||
ESCCHAR DB ESCCH ;Lead-in character for escape sequences
|
||
ESCTAB:
|
||
IF NOT IBM
|
||
DB "S" ;Copy one char
|
||
DB "V" ;Skip one char
|
||
DB "T" ;Copy to char
|
||
DB "W" ;Skip to char
|
||
DB "U" ;Copy line
|
||
DB "E" ;Kill line (no change in template)
|
||
DB "J" ;Reedit line (new template)
|
||
DB "D" ;Backspace
|
||
DB "P" ;Enter insert mode
|
||
DB "Q" ;Exit insert mode
|
||
DB "R" ;Escape character
|
||
DB "R" ;End of table
|
||
ENDIF
|
||
IF IBM
|
||
DB 64 ;Crtl-Z - F6
|
||
DB 77 ;Copy one char - -->
|
||
DB 59 ;Copy one char - F1
|
||
DB 83 ;Skip one char - DEL
|
||
DB 60 ;Copy to char - F2
|
||
DB 62 ;Skip to char - F4
|
||
DB 61 ;Copy line - F3
|
||
DB 61 ;Kill line (no change to template ) - Not used
|
||
DB 63 ;Reedit line (new template) - F5
|
||
DB 75 ;Backspace - <--
|
||
DB 82 ;Enter insert mode - INS (toggle)
|
||
DB 65 ;Escape character - F7
|
||
DB 65 ;End of table
|
||
ENDIF
|
||
|
||
ESCTABLEN EQU $-ESCTAB
|
||
IF NOT IBM
|
||
HEADER DB 13,10,"MS-DOS version 1.25"
|
||
IF HIGHMEM
|
||
DB "H"
|
||
ENDIF
|
||
IF DSKTEST
|
||
DB "D"
|
||
ENDIF
|
||
|
||
DB 13,10
|
||
DB "Copyright 1981,82 Microsoft, Inc.",13,10,"$"
|
||
ENDIF
|
||
|
||
QUIT:
|
||
MOV AH,0
|
||
JMP SHORT 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
|
||
POP CS:[TEMP] ;IP from the CALL 5
|
||
PUSHF ;Start re-ordering the stack
|
||
CLI
|
||
PUSH AX ;Save segment
|
||
PUSH CS:[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
|
||
MOV AX,CS:[SPSAVE]
|
||
MOV CS:[NSP],AX
|
||
MOV AX,CS:[SSSAVE]
|
||
MOV CS:[NSS],AX
|
||
POP AX
|
||
PUSH AX
|
||
ENDIF
|
||
|
||
MOV CS:[SPSAVE],SP
|
||
MOV CS:[SSSAVE],SS
|
||
MOV SP,CS
|
||
MOV SS,SP
|
||
REDISP:
|
||
MOV SP,OFFSET DOSGROUP:IOSTACK
|
||
STI ;Stack OK now
|
||
MOV BL,AH
|
||
MOV BH,0
|
||
SHL BX,1
|
||
CLD
|
||
CMP AH,12
|
||
JLE SAMSTK
|
||
MOV SP,OFFSET DOSGROUP:DSKSTACK
|
||
SAMSTK:
|
||
CALL CS:[BX+DISPATCH]
|
||
LEAVE:
|
||
CLI
|
||
MOV SP,CS:[SPSAVE]
|
||
MOV SS,CS:[SSSAVE]
|
||
MOV BP,SP
|
||
MOV BYTE PTR [BP.AXSAVE],AL
|
||
|
||
IF DSKTEST
|
||
MOV AX,CS:[NSP]
|
||
MOV CS:[SPSAVE],AX
|
||
MOV AX,CS:[NSS]
|
||
MOV CS:[SSSAVE],AX
|
||
ENDIF
|
||
|
||
POP AX
|
||
POP BX
|
||
POP CX
|
||
POP DX
|
||
POP SI
|
||
POP DI
|
||
POP BP
|
||
POP DS
|
||
POP ES
|
||
IRET
|
||
; Standard Functions
|
||
DISPATCH 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 FLUSHKB
|
||
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
|
||
DW MAKEFCB
|
||
DW GETDATE
|
||
DW SETDATE
|
||
DW GETTIME
|
||
DW SETTIME ;45
|
||
DW VERIFY
|
||
|
||
INUSE:
|
||
GETIO:
|
||
SETIO:
|
||
GETRDONLY:
|
||
SETATTRIB:
|
||
USERCODE:
|
||
MOV AL,0
|
||
RET
|
||
|
||
VERIFY:
|
||
AND AL,1
|
||
MOV CS:VERFLG,AL
|
||
RET
|
||
|
||
FLUSHKB:
|
||
PUSH AX
|
||
CALL FAR PTR BIOSFLUSH
|
||
POP AX
|
||
MOV AH,AL
|
||
CMP AL,1
|
||
JZ REDISPJ
|
||
CMP AL,6
|
||
JZ REDISPJ
|
||
CMP AL,7
|
||
JZ REDISPJ
|
||
CMP AL,8
|
||
JZ REDISPJ
|
||
CMP AL,10
|
||
JZ REDISPJ
|
||
MOV AL,0
|
||
RET
|
||
|
||
REDISPJ:JMP REDISP
|
||
|
||
READER:
|
||
AUXIN:
|
||
CALL STATCHK
|
||
CALL FAR PTR BIOSAUXIN
|
||
RET
|
||
|
||
PUNCH:
|
||
MOV AL,DL
|
||
AUXOUT:
|
||
PUSH AX
|
||
CALL STATCHK
|
||
POP AX
|
||
CALL FAR PTR BIOSAUXOUT
|
||
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,1
|
||
MOV DI,[DI+BX]
|
||
JNC HAVCLUS
|
||
SHR DI,1
|
||
SHR DI,1
|
||
SHR DI,1
|
||
SHR DI,1
|
||
STC
|
||
HAVCLUS:
|
||
RCL BX,1
|
||
AND DI,0FFFH
|
||
RET
|
||
HURTFAT:
|
||
PUSH AX
|
||
MOV AH,80H ;Signal Bad FAT to INT 24H handler
|
||
MOV DI,0FFFH ;In case INT 24H returns (it shouldn't)
|
||
CALL FATAL
|
||
POP AX ;Try to ignore bad FAT
|
||
RET
|
||
|
||
|
||
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,1
|
||
ADD BX,SI
|
||
ADD BX,DI
|
||
SHR DI,1
|
||
MOV DI,[BX]
|
||
JNC ALIGNED
|
||
SHL DX,1
|
||
SHL DX,1
|
||
SHL DX,1
|
||
SHL DX,1
|
||
AND DI,0FH
|
||
JMP SHORT PACKIN
|
||
ALIGNED:
|
||
AND DI,0F000H
|
||
PACKIN:
|
||
OR DI,DX
|
||
MOV [BX],DI
|
||
RET
|
||
|
||
DEVNAME:
|
||
MOV SI,OFFSET DOSGROUP:IONAME ;List of I/O devices with file names
|
||
MOV BH,NUMDEV ;BH = number of device names
|
||
LOOKIO:
|
||
MOV DI,OFFSET DOSGROUP:NAME1
|
||
MOV CX,4 ;All devices are 4 letters
|
||
REPE CMPSB ;Check for name in list
|
||
JZ IOCHK ;If first 3 letters OK, check for the rest
|
||
ADD SI,CX ;Point to next device name
|
||
DEC BH
|
||
JNZ LOOKIO
|
||
CRET:
|
||
STC ;Not found
|
||
RET
|
||
|
||
IOCHK:
|
||
IF IBM
|
||
CMP BH,NUMDEV ;Is it the first device?
|
||
JNZ NOTCOM1
|
||
MOV BH,2 ;Make it the same as AUX
|
||
NOTCOM1:
|
||
ENDIF
|
||
NEG BH
|
||
MOV CX,2 ;Check rest of name but not extension
|
||
MOV AX,2020H
|
||
REPE SCASW ;Make sure rest of name is blanks
|
||
JNZ CRET
|
||
RET1: RET ;Zero set so CREATE works
|
||
|
||
GETFILE:
|
||
; Same as GETNAME except ES:DI points to FCB on successful return
|
||
CALL MOVNAME
|
||
JC RET1
|
||
PUSH DX
|
||
PUSH DS
|
||
CALL FINDNAME
|
||
POP ES
|
||
POP DI
|
||
RET2: 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
|
||
; Zero set if attributes match (always except when creating)
|
||
; 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 RET2 ;Bad file name?
|
||
FINDNAME:
|
||
MOV AX,CS
|
||
MOV DS,AX
|
||
CALL DEVNAME
|
||
JNC RET2
|
||
CALL STARTSRCH
|
||
CONTSRCH:
|
||
CALL GETENTRY
|
||
JC RET2
|
||
SRCH:
|
||
MOV AH,BYTE PTR [BX]
|
||
OR AH,AH ;End of directory?
|
||
JZ FREE
|
||
CMP AH,[DELALL] ;Free entry?
|
||
JZ FREE
|
||
MOV SI,BX
|
||
MOV DI,OFFSET DOSGROUP:NAME1
|
||
MOV CX,11
|
||
WILDCRD:
|
||
REPE CMPSB
|
||
JZ FOUND
|
||
CMP BYTE PTR [DI-1],"?"
|
||
JZ WILDCRD
|
||
NEXTENT:
|
||
CALL NEXTENTRY
|
||
JNC SRCH
|
||
RET3: RET
|
||
|
||
FREE:
|
||
CMP [ENTFREE],-1 ;Found a free entry before?
|
||
JNZ TSTALL ;If so, ignore this one
|
||
MOV CX,[LASTENT]
|
||
MOV [ENTFREE],CX
|
||
TSTALL:
|
||
CMP AH,[DELALL] ;At end of directory?
|
||
JZ NEXTENT ;No - continue search
|
||
STC ;Report not found
|
||
RET
|
||
|
||
FOUND:
|
||
;Check if attributes allow finding it
|
||
MOV AH,[ATTRIB] ;Attributes of search
|
||
NOT AH
|
||
AND AH,[SI] ;Compare with attributes of file
|
||
ADD SI,15
|
||
AND AH,6 ;Only look at bits 1 and 2
|
||
JZ RET3
|
||
TEST BYTE PTR [CREATING],-1 ;Pass back mismatch if creating
|
||
JZ NEXTENT ;Otherwise continue searching
|
||
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
|
||
GETENT:
|
||
MOV [LASTENT],AX
|
||
MOV CL,4
|
||
SHL AX,CL
|
||
XOR DX,DX
|
||
SHL AX,1
|
||
RCL DX,1 ;Account for overflow in last shift
|
||
MOV BX,[BP.SECSIZ]
|
||
AND BL,255-31 ;Must be multiple of 32
|
||
DIV BX
|
||
MOV BX,DX ;Position within sector
|
||
MOV AH,[BP.DEVNUM] ;AL=Directory sector no.
|
||
CMP AX,[DIRBUFID]
|
||
JZ HAVDIRBUF
|
||
PUSH BX
|
||
CALL DIRREAD
|
||
POP BX
|
||
HAVDIRBUF:
|
||
MOV DX,OFFSET DOSGROUP: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
|
||
CMP BX,DX
|
||
JB HAVIT
|
||
INC AL ;Next directory sector
|
||
PUSH DX ;Save limit
|
||
CALL DIRREAD
|
||
POP DX
|
||
MOV BX,OFFSET DOSGROUP:DIRBUF
|
||
HAVIT:
|
||
CLC
|
||
RET
|
||
|
||
NONE:
|
||
CALL CHKDIRWRITE
|
||
STC
|
||
RET4: RET
|
||
|
||
|
||
DELETE: ; System call 19
|
||
CALL MOVNAME
|
||
MOV AL,-1
|
||
JC RET4
|
||
MOV AL,CS:[ATTRIB]
|
||
AND AL,6 ;Look only at hidden bits
|
||
CMP AL,6 ;Both must be set
|
||
JNZ NOTALL
|
||
MOV CX,11
|
||
MOV AL,"?"
|
||
MOV DI,OFFSET DOSGROUP:NAME1
|
||
REPE SCASB ;See if name is *.*
|
||
JNZ NOTALL
|
||
MOV BYTE PTR CS:[DELALL],0 ;DEL *.* - flag deleting all
|
||
NOTALL:
|
||
CALL FINDNAME
|
||
MOV AL,-1
|
||
JC RET4
|
||
OR BH,BH ;Check if device name
|
||
JS RET4 ;Can't delete I/O devices
|
||
DELFILE:
|
||
MOV BYTE PTR [DIRTYDIR],-1
|
||
MOV AH,[DELALL]
|
||
MOV BYTE PTR [BX],AH
|
||
MOV BX,[SI]
|
||
MOV 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
|
||
ADD SI,5
|
||
MOV DI,OFFSET DOSGROUP:NAME2
|
||
CALL LODNAME
|
||
JC ERRET ;Report error if second name invalid
|
||
CALL FINDNAME
|
||
JC ERRET
|
||
OR BH,BH ;Check if I/O device name
|
||
JS ERRET ;If so, can't rename it
|
||
MOV SI,OFFSET DOSGROUP:NAME1
|
||
MOV DI,OFFSET DOSGROUP:NAME3
|
||
MOV CX,6 ;6 words (12 bytes)--include attribute byte
|
||
REP MOVSW ;Copy name to search for
|
||
RENFIL:
|
||
MOV DI,OFFSET DOSGROUP:NAME1
|
||
MOV SI,OFFSET DOSGROUP:NAME2
|
||
MOV CX,11
|
||
NEWNAM:
|
||
LODSB
|
||
CMP AL,"?"
|
||
JNZ NOCHG
|
||
MOV AL,[BX]
|
||
NOCHG:
|
||
STOSB
|
||
INC BX
|
||
LOOP NEWNAM
|
||
MOV BYTE PTR [DI],6 ;Stop duplicates with any attributes
|
||
CALL DEVNAME ;Check if giving it a device name
|
||
JNC RENERR
|
||
PUSH [LASTENT] ;Save position of match
|
||
MOV [LASTENT],-1 ;Search entire directory for duplicate
|
||
CALL CONTSRCH ;See if new name already exists
|
||
POP AX
|
||
JNC RENERR ;Error if found
|
||
CALL GETENT ;Re-read matching entry
|
||
MOV DI,BX
|
||
MOV SI,OFFSET DOSGROUP:NAME1
|
||
MOV CX,5
|
||
MOVSB
|
||
REP MOVSW ;Replace old name with new one
|
||
MOV BYTE PTR [DIRTYDIR],-1 ;Flag change in directory
|
||
MOV SI,OFFSET DOSGROUP:NAME3
|
||
MOV DI,OFFSET DOSGROUP:NAME1
|
||
MOV CX,6 ;Include attribute byte
|
||
REP MOVSW ;Copy name back into search buffer
|
||
CALL CONTSRCH
|
||
JNC RENFIL
|
||
CALL CHKDIRWRITE
|
||
XOR AL,AL
|
||
RET
|
||
|
||
RENERR:
|
||
CALL CHKDIRWRITE
|
||
ERRET:
|
||
MOV AL,-1
|
||
RET5: RET
|
||
|
||
|
||
MOVNAME:
|
||
|
||
; Inputs:
|
||
; DS, DX point to FCB or extended FCB
|
||
; Outputs:
|
||
; DS:DX point to normal FCB
|
||
; 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 CS:WORD PTR [CREATING],0E500H ;Not creating, not DEL *.*
|
||
MOV AX,CS
|
||
MOV ES,AX
|
||
MOV DI,OFFSET DOSGROUP:NAME1
|
||
MOV SI,DX
|
||
LODSB
|
||
MOV CS:[EXTFCB],AL ;Set flag if extended FCB in use
|
||
MOV AH,0 ;Set default attributes
|
||
CMP AL,-1 ;Is it an extended FCB?
|
||
JNZ HAVATTRB
|
||
ADD DX,7 ;Adjust to point to normal FCB
|
||
ADD SI,6 ;Point to drive select byte
|
||
MOV AH,[SI-1] ;Get attribute byte
|
||
LODSB ;Get drive select byte
|
||
HAVATTRB:
|
||
MOV CS:[ATTRIB],AH ;Save attributes
|
||
CALL GETTHISDRV
|
||
LODNAME:
|
||
; This entry point copies a file name from DS,SI
|
||
; to ES,DI converting to upper case.
|
||
CMP BYTE PTR [SI]," " ;Don't allow blank as first letter
|
||
STC ;In case of error
|
||
JZ RET5
|
||
MOV CX,11
|
||
MOVCHK:
|
||
CALL GETLET
|
||
JB RET5
|
||
JNZ STOLET ;Is it a delimiter?
|
||
CMP AL," " ;This is the only delimiter allowed
|
||
STC ;In case of error
|
||
JNZ RET5
|
||
STOLET:
|
||
STOSB
|
||
LOOP MOVCHK
|
||
CLC ;Got through whole name - no error
|
||
RET6: RET
|
||
|
||
GETTHISDRV:
|
||
CMP CS:[NUMDRV],AL
|
||
JC RET6
|
||
DEC AL
|
||
JNS PHYDRV
|
||
MOV AL,CS:[CURDRV]
|
||
PHYDRV:
|
||
MOV CS:[THISDRV],AL
|
||
RET
|
||
|
||
|
||
OPEN: ;System call 15
|
||
CALL GETFILE
|
||
DOOPEN:
|
||
; Enter here to perform OPEN on file already found
|
||
; in directory. DS=CS, BX points to directory
|
||
; entry in DIRBUF, SI points to First Cluster field, and
|
||
; ES:DI point to the FCB to be opened. This entry point
|
||
; is used by CREATE.
|
||
JC ERRET
|
||
OR BH,BH ;Check if file is I/O device
|
||
JS OPENDEV ;Special handler if so
|
||
MOV AL,[THISDRV]
|
||
INC AX
|
||
STOSB
|
||
XOR AX,AX
|
||
IF ZEROEXT
|
||
ADD DI,11
|
||
STOSW ;Zero low byte of extent field if IBM only
|
||
ENDIF
|
||
IF NOT ZEROEXT
|
||
ADD DI,12 ;Point to high half of CURRENT BLOCK field
|
||
STOSB ;Set it to zero (CP/M programs set low byte)
|
||
ENDIF
|
||
MOV AL,128 ;Default record size
|
||
STOSW ;Set record size
|
||
LODSW ;Get starting cluster
|
||
MOV DX,AX ;Save it for the moment
|
||
MOVSW ;Transfer size to FCB
|
||
MOVSW
|
||
MOV AX,[SI-8] ;Get date
|
||
STOSW ;Save date in FCB
|
||
MOV AX,[SI-10] ;Get time
|
||
STOSW ;Save it in FCB
|
||
MOV AL,[BP.DEVNUM]
|
||
OR AL,40H
|
||
STOSB
|
||
MOV AX,DX ;Restore starting cluster
|
||
STOSW ; first cluster
|
||
STOSW ; last cluster accessed
|
||
XOR AX,AX
|
||
STOSW ; position of last cluster
|
||
RET
|
||
|
||
|
||
OPENDEV:
|
||
ADD DI,13 ;point to 2nd half of extent field
|
||
XOR AX,AX
|
||
STOSB ;Set it to zero
|
||
MOV AL,128
|
||
STOSW ;Set record size to 128
|
||
XOR AX,AX
|
||
STOSW
|
||
STOSW ;Set current size to zero
|
||
CALL DATE16
|
||
STOSW ;Date is todays
|
||
XCHG AX,DX
|
||
STOSW ;Use current time
|
||
MOV AL,BH ;Get device number
|
||
STOSB
|
||
XOR AL,AL ;No error
|
||
RET
|
||
FATERR:
|
||
XCHG AX,DI ;Put error code in DI
|
||
MOV AH,2 ;While trying to read FAT
|
||
MOV AL,[THISDRV] ;Tell which drive
|
||
CALL FATAL1
|
||
JMP SHORT FATREAD
|
||
STARTSRCH:
|
||
MOV AX,-1
|
||
MOV [LASTENT],AX
|
||
MOV [ENTFREE],AX
|
||
FATREAD:
|
||
|
||
; Inputs:
|
||
; DS = CS
|
||
; Function:
|
||
; If disk may have been changed, FAT is read in and buffers are
|
||
; flagged invalid. If not, no action is taken.
|
||
; Outputs:
|
||
; BP = Base of drive parameters
|
||
; Carry set if invalid drive returned by MAPDEV
|
||
; All other registers destroyed
|
||
|
||
MOV AL,[THISDRV]
|
||
XOR AH,AH ;Set default response to zero & clear carry
|
||
CALL FAR PTR BIOSDSKCHG ;See what BIOS has to say
|
||
JC FATERR
|
||
CALL GETBP
|
||
MOV AL,[THISDRV] ;Use physical unit number
|
||
MOV SI,[BP.FAT]
|
||
OR AH,[SI-1] ;Dirty byte for FAT
|
||
JS NEWDSK ;If either say new disk, then it's so
|
||
JNZ MAPDRV
|
||
MOV AH,1
|
||
CMP AX,WORD PTR [BUFDRVNO] ;Does buffer have dirty sector of this drive?
|
||
JZ MAPDRV
|
||
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 WORD PTR [BUFDRVNO],00FFH
|
||
BUFOK:
|
||
MOV [DIRBUFID],-1
|
||
CALL FIGFAT
|
||
NEXTFAT:
|
||
PUSH AX
|
||
CALL DSKREAD
|
||
POP AX
|
||
JC BADFAT
|
||
SUB AL,[BP.FATCNT]
|
||
JZ NEWFAT
|
||
CALL FATWRT
|
||
NEWFAT:
|
||
MOV SI,[BP.FAT]
|
||
MOV AL,[BP.DEVNUM]
|
||
MOV AH,[SI] ;Get first byte of FAT
|
||
OR AH,0F8H ;Put in range
|
||
CALL FAR PTR BIOSMAPDEV
|
||
MOV AH,0
|
||
MOV [SI-2],AX ;Set device no. and reset dirty bit
|
||
MAPDRV:
|
||
MOV AL,[SI-2] ;Get device number
|
||
GETBP:
|
||
MOV BP,[DRVTAB] ;Just in case drive isn't valid
|
||
AND AL,3FH ;Mask out dirty bit
|
||
CMP AL,[NUMIO]
|
||
CMC
|
||
JC RET7
|
||
PUSH AX
|
||
MOV AH,DPBSIZ
|
||
MUL AH
|
||
ADD BP,AX
|
||
POP AX
|
||
RET7: RET
|
||
|
||
BADFAT:
|
||
MOV CX,DI
|
||
ADD DX,CX
|
||
DEC AL
|
||
JNZ NEXTFAT
|
||
CALL FIGFAT ;Reset registers
|
||
CALL DREAD ;Try first FAT once more
|
||
JMP SHORT NEWFAT
|
||
|
||
OKRET1:
|
||
MOV AL,0
|
||
RET
|
||
|
||
CLOSE: ;System call 16
|
||
MOV DI,DX
|
||
CMP BYTE PTR [DI],-1 ;Check for extended FCB
|
||
JNZ NORMFCB3
|
||
ADD DI,7
|
||
NORMFCB3:
|
||
TEST BYTE PTR [DI.DEVID],0C0H ;Allow only dirty files
|
||
JNZ OKRET1 ;can't close if I/O device, or not writen
|
||
MOV AL,[DI] ;Get physical unit number
|
||
DEC AL ;Make zero = drive A
|
||
MOV AH,1 ;Look for dirty buffer
|
||
CMP AX,CS:WORD PTR [BUFDRVNO]
|
||
JNZ FNDDIR
|
||
;Write back dirty buffer if on same drive
|
||
PUSH DX
|
||
PUSH DS
|
||
PUSH CS
|
||
POP DS
|
||
MOV BYTE PTR [DIRTYBUF],0
|
||
MOV BX,[BUFFER]
|
||
MOV CX,1
|
||
MOV DX,[BUFSECNO]
|
||
MOV BP,[BUFDRVBP]
|
||
CALL DWRITE
|
||
POP DS
|
||
POP DX
|
||
FNDDIR:
|
||
CALL GETFILE
|
||
BADCLOSEJ:
|
||
JC BADCLOSE
|
||
MOV CX,ES:[DI.FIRCLUS]
|
||
MOV [SI],CX
|
||
MOV DX,ES:WORD PTR [DI.FILSIZ]
|
||
MOV [SI+2],DX
|
||
MOV DX,ES:WORD PTR [DI.FILSIZ+2]
|
||
MOV [SI+4],DX
|
||
MOV DX,ES:[DI.FDATE]
|
||
MOV [SI-2],DX
|
||
MOV DX,ES:[DI.FTIME]
|
||
MOV [SI-4],DX
|
||
CALL DIRWRITE
|
||
|
||
CHKFATWRT:
|
||
; Do FATWRT only if FAT is dirty and uses same I/O driver
|
||
MOV SI,[BP.FAT]
|
||
MOV AL,[BP.DEVNUM]
|
||
MOV AH,1
|
||
CMP [SI-2],AX ;See if FAT dirty and uses same driver
|
||
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
|
||
|
||
CALL FIGFAT
|
||
MOV BYTE PTR [BX-1],0
|
||
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 SI,[BP.FAT]
|
||
MOV BYTE PTR [SI-1],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,OFFSET DOSGROUP:DIRBUF
|
||
MOV CX,1
|
||
RET
|
||
|
||
|
||
CREATE: ;System call 22
|
||
CALL MOVNAME
|
||
JC ERRET3
|
||
MOV DI,OFFSET DOSGROUP:NAME1
|
||
MOV CX,11
|
||
MOV AL,"?"
|
||
REPNE SCASB
|
||
JZ ERRET3
|
||
MOV CS:BYTE PTR [CREATING],-1
|
||
PUSH DX
|
||
PUSH DS
|
||
CALL FINDNAME
|
||
JNC EXISTENT
|
||
MOV AX,[ENTFREE] ;First free entry found in FINDNAME
|
||
CMP AX,-1
|
||
JZ ERRPOP
|
||
CALL GETENT ;Point at that free entry
|
||
JMP SHORT FREESPOT
|
||
ERRPOP:
|
||
POP DS
|
||
POP DX
|
||
ERRET3:
|
||
MOV AL,-1
|
||
RET
|
||
|
||
EXISTENT:
|
||
JNZ ERRPOP ;Error if attributes don't match
|
||
OR BH,BH ;Check if file is I/O device
|
||
JS OPENJMP ;If so, no action
|
||
MOV CX,[SI] ;Get pointer to clusters
|
||
JCXZ FREESPOT
|
||
CMP CX,[BP.MAXCLUS]
|
||
JA FREESPOT
|
||
PUSH BX
|
||
MOV BX,CX
|
||
MOV SI,[BP.FAT]
|
||
CALL RELEASE ;Free any data already allocated
|
||
CALL FATWRT
|
||
POP BX
|
||
FREESPOT:
|
||
MOV DI,BX
|
||
MOV SI,OFFSET DOSGROUP:NAME1
|
||
MOV CX,5
|
||
MOVSB
|
||
REP MOVSW
|
||
MOV AL,[ATTRIB]
|
||
STOSB
|
||
XOR AX,AX
|
||
MOV CL,5
|
||
REP STOSW
|
||
CALL DATE16
|
||
XCHG AX,DX
|
||
STOSW
|
||
XCHG AX,DX
|
||
STOSW
|
||
XOR AX,AX
|
||
PUSH DI
|
||
MOV CL,6
|
||
SMALLENT:
|
||
REP STOSB
|
||
PUSH BX
|
||
CALL DIRWRITE
|
||
POP BX
|
||
POP SI
|
||
OPENJMP:
|
||
CLC ;Clear carry so OPEN won't fail
|
||
POP ES
|
||
POP DI
|
||
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.DEVNUM]
|
||
MOV [DIRBUFID],AX
|
||
CALL DIRCOMP
|
||
CALL DREAD
|
||
POP AX
|
||
RET8: 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.
|
||
; BP preserved. All other registers destroyed.
|
||
|
||
CALL DSKREAD
|
||
JNC RET8
|
||
MOV CS:BYTE PTR [READOP],0
|
||
CALL HARDERR
|
||
CMP AL,1 ;Check for retry
|
||
JZ DREAD
|
||
RET ;Ignore otherwise
|
||
|
||
|
||
HARDERR:
|
||
|
||
;Hard disk error handler. Entry conditions:
|
||
; DS:BX = Original disk transfer address
|
||
; DX = Original logical sector number
|
||
; CX = Number of sectors to go (first one gave the error)
|
||
; AX = Hardware error code
|
||
; DI = Original sector transfer count
|
||
; BP = Base of drive parameters
|
||
; [READOP] = 0 for read, 1 for write
|
||
|
||
XCHG AX,DI ;Error code in DI, count in AX
|
||
SUB AX,CX ;Number of sectors successfully transferred
|
||
ADD DX,AX ;First sector number to retry
|
||
PUSH DX
|
||
MUL [BP.SECSIZ] ;Number of bytes transferred
|
||
POP DX
|
||
ADD BX,AX ;First address for retry
|
||
MOV AH,0 ;Flag disk section in error
|
||
CMP DX,[BP.FIRFAT] ;In reserved area?
|
||
JB ERRINT
|
||
INC AH ;Flag for FAT
|
||
CMP DX,[BP.FIRDIR] ;In FAT?
|
||
JB ERRINT
|
||
INC AH
|
||
CMP DX,[BP.FIRREC] ;In directory?
|
||
JB ERRINT
|
||
INC AH ;Must be in data area
|
||
ERRINT:
|
||
SHL AH,1 ;Make room for read/write bit
|
||
OR AH,CS:[READOP]
|
||
FATAL:
|
||
MOV AL,[BP.DRVNUM] ;Get drive number
|
||
FATAL1:
|
||
PUSH BP ;The only thing we preserve
|
||
MOV CS:[CONTSTK],SP
|
||
CLI ;Prepare to play with stack
|
||
MOV SS,CS:[SSSAVE]
|
||
MOV SP,CS:[SPSAVE] ;User stack pointer restored
|
||
INT 24H ;Fatal error interrupt vector
|
||
MOV CS:[SPSAVE],SP
|
||
MOV CS:[SSSAVE],SS
|
||
MOV SP,CS
|
||
MOV SS,SP
|
||
MOV SP,CS:[CONTSTK]
|
||
STI
|
||
POP BP
|
||
CMP AL,2
|
||
JZ ERROR
|
||
RET
|
||
|
||
DSKREAD:
|
||
MOV AL,[BP.DEVNUM]
|
||
PUSH BP
|
||
PUSH BX
|
||
PUSH CX
|
||
PUSH DX
|
||
CALL FAR PTR BIOSREAD
|
||
POP DX
|
||
POP DI
|
||
POP BX
|
||
POP BP
|
||
RET9: RET
|
||
|
||
|
||
CHKDIRWRITE:
|
||
TEST BYTE PTR [DIRTYDIR],-1
|
||
JZ RET9
|
||
|
||
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 BYTE PTR [DIRTYDIR],0
|
||
MOV AL,BYTE PTR [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.
|
||
; BP preserved. All other registers destroyed.
|
||
|
||
MOV AL,[BP.DEVNUM]
|
||
MOV AH,CS:VERFLG
|
||
PUSH BP
|
||
PUSH BX
|
||
PUSH CX
|
||
PUSH DX
|
||
CALL FAR PTR BIOSWRITE
|
||
POP DX
|
||
POP DI
|
||
POP BX
|
||
POP BP
|
||
JNC RET9
|
||
MOV CS:BYTE PTR [READOP],1
|
||
CALL HARDERR
|
||
CMP AL,1 ;Check for retry
|
||
JZ DWRITE
|
||
RET
|
||
|
||
|
||
ABORT:
|
||
LDS SI,CS:DWORD PTR [SPSAVE]
|
||
MOV DS,[SI.CSSAVE]
|
||
XOR AX,AX
|
||
MOV ES,AX
|
||
MOV SI,SAVEXIT
|
||
MOV DI,EXIT
|
||
MOVSW
|
||
MOVSW
|
||
MOVSW
|
||
MOVSW
|
||
MOVSW
|
||
MOVSW
|
||
ERROR:
|
||
MOV AX,CS
|
||
MOV DS,AX
|
||
MOV ES,AX
|
||
CALL WRTFATS
|
||
XOR AX,AX
|
||
CLI
|
||
MOV SS,[SSSAVE]
|
||
MOV SP,[SPSAVE]
|
||
MOV DS,AX
|
||
MOV SI,EXIT
|
||
MOV DI,OFFSET DOSGROUP:EXITHOLD
|
||
MOVSW
|
||
MOVSW
|
||
POP AX
|
||
POP BX
|
||
POP CX
|
||
POP DX
|
||
POP SI
|
||
POP DI
|
||
POP BP
|
||
POP DS
|
||
POP ES
|
||
STI ;Stack OK now
|
||
JMP CS:DWORD PTR [EXITHOLD]
|
||
|
||
|
||
SEQRD: ;System call 20
|
||
CALL GETREC
|
||
CALL LOAD
|
||
JMP SHORT FINSEQ
|
||
|
||
SEQWRT: ;System call 21
|
||
CALL GETREC
|
||
CALL STORE
|
||
FINSEQ:
|
||
JCXZ SETNREX
|
||
ADD AX,1
|
||
ADC DX,0
|
||
JMP SHORT SETNREX
|
||
|
||
RNDRD: ;System call 33
|
||
CALL GETRRPOS1
|
||
CALL LOAD
|
||
JMP SHORT FINRND
|
||
|
||
RNDWRT: ;System call 34
|
||
CALL GETRRPOS1
|
||
CALL STORE
|
||
JMP SHORT FINRND
|
||
|
||
BLKRD: ;System call 39
|
||
CALL GETRRPOS
|
||
CALL LOAD
|
||
JMP SHORT FINBLK
|
||
|
||
BLKWRT: ;System call 40
|
||
CALL GETRRPOS
|
||
CALL STORE
|
||
FINBLK:
|
||
LDS SI,DWORD PTR [SPSAVE]
|
||
MOV [SI.CXSAVE],CX
|
||
JCXZ FINRND
|
||
ADD AX,1
|
||
ADC DX,0
|
||
FINRND:
|
||
MOV ES:WORD PTR [DI.RR],AX
|
||
MOV ES:[DI.RR+2],DL
|
||
OR DH,DH
|
||
JZ SETNREX
|
||
MOV ES:[DI.RR+3],DH ;Save 4 byte of RECPOS only if significant
|
||
SETNREX:
|
||
MOV CX,AX
|
||
AND AL,7FH
|
||
MOV ES:[DI.NR],AL
|
||
AND CL,80H
|
||
SHL CX,1
|
||
RCL DX,1
|
||
MOV AL,CH
|
||
MOV AH,DL
|
||
MOV ES:[DI.EXTENT],AX
|
||
MOV AL,CS:[DSKERR]
|
||
RET
|
||
|
||
GETRRPOS1:
|
||
MOV CX,1
|
||
GETRRPOS:
|
||
MOV DI,DX
|
||
CMP BYTE PTR [DI],-1
|
||
JNZ NORMFCB1
|
||
ADD DI,7
|
||
NORMFCB1:
|
||
MOV AX,WORD PTR [DI.RR]
|
||
MOV DX,WORD PTR [DI.RR+2]
|
||
RET
|
||
|
||
NOFILERR:
|
||
XOR CX,CX
|
||
MOV BYTE PTR [DSKERR],4
|
||
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
|
||
; BL = DEVID from 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)
|
||
; [THISDRV] = Physical drive unit number
|
||
; If SETUP detects no records will be transfered, it returns 1 level up
|
||
; with CX = 0.
|
||
|
||
PUSH AX
|
||
MOV AL,[DI]
|
||
DEC AL
|
||
MOV CS:[THISDRV],AL
|
||
MOV AL,[DI.DEVID]
|
||
MOV SI,[DI.RECSIZ]
|
||
OR SI,SI
|
||
JNZ HAVRECSIZ
|
||
MOV SI,128
|
||
MOV [DI.RECSIZ],SI
|
||
HAVRECSIZ:
|
||
PUSH DS
|
||
POP ES ;Set ES to DS
|
||
PUSH CS
|
||
POP DS ;Set DS to CS
|
||
OR AL,AL ;Is it a device?
|
||
JNS NOTDEVICE
|
||
MOV AL,0 ;Fake in drive 0 so we can get SP
|
||
NOTDEVICE:
|
||
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 WORD PTR [RECPOS],AX
|
||
MOV WORD PTR [RECPOS+2],DX
|
||
MOV [FCB],DI
|
||
MOV BX,[DMAADD]
|
||
MOV [NEXTADD],BX
|
||
MOV BYTE PTR [DSKERR],0
|
||
MOV BYTE PTR [TRANS],0
|
||
MOV BX,DX
|
||
MUL SI
|
||
MOV WORD PTR [BYTPOS],AX
|
||
PUSH DX
|
||
MOV AX,BX
|
||
MUL SI
|
||
POP BX
|
||
ADD AX,BX
|
||
ADC DX,0 ;Ripple carry
|
||
JNZ EOFERR
|
||
MOV WORD PTR [BYTPOS+2],AX
|
||
MOV DX,AX
|
||
MOV AX,WORD PTR [BYTPOS]
|
||
MOV BX,[BP.SECSIZ]
|
||
CMP DX,BX ;See if divide will overflow
|
||
JNC EOFERR
|
||
DIV BX
|
||
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 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 be less than 64K
|
||
MOV AX,[DMAADD]
|
||
NEG AX ;Amount of room left in segment
|
||
JNZ PARTSEG ;All 64K available?
|
||
DEC AX ;If so, reduce by one
|
||
PARTSEG:
|
||
XOR DX,DX
|
||
DIV SI ;How many records will fit?
|
||
MOV [RECCNT],AX
|
||
MUL SI ;Translate that back into bytes
|
||
MOV BYTE PTR [DSKERR],2 ;Flag that trimming took place
|
||
MOV CX,AX
|
||
JCXZ NOROOM
|
||
OK:
|
||
MOV BL,ES:[DI.DEVID]
|
||
MOV SI,[BP.FAT]
|
||
RET
|
||
|
||
EOFERR:
|
||
MOV BYTE PTR [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 [BP.SECSIZ] ;How many whole sectors?
|
||
MOV [SECCNT],AX
|
||
MOV [BYTCNT2],DX ;Bytes remaining for last sector
|
||
RET10: 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.
|
||
|
||
MOV BX,ES:[DI.LSTCLUS]
|
||
MOV DX,ES:[DI.CLUSPOS]
|
||
OR BX,BX
|
||
JZ NOCLUS
|
||
SUB CX,DX
|
||
JNB FINDIT
|
||
ADD CX,DX
|
||
XOR DX,DX
|
||
MOV BX,ES:[DI.FIRCLUS]
|
||
FINDIT:
|
||
JCXZ RET10
|
||
SKPCLP:
|
||
CALL UNPACK
|
||
CMP DI,0FF8H
|
||
JAE RET10
|
||
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
|
||
MOV [PREREAD],AL
|
||
CMP DX,[BUFSECNO]
|
||
JNZ GETSEC
|
||
MOV AL,[BUFDRVNO]
|
||
CMP AL,[THISDRV]
|
||
JZ FINBUF ;Already have it?
|
||
GETSEC:
|
||
XOR AL,AL
|
||
XCHG [DIRTYBUF],AL ;Read dirty flag and reset it
|
||
OR AL,AL
|
||
JZ RDSEC
|
||
PUSH DX
|
||
PUSH BP
|
||
MOV BP,[BUFDRVBP]
|
||
MOV BX,[BUFFER]
|
||
MOV CX,1
|
||
MOV DX,[BUFSECNO]
|
||
CALL DWRITE
|
||
POP BP
|
||
POP DX
|
||
RDSEC:
|
||
TEST BYTE PTR [PREREAD],-1
|
||
JNZ SETBUF
|
||
XOR AX,AX
|
||
MOV [BUFSECNO],AX ;Set buffer valid in case of disk error
|
||
DEC AX
|
||
MOV [BUFDRVNO],AL
|
||
MOV BX,[BUFFER]
|
||
MOV CX,1
|
||
PUSH DX
|
||
CALL DREAD
|
||
POP DX
|
||
SETBUF:
|
||
MOV [BUFSECNO],DX
|
||
MOV AL,[THISDRV]
|
||
MOV [BUFDRVNO],AL
|
||
MOV [BUFDRVBP],BP
|
||
FINBUF:
|
||
MOV BYTE PTR [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,1
|
||
JNC EVENRD
|
||
MOVSB
|
||
EVENRD:
|
||
REP MOVSW
|
||
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,1
|
||
JNC EVENWRT
|
||
MOVSB
|
||
EVENWRT:
|
||
REP MOVSW
|
||
POP ES
|
||
POP DS
|
||
MOV BYTE PTR [DIRTYBUF],1
|
||
RET
|
||
|
||
NEXTSEC:
|
||
TEST BYTE PTR [TRANS],-1
|
||
JZ CLRET
|
||
MOV AL,[SECCLUSPOS]
|
||
INC AL
|
||
CMP AL,[BP.CLUSMSK]
|
||
JBE SAVPOS
|
||
MOV BX,[CLUSNUM]
|
||
CMP BX,0FF8H
|
||
JAE NONEXT
|
||
MOV SI,[BP.FAT]
|
||
CALL UNPACK
|
||
MOV [CLUSNUM],DI
|
||
INC [LASTPOS]
|
||
MOV AL,0
|
||
SAVPOS:
|
||
MOV [SECCLUSPOS],AL
|
||
CLRET:
|
||
CLC
|
||
RET
|
||
NONEXT:
|
||
STC
|
||
RET
|
||
|
||
TRANBUF:
|
||
LODSB
|
||
STOSB
|
||
CMP AL,13 ;Check for carriage return
|
||
JNZ NORMCH
|
||
MOV BYTE PTR [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]
|
||
AND ES:BYTE PTR [DI.DEVID],0FFH-40H ;Mark as no more data available
|
||
SETFCBJ:
|
||
JMP SETFCB
|
||
|
||
READDEV:
|
||
PUSH ES
|
||
LES DI,DWORD PTR [DMAADD]
|
||
INC BL
|
||
JZ READCON
|
||
INC BL
|
||
JNZ ENDRDDEV
|
||
READAUX:
|
||
CALL AUXIN
|
||
STOSB
|
||
CMP AL,1AH
|
||
LOOPNZ READAUX
|
||
JMP SHORT ENDRDDEV
|
||
|
||
READCON:
|
||
PUSH CS
|
||
POP DS
|
||
MOV SI,[CONTPOS]
|
||
OR SI,SI
|
||
JNZ TRANBUF
|
||
CMP BYTE PTR [CONBUF],128
|
||
JZ GETBUF
|
||
MOV WORD PTR [CONBUF],0FF80H ;Set up 128-byte buffer with no template
|
||
GETBUF:
|
||
PUSH CX
|
||
PUSH ES
|
||
PUSH DI
|
||
MOV DX,OFFSET DOSGROUP:CONBUF
|
||
CALL BUFIN ;Get input buffer
|
||
POP DI
|
||
POP ES
|
||
POP CX
|
||
MOV SI,2 + OFFSET DOSGROUP:CONBUF
|
||
CMP BYTE PTR [SI],1AH ;Check for Ctrl-Z in first character
|
||
JNZ TRANBUF
|
||
MOV AL,1AH
|
||
STOSB
|
||
MOV AL,10
|
||
CALL OUT ;Send linefeed
|
||
XOR SI,SI
|
||
JMP SHORT 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
|
||
OR BL,BL ;Check for named device I/O
|
||
JS READDEV
|
||
MOV AX,ES:WORD PTR [DI.FILSIZ]
|
||
MOV BX,ES:WORD PTR [DI.FILSIZ+2]
|
||
SUB AX,WORD PTR [BYTPOS]
|
||
SBB BX,WORD PTR [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 BYTE PTR [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]
|
||
PUSH DX
|
||
PUSH BX
|
||
PUSHF ;Save carry flag
|
||
CALL DREAD
|
||
POPF ;Restore carry flag
|
||
POP DI ;Initial transfer address
|
||
POP AX ;First sector transfered
|
||
POP DS
|
||
JC NOTBUFFED ;Was one of those sectors in the buffer?
|
||
CMP BYTE PTR [DIRTYBUF],0 ;Is buffer dirty?
|
||
JZ NOTBUFFED ;If not no problem
|
||
;We have transfered in a sector from disk when a dirty copy of it is in the buffer.
|
||
;We must transfer the sector from the buffer to correct memory address
|
||
SUB AX,[BUFSECNO] ;How many sectors into the transfer?
|
||
NEG AX
|
||
MOV CX,[BP.SECSIZ]
|
||
MUL CX ;How many bytes into the transfer?
|
||
ADD DI,AX
|
||
MOV SI,[BUFFER]
|
||
PUSH ES
|
||
MOV ES,[DMAADD+2] ;Get disk transfer segment
|
||
SHR CX,1
|
||
REP MOVSW
|
||
JNC EVENMOV
|
||
MOVSB
|
||
EVENMOV:
|
||
POP ES
|
||
NOTBUFFED:
|
||
POP CX
|
||
POP BX
|
||
JCXZ RDLAST
|
||
CMP BX,0FF8H
|
||
JAE SETFCB
|
||
MOV DL,0
|
||
INC [LASTPOS] ;We'll be using next cluster
|
||
JMP SHORT RDLP
|
||
|
||
SETFCB:
|
||
MOV SI,[FCB]
|
||
MOV AX,[NEXTADD]
|
||
MOV DI,AX
|
||
SUB AX,[DMAADD] ;Number of bytes transfered
|
||
XOR DX,DX
|
||
MOV CX,ES:[SI.RECSIZ]
|
||
DIV CX ;Number of records
|
||
CMP AX,[RECCNT] ;Check if all records transferred
|
||
JZ FULLREC
|
||
MOV BYTE PTR [DSKERR],1
|
||
OR DX,DX
|
||
JZ FULLREC ;If remainder 0, then full record transfered
|
||
MOV BYTE PTR [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,1
|
||
JNC EVENFIL
|
||
STOSB
|
||
EVENFIL:
|
||
REP STOSW
|
||
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]
|
||
MOV ES:[DI.LSTCLUS],AX
|
||
MOV AX,[LASTPOS]
|
||
MOV ES:[DI.CLUSPOS],AX
|
||
ADDREC:
|
||
MOV AX,WORD PTR [RECPOS]
|
||
MOV DX,WORD PTR [RECPOS+2]
|
||
JCXZ RET28 ;If no records read, don't change position
|
||
DEC CX
|
||
ADD AX,CX ;Update current record position
|
||
ADC DX,0
|
||
INC CX
|
||
RET28: RET
|
||
|
||
RDLAST:
|
||
MOV AX,[BYTCNT2]
|
||
OR AX,AX
|
||
JZ SETFCB
|
||
MOV [BYTCNT1],AX
|
||
CALL NEXTSEC
|
||
JC SETFCB
|
||
MOV [BYTSECPOS],0
|
||
CALL BUFRD
|
||
JMP SHORT SETFCB
|
||
|
||
WRTDEV:
|
||
PUSH DS
|
||
LDS SI,DWORD PTR [DMAADD]
|
||
OR BL,40H
|
||
INC BL
|
||
JZ WRTCON
|
||
INC BL
|
||
JZ WRTAUX
|
||
INC BL
|
||
JZ ENDWRDEV ;Done if device is NUL
|
||
WRTLST:
|
||
LODSB
|
||
CMP AL,1AH
|
||
JZ ENDWRDEV
|
||
CALL LISTOUT
|
||
LOOP WRTLST
|
||
JMP SHORT ENDWRDEV
|
||
|
||
WRTAUX:
|
||
LODSB
|
||
CALL AUXOUT
|
||
CMP AL,1AH
|
||
LOOPNZ WRTAUX
|
||
JMP SHORT ENDWRDEV
|
||
|
||
WRTCON:
|
||
LODSB
|
||
CMP AL,1AH
|
||
JZ ENDWRDEV
|
||
CALL OUT
|
||
LOOP WRTCON
|
||
ENDWRDEV:
|
||
POP DS
|
||
MOV CX,[RECCNT]
|
||
MOV DI,[FCB]
|
||
JMP SHORT ADDREC
|
||
|
||
HAVSTART:
|
||
MOV CX,AX
|
||
CALL SKPCLP
|
||
JCXZ DOWRTJ
|
||
CALL ALLOCATE
|
||
JNC DOWRTJ
|
||
WRTERR:
|
||
MOV BYTE PTR [DSKERR],1
|
||
LVDSK:
|
||
MOV AX,WORD PTR [RECPOS]
|
||
MOV DX,WORD PTR [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
|
||
|
||
CALL SETUP
|
||
CALL DATE16
|
||
MOV ES:[DI.FDATE],AX
|
||
MOV ES:[DI.FTIME],DX
|
||
OR BL,BL
|
||
JS WRTDEV
|
||
AND BL,3FH ;Mark file as dirty
|
||
MOV ES:[DI.DEVID],BL
|
||
CALL BREAKDOWN
|
||
MOV AX,WORD PTR [BYTPOS]
|
||
MOV DX,WORD PTR [BYTPOS+2]
|
||
JCXZ WRTEOFJ
|
||
DEC CX
|
||
ADD AX,CX
|
||
ADC DX,0 ;AX:DX=last byte accessed
|
||
DIV [BP.SECSIZ] ;AX=last sector accessed
|
||
MOV CL,[BP.CLUSSHFT]
|
||
SHR AX,CL ;Last cluster to be accessed
|
||
PUSH AX
|
||
MOV AX,ES:WORD PTR [DI.FILSIZ]
|
||
MOV DX,ES:WORD PTR [DI.FILSIZ+2]
|
||
DIV [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 ;See if no more data
|
||
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 BYTE PTR [TRANS],1 ;A transfer is taking place
|
||
MOV DL,[SECCLUSPOS]
|
||
MOV BX,[CLUSNUM]
|
||
MOV CX,[SECCNT]
|
||
WRTLP:
|
||
CALL OPTIMIZE
|
||
JC NOTINBUF ;Is one of the sectors buffered?
|
||
MOV [BUFSECNO],0 ;If so, invalidate the buffer since we're
|
||
MOV WORD PTR [BUFDRVNO],0FFH ; completely rewritting it
|
||
NOTINBUF:
|
||
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
|
||
JMP SHORT 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,WORD PTR [BYTPOS]
|
||
MOV DX,WORD PTR [BYTPOS+2]
|
||
ADC DX,0
|
||
MOV CX,DX
|
||
MOV DI,[FCB]
|
||
CMP AX,ES:WORD PTR [DI.FILSIZ]
|
||
SBB CX,ES:WORD PTR [DI.FILSIZ+2]
|
||
JB SAMSIZ
|
||
MOV ES:WORD PTR [DI.FILSIZ],AX
|
||
MOV ES:WORD PTR [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
|
||
SBB DX,0
|
||
DIV [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,WORD PTR [BYTPOS]
|
||
MOV ES:WORD PTR [DI.FILSIZ],AX
|
||
MOV AX,WORD PTR [BYTPOS+2]
|
||
MOV ES:WORD PTR [DI.FILSIZ+2],AX
|
||
XOR CX,CX
|
||
JMP ADDREC
|
||
|
||
RELFILE:
|
||
MOV DX,0FFFH
|
||
CALL RELBLKS
|
||
SETDIRT:
|
||
MOV BYTE PTR [SI-1],1
|
||
JMP SHORT UPDATE
|
||
|
||
KILLFIL:
|
||
XOR BX,BX
|
||
XCHG BX,ES:[DI.FIRCLUS]
|
||
OR BX,BX
|
||
JZ UPDATE
|
||
CALL RELEASE
|
||
JMP SHORT 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
|
||
; Carry clear if a sector to transfer is in the buffer
|
||
; Carry set otherwise
|
||
; [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
|
||
MOV 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 [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
|
||
;Now let's see if any of these sectors are already in the buffer
|
||
CMP [BUFSECNO],DX
|
||
JC RET100 ;If DX > [BUFSECNO] then not in buffer
|
||
MOV SI,DX
|
||
ADD SI,CX ;Last sector + 1
|
||
CMP [BUFSECNO],SI
|
||
CMC
|
||
JC RET100 ;If SI <= [BUFSECNO] then not in buffer
|
||
PUSH AX
|
||
MOV AL,[BP.DEVNUM]
|
||
CMP AL,[BUFDRVNO] ;Is buffer for this drive?
|
||
POP AX
|
||
JZ RET100 ;If so, then we match
|
||
STC ;No match
|
||
RET100: 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
|
||
JMP SHORT 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
|
||
CMP BYTE PTR [DI],-1 ;Check for extended FCB
|
||
JNZ NORMFCB2
|
||
ADD DI,7
|
||
NORMFCB2:
|
||
MOV CX,1
|
||
MOV AL,[DI.NR]
|
||
MOV DX,[DI.EXTENT]
|
||
SHL AL,1
|
||
SHR DX,1
|
||
RCR AL,1
|
||
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 DX ;AX=max no. of records in file
|
||
MOV CX,AX
|
||
SUB CX,WORD PTR [RECPOS] ;CX=max no. of records that could be written
|
||
JA MAXREC
|
||
XOR CX,CX ;If CX was negative, zero it
|
||
MAXREC:
|
||
STC
|
||
RET11: RET
|
||
|
||
TRYOUT:
|
||
CALL UNPACK
|
||
JZ HAVFRE
|
||
TRYIN:
|
||
DEC AX
|
||
JLE FINDFRE
|
||
XCHG AX,BX
|
||
CALL UNPACK
|
||
JZ HAVFRE
|
||
XCHG AX,BX
|
||
JMP SHORT FINDFRE
|
||
HAVFRE:
|
||
XCHG BX,DX
|
||
MOV AX,DX
|
||
CALL PACK
|
||
MOV BX,AX
|
||
LOOP ALLOC
|
||
MOV DX,0FFFH
|
||
CALL PACK
|
||
MOV BYTE PTR [SI-1],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 RET11
|
||
MOV DI,[FCB]
|
||
MOV ES:[DI.FIRCLUS],BX
|
||
RET12: 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 RET12
|
||
MOV AX,DI
|
||
CALL PACK
|
||
CMP AX,0FF8H
|
||
MOV BX,AX
|
||
JB RELEASE
|
||
RET13: 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 RET13
|
||
MOV BX,DI
|
||
JMP SHORT GETEOF
|
||
|
||
|
||
SRCHFRST: ;System call 17
|
||
CALL GETFILE
|
||
SAVPLCE:
|
||
; Search-for-next enters here to save place and report
|
||
; findings.
|
||
JC KILLSRCH
|
||
OR BH,BH
|
||
JS SRCHDEV
|
||
MOV AX,[LASTENT]
|
||
MOV ES:[DI.FILDIRENT],AX
|
||
MOV ES:[DI.DRVBP],BP
|
||
;Information in directory entry must be copied into the first
|
||
; 33 bytes starting at the disk transfer address.
|
||
MOV SI,BX
|
||
LES DI,DWORD PTR [DMAADD]
|
||
MOV AX,00FFH
|
||
CMP AL,[EXTFCB]
|
||
JNZ NORMFCB
|
||
STOSW
|
||
INC AL
|
||
STOSW
|
||
STOSW
|
||
MOV AL,[ATTRIB]
|
||
STOSB
|
||
NORMFCB:
|
||
MOV AL,[THISDRV]
|
||
INC AL
|
||
STOSB ;Set drive number
|
||
MOV CX,16
|
||
REP MOVSW ;Copy remaining 10 characters of name
|
||
XOR AL,AL
|
||
RET
|
||
|
||
KILLSRCH:
|
||
KILLSRCH1 EQU KILLSRCH+1
|
||
;The purpose of the KILLSRCH1 label is to provide a jump label to the following
|
||
; instruction which leaves out the segment override.
|
||
MOV WORD PTR ES:[DI.FILDIRENT],-1
|
||
MOV AL,-1
|
||
RET
|
||
|
||
SRCHDEV:
|
||
MOV ES:[DI.FILDIRENT],BX
|
||
LES DI,DWORD PTR [DMAADD]
|
||
XOR AX,AX
|
||
STOSB ;Zero drive byte
|
||
SUB SI,4 ;Point to device name
|
||
MOVSW
|
||
MOVSW
|
||
MOV AX,2020H
|
||
STOSB
|
||
STOSW
|
||
STOSW
|
||
STOSW ;Fill with 8 blanks
|
||
XOR AX,AX
|
||
MOV CX,10
|
||
REP STOSW
|
||
STOSB
|
||
RET14: RET
|
||
|
||
SRCHNXT: ;System call 18
|
||
CALL MOVNAME
|
||
MOV DI,DX
|
||
JC NEAR PTR KILLSRCH1
|
||
MOV BP,[DI.DRVBP]
|
||
MOV AX,[DI.FILDIRENT]
|
||
OR AX,AX
|
||
JS NEAR PTR KILLSRCH1
|
||
PUSH DX
|
||
PUSH DS
|
||
PUSH CS
|
||
POP DS
|
||
MOV [LASTENT],AX
|
||
CALL CONTSRCH
|
||
POP ES
|
||
POP DI
|
||
JMP SAVPLCE
|
||
|
||
|
||
FILESIZE: ;System call 35
|
||
CALL GETFILE
|
||
MOV AL,-1
|
||
JC RET14
|
||
ADD DI,33 ;Write size in RR field
|
||
MOV CX,ES:[DI.RECSIZ-33]
|
||
OR CX,CX
|
||
JNZ RECOK
|
||
MOV CX,128
|
||
RECOK:
|
||
XOR AX,AX
|
||
XOR DX,DX ;Intialize size to zero
|
||
OR BH,BH ;Check for named I/O device
|
||
JS DEVSIZ
|
||
INC SI
|
||
INC SI ;Point to length field
|
||
MOV AX,[SI+2] ;Get high word of size
|
||
DIV CX
|
||
PUSH AX ;Save high part of result
|
||
LODSW ;Get low word of size
|
||
DIV 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:
|
||
STOSW
|
||
MOV AX,DX
|
||
STOSB
|
||
MOV AL,0
|
||
CMP CX,64
|
||
JAE RET14 ;Only 3-byte field if RECSIZ >= 64
|
||
MOV ES:[DI],AH
|
||
RET
|
||
|
||
|
||
SETDMA: ;System call 26
|
||
MOV CS:[DMAADD],DX
|
||
MOV CS:[DMAADD+2],DS
|
||
RET
|
||
|
||
NOSUCHDRV:
|
||
MOV AL,-1
|
||
RET
|
||
|
||
GETFATPT: ;System call 27
|
||
MOV DL,0 ;Use default drive
|
||
|
||
GETFATPTDL: ;System call 28
|
||
PUSH CS
|
||
POP DS
|
||
MOV AL,DL
|
||
CALL GETTHISDRV
|
||
JC NOSUCHDRV
|
||
CALL FATREAD
|
||
MOV BX,[BP.FAT]
|
||
MOV AL,[BP.CLUSMSK]
|
||
INC AL
|
||
MOV DX,[BP.MAXCLUS]
|
||
DEC DX
|
||
MOV CX,[BP.SECSIZ]
|
||
LDS SI,DWORD PTR [SPSAVE]
|
||
MOV [SI.BXSAVE],BX
|
||
MOV [SI.DXSAVE],DX
|
||
MOV [SI.CXSAVE],CX
|
||
MOV [SI.DSSAVE],CS
|
||
RET
|
||
|
||
|
||
GETDSKPT: ;System call 31
|
||
PUSH CS
|
||
POP DS
|
||
MOV AL,[CURDRV]
|
||
MOV [THISDRV],AL
|
||
CALL FATREAD
|
||
LDS SI,DWORD PTR [SPSAVE]
|
||
MOV [SI.BXSAVE],BP
|
||
MOV [SI.DSSAVE],CS
|
||
RET
|
||
|
||
|
||
DSKRESET: ;System call 13
|
||
PUSH CS
|
||
POP DS
|
||
WRTFATS:
|
||
; DS=CS. Writes back all dirty FATs. All registers destroyed.
|
||
XOR AL,AL
|
||
XCHG AL,[DIRTYBUF]
|
||
OR AL,AL
|
||
JZ NOBUF
|
||
MOV BP,[BUFDRVBP]
|
||
MOV DX,[BUFSECNO]
|
||
MOV BX,[BUFFER]
|
||
MOV CX,1
|
||
CALL DWRITE
|
||
NOBUF:
|
||
MOV CL,[NUMIO]
|
||
MOV CH,0
|
||
MOV BP,[DRVTAB]
|
||
WRTFAT:
|
||
PUSH CX
|
||
CALL CHKFATWRT
|
||
POP CX
|
||
ADD BP,DPBSIZ
|
||
LOOP WRTFAT
|
||
RET
|
||
|
||
|
||
GETDRV: ;System call 25
|
||
MOV AL,CS:[CURDRV]
|
||
RET15: RET
|
||
|
||
|
||
SETRNDREC: ;System call 36
|
||
CALL GETREC
|
||
MOV [DI+33],AX
|
||
MOV [DI+35],DL
|
||
CMP [DI.RECSIZ],64
|
||
JAE RET15
|
||
MOV [DI+36],DH ;Set 4th byte only if record size < 64
|
||
RET16: RET
|
||
|
||
|
||
SELDSK: ;System call 14
|
||
MOV AL,CS:[NUMDRV]
|
||
CMP DL,AL
|
||
JNB RET17
|
||
MOV CS:[CURDRV],DL
|
||
RET17: RET
|
||
|
||
BUFIN: ;System call 10
|
||
MOV AX,CS
|
||
MOV ES,AX
|
||
MOV SI,DX
|
||
MOV CH,0
|
||
LODSW
|
||
OR AL,AL
|
||
JZ RET17
|
||
MOV BL,AH
|
||
MOV BH,CH
|
||
CMP AL,BL
|
||
JBE NOEDIT
|
||
CMP BYTE PTR [BX+SI],0DH
|
||
JZ EDITON
|
||
NOEDIT:
|
||
MOV BL,CH
|
||
EDITON:
|
||
MOV DL,AL
|
||
DEC DX
|
||
NEWLIN:
|
||
MOV AL,CS:[CARPOS]
|
||
MOV CS:[STARTPOS],AL
|
||
PUSH SI
|
||
MOV DI,OFFSET DOSGROUP:INBUF
|
||
MOV AH,CH
|
||
MOV BH,CH
|
||
MOV DH,CH
|
||
GETCH:
|
||
CALL IN
|
||
CMP AL,"F"-"@" ;Ignore ^F
|
||
JZ GETCH
|
||
CMP AL,CS:ESCCHAR
|
||
JZ ESC
|
||
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
|
||
SAVCH:
|
||
CMP DH,DL
|
||
JAE BUFFUL
|
||
STOSB
|
||
INC DH
|
||
CALL BUFOUT
|
||
OR AH,AH
|
||
JNZ GETCH
|
||
CMP BH,BL
|
||
JAE GETCH
|
||
INC SI
|
||
INC BH
|
||
JMP SHORT GETCH
|
||
|
||
BUFFUL:
|
||
MOV AL,7
|
||
CALL OUT
|
||
JMP SHORT GETCH
|
||
|
||
ESC:
|
||
CALL IN
|
||
MOV CL,ESCTABLEN
|
||
PUSH DI
|
||
MOV DI,OFFSET DOSGROUP:ESCTAB
|
||
REPNE SCASB
|
||
POP DI
|
||
SHL CX,1
|
||
MOV BP,CX
|
||
JMP [BP+OFFSET DOSGROUP:ESCFUNC]
|
||
|
||
ENDLIN:
|
||
STOSB
|
||
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,OFFSET DOSGROUP:INBUF
|
||
MOV CL,DH
|
||
REP MOVSB
|
||
RET
|
||
CRLF:
|
||
MOV AL,13
|
||
CALL OUT
|
||
MOV AL,10
|
||
JMP OUT
|
||
|
||
PHYCRLF:
|
||
CALL CRLF
|
||
JMP SHORT GETCH
|
||
|
||
KILNEW:
|
||
MOV AL,"\"
|
||
CALL OUT
|
||
POP SI
|
||
PUTNEW:
|
||
CALL CRLF
|
||
MOV AL,CS:[STARTPOS]
|
||
CALL TAB
|
||
JMP NEWLIN
|
||
|
||
BACKSP:
|
||
OR DH,DH
|
||
JZ OLDBAK
|
||
CALL BACKUP
|
||
MOV AL,ES:[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:
|
||
SCASB
|
||
JNA CHKCNT
|
||
CMP ES:BYTE PTR [DI+1],9
|
||
JZ HAVTAB
|
||
DEC BL
|
||
CHKCNT:
|
||
LOOP FNDPOS
|
||
FIGTAB:
|
||
SUB BL,CS:[STARTPOS]
|
||
HAVTAB:
|
||
SUB BL,DH
|
||
ADD CL,BL
|
||
AND CL,7
|
||
CLD
|
||
POP BX
|
||
POP DI
|
||
JZ OLDBAK
|
||
TABBAK:
|
||
CALL BACKMES
|
||
LOOP TABBAK
|
||
JMP SHORT 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
|
||
JMP SHORT COPYEACH
|
||
|
||
COPYSTR:
|
||
CALL FINDOLD
|
||
JMP SHORT COPYEACH
|
||
|
||
COPYONE:
|
||
MOV CL,1
|
||
COPYEACH:
|
||
MOV AH,0
|
||
CMP DH,DL
|
||
JZ GETCH2
|
||
CMP BH,BL
|
||
JZ GETCH2
|
||
LODSB
|
||
STOSB
|
||
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 SCASB
|
||
POP DI
|
||
POP ES
|
||
JNZ NOTFND
|
||
NOT CL
|
||
ADD CL,BL
|
||
SUB CL,BH
|
||
RET30: 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:
|
||
IF TOGLINS
|
||
NOT AH
|
||
JMP GETCH
|
||
ENDIF
|
||
IF NOT TOGLINS
|
||
MOV AH,-1
|
||
JMP GETCH
|
||
|
||
EXITINS:
|
||
MOV AH,0
|
||
JMP GETCH
|
||
ENDIF
|
||
|
||
ESCFUNC DW GETCH
|
||
DW TWOESC
|
||
IF NOT TOGLINS
|
||
DW EXITINS
|
||
ENDIF
|
||
DW ENTERINS
|
||
DW BACKSP
|
||
DW REEDIT
|
||
DW KILNEW
|
||
DW COPYLIN
|
||
DW SKIPSTR
|
||
DW COPYSTR
|
||
DW SKIPONE
|
||
DW COPYONE
|
||
|
||
IF IBM
|
||
DW COPYONE
|
||
DW CTRLZ
|
||
CTRLZ:
|
||
MOV AL,"Z"-"@"
|
||
JMP SAVCH
|
||
ENDIF
|
||
BUFOUT:
|
||
CMP AL," "
|
||
JAE OUT
|
||
CMP AL,9
|
||
JZ OUT
|
||
PUSH AX
|
||
MOV AL,"^"
|
||
CALL OUT
|
||
POP AX
|
||
OR AL,40H
|
||
JMP SHORT OUT
|
||
|
||
NOSTOP:
|
||
CMP AL,"P"-"@"
|
||
JZ INCHK
|
||
IF NOT TOGLPRN
|
||
CMP AL,"N"-"@"
|
||
JZ INCHK
|
||
ENDIF
|
||
CMP AL,"C"-"@"
|
||
JZ INCHK
|
||
RET
|
||
|
||
CONOUT: ;System call 2
|
||
MOV AL,DL
|
||
OUT:
|
||
CMP AL,20H
|
||
JB CTRLOUT
|
||
CMP AL,7FH
|
||
JZ OUTCH
|
||
INC CS:BYTE PTR [CARPOS]
|
||
OUTCH:
|
||
PUSH AX
|
||
CALL STATCHK
|
||
POP AX
|
||
CALL FAR PTR BIOSOUT
|
||
TEST CS:BYTE PTR [PFLAG],-1
|
||
JZ RET18
|
||
CALL FAR PTR BIOSPRINT
|
||
RET18: RET
|
||
|
||
STATCHK:
|
||
CALL FAR PTR BIOSSTAT
|
||
JZ RET18
|
||
CMP AL,'S'-'@'
|
||
JNZ NOSTOP
|
||
CALL FAR PTR BIOSIN ;Eat Cntrl-S
|
||
INCHK:
|
||
CALL FAR PTR BIOSIN
|
||
CMP AL,'P'-'@'
|
||
JZ PRINTON
|
||
IF NOT TOGLPRN
|
||
CMP AL,'N'-'@'
|
||
JZ PRINTOFF
|
||
ENDIF
|
||
CMP AL,'C'-'@'
|
||
JNZ RET18
|
||
; Ctrl-C handler.
|
||
; "^C" and CR/LF is printed. 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.
|
||
MOV AL,3 ;Display "^C"
|
||
CALL BUFOUT
|
||
CALL CRLF
|
||
CLI ;Prepare to play with stack
|
||
MOV SS,CS:[SSSAVE]
|
||
MOV SP,CS:[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
|
||
JMP COMMAND ;Repeat command otherwise
|
||
|
||
PRINTON:
|
||
IF TOGLPRN
|
||
NOT CS:BYTE PTR [PFLAG]
|
||
RET
|
||
ENDIF
|
||
IF NOT TOGLPRN
|
||
MOV CS:BYTE PTR [PFLAG],1
|
||
RET
|
||
|
||
PRINTOFF:
|
||
MOV CS:BYTE PTR [PFLAG],0
|
||
RET
|
||
ENDIF
|
||
|
||
CTRLOUT:
|
||
CMP AL,13
|
||
JZ ZERPOS
|
||
CMP AL,8
|
||
JZ BACKPOS
|
||
CMP AL,9
|
||
JNZ OUTCHJ
|
||
MOV AL,CS:[CARPOS]
|
||
OR AL,0F8H
|
||
NEG AL
|
||
TAB:
|
||
PUSH CX
|
||
MOV CL,AL
|
||
MOV CH,0
|
||
JCXZ POPTAB
|
||
TABLP:
|
||
MOV AL," "
|
||
CALL OUT
|
||
LOOP TABLP
|
||
POPTAB:
|
||
POP CX
|
||
RET19: RET
|
||
|
||
ZERPOS:
|
||
MOV CS:BYTE PTR [CARPOS],0
|
||
OUTCHJ: JMP OUTCH
|
||
|
||
BACKPOS:
|
||
DEC CS:BYTE PTR [CARPOS]
|
||
JMP OUTCH
|
||
|
||
|
||
CONSTAT: ;System call 11
|
||
CALL STATCHK
|
||
MOV AL,0
|
||
JZ RET19
|
||
OR AL,-1
|
||
RET
|
||
|
||
|
||
CONIN: ;System call 1
|
||
CALL IN
|
||
PUSH AX
|
||
CALL OUT
|
||
POP AX
|
||
RET
|
||
|
||
|
||
IN: ;System call 8
|
||
CALL INCHK
|
||
JZ IN
|
||
RET29: RET
|
||
|
||
RAWIO: ;System call 6
|
||
MOV AL,DL
|
||
CMP AL,-1
|
||
JNZ RAWOUT
|
||
LDS SI,DWORD PTR CS:[SPSAVE] ;Get pointer to register save area
|
||
CALL FAR PTR BIOSSTAT
|
||
JNZ RESFLG
|
||
OR BYTE PTR [SI.FSAVE],40H ;Set user's zero flag
|
||
XOR AL,AL
|
||
RET
|
||
|
||
RESFLG:
|
||
AND BYTE PTR [SI.FSAVE],0FFH-40H ;Reset user's zero flag
|
||
RAWINP: ;System call 7
|
||
CALL FAR PTR BIOSIN
|
||
RET
|
||
RAWOUT:
|
||
CALL FAR PTR BIOSOUT
|
||
RET
|
||
|
||
LIST: ;System call 5
|
||
MOV AL,DL
|
||
LISTOUT:
|
||
PUSH AX
|
||
CALL STATCHK
|
||
POP AX
|
||
CALL FAR PTR BIOSPRINT
|
||
RET20: RET
|
||
|
||
PRTBUF: ;System call 9
|
||
MOV SI,DX
|
||
OUTSTR:
|
||
LODSB
|
||
CMP AL,"$"
|
||
JZ RET20
|
||
CALL OUT
|
||
JMP SHORT OUTSTR
|
||
|
||
OUTMES: ;String output for internal messages
|
||
LODS CS:BYTE PTR [SI]
|
||
CMP AL,"$"
|
||
JZ RET20
|
||
CALL OUT
|
||
JMP SHORT OUTMES
|
||
|
||
|
||
MAKEFCB: ;Interrupt call 41
|
||
DRVBIT EQU 2
|
||
NAMBIT EQU 4
|
||
EXTBIT EQU 8
|
||
MOV DL,0 ;Flag--not ambiguous file name
|
||
TEST AL,DRVBIT ;Use current drive field if default?
|
||
JNZ DEFDRV
|
||
MOV BYTE PTR ES:[DI],0 ;No - use default drive
|
||
DEFDRV:
|
||
INC DI
|
||
MOV CX,8
|
||
TEST AL,NAMBIT ;Use current name fiels as defualt?
|
||
XCHG AX,BX ;Save bits in BX
|
||
MOV AL," "
|
||
JZ FILLB ;If not, go fill with blanks
|
||
ADD DI,CX
|
||
XOR CX,CX ;Don't fill any
|
||
FILLB:
|
||
REP STOSB
|
||
MOV CL,3
|
||
TEST BL,EXTBIT ;Use current extension as default
|
||
JZ FILLB2
|
||
ADD DI,CX
|
||
XOR CX,CX
|
||
FILLB2:
|
||
REP STOSB
|
||
XCHG AX,CX ;Put zero in AX
|
||
STOSW
|
||
STOSW ;Initialize two words after to zero
|
||
SUB DI,16 ;Point back at start
|
||
TEST BL,1 ;Scan off separators if not zero
|
||
JZ SKPSPC
|
||
CALL SCANB ;Peel off blanks and tabs
|
||
CALL DELIM ;Is it a one-time-only delimiter?
|
||
JNZ NOSCAN
|
||
INC SI ;Skip over the delimiter
|
||
SKPSPC:
|
||
CALL SCANB ;Always kill preceding blanks and tabs
|
||
NOSCAN:
|
||
CALL GETLET
|
||
JBE NODRV ;Quit if termination character
|
||
CMP BYTE PTR[SI],":" ;Check for potential drive specifier
|
||
JNZ NODRV
|
||
INC SI ;Skip over colon
|
||
SUB AL,"@" ;Convert drive letter to binary drive number
|
||
JBE BADDRV ;Valid drive numbers are 1-15
|
||
CMP AL,CS:[NUMDRV]
|
||
JBE HAVDRV
|
||
BADDRV:
|
||
MOV DL,-1
|
||
HAVDRV:
|
||
STOSB ;Put drive specifier in first byte
|
||
INC SI
|
||
DEC DI ;Counteract next two instructions
|
||
NODRV:
|
||
DEC SI ;Back up
|
||
INC DI ;Skip drive byte
|
||
MOV CX,8
|
||
CALL GETWORD ;Get 8-letter file name
|
||
CMP BYTE PTR [SI],"."
|
||
JNZ NODOT
|
||
INC SI ;Skip over dot if present
|
||
MOV CX,3 ;Get 3-letter extension
|
||
CALL MUSTGETWORD
|
||
NODOT:
|
||
LDS BX,CS:DWORD PTR [SPSAVE]
|
||
MOV [BX.SISAVE],SI
|
||
MOV AL,DL
|
||
RET
|
||
|
||
NONAM:
|
||
ADD DI,CX
|
||
DEC SI
|
||
RET
|
||
|
||
GETWORD:
|
||
CALL GETLET
|
||
JBE NONAM ;Exit if invalid character
|
||
DEC SI
|
||
MUSTGETWORD:
|
||
CALL GETLET
|
||
JBE FILLNAM
|
||
JCXZ MUSTGETWORD
|
||
DEC CX
|
||
CMP AL,"*" ;Check for ambiguous file specifier
|
||
JNZ NOSTAR
|
||
MOV AL,"?"
|
||
REP STOSB
|
||
NOSTAR:
|
||
STOSB
|
||
CMP AL,"?"
|
||
JNZ MUSTGETWORD
|
||
OR DL,1 ;Flag ambiguous file name
|
||
JMP MUSTGETWORD
|
||
FILLNAM:
|
||
MOV AL," "
|
||
REP STOSB
|
||
DEC SI
|
||
RET21: RET
|
||
|
||
SCANB:
|
||
LODSB
|
||
CALL SPCHK
|
||
JZ SCANB
|
||
DEC SI
|
||
RET
|
||
|
||
GETLET:
|
||
;Get a byte from [SI], convert it to upper case, and compare for delimiter.
|
||
;ZF set if a delimiter, CY set if a control character (other than TAB).
|
||
LODSB
|
||
AND AL,7FH
|
||
CMP AL,"a"
|
||
JB CHK
|
||
CMP AL,"z"
|
||
JA CHK
|
||
SUB AL,20H ;Convert to upper case
|
||
CHK:
|
||
CMP AL,"."
|
||
JZ RET21
|
||
CMP AL,'"'
|
||
JZ RET21
|
||
CMP AL,"/"
|
||
JZ RET21
|
||
CMP AL,"["
|
||
JZ RET21
|
||
CMP AL,"]"
|
||
JZ RET21
|
||
|
||
IF IBM
|
||
DELIM:
|
||
ENDIF
|
||
CMP AL,":" ;Allow ":" as separator in IBM version
|
||
JZ RET21
|
||
IF NOT IBM
|
||
DELIM:
|
||
ENDIF
|
||
|
||
CMP AL,"+"
|
||
JZ RET101
|
||
CMP AL,"="
|
||
JZ RET101
|
||
CMP AL,";"
|
||
JZ RET101
|
||
CMP AL,","
|
||
JZ RET101
|
||
SPCHK:
|
||
CMP AL,9 ;Filter out tabs too
|
||
JZ RET101
|
||
;WARNING! " " MUST be the last compare
|
||
CMP AL," "
|
||
RET101: RET
|
||
|
||
SETVECT: ; Interrupt call 37
|
||
XOR BX,BX
|
||
MOV ES,BX
|
||
MOV BL,AL
|
||
SHL BX,1
|
||
SHL BX,1
|
||
MOV ES:[BX],DX
|
||
MOV ES:[BX+2],DS
|
||
RET
|
||
|
||
|
||
NEWBASE: ; Interrupt call 38
|
||
MOV ES,DX
|
||
LDS SI,CS:DWORD PTR [SPSAVE]
|
||
MOV DS,[SI.CSSAVE]
|
||
XOR SI,SI
|
||
MOV DI,SI
|
||
MOV AX,DS:[2]
|
||
MOV CX,80H
|
||
REP MOVSW
|
||
|
||
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)
|
||
; [18] to [21] have fatal error address (from INT 24H)
|
||
; DX,BP unchanged. All other registers destroyed.
|
||
|
||
XOR CX,CX
|
||
MOV DS,CX
|
||
MOV ES,DX
|
||
MOV SI,EXIT
|
||
MOV DI,SAVEXIT
|
||
MOVSW
|
||
MOVSW
|
||
MOVSW
|
||
MOVSW
|
||
MOVSW
|
||
MOVSW
|
||
MOV ES:[2],AX
|
||
SUB AX,DX
|
||
CMP AX,MAXDIF
|
||
JBE HAVDIF
|
||
MOV AX,MAXDIF
|
||
HAVDIF:
|
||
MOV BX,ENTRYPOINTSEG
|
||
SUB BX,AX
|
||
SHL AX,1
|
||
SHL AX,1
|
||
SHL AX,1
|
||
SHL AX,1
|
||
MOV DS,DX
|
||
MOV DS:[6],AX
|
||
MOV DS:[8],BX
|
||
MOV DS:[0],20CDH ;"INT INTTAB"
|
||
MOV DS:(BYTE PTR [5]),LONGCALL
|
||
RET
|
||
|
||
DATE16:
|
||
PUSH CX
|
||
CALL READTIME
|
||
SHL CL,1 ;Minutes to left part of byte
|
||
SHL CL,1
|
||
SHL CX,1 ;Push hours and minutes to left end
|
||
SHL CX,1
|
||
SHL CX,1
|
||
SHR DH,1 ;Count every two seconds
|
||
OR CL,DH ;Combine seconds with hours and minutes
|
||
MOV DX,CX
|
||
POP CX
|
||
MOV AX,WORD PTR [MONTH] ;Fetch month and year
|
||
SHL AL,1 ;Push month to left to make room for day
|
||
SHL AL,1
|
||
SHL AL,1
|
||
SHL AL,1
|
||
SHL AX,1
|
||
OR AL,[DAY]
|
||
RET22: RET
|
||
|
||
FOURYEARS EQU 3*365+366
|
||
|
||
READTIME:
|
||
;Gets time in CX:DX. Figures new date if it has changed.
|
||
;Uses AX, CX, DX.
|
||
CALL FAR PTR BIOSGETTIME
|
||
CMP AX,[DAYCNT] ;See if day count is the same
|
||
JZ RET22
|
||
CMP AX,FOURYEARS*30 ;Number of days in 120 years
|
||
JAE RET22 ;Ignore if too large
|
||
MOV [DAYCNT],AX
|
||
PUSH SI
|
||
PUSH CX
|
||
PUSH DX ;Save time
|
||
XOR DX,DX
|
||
MOV CX,FOURYEARS ;Number of days in 4 years
|
||
DIV CX ;Compute number of 4-year units
|
||
SHL AX,1
|
||
SHL AX,1
|
||
SHL AX,1 ;Multiply by 8 (no. of half-years)
|
||
MOV CX,AX ;<240 implies AH=0
|
||
MOV SI,OFFSET DOSGROUP:YRTAB ;Table of days in each year
|
||
CALL DSLIDE ;Find out which of four years we're in
|
||
SHR CX,1 ;Convert half-years to whole years
|
||
JNC SK ;Extra half-year?
|
||
ADD DX,200
|
||
SK:
|
||
CALL SETYEAR
|
||
MOV CL,1 ;At least at first month in year
|
||
MOV SI,OFFSET DOSGROUP:MONTAB ;Table of days in each month
|
||
CALL DSLIDE ;Find out which month we're in
|
||
MOV [MONTH],CL
|
||
INC DX ;Remainder is day of month (start with one)
|
||
MOV [DAY],DL
|
||
CALL WKDAY ;Set day of week
|
||
POP DX
|
||
POP CX
|
||
POP SI
|
||
RET23: RET
|
||
|
||
DSLIDE:
|
||
MOV AH,0
|
||
DSLIDE1:
|
||
LODSB ;Get count of days
|
||
CMP DX,AX ;See if it will fit
|
||
JB RET23 ;If not, done
|
||
SUB DX,AX
|
||
INC CX ;Count one more month/year
|
||
JMP SHORT DSLIDE1
|
||
|
||
SETYEAR:
|
||
;Set year with value in CX. Adjust length of February for this year.
|
||
MOV BYTE PTR [YEAR],CL
|
||
CHKYR:
|
||
TEST CL,3 ;Check for leap year
|
||
MOV AL,28
|
||
JNZ SAVFEB ;28 days if no leap year
|
||
INC AL ;Add leap day
|
||
SAVFEB:
|
||
MOV [MONTAB+1],AL ;Store for February
|
||
RET
|
||
|
||
;Days in year
|
||
YRTAB DB 200,166 ;Leap year
|
||
DB 200,165
|
||
DB 200,165
|
||
DB 200,165
|
||
|
||
;Days of each month
|
||
MONTAB DB 31 ;January
|
||
DB 28 ;February--reset each time year changes
|
||
DB 31 ;March
|
||
DB 30 ;April
|
||
DB 31 ;May
|
||
DB 30 ;June
|
||
DB 31 ;July
|
||
DB 31 ;August
|
||
DB 30 ;September
|
||
DB 31 ;October
|
||
DB 30 ;November
|
||
DB 31 ;December
|
||
|
||
GETDATE: ;Function call 42
|
||
PUSH CS
|
||
POP DS
|
||
CALL READTIME ;Check for rollover to next day
|
||
MOV AX,[YEAR]
|
||
MOV BX,WORD PTR [DAY]
|
||
LDS SI,DWORD PTR [SPSAVE] ;Get pointer to user registers
|
||
MOV [SI.DXSAVE],BX ;DH=month, DL=day
|
||
ADD AX,1980 ;Put bias back
|
||
MOV [SI.CXSAVE],AX ;CX=year
|
||
MOV AL,CS:[WEEKDAY]
|
||
RET24: RET
|
||
|
||
SETDATE: ;Function call 43
|
||
MOV AL,-1 ;Be ready to flag error
|
||
SUB CX,1980 ;Fix bias in year
|
||
JC RET24 ;Error if not big enough
|
||
CMP CX,119 ;Year must be less than 2100
|
||
JA RET24
|
||
OR DH,DH
|
||
JZ RET24
|
||
OR DL,DL
|
||
JZ RET24 ;Error if either month or day is 0
|
||
CMP DH,12 ;Check against max. month
|
||
JA RET24
|
||
PUSH CS
|
||
POP DS
|
||
CALL CHKYR ;Set Feb. up for new year
|
||
MOV AL,DH
|
||
MOV BX,OFFSET DOSGROUP:MONTAB-1
|
||
XLAT ;Look up days in month
|
||
CMP AL,DL
|
||
MOV AL,-1 ;Restore error flag, just in case
|
||
JB RET24 ;Error if too many days
|
||
CALL SETYEAR
|
||
MOV WORD PTR [DAY],DX ;Set both day and month
|
||
SHR CX,1
|
||
SHR CX,1
|
||
MOV AX,FOURYEARS
|
||
MOV BX,DX
|
||
MUL CX
|
||
MOV CL,BYTE PTR [YEAR]
|
||
AND CL,3
|
||
MOV SI,OFFSET DOSGROUP:YRTAB
|
||
MOV DX,AX
|
||
SHL CX,1 ;Two entries per year, so double count
|
||
CALL DSUM ;Add up the days in each year
|
||
MOV CL,BH ;Month of year
|
||
MOV SI,OFFSET DOSGROUP:MONTAB
|
||
DEC CX ;Account for months starting with one
|
||
CALL DSUM ;Add up days in each month
|
||
MOV CL,BL ;Day of month
|
||
DEC CX ;Account for days starting with one
|
||
ADD DX,CX ;Add in to day total
|
||
XCHG AX,DX ;Get day count in AX
|
||
MOV [DAYCNT],AX
|
||
CALL FAR PTR BIOSSETDATE
|
||
WKDAY:
|
||
MOV AX,[DAYCNT]
|
||
XOR DX,DX
|
||
MOV CX,7
|
||
INC AX
|
||
INC AX ;First day was Tuesday
|
||
DIV CX ;Compute day of week
|
||
MOV [WEEKDAY],DL
|
||
XOR AL,AL ;Flag OK
|
||
RET25: RET
|
||
|
||
DSUM:
|
||
MOV AH,0
|
||
JCXZ RET25
|
||
DSUM1:
|
||
LODSB
|
||
ADD DX,AX
|
||
LOOP DSUM1
|
||
RET
|
||
|
||
GETTIME: ;Function call 44
|
||
PUSH CS
|
||
POP DS
|
||
CALL READTIME
|
||
LDS SI,DWORD PTR [SPSAVE] ;Get pointer to user registers
|
||
MOV [SI.DXSAVE],DX
|
||
MOV [SI.CXSAVE],CX
|
||
XOR AL,AL
|
||
RET26: RET
|
||
|
||
SETTIME: ;Function call 45
|
||
;Time is in CX:DX in hours, minutes, seconds, 1/100 sec.
|
||
MOV AL,-1 ;Flag in case of error
|
||
CMP CH,24 ;Check hours
|
||
JAE RET26
|
||
CMP CL,60 ;Check minutes
|
||
JAE RET26
|
||
CMP DH,60 ;Check seconds
|
||
JAE RET26
|
||
CMP DL,100 ;Check 1/100's
|
||
JAE RET26
|
||
CALL FAR PTR BIOSSETTIME
|
||
XOR AL,AL
|
||
RET
|
||
|
||
|
||
; Default handler for division overflow trap
|
||
DIVOV:
|
||
PUSH SI
|
||
PUSH AX
|
||
MOV SI,OFFSET DOSGROUP:DIVMES
|
||
CALL OUTMES
|
||
POP AX
|
||
POP SI
|
||
INT 23H ;Use Ctrl-C abort on divide overflow
|
||
IRET
|
||
|
||
CODSIZ EQU $-CODSTRT ;Size of code segment
|
||
CODE ENDS
|
||
|
||
|
||
;***** DATA AREA *****
|
||
CONSTANTS SEGMENT BYTE
|
||
ORG 0
|
||
CONSTRT EQU $ ;Start of constants segment
|
||
|
||
IONAME:
|
||
IF NOT IBM
|
||
DB "PRN ","LST ","NUL ","AUX ","CON "
|
||
ENDIF
|
||
IF IBM
|
||
DB "COM1","PRN ","LPT1","NUL ","AUX ","CON "
|
||
ENDIF
|
||
DIVMES DB 13,10,"Divide overflow",13,10,"$"
|
||
CARPOS DB 0
|
||
STARTPOS DB 0
|
||
PFLAG DB 0
|
||
DIRTYDIR DB 0 ;Dirty buffer flag
|
||
NUMDRV DB 0 ;Number of drives
|
||
NUMIO DB ? ;Number of disk tables
|
||
VERFLG DB 0 ;Initialize with verify off
|
||
CONTPOS DW 0
|
||
DMAADD DW 80H ;User's disk transfer address (disp/seg)
|
||
DW ?
|
||
ENDMEM DW ?
|
||
MAXSEC DW 0
|
||
BUFFER DW ?
|
||
BUFSECNO DW 0
|
||
BUFDRVNO DB -1
|
||
DIRTYBUF DB 0
|
||
BUFDRVBP DW ?
|
||
DIRBUFID DW -1
|
||
DAY DB 0
|
||
MONTH DB 0
|
||
YEAR DW 0
|
||
DAYCNT DW -1
|
||
WEEKDAY DB 0
|
||
CURDRV DB 0 ;Default to drive A
|
||
DRVTAB DW 0 ;Address of start of DPBs
|
||
DOSLEN EQU CODSIZ+($-CONSTRT) ;Size of CODE + CONSTANTS segments
|
||
CONSTANTS ENDS
|
||
|
||
DATA SEGMENT WORD
|
||
; Init code overlaps with data area below
|
||
|
||
ORG 0
|
||
INBUF DB 128 DUP (?)
|
||
CONBUF DB 131 DUP (?) ;The rest of INBUF and console buffer
|
||
LASTENT DW ?
|
||
EXITHOLD DB 4 DUP (?)
|
||
FATBASE DW ?
|
||
NAME1 DB 11 DUP (?) ;File name buffer
|
||
ATTRIB DB ?
|
||
NAME2 DB 11 DUP (?)
|
||
NAME3 DB 12 DUP (?)
|
||
EXTFCB DB ?
|
||
;WARNING - the following two items are accessed as a word
|
||
CREATING DB ?
|
||
DELALL DB ?
|
||
TEMP LABEL WORD
|
||
SPSAVE DW ?
|
||
SSSAVE DW ?
|
||
CONTSTK DW ?
|
||
SECCLUSPOS DB ? ;Position of first sector within cluster
|
||
DSKERR DB ?
|
||
TRANS DB ?
|
||
PREREAD DB ? ;0 means preread; 1 means optional
|
||
READOP DB ?
|
||
THISDRV DB ?
|
||
|
||
EVEN
|
||
FCB DW ? ;Address of user FCB
|
||
NEXTADD DW ?
|
||
RECPOS DB 4 DUP (?)
|
||
RECCNT DW ?
|
||
LASTPOS DW ?
|
||
CLUSNUM DW ?
|
||
SECPOS DW ? ;Position of first sector accessed
|
||
VALSEC DW ? ;Number of valid (previously written) sectors
|
||
BYTSECPOS DW ? ;Position of first byte within sector
|
||
BYTPOS DB 4 DUP (?) ;Byte position in file of access
|
||
BYTCNT1 DW ? ;No. of bytes in first sector
|
||
BYTCNT2 DW ? ;No. of bytes in last sector
|
||
SECCNT DW ? ;No. of whole sectors
|
||
ENTFREE DW ?
|
||
|
||
DB 80H DUP (?) ;Stack space
|
||
IOSTACK LABEL BYTE
|
||
DB 80H DUP (?)
|
||
DSKSTACK LABEL BYTE
|
||
|
||
IF DSKTEST
|
||
NSS DW ?
|
||
NSP DW ?
|
||
ENDIF
|
||
|
||
DIRBUF LABEL WORD
|
||
|
||
;Init code below overlaps with data area above
|
||
|
||
ORG 0
|
||
|
||
MOVFAT:
|
||
;This section of code is safe from being overwritten by block move
|
||
REP MOVS BYTE PTR [DI],[SI]
|
||
CLD
|
||
MOV ES:[DMAADD+2],DX
|
||
MOV SI,[DRVTAB] ;Address of first DPB
|
||
MOV AL,-1
|
||
MOV CL,[NUMIO] ;Number of DPBs
|
||
FLGFAT:
|
||
MOV DI,ES:[SI.FAT] ;get pointer to FAT
|
||
DEC DI ;Point to dirty byte
|
||
STOSB ;Flag as unused
|
||
ADD SI,DPBSIZ ;Point to next DPB
|
||
LOOP FLGFAT
|
||
MOV AX,[ENDMEM]
|
||
CALL SETMEM ;Set up segment
|
||
|
||
XXX PROC FAR
|
||
RET
|
||
XXX ENDP
|
||
|
||
DOSINIT:
|
||
CLI
|
||
CLD
|
||
PUSH CS
|
||
POP ES
|
||
MOV ES:[ENDMEM],DX
|
||
LODSB ;Get no. of drives & no. of I/O drivers
|
||
MOV ES:[NUMIO],AL
|
||
MOV DI,OFFSET DOSGROUP:MEMSTRT
|
||
PERDRV:
|
||
MOV BP,DI
|
||
MOV AL,ES:[DRVCNT]
|
||
STOSB ;DEVNUM
|
||
LODSB ;Physical unit no.
|
||
STOSB ;DRVNUM
|
||
CMP AL,15
|
||
JA BADINIT
|
||
CBW ;Index into FAT size table
|
||
SHL AX,1
|
||
ADD AX,OFFSET DOSGROUP:FATSIZTAB
|
||
XCHG BX,AX
|
||
LODSW ;Pointer to DPT
|
||
PUSH SI
|
||
MOV SI,AX
|
||
LODSW
|
||
STOSW ;SECSIZ
|
||
MOV DX,AX
|
||
CMP AX,ES:[MAXSEC]
|
||
JBE NOTMAX
|
||
MOV ES:[MAXSEC],AX
|
||
NOTMAX:
|
||
LODSB
|
||
DEC AL
|
||
STOSB ;CLUSMSK
|
||
JZ HAVSHFT
|
||
CBW
|
||
FIGSHFT:
|
||
INC AH
|
||
SAR AL,1
|
||
JNZ FIGSHFT
|
||
MOV AL,AH
|
||
HAVSHFT:
|
||
STOSB ;CLUSSHFT
|
||
MOVSW ;FIRFAT (= number of reserved sectors)
|
||
MOVSB ;FATCNT
|
||
MOVSW ;MAXENT
|
||
MOV AX,DX ;SECSIZ again
|
||
MOV CL,5
|
||
SHR AX,CL
|
||
MOV CX,AX ;Directory entries per sector
|
||
DEC AX
|
||
ADD AX,ES:[BP.MAXENT]
|
||
XOR DX,DX
|
||
DIV CX
|
||
STOSW ;DIRSEC (temporarily)
|
||
MOVSW ;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
|
||
DEC WORD PTR ES:[BP.DSKSIZ] ;Damp those oscillations
|
||
JMP SHORT FNDFATSIZ ;Try again
|
||
|
||
BADINIT:
|
||
MOV SI,OFFSET DOSGROUP:BADMES
|
||
CALL OUTMES
|
||
STI
|
||
HLT
|
||
|
||
HAVFATSIZ:
|
||
STOSB ;FATSIZ
|
||
MUL ES:BYTE PTR[BP.FATCNT] ;Space occupied by all FATs
|
||
ADD AX,ES:[BP.FIRFAT]
|
||
STOSW ;FIRDIR
|
||
ADD AX,ES:[BP.DIRSEC]
|
||
MOV ES:[BP.FIRREC],AX ;Destroys DIRSEC
|
||
CALL FIGMAX
|
||
MOV ES:[BP.MAXCLUS],CX
|
||
MOV AX,BX ;Pointer into FAT size table
|
||
STOSW ;Allocate space for FAT pointer
|
||
MOV AL,ES:[BP.FATSIZ]
|
||
XOR AH,AH
|
||
MUL ES:[BP.SECSIZ]
|
||
CMP AX,ES:[BX] ;Bigger than already allocated
|
||
JBE SMFAT
|
||
MOV ES:[BX],AX
|
||
SMFAT:
|
||
POP SI ;Restore pointer to init. table
|
||
MOV AL,ES:[DRVCNT]
|
||
INC AL
|
||
MOV ES:[DRVCNT],AL
|
||
CMP AL,ES:[NUMIO]
|
||
JAE CONTINIT
|
||
JMP PERDRV
|
||
|
||
BADINITJ:
|
||
JMP BADINIT
|
||
|
||
CONTINIT:
|
||
PUSH CS
|
||
POP DS
|
||
;Calculate true address of buffers, FATs, free space
|
||
MOV BP,[MAXSEC]
|
||
MOV AX,OFFSET DOSGROUP:DIRBUF
|
||
ADD AX,BP
|
||
MOV [BUFFER],AX ;Start of buffer
|
||
ADD AX,BP
|
||
MOV [DRVTAB],AX ;Start of DPBs
|
||
SHL BP,1 ;Two sectors - directory and buffer
|
||
ADD BP,DI ;Allocate buffer space
|
||
ADD BP,ADJFAC ;True address of FATs
|
||
PUSH BP
|
||
MOV SI,OFFSET DOSGROUP:FATSIZTAB
|
||
MOV DI,SI
|
||
MOV CX,16
|
||
TOTFATSIZ:
|
||
INC BP ;Add one for Dirty byte
|
||
INC BP ;Add one for I/O device number
|
||
LODSW ;Get size of this FAT
|
||
XCHG AX,BP
|
||
STOSW ;Save address of this FAT
|
||
ADD BP,AX ;Compute size of next FAT
|
||
CMP AX,BP ;If size was zero done
|
||
LOOPNZ TOTFATSIZ
|
||
MOV AL,15
|
||
SUB AL,CL ;Compute number of FATs used
|
||
MOV [NUMDRV],AL
|
||
XOR AX,AX ;Set zero flag
|
||
REPZ SCASW ;Make sure all other entries are zero
|
||
JNZ BADINITJ
|
||
ADD BP,15 ;True start of free space
|
||
MOV CL,4
|
||
SHR BP,CL ;First free segment
|
||
MOV DX,CS
|
||
ADD DX,BP
|
||
MOV BX,0FH
|
||
MOV CX,[ENDMEM]
|
||
CMP CX,1 ;Use memory scan?
|
||
JNZ SETEND
|
||
MOV CX,DX ;Start scanning just after DOS
|
||
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:
|
||
IF HIGHMEM
|
||
SUB CX,BP
|
||
MOV BP,CX ;Segment of DOS
|
||
MOV DX,CS ;Program segment
|
||
ENDIF
|
||
IF NOT HIGHMEM
|
||
MOV BP,CS
|
||
ENDIF
|
||
; BP has segment of DOS (whether to load high or run in place)
|
||
; DX has program segment (whether after DOS or overlaying DOS)
|
||
; CX has size of memory in paragraphs (reduced by DOS size if HIGHMEM)
|
||
MOV CS:[ENDMEM],CX
|
||
IF HIGHMEM
|
||
MOV ES,BP
|
||
XOR SI,SI
|
||
MOV DI,SI
|
||
MOV CX,(DOSLEN+1)/2
|
||
PUSH CS
|
||
POP DS
|
||
REP MOVSW ;Move DOS to high memory
|
||
ENDIF
|
||
XOR AX,AX
|
||
MOV DS,AX
|
||
MOV ES,AX
|
||
MOV DI,INTBASE
|
||
MOV AX,OFFSET DOSGROUP:QUIT
|
||
STOSW ;Set abort address--displacement
|
||
MOV AX,BP
|
||
MOV BYTE PTR DS:[ENTRYPOINT],LONGJUMP
|
||
MOV WORD PTR DS:[ENTRYPOINT+1],OFFSET DOSGROUP:ENTRY
|
||
MOV WORD PTR DS:[ENTRYPOINT+3],AX
|
||
MOV WORD PTR DS:[0],OFFSET DOSGROUP:DIVOV ;Set default divide trap address
|
||
MOV DS:[2],AX
|
||
MOV CX,9
|
||
REP STOSW ;Set 5 segments (skip 2 between each)
|
||
MOV WORD PTR DS:[INTBASE+4],OFFSET DOSGROUP:COMMAND
|
||
MOV WORD PTR DS:[INTBASE+12],OFFSET DOSGROUP:IRET ;Ctrl-C exit
|
||
MOV WORD PTR DS:[INTBASE+16],OFFSET DOSGROUP:IRET ;Fatal error exit
|
||
MOV AX,OFFSET BIOSREAD
|
||
STOSW
|
||
MOV AX,BIOSSEG
|
||
STOSW
|
||
STOSW ;Add 2 to DI
|
||
STOSW
|
||
MOV WORD PTR DS:[INTBASE+18H],OFFSET BIOSWRITE
|
||
MOV WORD PTR DS:[EXIT],100H
|
||
MOV WORD PTR DS:[EXIT+2],DX
|
||
IF NOT IBM
|
||
MOV SI,OFFSET DOSGROUP:HEADER
|
||
CALL OUTMES
|
||
ENDIF
|
||
PUSH CS
|
||
POP DS
|
||
PUSH CS
|
||
POP ES
|
||
;Move the FATs into position
|
||
MOV AL,[NUMIO]
|
||
CBW
|
||
XCHG AX,CX
|
||
MOV DI,OFFSET DOSGROUP:MEMSTRT.FAT
|
||
FATPOINT:
|
||
MOV SI,WORD PTR [DI] ;Get address within FAT address table
|
||
MOVSW ;Set address of this FAT
|
||
ADD DI,DPBSIZ-2 ;Point to next DPB
|
||
LOOP FATPOINT
|
||
POP CX ;True address of first FAT
|
||
MOV SI,OFFSET DOSGROUP:MEMSTRT ;Place to move DPBs from
|
||
MOV DI,[DRVTAB] ;Place to move DPBs to
|
||
SUB CX,DI ;Total length of DPBs
|
||
CMP DI,SI
|
||
JBE MOVJMP ;Are we moving to higher or lower memory?
|
||
DEC CX ;Move backwards to higher memory
|
||
ADD DI,CX
|
||
ADD SI,CX
|
||
INC CX
|
||
STD
|
||
MOVJMP:
|
||
MOV ES,BP
|
||
JMP MOVFAT
|
||
|
||
FIGFATSIZ:
|
||
MUL ES:BYTE PTR[BP.FATCNT]
|
||
ADD AX,ES:[BP.FIRFAT]
|
||
ADD AX,ES:[BP.DIRSEC]
|
||
FIGMAX:
|
||
;AX has equivalent of FIRREC
|
||
SUB AX,ES:[BP.DSKSIZ]
|
||
NEG AX
|
||
MOV CL,ES:[BP.CLUSSHFT]
|
||
SHR AX,CL
|
||
INC AX
|
||
MOV CX,AX ;MAXCLUS
|
||
INC AX
|
||
MOV DX,AX
|
||
SHR DX,1
|
||
ADC AX,DX ;Size of FAT in bytes
|
||
MOV SI,ES:[BP.SECSIZ]
|
||
ADD AX,SI
|
||
DEC AX
|
||
XOR DX,DX
|
||
DIV SI
|
||
RET
|
||
|
||
BADMES:
|
||
DB 13,10,"INIT TABLE BAD",13,10,"$"
|
||
|
||
FATSIZTAB:
|
||
DW 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
||
DRVCNT DB 0
|
||
|
||
MEMSTRT LABEL WORD
|
||
ADJFAC EQU DIRBUF-MEMSTRT
|
||
DATA ENDS
|
||
END
|
||
|