MS-DOS/v2.0/source/ROM.ASM
2018-09-21 17:53:34 -07:00

530 lines
14 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; 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