MS-DOS/v2.0/source/ROM.ASM

530 lines
14 KiB
NASM
Raw Normal View History

1983-08-13 01:53:34 +01:00
;
; Disk utilities of MSDOS
;
INCLUDE DOSSEG.ASM
CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME SS:DOSGROUP,CS:DOSGROUP
.XLIST
.xcref
INCLUDE DOSSYM.ASM
INCLUDE DEVSYM.ASM
.cref
.list
TITLE ROM - miscellaneous routines
NAME ROM
i_need CLUSNUM,WORD
i_need NEXTADD,WORD
i_need LASTPOS,WORD
i_need SECCLUSPOS,BYTE
i_need FATBYT,WORD
i_need RECPOS,4
i_need THISFCB,DWORD
i_need TRANS,BYTE
i_need BYTCNT1,WORD
i_need CURBUF,DWORD
i_need BYTSECPOS,WORD
i_need DMAADD,WORD
i_need SECPOS,WORD
i_need VALSEC,WORD
procedure GET_random_record,NEAR
entry GETRRPOS1
MOV CX,1
entry GetRRPos
MOV DI,DX
CMP BYTE PTR [DI],-1
JNZ NORMFCB1
ADD DI,7
NORMFCB1:
MOV AX,WORD PTR [DI.fcb_RR]
MOV DX,WORD PTR [DI.fcb_RR+2]
return
GET_random_record ENDP
SUBTTL FNDCLUS -- Skip over allocation units
PAGE
procedure FNDCLUS,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; CX = No. of clusters to skip
; ES:BP = Base of drive parameters
; [THISFCB] 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.
PUSH ES
LES DI,[THISFCB]
MOV BX,ES:[DI.fcb_LSTCLUS] ; fcb_lstclus is packed with dir clus
AND BX,0FFFh ; get rid of dir nibble
MOV DX,ES:[DI.fcb_CLUSPOS]
OR BX,BX
JZ NOCLUS
SUB CX,DX
JNB FINDIT
ADD CX,DX
XOR DX,DX
MOV BX,ES:[DI.fcb_FIRCLUS]
FINDIT:
POP ES
JCXZ RET10
entry SKPCLP
invoke UNPACK
CMP DI,0FF8H
JAE RET10
XCHG BX,DI
INC DX
LOOP SKPCLP
RET10: return
NOCLUS:
POP ES
INC CX
DEC DX
return
FNDCLUS ENDP
SUBTTL BUFSEC -- BUFFER A SECTOR AND SET UP A TRANSFER
PAGE
procedure BUFSEC,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; AH = priority of buffer
; AL = 0 if buffer must be read, 1 if no pre-read needed
; ES: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:
; ES:DI = Pointer to buffer
; SI = 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
invoke GETBUFFR
MOV BYTE PTR [TRANS],1 ; A transfer is taking place
MOV SI,[NEXTADD]
MOV DI,SI
MOV CX,[BYTCNT1]
ADD DI,CX
MOV [NEXTADD],DI
LES DI,[CURBUF]
ADD DI,BUFINSIZ ; Point to buffer
ADD DI,[BYTSECPOS]
return
BUFSEC ENDP
SUBTTL BUFRD, BUFWRT -- PERFORM BUFFERED READ AND WRITE
PAGE
procedure BUFRD,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Do a partial sector read via one of the system buffers
; ES:BP Points to DPB
PUSH ES
MOV AX,LBRPRI SHL 8 ; Assume last byte read
CALL BUFSEC
MOV BX,ES
MOV ES,[DMAADD+2]
MOV DS,BX
ASSUME DS:NOTHING
XCHG DI,SI
SHR CX,1
JNC EVENRD
MOVSB
EVENRD:
REP MOVSW
POP ES
LDS DI,[CURBUF]
LEA BX,[DI.BufInSiz]
SUB SI,BX ; Position in buffer
invoke PLACEBUF
CMP SI,ES:[BP.dpb_sector_size]
JB RBUFPLACED
invoke PLACEHEAD
RBUFPLACED:
PUSH SS
POP DS
return
BUFRD ENDP
procedure BUFWRT,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Do a partial sector write via one of the system buffers
; ES:BP Points to DPB
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
XOR AL,AL
NOREAD:
PUSH ES
CALL BUFSEC
MOV DS,[DMAADD+2]
ASSUME DS:NOTHING
SHR CX,1
JNC EVENWRT
MOVSB
EVENWRT:
REP MOVSW
POP ES
LDS BX,[CURBUF]
MOV BYTE PTR [BX.BUFDIRTY],1
LEA SI,[BX.BufInSiz]
SUB DI,SI ; Position in buffer
MOV SI,DI
MOV DI,BX
invoke PLACEBUF
CMP SI,ES:[BP.dpb_sector_size]
JB WBUFPLACED
invoke PLACEHEAD
WBUFPLACED:
PUSH SS
POP DS
return
BUFWRT ENDP
SUBTTL NEXTSEC -- Compute next sector to read or write
PAGE
procedure NEXTSEC,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Compute the next sector to read or write
; ES:BP Points to DPB
TEST BYTE PTR [TRANS],-1
JZ CLRET
MOV AL,[SECCLUSPOS]
INC AL
CMP AL,ES:[BP.dpb_cluster_mask]
JBE SAVPOS
MOV BX,[CLUSNUM]
CMP BX,0FF8H
JAE NONEXT
invoke UNPACK
MOV [CLUSNUM],DI
INC [LASTPOS]
MOV AL,0
SAVPOS:
MOV [SECCLUSPOS],AL
CLRET:
CLC
return
NONEXT:
STC
return
NEXTSEC ENDP
SUBTTL OPTIMIZE -- DO A USER DISK REQUEST WELL
PAGE
procedure OPTIMIZE,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; BX = Physical cluster
; CX = No. of records
; DL = sector within cluster
; ES: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
; ES:BP unchanged. Note that segment of transfer not set.
PUSH DX
PUSH BX
MOV AL,ES:[BP.dpb_cluster_mask]
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 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
; ES:BP Points to DPB
; ES:SI has FAT pointer
invoke 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 ES:[BP.dpb_sector_size] ; 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
invoke FIGREC
MOV BX,SI
return
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
OPTIMIZE ENDP
SUBTTL FIGREC -- Figure sector in allocation unit
PAGE
procedure FIGREC,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DX = Physical cluster number
; BL = Sector postion within cluster
; ES:BP = Base of drive parameters
; Outputs:
; DX = physical sector number
; No other registers affected.
PUSH CX
MOV CL,ES:[BP.dpb_cluster_shift]
DEC DX
DEC DX
SHL DX,CL
OR DL,BL
ADD DX,ES:[BP.dpb_first_sector]
POP CX
return
FIGREC ENDP
SUBTTL GETREC -- Figure record in file from fcb
PAGE
procedure GETREC,NEAR
ASSUME DS:NOTHING,ES:NOTHING
; Inputs:
; DS:DX point to FCB
; Outputs:
; CX = 1
; DX:AX = Record number determined by fcb_EXTENT and fcb_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.fcb_NR]
MOV DX,[DI.fcb_EXTENT]
SHL AL,1
SHR DX,1
RCR AL,1
MOV AH,DL
MOV DL,DH
MOV DH,0
return
GETREC ENDP
SUBTTL ALLOCATE -- Assign disk space
PAGE
procedure ALLOCATE,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; BX = Last cluster of file (0 if null file)
; CX = No. of clusters to allocate
; DX = Position of cluster BX
; ES:BP = Base of drive parameters
; [THISFCB] = Points to FCB
; 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
; fcb_FIRCLUS field of FCB set if file was null
; SI,BP unchanged. All other registers destroyed.
PUSH BX ; save the fat byte
XOR BX,BX
invoke UNPACK
MOV [FATBYT],DI
POP BX
PUSH DX
PUSH CX
PUSH BX
MOV AX,BX
CLUSALLOC:
MOV DX,BX
FINDFRE:
INC BX
CMP BX,ES:[BP.dpb_max_cluster]
JLE TRYOUT
CMP AX,1
JG TRYIN
POP BX
MOV DX,0FFFH
invoke RELBLKS
POP AX ; No. of clusters requested
SUB AX,CX ; AX=No. of clusters allocated
POP DX
invoke RESTFATBYT
INC DX ; Position of first cluster allocated
ADD AX,DX ; AX=max no. of cluster in file
MOV DL,ES:[BP.dpb_cluster_mask]
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
return
TRYOUT:
invoke UNPACK
JZ HAVFRE
TRYIN:
DEC AX
JLE FINDFRE
XCHG AX,BX
invoke UNPACK
JZ HAVFRE
XCHG AX,BX
JMP SHORT FINDFRE
HAVFRE:
XCHG BX,DX
MOV AX,DX
invoke PACK
MOV BX,AX
LOOP CLUSALLOC
MOV DX,0FFFH
invoke PACK
POP BX
POP CX ; Don't need this stuff since we're successful
POP DX
invoke UNPACK
invoke RESTFATBYT
XCHG BX,DI
OR DI,DI
retnz
PUSH ES
LES DI,[THISFCB]
AND BX,0FFFh
MOV ES:[DI.fcb_FIRCLUS],BX
AND ES:[DI.fcb_LSTCLUS],0F000h ; clear out old lstclus
OR ES:[DI.fcb_LSTCLUS],BX ; or the new guy in...
POP ES
return
ALLOCATE ENDP
procedure RESTFATBYT,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
PUSH BX
PUSH DX
PUSH DI
XOR BX,BX
MOV DX,[FATBYT]
invoke PACK
POP DI
POP DX
POP BX
return
RESTFATBYT ENDP
SUBTTL RELEASE -- DEASSIGN DISK SPACE
PAGE
procedure RELEASE,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; BX = Cluster in file
; ES:BP = Base of drive parameters
; Function:
; Frees cluster chain starting with [BX]
; AX,BX,DX,DI all destroyed. Other registers unchanged.
XOR DX,DX
entry RELBLKS
; Enter here with DX=0FFFH to put an end-of-file mark
; in the first cluster and free the rest in the chain.
invoke UNPACK
retz
MOV AX,DI
invoke PACK
CMP AX,0FF8H
MOV BX,AX
JB RELEASE
RET12: return
RELEASE ENDP
SUBTTL GETEOF -- Find the end of a file
PAGE
procedure GETEOF,NEAR
ASSUME DS:DOSGROUP,ES:NOTHING
; Inputs:
; ES:BP Points to DPB
; BX = Cluster in a file
; DS = CS
; Outputs:
; BX = Last cluster in the file
; DI destroyed. No other registers affected.
invoke UNPACK
CMP DI,0FF8H
JAE RET12
MOV BX,DI
JMP SHORT GETEOF
GETEOF ENDP
do_ext
CODE ENDS
END