📄 fhinit.asm
字号:
SUB AX,BX ;compute amount of data to move
MOV DX,BX ;start of data - size needed = ...
SUB DX,CX ;... start of data destination
cCall B$FHMove ;move the data
POP AX ;recover increment needed
POP SI ;recover entry FHD
; Data is moved, now update all .FHD_hData fields for owners of
; the moved data.
XOR BX,BX ;adjust all descriptors
MOV DX,BX ;starting with the Entry FHD to the
DEC DX ;end of the descriptor chain
NEG AX ;make negative to move heap down
cCall FHAdjDescSegSI ;adjust the descriptors
MOV BX,SI ;[BX] = entry FHD
SUB [BX].FHD_cPara,AX ;update the size to reflect the allocation
RealcDone:
cEnd
;***
;B$FHDeallocFAR - far entrypoint for B$FHDealloc.
;
;Purpose:
; Added with revision [75].
; Far entrypoint for B$FHDealloc (called from LOADRTM segment).
;Entry:
; Same as B$FHDealloc
;Exit:
; Same as B$FHDealloc
;Uses:
; Same as B$FHDealloc
;Exceptions:
; Same as B$FHDealloc
;******************************************************************************
cProc B$FHDeallocFAR,<FAR,PUBLIC>
cBegin
CALL B$FHDealloc
cEnd
;***
; B$FHDealloc - deallocate a far heap entry (DOS 3 & 5)
;
;Purpose:
; Deallocate the far heap entry referenced by the given
; far heap descriptor.
;Entry:
; BX = far heap descriptor of entry to be deallocated
;Exit:
; None.
;Uses:
; None.
;Exceptions:
; Fatal internal error if descriptor not in descriptor list.
;******************************************************************************
cProc B$FHDealloc,<NEAR,PUBLIC>,<AX,SI>
cBegin
; Determine the far heap descriptor preceding the one to
; be deallocated using FHPrevDesc. Remove the descriptor
; to be deallocated from the descriptor list and then clear
; the descriptor segment (FHD_hData).
CALL FHPrevDesc ;pointer to previous FHD is in SI
MOV AX,[BX].FHD_pNext ;get FHD after the one to be deallocated
MOV [SI].FHD_pNext,AX ;link this with the previous FHD
MOV [BX].FHD_hData,0 ;clear the deallocated FHD segment value
cEnd
;***
; FHPrevDesc, B$FHPrevDescSI - get previous descriptor in list (DOS 3 & 5)
;
;Purpose:
; Given a far heap descriptor in the descriptor list,
; determine its predecessor in the list.
;Entry:
; BX = FHD offset of the far heap descriptor
; SI = FHD offset of FHD to start search with (B$FHPrevDescSI only)
;Exit:
; SI = FHD offset of the predecessor FHD to that pointed
; pointer by BX
;Uses:
; None.
;Exceptions:
; Fatal internal error if given FHD not in descriptor list.
;******************************************************************************
cProc FHPrevDesc,<NEAR>
cBegin
MOV SI,OFFSET DGROUP:b$FHDStart ;get first FHD of the list
cEnd <nogen> ;fall into B$FHPrevDescSI
cProc B$FHPrevDescSI,<NEAR,PUBLIC>
cBegin
FHPrevLoop:
CMP [SI].FHD_pNext,BX ;test if predecessor to entry FHD
JE FHPrevFound ;if found, then exit with SI set
MOV SI,[SI].FHD_pNext ;get the next FHD in the descriptor list
CMP SI,OFFSET DGROUP:b$FHDEnd ;test if final descriptor
JNZ FHPrevLoop ;if not, then loop to process next FHD
JMP SHORT FHPrevError ;fatal error if FHD not found
FHPrevFound:
cEnd
FHPrevError:
JMP B$ERR_FHC ;give far heap inconsistency error
;***
; B$FHCompact - compact the far heap (DOS 3 & 5)
;
;Purpose:
; Compact the far heap entries to upper memory within the
; far heap.
; This routine is a nop for DOS 5.
;
;Entry:
; None.
;Exit:
; SI = DGROUP offset of the next to last far heap descriptor
; in the FHD list.
;Uses:
; None.
;Exceptions:
; Fatal internal error if far heap inconsistency.
;******************************************************************************
cProc B$FHCompact,<NEAR,PUBLIC>,<AX,BX,CX,DX,DI,ES>
cBegin
CALL ShrinkHelp ; Kick the help system to release all
call CompressBufs ; compress the document buffers
; SI is a pointer that traverses down the far heap descriptor
; list starting at b$FHDStart. DX points to the segment in the
; compacted far heap space.
MOV SI,OFFSET DGROUP:b$FHDStart ;initialize the FHD list pointer
MOV DX,[SI].FHD_hDATA ;get segment pointer to compacted space
; This loop is executed for each entry in the far heap. SI points
; to the descriptor in the list while BX points to the start of the
; far heap entry referenced by the descriptor.
FHCompactLoop:
MOV BX,[SI].FHD_hData ;get segment referenced by descriptor at SI
MOV AX,[SI].FHD_cPara ;get the length of the far heap entry
SUB DX,AX ;compute entry start segment after compaction
CMP BX,DX ;test source and destination if movement needed
JE FHCompactSkip ;if no movement needed, just skip to next entry
CALL B$FHMove ;move the entry from BX:0 to DX:0
MOV [SI].FHD_hData,DX ;update descriptor with new entry segment
FHCompactSkip:
; Save the descriptor pointer in AX in case of exit. Check far heap
; consistency by ensuring segments of adjacent descriptors in the list
; are not increasing. Advance SI to the next descriptor in the list
; and, if not the last, loop to process it.
MOV AX,SI ;save the descriptor pointer
MOV SI,[SI].FHD_pNext ;point to next descriptor in the list
CMP [SI].FHD_hData,BX ;test if entry segments are not increasing
JA FHCompactError ;if not, then internal error
CMP SI,OFFSET DGROUP:b$FHDEnd ;test if last is reserved descriptor
JNE FHCompactLoop ;if not, process it
; Finished with the compaction. Check whether the last descriptor is
; the special one reserved. Set exit variable with next to last
; descriptor in the list. This is used to directly determine the size
; and location of the unallocated space in the far heap.
CMP [SI].FHD_cPara,0 ;test if entry size is zero
JNZ FHCompactError ;if not, then internal error
CMP [SI].FHD_pNext,0 ;test if link field is zero
JNZ FHCompactError ;if not, then internal error
MOV SI,AX ;set exit variable to next to last descriptor
cEnd
FHCompactError:
JMP B$ERR_FHC ;give far heap inconsistency error
;***
; B$FHMove - move or clear a far heap region (DOS 3)
;
;Purpose:
; Moves a far heap region either up or down within the far heap
; or clears a far heap region to zeroes. The region may consist
; of one or more far heap entries, even the entire heap.
;
;Entry:
; BX = starting segment of the far heap region to move
; DX = destination segment of the far heap region
; AX = size of region to move in paragraphs
;
;Exit:
; if BX > DX, move AX paragraphs down from BX:0 to DX:0
; if BX < DX, move AX paragraphs up from BX:0 to DX:0
; if BX = DX, clear AX paragraphs from BX:0
;
;Uses:
; AX, BX, CX, DX, DI, ES.
;Exceptions:
; None.
;******************************************************************************
; Since the repeated string move instruction (REP MOVSW) is used,
; a memory region must be split into a number of 64K-byte
; partitions followed by final partition of less than 64K bytes.
;
; For moving a region down in memory, the lowest word in the
; region is moved down first, followed by the next up to the
; highest word in the region. To implement this using the minimum
; number of string move instructions, the first partition is defined
; at the lower boundary of the region with any succeeding partitions
; located 64K bytes (or 1000H paragraphs) higher in memory. The
; string moves are executed with the direction flag cleared (CLD).
;
; For moving a region up in memory, the highest word in the
; region is moved up first, followed by the next down to the lowest
; word in the region. The first partition is defined from the
; upper boundary of the region with any succeeding partitions
; located 64K bytes (or 1000H paragraphs) lower in memory. The
; the string moves are executed with the direction flag set (STD).
;
; For clearing a region in memory, each partition is cleared
; separately. The partitions are defined from lowest word in the
; region to the highest as in moving the region down. The first
; word of the partition is cleared and then a repeated string move
; propagated the cleared word to the end of the partition.
cProc B$FHMove,<PUBLIC,NEAR>,<SI,DS>
cBegin
; Add assertion to check if FH is expected to be stable.
DbAssertRel [B$FHStable],Z,0,FH_TEXT,<Attempted to relocate far heap when not expected to.>
; On procedure entry, the direction flag is assumed cleared and BX
; and DX point to the lower boundary of the region before and after
; the move, respectively. For moving down or clearing, BX and DX
; also point to the start of the first partition to be moved or
; cleared.
CMP BX,DX ;test if moving down or clearing region
JAE FHMoveLoop ;if so, then jump to start of partition loop
; For moving up the direction flag must be set and BX and DX point
; to the end of the region which is also the end of the first
; partition. They will be adjusted to the partition start before
; the string move is done.
STD ;set direction flag - moves go from high to low
ADD BX,AX ;source pointer at partition end
ADD DX,AX ;destination pointer at partition end
; This loop is executed for each partition. The size of the partition
; in paragraphs is computed. AX contains the number of paragraphs
; left to process.
FHMoveLoop:
MOV CX,1000H ;get default size of partition
CMP CX,AX ;test if a full partition can be processed
JB FHNotLast ;if so, then jump to use the default size
MOV CX,AX ;othewise use the remaining paragraphs
FHNotLast:
SUB AX,CX ;update paragraphs left to process
; If moving up, update the partition pointers in BX and DX to the
; start of the next partition lower in memory.
CMP BX,DX ;test if moving entry up
JAE FHNotUpNext ;if not, jump to set segments
SUB BX,CX ;point to start of source partition
SUB DX,CX ;point to start of destination partition
FHNotUpNext:
; Set segment registers in preparation to string move.
MOV DS,BX ;set the source segment register
MOV ES,DX ;set the destination segment register
; If moving down or clearing, update the partition pointers in
; BX and DX to start of the next partition up in memory.
CMP BX,DX ;test if moving down or clearing
JB FHNotDownNext ;if not, then jump to set the count
ADD BX,CX ;point to start of next source partition
ADD DX,CX ;point to start of next destination partition
FHNotDownNext:
; Compute the word count for the string move.
SHL CX,1 ;Paragraphs to words - shift once...
SHL CX,1 ;...and twice...
SHL CX,1 ;...and thrice for the word count
; Compute the source offset. If moving down or clearing, the offset
; is zero. If moving up, the offset is the byte offset of the last
; word in the partition.
XOR SI,SI ;assume source offset is zero
CMP BX,DX ;test if moving entry up
JAE FHNotUpOffset ;if not, then use jump to use the zero offset
MOV SI,CX ;get the word count for partition
DEC SI ;make zero-relative word index
SHL SI,1 ;shift to make byte offset of last word
FHNotUpOffset:
; Compute the destination offset. If moving up or down, it is the
; same as the source offset. If clearing, it is two more than the
; source offset. Clearing uses a string move to overlap an initial
; zero word entry through the entire partition.
MOV DI,SI ;assume moving - destination same as source
CMP BX,DX ;test if clearing partition
JNE FHNotClear ;if not, then jump to perfrom string move
MOV [SI],SI ;clear the first word of the partition
INC DI ;set destination pointer to...
INC DI ;the next word in the partition
DEC CX ;first word is already zero
FHNotClear:
; Perform the string move. If any more partitions, then loop to
; process them.
REP MOVSW ;move or clear the partition
OR AX,AX ;test if more partitions to process
JNZ FHMoveLoop ;if so, then jump
CLD ;clear the direction flag
cEnd
;***
; B$FHTestRaiseBottom - raise bottom only if below DGROUP end
; B$FHRaiseBottom - raise the bottom of the far heap (DOS 3)
;
;Purpose:
; Raise the bottom boundary of the far heap to allow the released space to be
; used for near heap allocations. The far heap is raised to maximize the near
; heap size.
;
;Entry:
; None.
;
;Exit:
; None.
;
;Uses:
; AX (B$FHTestRaiseBottom)
; None.
;
;Exceptions:
; None.
;
;******************************************************************************
cProc B$FHTestRaiseBottom,<NEAR,PUBLIC> ; Important: no frame
cBegin
MOV AX,DS ; [AX] = paragraph base of dgroup
ADD AH,10H ; [AX] = paragraph base of dgroup + 64k
CMP AX,b$FHDEnd.FHD_hData ; See if FH below end of DGROUP
JA B$FHRaiseBottom ; Jump if it is, see if can reclaim DGROUP
cEnd
; Make B$FHRaiseBottom be called by vector
cProc B$FHRaiseBottom,<NEAR,PUBLIC>,<AX,BX,CX,DX,SI>
cBegin
; Compute the paragraphs to raise the far heap to maximize the
; near heap size.
MOV DX,0FFFEH ;get maximum DGROUP for near heap
SUB DX,b$NH_last ;subtract to get maximum amount to raise
MOV CL,4 ;byte-to-paragraph shift count
SHR DX,CL ;compute maximum paragraphs to raise
; Compute the paragraphs of free space in the far heap.
CALL B$FHCompact ;compact the far heap (SI = desc of top entry)
CALL FHParaSize ;get paragraphs of free space
; Select the minimum of the two values to use to raise the far heap.
CMP AX,DX ;compare available room with maximum request
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -