📄 fhinit.asm
字号:
; To adjust selected far heap descriptors by adding a given
; value to the segment value 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.
; This routine is used when Far Heap DATA is moved.
;Entry:
; AX = adjustment value to the segment of each affected
; far heap descriptor.
; BX = lower DGROUP offset of descriptor range, inclusive.
; DX = upper DGROUP offset of descriptor range, exclusive.
; SI = descriptor to start adjustments with (FHAdjDescSegSI only)
;Exit:
; None.
;Uses:
; None.
;Exceptions:
; None.
;******************************************************************************
cProc FHAdjDescSegSI,<NEAR>,<SI>
cBegin
JMP SHORT AdjDescSegCommon
cEnd <nogen>
cProc B$FHAdjDescSeg,<NEAR,PUBLIC>,<SI>
cBegin
MOV SI,b$FHDStart.FHD_pNext ;[16]start with second FH desc in list
AdjDescSegCommon:
XOR CX,CX ;No adjustment for pNext field
cCall FHAdjDesc ;common routine to adjust seg/descriptor
cEnd
;***
; FHAdjDesc - adjust a range of far heap descriptors (DOS 3 & 5)
;
;Purpose:
; Added as part of revision [11].
; To adjust selected far heap descriptors by adding a given
; value to the segment value and/or 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.
; This routine is used when Far Heap DATA and or Far Heap
; descriptors are moved.
;Entry:
; AX = adjustment value to the segment of each affected
; far heap descriptor.
; CX = 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 = ptr to FHD to start search with.
;Exit:
; None.
;Uses:
; None.
;Exceptions:
; None.
;******************************************************************************
cProc FHAdjDesc,<NEAR,PUBLIC>,<SI,DI>
cBegin
; Using SI, traverse the descriptor list until the ending of the
; descriptor list is reached.
MOV DI,SI ;fall into loop
FHAdjDescLoop:
MOV SI,DI ;[SI] = current desc location
MOV DI,[SI].FHD_pNext ;[DI] = next descriptor in the list
OR DI,DI ;test if end of descriptor list
JZ FHAdjDescDone ;if so, then done
DbAssertRel DI,NZ,-1,FH_TEXT,<FHAdjDesc found a pNext field containing 0FFFFH>
; For each descriptor, adjust if in the specified range.
CMP DI,BX ;test against lower range, inclusive
JB FHAdjDescLoop ;if less, then loop for next
CMP DI,DX ;test against upper range, exclusive
JAE FHAdjDescLoop ;if more or equal, then loop for next
ADD [SI].FHD_hData,AX ;in range - adjust FH segment
ADD [SI].FHD_pNext,CX ;in range - adjust FH desc list
JMP SHORT FHAdjDescLoop ;loop for next descriptor
; Done - restore and return.
FHAdjDescDone:
cEnd
PAGE
;***
; B$FHAdjOneDesc - adjust a far heap descriptor (DOS 3 & 5)
;
;Purpose:
; Added as part of revision [44].
; This routine is called when a single far heap descriptor is about to be
; moved. We traverse the FHD chain in search of the FHD containing a pNext that
; points to the FHD about to move, and then we adjust that pNext to reflect the
; movement. This routine adjusts only one FHD, and stops as soon as a match is
; found, or the end of the FHD chain is found.
;
; NOTE: THIS ROUTINE IS SPEED CRITICAL. The code below is written for speed.
; The main loop deals with TWO successive FHDs each time through the loop to
; eliminate a bit of pointer movement.
;
;Entry:
; [CX] = adjustment value to the pNext field of the affected far heap
; descriptor.
; [DX] = pointer to FHD which is about to move.
;
;Exit:
; None.
;
;Uses:
; Per Convention
;
;Exceptions:
; None.
;******************************************************************************
cProc B$FHAdjOneDesc,<NEAR,PUBLIC>,<SI>
cBegin
MOV SI,OFFSET DGROUP:b$FHDStart ;Start with beginning of list
ADJONELOOP:
DbAssertRel SI,NZ,0,FH_TEXT,<FHAdjOneDesc hit end of FarHeap Chain>
MOV BX,[SI].FHD_pNext ;[BX] = next descriptor in the list
CMP BX,DX ;do we point to the FHD of interest?
JZ ADJONESI ;Then adjust the next pointer via BX
DbAssertRel BX,NZ,0,FH_TEXT,<FHAdjOneDesc hit end of FarHeap Chain>
MOV SI,[BX].FHD_pNext ;[SI] = next descriptor in the list
CMP SI,DX ;do we point to the FHD of interest?
JNZ ADJONELOOP ;Loop until we do or are done
MOV SI,BX ;[SI] = pointer to preceding FDH for adjust
ADJONESI:
ADD [SI].FHD_pNext,CX ;adjust FH desc list
ADJONEDONE:
cEnd
;***
; B$SETM - SETMEM function runtime entry point (DOS 3 & 5)
;
;Purpose:
; To attempt to adjust the top limit of the far heap by the
; (signed) number of bytes in the input parameter. The function
; returns the space allocated for both the near and far heaps in bytes.
;Entry:
; [SP+4] = low-order word of adjustment value.
; [SP+6] = high-order word of adjustment value.
;Exit:
; DX:AX = 32-bit size of near and far heaps in bytes.
;Uses:
; None.
;Exceptions:
; None.
;******************************************************************************
cProc B$SETM,<FAR,PUBLIC>
parmD incr
cBegin
; Get adjustment value in DX:AX.
MOV AX,off_incr ;get low-order word
MOV DX,seg_incr ;get high-order word
; Test sign of adjustment value and jump if negative.
OR DX,DX ;test if adjustment is negative
JS FHSetMemNeg ;if so, then jump
; Positive adjustment. Get request in AX and raise far heap top.
CALL FHSetMemReq ;get request value in AX
CALL B$FHRaiseTop ;attempt to raise far heap top
JMP SHORT FHSetMemCommon ;jump to common code to finish
; Negative adjustment. Negate value, get request in AX, and lower
; the far heap
FHSetMemNeg:
NEG AX ;negate lower word of value in DX:AX
ADC DX,0 ;propagate carry to upper word
NEG DX ;and negate upper word to finish
FHSetMemLower:
CALL FHSetMemReq ;get request value in AX
CALL B$FHLowerTop ;attempt to lower far heap top
; Common code. Calculate size of far and near heaps and
; return value to caller.
FHSetMemCommon:
CALL B$FHTestRaiseBottom ; and attempt to raise bottom also
CALL FHSetMemValue ;compute size in DX:AX
; 32K near heap + 128K far heap
call fEditorActive ; did we start with /Editor
jnz SetMem_Exit ; brif so, allow anything
cmp dx,2 ; less than 128K total free?
jb SetMem_Exit ; brif so -- exit
ja TooBig ; brif more than 172K free -- too much free
or ax,ax ; less than 128K + 32K free?
jns SetMem_Exit ; brif so -- exit
TooBig: ; Reserve <ABOUT> 128K + 32K heap space
sub ax,7ff0h ; Can't do 8000h or it will infinite loop!)
sbb dx,2
jmp FHSetMemLower ; lower top of far heap by DX:AX
SetMem_Exit:
cEnd
;***
; FHSetMemReq - compute SETMEM request value (DOS 3)
;
;Purpose:
; Convert the given request value in bytes to paragraphs.
; If more than 1M bytes, return 0FFFFH paragraphs.
;Entry:
; DX:AX = 32-bit request value in bytes.
;Exit:
; AX = 16-bit request value in paragraphs.
;Uses:
; DX.
;Exceptions:
; None.
;******************************************************************************
cProc FHSetMemReq,<NEAR>
cBegin
CALL FHByteToPara ;convert DX:AX in bytes to DX:AX in paragraphs
OR DX,DX ;test if over 0FFFFH paragraphs
JZ FHSetMemReqOK ;if not, then request is okay as is
MOV AX,0FFFFH ;set maximum request
FHSetMemReqOK:
cEnd
;***
; FHSetMemValue - compute the SETMEM function value (DOS 3)
;
;Purpose:
; Compute the size of the near and far heaps in bytes.
; This is the value returned by the SETMEM function.
;Entry:
; None.
;Exit:
; DX:AX = size of heaps in bytes.
;Uses:
; None.
;Exceptions:
; None.
;******************************************************************************
cProc FHSetMemValue,<NEAR>,<CX>
cBegin
; Compute the paragraph start of the near heap.
MOV AX,b$NH_first ;get DGROUP offset of the near heap start
MOV CL,4 ;byte-to-paragraph factor is 4
SHR AX,CL ;get paragraph offser to DGROUP of NH start
MOV CX,DS ;get DGROUP paragraph value
ADD AX,CX ;add to get paragraph start of near heap
; Difference from far heap start to near heap start is value
; to compute. Convert size from paragraphs to bytes.
MOV DX,b$FHDStart.FHD_hData ;get starting (top) paragraph of FH
SUB DX,AX ;paragraph size of near and far heaps
MOV AX,DX ;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
;***
; FHSetTop - set new top of the far heap. (DOS 3)
;
;Purpose:
; Set the new top of the far heap by reallocating the DOS
; memory block containing the program and updating the starting
; descriptor which defines the top of the far heap.
;Entry:
; AX = number of paragraphs to adjust the far heap top.
; (positive grows, negative shrinks)
;Exit:
; AX = number of paragraphs actually adjusted. This number
; may be different than the entry value if the heap grows
; and insufficient memory is available.
;Uses:
; ES.
;Exceptions:
; Fatal error if DOS reallocation fails with legal pool size.
;
;******************************************************************************
cProc FHSetTop,<NEAR>,<BX>
cBegin
; Attempt to reallocate the DOS block with the given increment
; of size.
MOV ES,__acmdseg ;get DOS memory block address
MOV BX,b$FHDStart.FHD_hData ;get top segment of the far heap
SUB BX,__acmdseg ;subtract to get present block size
ADD BX,AX ;add increment to get new block size
MOV AH,4AH ;get DOS function to reallocate
CALL B$FHMemDosCall ;call to perform INT and handle fatal errors
JNC FHSetTopDone ;if no error, then jump
; Reallocation failed with attempted increment. Try to reallocate
; with the given maximum size returned in BX.
MOV AH,4AH ;try the reallocation again
CALL B$FHMemDosCall ;call to perform INT and handle fatal errors
JC FHSetTopError ;if reallocation failed, then fatal error
; Reallocation with new block size in BX succeeded. Update the
; far heap descriptor for the top of far heap.
FHSetTopDone:
ADD BX,__acmdseg ;add to get new top far heap segment
MOV AX,BX ;move top segment...
SUB AX,b$FHDStart.FHD_hData ;and subtract to get change in top seg
MOV b$FHDStart.FHD_hData,BX ;update new top segment in descriptor
cEnd
FHSetTopError:
JMP B$ERR_OM_FH ;give out of memory error
;***
; B$FHMemDosCall - perform memory DOS call (DOS 3)
;
;Purpose:
; Performs the INT 21H for the DOS allocate, deallocate, and
; reallocate calls. Error checking is done here to save space.
;Entry:
; Setup for the appropriate DOS call, this call replaces the
; INT 21H instruction. The DOS calls used are allocate memory
; (48H), deallocate memory (49H), and reallocate memory (4AH).
;Exit:
; Post-INT 21H register changes.
;Uses:
; Post-INT 21H register changes.
;Exceptions:
; B$ERR_MEM if arena is trashed.
; B$ERR_FHC if bad memory block address.
;******************************************************************************
cProc B$FHMemDosCall,<NEAR,PUBLIC>
cBegin
INT 21H ;perform the DOS call
JNC FHMemDosReturn ;if successful, then exit now
CMP AX,8 ;test if out of memory
JNE FHMemDosError ;if not, then jump to trap error
STC ;set the carry again
FHMemDosReturn:
cEnd
FHMemDosError:
CMP AX,7 ;test if error was arena destroyed
JNE FHMemDosBlock ;if not, then invalid block was used
JMP B$ERR_MEM ;jump to fatal error for arena destroyed
FHMemDosBlock:
JMP B$ERR_FHC ;jump to fatal error for inconsistenct FH
sEnd FH_TEXT
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -