📄 fhinit.asm
字号:
JB FHRaiseBotAvail ;if available room less than max, jump
MOV AX,DX ;else use the maximum
FHRaiseBotAvail:
ADD b$FHDEnd.FHD_hData,AX ;adjust the bottom FH boundary
; Raise the top of the near heap by AX paragraphs.
SHL AX,CL ;movement amount now in bytes (CL still 4)
MOV CX,AX ;new near heap ending offset is...
ADD CX,b$NH_last ;...adjusted by the amount
MOV AX,b$NH_first ;use present near heap starting offset
CALL B$NHMOV ;raise the near heap top
MOV b$NH_last,CX ;update the near heap ending offset
cEnd
;***
; B$FHLowerBottom - lower bottom boundary of far heap. (DOS 3)
;
;Purpose:
; Lower the bottom boundary of the far heap to allow the released
; space to be used for far heap allocations. If the far heap
; cannot be lowered by the requested amount, it is lowered the
; maximum amount possible. The top of the near heap is lowered
; as necessary.
;Entry:
; AX = number of paragraphs requested to lower.
;Exit:
; None
;Uses:
; AX
;Exceptions:
; Fatal error due to near heap inconsistency.
;******************************************************************************
cProc B$FHLowerBottom,<NEAR,PUBLIC>,<CX>
cBegin
; First screen the request for unreasonable requests. This includes
; a request at or over 1000H paragraphs (64K bytes).
TEST AH,0F0H ;test if request is 64K bytes or over
JNZ FHLowerBotMax ;if so, just try for maximum request
; Convert the request to bytes and compute the new ending offset.
; If the byte request is larger than the near heap ending offset,
; then just try the maximum request.
MOV CL,4 ;paragraph-to-byte shift is four...
SHL AX,CL ;shift to get bytes to lower near heap
MOV CX,b$NH_last ;get present ending offset of near heap
SUB CX,AX ;compute new ending offset in request
JC FHLowerBotMax ;if ending offset would be negative, then max
; If this ending offset is before the current starting offset,
; then just try maximum request.
MOV AX,b$NH_first ;get start of near heap for move operation
; Fix comparison order in CMP.
CMP CX,AX ;test if starting offset before computed ending
JBE FHLowerBotMax ;if so, just try for maximum room available
; Try to lower the far heap by the request amount.
CALL B$NHMOV ;lower near heap to maximum size
JNC FHLowerBotDone ;if successful, jump to clean up and exit
; If the near heap cannot be lowered by the requested amount,
; lower it by the maximum amount possible.
FHLowerBotMax:
MOV AX,b$NH_first ;get the near heap starting offset
XOR CX,CX ;set offset for maximum release of near heap
CALL B$NHMOV ;lower near heap to maximum size
;
; After the lowering, update the near heap ending offset variable, and compute
; the new start of the far heap, which is the immediately following paragraph.
;
FHLowerBotDone:
MOV b$NH_last,CX ; update new near heap ending offset
XCHG AX,CX ; [AX] = end of near heap
MOV CL,4 ; [CL] = byte to para chift count
ADD AX,10H ; [AX] = end of near heap + 1 para
RCR AX,CL
AND AH,01FH ; [AX] = para dgroup offset of far heap
MOV CX,DS
ADD AX,CX ; [AX] = absolute para far heap start
MOV b$FHDEnd.FHD_hData,AX ; Set the new far heap base
cEnd
;***
; B$FHRaiseTop - raise top boundary of far heap (DOS 3)
;
;Purpose:
; Raise the top boundary of the far heap to allow the reclaimed
; space to be used for far heap allocations. If the far heap
; cannot be raised by the requested amount, it is raised the
; maximum amount possible.
;Entry:
; AX = number of paragraphs requested to raise.
;Exit:
; AX = number of paragraphs actually reclaimed.
;Uses:
; None.
;Exceptions:
; Fatal error due to far heap inconsistency.
;******************************************************************************
cProc B$FHRaiseTop,<NEAR,PUBLIC>,<BX,ES>
cBegin
; Calculate the paragraph increment from the current far heap
; top to the theoretical maximum paragraph. Attempt to reallocate
; with the minimum of this value and the requested value.
MOV BX,b$FHDStart.FHD_hData ;get the top of the far heap
NOT BX ;invert for calculation 0FFFFH-FHTop
CMP AX,BX ;test for minimum of the two values
JB FHRaiseTopReq ;if request if less, then use it
MOV AX,BX ;use the calculated maximum value
FHRaiseTopReq:
CALL FHSetTop ;attempt to reset the far heap top
cEnd
;***
; B$FHLowerTop - lower top boundary of far heap (DOS 3)
;
;Purpose:
; Lower the top boundary of the far heap to allow the released
; space to be used for external allocations. If the far heap
; cannot be lowered by the requested amount, it is lowered the
; maximum amount possible.
;Entry:
; AX = number of paragraphs requested to lower.
;Exit:
; AX = number of paragraphs actually released.
;Uses:
; None.
;Exceptions:
; Fatal error due to far heap inconsistency.
;******************************************************************************
cProc B$FHLowerTop,<NEAR,PUBLIC>,<BX,CX,DX,SI,DI,ES>
cBegin
; First, compact the far heap and determine the size of the
; unallocated space after compaction.
MOV CX,AX ;save requested allocation
CALL B$FHCompact ;compact - SI is next to last desc in list
CALL FHParaSize ;get unallocated size in AX
; We will need to use the FHD_hData field from the descriptor pointed
; to by SI, but the descriptor may move during B$FHLowerBottom. So get
; the seg value now. (The descriptor may move but the data won't.)
MOV SI,[SI].FHD_hData ; get data seg of entry
; Test if request can fit within the unallocated space left.
;if enough, then branch to move heap
CMP CX,AX ;test request against unallocated space
JBE FHLowTopFit ;if enough, then branch to move heap
; Compute the room still needed from the near heap and try to
; obtain it.
SUB AX,CX ;subtract request size from unalloc space...
NEG AX ;...and negate to compute room needed
CALL B$FHLowerBottom ;try to lower far heap bottom AX paragraphs
; Set up for far heap move. Get present far heap starting
; paragraph in BX.
FHLowTopFit:
MOV BX,SI ;segment of next to last entry is start
; Compute new starting paragraph in DX.
MOV DX,BX ;start with present ending segment
SUB DX,CX ;subtract request size (size if full request)
JB FHLowMaxDown ;if wraparound, just use lower FH bound
CMP DX,b$FHDEnd.FHD_hData ;test if all memory requested released
JA FHLowTopFull ;if so, then jump to process full request
FHLowMaxDown:
MOV DX,b$FHDEnd.FHD_hData ;set to partial request (end of heap)
FHLowTopFull:
;
; Check for the source and destination apara's to be the same. If they are, we
; didn't release anything, and needn't do more.
;
XOR AX,AX ; return value if no movement
CMP BX,DX
JZ FHLowTopDone ; nothing to move, just quit.
; Compute size of entire allocated far heap for move and perform
; the move down in memory.
MOV AX,b$FHDStart.FHD_hData ;get starting segment of far heap
SUB AX,BX ;subtract ending segment for allocated size
CALL B$FHMove ;move far heap data to new location
; Compute the actual distance moved. Since the move was down,
; this value is negative. Set the far heap top to update the
; descriptor and reallocate the DOS block to reflect the new
; starting segment.
MOV AX,DX ;get new ending segment of far heap
SUB AX,BX ;subtract old ending segment to get distance
CALL FHSetTop ;reallocate the block to release the space
; Adjust all allocated descriptors in the descriptor list to
; reflect the far heap movement.
XOR BX,BX ;adjust all descriptors - lowest starting...
MOV DX,0FFFFH ;...and highest ending offset to adjust
CALL B$FHAdjDescSeg ;adjust all descriptor segments by AX
; Negate the sense of the move to return a positive value.
NEG AX ;return positive paragraphs returned
FHLowTopDone:
cEnd
;***
; B$FHByteSize - get size of unallocated entry after compaction (DOS 3)
;
;Purpose:
; Return the size in bytes of the unallocated entry,
; if present, after a far heap compaction is performed.
;Entry:
; SI = DGROUP offset to next to last far heap descriptor in
; the descriptor list. Returned by the far heap compaction
; routine B$FHCompact.
;Exit:
; DX:AX = size in bytes of the unallocated entry.
;Uses:
; None.
;Exceptions:
; None.
;******************************************************************************
cProc B$FHByteSize,<NEAR,PUBLIC>
cBegin
; Get the entry size in paragraphs in AX and then convert to
; bytes in DX:AX.
CALL FHParaSize ;get entry size in paragraphs
MOV DX,AX ;move into both registers
MOV CL,4 ;shift count for lower word
SHL AX,CL ;compute low-word byte size
MOV CL,12 ;shift count for upper word
SHR DX,CL ;compute high-word byte size
cEnd
;***
; FHParaSize - get size of unallocated entry after compaction (DOS 3)
;
;Purpose:
; Return the size in paragraphs of the unallocated entry,
; if present, after a far heap compaction is performed.
;Entry:
; SI = DGROUP offset to next to last far heap descriptor in
; the descriptor list. Returned by the far heap compaction
; routine B$FHCompact.
;Exit:
; AX = size in paragraphs of the unallocated entry.
;Uses:
; None.
;Exceptions:
; None.
;******************************************************************************
cProc FHParaSize,<NEAR>
cBegin
; Size of entry is the difference between the segment values
; of the next-to-last entry in the descriptor list and the
; last entry.
MOV AX,[SI].FHD_hData ;get value of next-to-last entry
SUB AX,b$FHDEnd.FHD_hData ;subtract value of last entry
cEnd
;***
;B$FHSelect, B$FHSelectSI - Call a proc for each FH descriptor (DOS 3 & 5)
;
;Purpose:
; Added as part of revision [11].
; This routine is used to indirectly dispatch to a routine
; for each FH descriptor. The called routine takes specific
; action for the descriptor and returns a flag stating whether
; or not to deallocate the entry.
;Entry:
; SI = Address of descriptor to start with (B$FHSelectSI only)
; AX = Address of near routine to dispatch to
; BX = parameter passed/returned from dispatch routine
; CX = parameter passed/returned to dispatched routine
;Exit:
; None.
;Uses:
; Per Convention.
;Exceptions:
; None.
;******************************************************************************
cProc B$FHSelectSI,<NEAR,PUBLIC>,<SI>
cBegin
JMP SHORT FHSelect ;jmp to common code
cEnd <nogen>
cProc B$FHSelect,<PUBLIC,NEAR>,<SI>
cBegin
MOV SI,OFFSET DGROUP:b$FHDStart ;point to start of descriptor chain
FHSelect:
PUSH DI
XCHG AX,DI ;DI points to address of routine to call
SelectLoop:
MOV SI,[SI].FHD_pNext ;get ptr to next descriptor in chain
CMP SI,OFFSET DGROUP:b$FHDEnd ;test if final descriptor
JZ SelectDone ;brif so - finished
DbAssertRel SI,NZ,-1,FH_TEXT,<FHSelect found pNext field containing 0FFFFH>
CALL DI ;call routine
OR AX,AX ;deallocate entry?
JZ SelectLoop ;brif not - get next descriptor
PUSH BX
MOV BX,SI
cCall B$FHDealloc ;deallocate entry
POP BX
JMP SHORT SelectLoop ;go get next descriptor
SelectDone:
POP DI
cEnd
;***
; B$FHAdjDesc,B$FHAdjDescSI - adjust a range of far heap descriptor (DOS 3 & 5)
;
;Purpose:
; Added as part of revision [11].
; To adjust selected far heap descriptors by adding a given
; value to the pNext field in each descriptor. The
; selection is determined by the DGROUP offset of the
; descriptor being in the specified range. The static
; starting and ending descriptors are never adjusted here.
; These routines are used when Far Heap DESCRIPTORS are moved.
;Entry:
; AX = adjustment value to the pNext field of each affected
; far heap descriptor.
; BX = lower DGROUP offset of descriptor range, inclusive.
; DX = upper DGROUP offset of descriptor range, exclusive.
; SI = address of descriptor to start adjustment with.
;Exit:
; None.
;Uses:
; None.
;Exceptions:
; None.
;******************************************************************************
cProc B$FHAdjDescSI,<NEAR,PUBLIC>,<SI>
cBegin
JMP SHORT FHAdjDescCommon
cEnd <nogen>
cProc B$FHAdjDesc,<NEAR,PUBLIC>,<SI>
cBegin
MOV SI,OFFSET DGROUP:b$FHDStart ;Start with beginning of list
FHAdjDescCommon:
XCHG AX,CX ;CX = desc adjustment
XOR AX,AX ;no segment adjustment
cCall FHAdjDesc ;call common routine to adjust seg/desc
cEnd
;***
; B$FHAdjDescSeg,FHAdjDescSegSI - adjust a range of far heap descriptor segments (DOS 3)
;
;Purpose:
; FHAdjDescSegSI added as part of revision [32].
; Renamed and rewritten as part of revision [11].
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -