; ; Far heap functions. ; ; Copyright (c) Mix Software 1988 ; ; Extended memory heap ; GLOBAL ; MINHEAP EQU 4 ; Minimum size of a heap ; ; Heap descriptor: ; H$FREE EQU 0 H$MIN EQU 2 H$MAX EQU 4 H$CURUSE EQU 6 H$MAXUSE EQU 8 ; ; Packet pointer points to previous paragraph ; All packets have length at offset >0E ; Allocated flag is at offset >0D ; Free packets have pointer to prior and next in data area ; H$LEN EQU >000E ; Length of packet H$AVAIL EQU >000D ; 1 = available, 0=allocated H$SUCC EQU >0010 ; Pointer to next packet H$PRED EQU >0012 ; Pointer to previous packet ; ENDGLOBAL ; ; ; ---------------------------------------------------------- ; ; FALLOC ; allocate a packet from extended heap ; called as a C function: ; char far *falloc(size) ; unsigned size; /* size in bytes */ ; returns address of packet or 0 if none available ; IDT falloc IF UPPER DEF FALLOC ENDIF DEF falloc FREF _FALLOC FREF fnewheap DREF $$FARHP falloc EQU $ FALLOC CMP [$$FARHP],0 JNZ OK MOV AX,$$FARHP PUSH AX MOV AX,-1 PUSH AX CALLFAR fnewheap ADD SP,%4 OK MOV AX,$$FARHP PUSH AX MOV SI,SP MOV AX,[SI][%PARM1] ADD AX,2+1+15 ; Reserve two bytes for length, ; ; one byte for available flag, AND AL,%#F0 ; and round up to paragraph boundary MOV CL,4 ; Convert size to paragraphs SHIFT SHR AX,CL PUSH AX CALLFAR _FALLOC ADD SP,%4 RETSEG END ; ; ---------------------------------------------------------- ; ; FCALLOC ; allocate a packet from extended heap ; called as a C function: ; char far *fcalloc(number,size) ; unsigned number; /* number of elements */ ; unsigned size; /* size of an element in bytes */ ; returns address of packet or 0 if none available ; IDT fcalloc IF UPPER DEF FCALLOC ENDIF DEF fcalloc FREF _FALLOC FREF fnewheap DREF $$FARHP fcalloc equ $ FCALLOC CMP [$$FARHP],0 JNZ OK MOV AX,$$FARHP PUSH AX MOV AX,-1 PUSH AX CALLFAR fnewheap ADD SP,%4 OK MOV AX,$$FARHP PUSH AX MOV SI,SP MOV AX,[SI][%PARM1] MUL [SI][%PARM2] ADD AX,2+1+15 ; Reserve two bytes for length, ; ; one byte for available flag, ADC DX,%0 AND AL,%#F0 ; and round up to paragraph boundary MOV CX,4 ; Convert size to paragraphs SHIFT SHR DX,1 RCR AX,1 LOOP SHIFT PUSH AX CALLFAR _FALLOC ADD SP,%4 RETSEG END ; ; ---------------------------------------------------------- ; ; farcalloc ; allocate a packet from extended heap ; called as a C function: ; void far *farcalloc(number,size) ; unsigned long number; /* number of elements */ ; unsigned long size; /* size of an element in bytes */ ; returns address of packet or 0 if none available ; IDT farcallo IF LONGNAME LDEF farcalloc ENDIF IF SHORTNAM DEF Fcalloc ENDIF FREF _FALLOC FREF fnewheap FREF $_LUMUL DREF $$FARHP farcalloc equ $ Fcalloc PUSH BP MOV BP,SP CMP [$$FARHP],0 JNZ OK MOV AX,$$FARHP PUSH AX MOV AX,-1 PUSH AX CALLFAR fnewheap ADD SP,%4 OK MOV AX,$$FARHP PUSH AX PUSH [BP][%PARM4] PUSH [BP][%PARM3] PUSH [BP][%PARM2] PUSH [BP][%PARM1] CALLFAR $_LUMUL ; Number of items * size ADD SP,%8 ADD AX,2+1+15 ; Reserve two bytes for length, ; ; one byte for available flag, ADC DX,%0 AND AL,%#F0 ; and round up to paragraph boundary MOV CX,4 ; Convert size to paragraphs SHIFT SHR DX,1 RCR AX,1 LOOP SHIFT PUSH AX CALLFAR _FALLOC ADD SP,%4 POP BP RETSEG END ; ; ---------------------------------------------------------- ; ; void far *farrealloc(void far *block, newsize) ; void far *block - previous pointer to block ; unsigned long newsize - requested size ; return the new pointer ; IDT farreall IF LONGNAME LDEF farrealloc LFREF farmalloc ENDIF IF SHORTNAM DEF Frealloc FREF Fmalloc ENDIF FREF _FFREE FREF _FALLOC DREF $$FARHP farrealloc EQU $ Frealloc PUSH BP MOV BP,SP MOV AX,[BP][%PARM1] OR AX,[BP][%PARM2] JZ MALLOC CMP [$$FARHP],0 JZ NULL1 MOV AX,[BP][%PARM3] ; New size MOV DX,[BP][%PARM4] ADD AX,2+1+15 ; allow extra for length, flag ADC DX,%0 AND AL,%#F0 ; round up to paragraph boundary MOV CX,4 ; Convert size to paragraphs SHIFT SHR DX,1 RCR AX,1 LOOP SHIFT MOV BX,[BP][%PARM2] ; segment part of old pointer DEC BX ; point to block header MOV ES,BX SEGES CMP %[H$AVAIL],0 JNZ NULL1 ; This is not a valid block SEGES MOV DX,[H$LEN] ; Old length CMP AX,DX JZ SAME1 JA EXPAND JMP SHRINK ; Make smaller NULL1 JMP NULL MALLOC PUSH [BP][%PARM4] PUSH [BP][%PARM3] IF LONGNAME CALLFAR farmalloc ENDIF IF ~LONGNAME callfar Fmalloc ENDIF ADD SP,%4 POP BP RETFAR EXPAND MOV SI,BX ADD SI,DX ; Next block header MOV ES,SI SEGES CMP %[H$AVAIL],0 JZ MOVE MOV CX,AX SUB CX,DX ; additional space needed SEGES CMP CX,[H$LEN] JA MOVE ; Not enough space in next block ; ; Expand in place ; CX = size needed, ES is next block, AX = new size ; SEGES ; Allocate entire next block MOV AX,[H$PRED] SEGES MOV BX,[H$SUCC] JNZ PARTIAL SEGES MOV CX,[H$LEN] MOV ES,AX SEGES MOV [H$SUCC],BX MOV ES,BX SEGES MOV [H$PRED],AX ADJUST MOV AX,[BP][%PARM2] DEC AX MOV ES,AX SEGES ADD [H$LEN],CX ; adjust size MOV SI,[$$FARHP] MOV AX,[SI][%H$CURUSE] MOV [SI][%H$CURUSE],CX CMP AX,[SI][%H$MAXUSE] JBE ADJDONE MOV [SI][%H$MAXUSE],CX SAME1 EQU $ ADJDONE JMP SAME ; ; Allocate a part of the next block ; ES = next block, AX = predecessor, BX = successor ; PARTIAL SEGES MOV DX,[H$LEN] SUB DX,CX ; New length MOV SI,ES ADD SI,CX MOV ES,SI ; address of reduced block SEGES MOV [H$LEN],DX SEGES MOV [H$PRED],AX SEGES MOV [H$SUCC],BX SEGES MOV %[H$AVAIL],%1 MOV ES,AX SEGES MOV [H$SUCC],SI MOV ES,BX SEGES MOV [H$PRED],SI JMPS ADJUST ; ; relocate the block - ES points to the old block ; AX is the new size (in paragraphs) ; MOVE PUSH ES PUSH [$$FARHP] PUSH AX CALLFAR _FALLOC ; allocate a new block ADD SP,%4 POP BX ; recover original segment TEST AX,AX JZ NULL ; Not enough space MOV ES,BX SEGES MOV DX,[H$LEN] ; Length of old data INC BX ; Segment address of old data PUSH AX PUSH DS COPYBLK MOV DS,BX MOV ES,AX CMP DX,>0800 ; Is size > 32k JB COPYLAST MOV CX,>4000 ; Move a 32k block REP MOVSW ADD BX,>0800 ADD AX,>0800 SUB DX,>0800 JMPS COPYBLK COPYLAST CMP DX,%0 ; Move partial block JZ COPYDONE SHL DX,1 SHL DX,1 SHL DX,1 MOV CX,DX REP MOVSW COPYDONE POP AX MOV DS,AX PUSH [$$FARHP] ; Release old block PUSH [BX][%PARM2] CALLFAR _FFREE ADD SP,%4 POP DX ; Segment of new block XOR AX,AX POP BP RETFAR ; ; decrease size of block ; DX = old length, AX = new length ; SHRINK SEGES MOV [H$LEN],AX ; Adjust length MOV BX,ES ADD BX,AX ; Part to be released MOV ES,BX SEGES ; Make new allocated block MOV %[H$AVAIL],%0 ; from excess memory SUB DX,AX SEGES MOV [H$LEN],DX PUSH [$$FARHP] ; heap descriptor PUSH ES ; block to be released CALLFAR _FFREE ; release the excess space ADD SP,%4 ; return pointer to original block SAME MOV AX,[BP][%PARM1] MOV DX,[BP][%PARM2] POP BP RETFAR NULL XOR AX,AX XOR DX,DX POP BP RETFAR END ; ; ---------------------------------------------------------- ; ; farmalloc ; allocate a packet from extended heap ; called as a C function: ; void far *farmalloc(size) ; unsigned long size; ; returns address of packet or 0 if none available ; IDT farmalloc IF LONGNAME LDEF farmalloc ENDIF IF SHORTNAM DEF Fmalloc ENDIF FREF _FALLOC FREF fnewheap DREF $$FARHP farmalloc equ $ Fmalloc PUSH BP MOV BP,SP CMP [$$FARHP],0 JNZ OK MOV AX,$$FARHP PUSH AX MOV AX,-1 PUSH AX CALLFAR fnewheap ADD SP,%4 OK MOV AX,$$FARHP PUSH AX MOV AX,[BP][%PARM1] MOV DX,[BP][%PARM2] ADD AX,2+1+15 ; Reserve two bytes for length, ; ; one byte for available flag, ADC DX,%0 AND AL,%#F0 ; and round up to paragraph boundary MOV CX,4 ; Convert size to paragraphs SHIFT SHR DX,1 RCR AX,1 LOOP SHIFT PUSH AX CALLFAR _FALLOC ADD SP,%4 POP BP RETSEG END ; ; ---------------------------------------------------------- ; ; HALLOC ; allocate a packet from extended heap ; called as a C function: ; char far *halloc(number,size) ; long number; /* number of elements */ ; unsigned size; /* size of an element in bytes */ ; returns address of packet or 0 if none available ; IDT halloc IF UPPER DEF HALLOC ENDIF DEF halloc FREF _FALLOC FREF fnewheap DREF $$FARHP halloc equ $ HALLOC CMP [$$FARHP],0 JNZ OK MOV AX,$$FARHP PUSH AX MOV AX,-1 PUSH AX CALLFAR fnewheap ADD SP,%4 OK MOV AX,$$FARHP PUSH AX MOV SI,SP MOV AX,[SI][%PARM2] MUL [SI][%PARM3] MOV CX,AX MOV AX,[SI][%PARM1] MUL [SI][%PARM3] ADD DX,CX ADD AX,2+1+15 ; Reserve two bytes for length, ; ; one byte for available flag, ADC DX,%0 AND AL,%#F0 ; and round up to paragraph boundary MOV CX,4 ; Convert size to paragraphs SHIFT SHR DX,1 RCR AX,1 LOOP SHIFT PUSH AX CALLFAR _FALLOC ADD SP,%4 RETSEG END ; ; ---------------------------------------------------------- ; ; _fmsize(ptr) return size of the block ; char far *ptr; ; IDT _fmsize DEF _fmsize _fmsize MOV SI,SP MOV BX,[SI][%PARM1-2] MOV AX,[SI][%PARM2-2] DEC AX MOV ES,AX SEGES MOV AX,[BX][H$LEN] MOV CL,4 SHL AX,CL SUB AX,3 RETSEG END ; ; ---------------------------------------------------------- ; ; long farcoreleft ; return the amount of memory left in far heap ; IDT farcorel IF LONGNAME LDEF farcoreleft ENDIF IF SHORTNAM DEF farcorel ENDIF FREF fnewheap DREF $$FARHP farcorel CMP [$$FARHP],0 JNZ OK MOV AX,$$FARHP PUSH AX MOV AX,-1 PUSH AX CALLFAR fnewheap ADD SP,%4 OK XOR DX,DX MOV SI,$$FARHP MOV AX,[SI][H$MAX] SUB AX,[SI][H$MIN] SUB AX,[SI][H$CURUSE] MOV CX,4 SHIFT SHL AX,1 RCL DX,1 LOOP SHIFT DONE RETFAR END ; ; ---------------------------------------------------------- ; ; _FALLOC ; allocate a packet from extended heap ; called as a C function: ; int _falloc(size,desc) ; int size; /* size in paragraphs */ ; heapdesc *desc; /* address of heap descriptor */ ; returns address of packet or 0 if none available ; address is a 16 bit segment value ; IDT _FALLOC DEF _FALLOC _FALLOC PUSH BP MOV BP,SP MOV SI,[BP][%PARM2] ; SI = Address of descriptor CMP [SI],0 JZ NOSPACE MOV DX,[BP][%PARM1] ; Size requested TEST DX,DX ; Check for zero JNZ FALLOC01 INC DX ; Minimum size is one paragraph ; ; Set BX to point to the current free list ; FALLOC01 MOV BX,[%H$FREE][SI] ; ; Search free list for a packet of sufficient size ; NEWLOOP MOV ES,BX SEGES CMP DX,[H$LEN] ; COMPARE LENGTHS JBE FALLOC02 ; ; The current packet in the free list is not large enough ; move to the next packet ; ES contains the address of the current packet ; DX contains the required size ; FALLOC03 SEGES MOV BX,[H$SUCC] ; BX = next packet CMP BX,[SI][%H$FREE] ; All packets checked? JNZ NEWLOOP ; No packet is large enough NOSPACE XOR BX,BX JMP FALLOC08 ; ; The current packet is large enough ; remove needed space & check result for > 0 ; FALLOC02 SEGES MOV AX,[H$LEN] ; GET PACKET SIZE SUB AX,DX ; SUBTRACT NEEDED SPACE JNZ FALLOC04 ; ; Allocate entire packet ; length is in DX, location is in BX,ES ; SEGES MOV AX,[H$SUCC] ; GET SUCCESSOR FIELD MOV [SI][%H$FREE],AX ; NEW FREE LIST SEGES MOV CX,[H$PRED] ; CX = PREDECESSOR ; ; LAST+2 := NEXT ; MOV ES,CX SEGES MOV [H$SUCC],AX ; ; NEXT+4 := LAST ; MOV ES,AX ; Point to successor SEGES MOV [H$PRED],CX ; set next@.lat to cur@.last JMPS FALLOC05 ; ; Reduce the size of the packet ; AX Contains the new length ; DX Contains the length of the new packet ; BX, ES point to the packet ; ; FALLOC04 PUSH BX ; SAVE CURRENT PACKET ADDR SEGES MOV CX,[H$PRED] ; Get links PUSH CX SEGES MOV CX,[H$SUCC] ADD BX,DX ; BX <-- ADDR OF NEW FREE PKT MOV ES,BX SEGES MOV [H$LEN],AX ; SET NEW LENGTH SEGES MOV %[H$AVAIL],%1 ; MARK NOT ALLOCATED ; ; SET SUCCESSOR OF NEW FREE PACKET TO SUCCESSOR OF OLD ; FREE PACKET & PREDECESSOR OF NEW TO PREDECESSOR OF OLD ; SEGES MOV [H$SUCC],CX POP AX SEGES MOV [H$PRED],AX ; ; Link around newly allocated space ; last@.next := newsp ; next@.last := newsp ; MOV ES,AX SEGES MOV [H$SUCC],BX MOV ES,CX SEGES MOV [H$PRED],BX ; NEXT@.PRED = NEW FREE PKT MOV [SI][%H$FREE],CX POP BX ; ; AT THIS POINT DX CONTAINS THE LENGTH OF THE NEWLY ALLOCATED ; PACKET, AND BX CONTAINS ITS ADDRESS ; ; SET THE LENGTH OF THE NEWLY ALLOCATED PACKET. ; FALLOC05 MOV ES,BX SEGES MOV [H$LEN],DX SEGES MOV %[H$AVAIL],%0 INC BX ; POINT TO DATA AREA ; ; ADD SIZE OF CURRENT PACKET TO CURRENT HEAP ALLOCATED ; ADD [SI][%H$CURUSE],DX ; ADD TO CURRENT ALLOCATION MOV AX,[SI][%H$CURUSE] ; LARGER THAN MAX USED? CMP AX,[SI][%H$MAXUSE] JB FALLOC09 MOV [SI][%H$MAXUSE],AX ; SET MAXIMUM HEAP USED ; ; Zero the memory, BX = segment, DX = length ; FALLOC09 MOV ES,BX FALLOC11 TEST DX,>F800 JZ FALLOC10 MOV CX,>4000 ; zero 32k bytes (16k words) XOR DI,DI XOR AX,AX REP STOSW MOV AX,ES ADD AX,>0800 MOV ES,AX SUB DX,>0800 JMPS FALLOC11 FALLOC10 MOV CL,4 SHL DX,CL SUB DX,2+1 ; linkage for next packet MOV CX,DX XOR DI,DI XOR AX,AX REP STOSB FALLOC08 MOV DX,BX XOR AX,AX POP BP RETSEG ; END ; ; ------------------------------------------------------------ ; ; FFREE ; Release a packet in extended heap ; called as a C function: ; int ffree(ptr) ; char far *ptr; /* pointer value */ ; returns 0 if successful, -1 on error ; ; IDT ffree IF UPPER DEF FFREE ENDIF DEF ffree DEF hfree DEF farfree DREF $$FARHP FREF _FFREE ; ffree EQU $ hfree EQU $ farfree EQU $ FFREE MOV SI,SP MOV AX,[SI][%PARM2-2] ; segment value MOV BX,[SI][%PARM1-2] ; Offset MOV CX,AX OR CX,BX JZ NIL ; TEST BX,BX ; JNZ INVALID ; offset must be zero CMP [$$FARHP],0 JZ INVALID ; no far heap available MOV BX,$$FARHP PUSH BX PUSH AX CALLFAR _FFREE ADD SP,%4 RETSEG INVALID MOV AX,-1 RETSEG NIL XOR AX,AX RETSEG END ; ; ; ------------------------------------------------------------ ; ; _FFREE ; Release a packet in extended heap ; called as a C function: ; int _ffree(ptr,desc) ; int ptr; /* pointer value (segment only) */ ; heapdesc *desc; /* address of heap descriptor */ ; returns 0 if successful, -1 on error ; ; IDT _FFREE DEF _FFREE ; _FFREE PUSH BP MOV BP,SP MOV SI,[BP][%PARM2] ; SI = Address of descriptor MOV BX,[BP][%PARM1] ; Pointer value TEST BX,BX JNZ FREE01 XOR AX,AX POP BP RETFAR FREE01 DEC BX ; POINT TO LENGTH FIELD ; ; CHECK POINTER AGAINST LOWER BOUND OF HEAP - ERROR IF LESS ; CMP BX,[SI][%H$MIN] JBE INVPKT1 ; ; GET LENGTH OF THE PACKET ; FR01 MOV ES,BX SEGES MOV CX,[H$LEN] ; Get length SEGES TEST %[H$AVAIL],%1 JNZ INVPKT1 ; NOT ALLOCATED MOV AX,BX ADD AX,CX ; AX POINTS TO NEXT PACKET ; ; CHECK PTR + SIZE OF PACKET AGAINST HEAP UPPER BOUND ; CMP AX,[SI][%H$MAX] JBE FR02 INVPKT1 JMP INVPKT ; ; BX = ADDRESS OF RELEASED PACKET ; CX = SIZE OF RELEASED PACKET ; AX = ADDRESS OF NEXT PACKET ; ; PACKET IS VALID, RELEASE IT ; FR02 SUB [SI][%H$CURUSE],CX ; SUBTRACT FROM CURRENT ; ; Is next packet allocated? ; CMP AX,[SI][%H$MAX] JAE FR04 ; Next packet is anchor MOV ES,AX SEGES TEST %[H$AVAIL],%1 ; Check allocation flag JZ FR03 ; Not available ; ; Next packet is available, merge current and next packets ; SEGES MOV DX,[H$LEN] ; Get size of packet TEST DX,DX ; CHECK FOR ZERO JZ FR03 ; DON'T MERGE WITH ANCHOR ADD CX,DX ; CX = SIZE OF COMBINATION ; ; ASSIGN FREELIST TO NEW PACKET ; MOV [SI][%H$FREE],BX ; ; Find the previous packet that is free and closest ; to the packet being released ; SEGES MOV AX,[H$SUCC] ; GET NEXT FIELD FOR CURRENT SEGES MOV DX,[H$PRED] ; PREV LINK OF NEXT FREE PKT ; ; AT THIS POINT: ; BX = CURRENT PACKET ; AX = NEXT PACKET ; DX = PREVIOUS PACKET ; CX = NEW LENGTH OF CURRENT ; JMPS FR06 ; CHECK FOR LAST PACKET FREE ; ; Next packet is not available ; find the next packet that is available to get ; its last packet pointer ; AX = NEXT PACKET ; CX = PACKET SIZE ; BX = CURRENT PACKET ; FR03 SEGES MOV DX,[H$LEN] ; GET SIZE OF NEXT PACKET ADD AX,DX CMP AX,[SI][H$MAX] ; Top of heap? JB FR05 FR04 MOV AX,[SI][%H$MIN] ; Wrap around to anchor FR05 MOV ES,AX SEGES TEST %[H$AVAIL],%1 ; CHECK FOR ALLOCATED JZ FR03 ; LOOP UNTIL FREE ; ; AX and SI now point to the next free packet ; get the last pointer from the next packet ; SEGES MOV DX,[H$PRED] ; ; At this point: ; AX = next free packet ; BX = current packet ; CX = current packet length ; DX = last packet ; ; Check last packet. If the last free packet is contiguous ; with the current packet, they can be merged into a single ; packet. ; FR06 PUSH AX ; SAVE MOV ES,DX SEGES MOV AX,[H$LEN] ; Length of previous pkt ADD AX,DX ; AX <-- LAST+SIZE(LAST) CMP AX,BX JNZ FR07 ; CAN NOT JOIN ; ; The last packet is contiguous with the current packet, ; merge them. ; SEGES ADD [H$LEN],CX ; Add lengths POP AX SEGES MOV [H$SUCC],AX ; Set pointer to next MOV ES,AX SEGES MOV [H$PRED],DX ; Set Next@.last to merged pkt ; ; Set free list to merged packet ; MOV [SI][%H$FREE],DX XOR AX,AX POP BP RETFAR ; ; ; The last packet is not contiguous with the current packet ; a new packet is created for the packet being released. ; ; TOS = NEXT ; BX = CURRENT ; DX = PREVIOUS ; CX = LENGTH ; FR07 MOV ES,BX SEGES MOV [H$LEN],CX ; SET SIZE SEGES MOV %[H$AVAIL],%1 POP AX SEGES MOV [H$SUCC],AX ; SET NEXT POINTER SEGES MOV [H$PRED],DX ; SET PREVIOUS MOV ES,DX SEGES MOV [H$SUCC],BX ; SET PREV@.NEXT MOV ES,AX SEGES MOV [H$PRED],BX ; SET NEXT@.LAST XOR AX,AX POP BP RETSEG ; ; INVALID PACKET POINTER ; INVPKT MOV AX,-1 ; Return -1 to indicate error POP BP RETSEG END ; ; ---------------------------------------------------------- ; ; FNEWHEAP ; Allocate a new heap from the pool of extended memory ; called as a C function: ; int fnewheap(size, desc); ; int size; /* size in paragraphs */ ; descriptor *desc; /* address of descriptor */ ; Fills in descriptor with heap parameters. ; A size of >FFFF indicates allocate as much as possible. ; Returns the size allocated, 0 if none. ; IDT fnewheap IF UPPER DEF FNEWHEAP ENDIF DEF fnewheap DREF $$MAXSEG ; First unavailable paragraph DREF $$TOPSEG ; First unused paragraph fnewheap EQU $ FNEWHEAP PUSH BP MOV BP,SP MOV SI,[BP][%PARM2] ; SI = Address of descriptor MOV CX,[BP][%PARM1] ; CX = requested size CMP CX,MINHEAP JAE SIZESET MOV CX,MINHEAP ; Set minimum size SIZESET CMP CX,-1 ; Allow for anchor & final blk JZ MAXSIZE ADD CX,%2 ; Allow for anchor & final blk MAXSIZE MOV AX,[$$TOPSEG] ; First unused data MOV DX,[$$MAXSEG] ; Top of all memory CMP AX,DX JAE NOSPACE SUB DX,AX ; Total size available CMP CX,DX JBE ENOUGH ; requested size is available CMP DX,MINHEAP JB NOSPACE MOV CX,DX ; Supply all remaining ENOUGH ADD [$$TOPSEG],CX ; Add size to top segment MOV [SI][%H$MIN],AX ; Set heap bounds MOV DX,[$$TOPSEG] DEC DX MOV [SI][%H$MAX],DX MOV [SI][%H$CURUSE],0 MOV [SI][%H$MAXUSE],0 MOV DX,AX ; Point to heap origin INC AX ; AX points to free space area MOV [SI][%H$FREE],AX ; ; Create the heap anchor ; MOV BX,DS MOV DS,DX ; Point to anchor MOV %[H$AVAIL],%1 ; Anchor is available MOV [H$LEN],0 ; Length of packet is 0 MOV [H$SUCC],AX ; Cicrular link to 2nd packet MOV [H$PRED],AX ; Cicrular link to 2nd packet MOV DS,AX MOV %[H$AVAIL],%1 SUB CX,%2 ; Remove size of anchor MOV [H$LEN],CX MOV [H$SUCC],DX ; Cicrular link to anchor packet MOV [H$PRED],DX ; Cicrular link to anchor packet MOV DS,BX EXIT POP BP MOV AX,CX RETSEG NOSPACE XOR AX,AX ; Return 0 for none available JMPS EXIT END ; ; ---------------------------------------------------------- ; ; FRELHEAP ; Release a heap to the pool of extended memory ; called as a C function: ; int frelheap(desc); ; descriptor *desc; /* address of descriptor */ ; Releases heap if it is the last item in extended memory. ; Returns 0 if released, -1 if not at end of memory. ; IDT frelheap IF UPPER DEF FRELHEAP ENDIF DEF frelheap DREF $$MAXSEG ; First unavailable paragraph DREF $$TOPSEG ; First unused paragraph frelheap EQU $ FRELHEAP PUSH BP MOV BP,SP MOV SI,[BP][%PARM1] ; SI = Address of descriptor MOV CX,[SI][H$MAX] ; Top of this heap INC CX ; Address expected in $$TOPSEG CMP CX,[$$TOPSEG] ; Is this the top item? JNZ NOTLAST MOV CX,[SI][%H$MIN] ; Release to minimum MOV [$$TOPSEG],CX XOR AX,AX MOV [SI],AX POP BP RETSEG NOTLAST MOV AX,-1 POP BP RETSEG END ; ; ---------------------------------------------------------- ; ; Shrink memory to allow loading other programs and ; for memory resident programs. ; ; int farsetsize(int farheap_needed) ; one argument, amount of far heap requested ; in paragraphs ; Returns address of top of memory (segment) ; IDT farsetsz IF LONGNAME LDEF farsetsize ENDIF IF SHORTNAM def Fsetsize ENDIF REF $$PSP REF $$TOPSEG REF $$ENDDS REF $$MAXSEG REF $$FARHP REF _doserrno FREF _FHIGH ; farsetsize EQU $ Fsetsize PUSH BP MOV BP,SP MOV DX,[BP][%PARM1] ADD DX,[$$ENDDS] ; Requested top of memory CMP DX,[$$MAXSEG] ; More than available? JAE DONE CMP DX,[$$TOPSEG] ; More than allocated? JAE SHRINK ; Shrink to size CMP [$$FARHP],0 ; Far heap in use? JZ DONE ; No, unable to shrink MOV SI,$$FARHP MOV CX,[SI][H$MAX] ; Top of this heap INC CX ; Address expected in $$TOPSEG CMP CX,[$$TOPSEG] ; Is this the top item? JNZ DONE ; Far heap is not top item PUSH SI CALLFAR _FHIGH ; find top packet POP SI TEST AX,AX JZ DONE ; No free space in far heap SUB AX,2 ; header of last free block MOV DX,AX MOV ES,AX MOV CX,[BP][%PARM1] ADD CX,[$$ENDDS] ; Requested top of memory CMP CX,DX JBE MINIMUM ; shrink to minimum size SUB CX,AX ; space to keep ADD DX,CX MOV [SI][%H$MAX],DX SEGES MOV [H$LEN],CX INC DX JMPS SHRINK MINIMUM INC DX MOV [SI][%H$MAX],DX INC DX SEGES MOV [H$LEN],1 ; ; Shrink memory and update system parameters ; DX = top segment ; SHRINK MOV [$$MAXSEG],DX CMP DX,[$$TOPSEG] JAE K1 MOV [$$TOPSEG],DX K1 MOV BX,DX SUB BX,[$$PSP] ; Size in use MOV ES,[$$PSP] ; Shrink memory SEGES MOV [2],DX MOV AX,>4A00 INT >21 JB ERROR DONE MOV AX,[$$MAXSEG] ; Total program size SUB AX,[$$PSP] POP BP RETFAR ERROR MOV [_doserrno],AX MOV AX,-1 POP BP RETFAR END ; ; ---------------------------------------------------------- ; ; _FMAX ; find the address of free memory ; int _FMAX() ; returns segment address of first usable paragraph ; in extended memory. If the default far heap is at ; the top of memory, any unused part of it is available. ; IDT _FMAX DEF _FMAX DREF $$FARHP DREF $$TOPSEG FREF _FHIGH _FMAX MOV SI,$$FARHP CMP [SI],0 JZ USEMEM MOV CX,[SI][H$MAX] ; Top of this heap INC CX ; Address expected in $$TOPSEG CMP CX,[$$TOPSEG] ; Is this the top item? JNZ USEMEM PUSH SI CALLFAR _FHIGH POP SI TEST AX,AX JZ USEMEM ADD AX,2 ; Preserve packet header RETSEG USEMEM MOV AX,[$$TOPSEG] RETSEG END ; ; ---------------------------------------------------------- ; ; _FHIGH ; find highest address currently in use ; called as a C function: ; int _FHIGH(desc) ; int size; /* size in bytes */ ; returns address of highest packet or 0 if none ; IDT _FHIGH DEF _FHIGH _FHIGH PUSH BP MOV BP,SP MOV SI,[BP][%PARM1] ; SI = Address of descriptor MOV BX,[SI][%H$FREE] ; Search free space list SRCH MOV ES,BX SEGES MOV AX,[H$LEN] ; Length of packet ADD AX,BX ; End of packet CMP AX,[SI][%H$MAX] ; Does it go to end? JAE FOUND SEGES MOV BX,[H$SUCC] ; Try next packet CMP BX,[SI][%H$FREE] ; full circle? JNZ SRCH XOR AX,AX ; Return 0 for none available POP BP RETSEG ; ; Highest block has been found ; return its address ; First available paragraph is two greater ; FOUND ADD BX,%2 MOV AX,BX POP BP RETSEG END ; ; ---------------------------------------------------------- ; ; Default far heap data area ; contains descriptor for far heap ; IDT $$FARHP DDEF $$FARHP DORG $ $$FARHP DW 0,0,0,0,0 END