mirror of
https://github.com/elliotnunn/sys7.1-doc-wip.git
synced 2024-12-12 20:29:12 +00:00
4484 lines
170 KiB
Plaintext
4484 lines
170 KiB
Plaintext
;
|
||
; File: MemoryMgrInternal.a
|
||
;
|
||
; Contains: Macintosh Assembly Language Memory Manager Internals
|
||
;
|
||
; Written by: Martin P. Haeberli October 1982, to June 1983
|
||
;
|
||
; Copyright: © 1982-1993 by Apple Computer, Inc., all rights reserved.
|
||
;
|
||
; Change History (most recent first):
|
||
;
|
||
; <SM13> 6/14/93 kc Roll in Ludwig.
|
||
; <LW5> 5/3/93 KW Roll in fix to HBlockMove. Make sure noQueueBit (9) is clear.
|
||
; Ensures cache is flushed.
|
||
; <SM12> 4/23/93 kc Fix the rover. Earlier on, because of a bug that was corrupting
|
||
; the AllocPtr, we changed the code to clear the AllocPtr instead
|
||
; of setting it. The bug was caused when we merged two blocks
|
||
; leaving the AllocPtr pointing to the middle of the block. There
|
||
; is a significant performance improvement with this change.
|
||
; <SM11> 3/1/93 CSS Fix MMHPrologue to handle empty handles better. This doesn't fix
|
||
; the problem perfectly, but it should handle most three heap
|
||
; situations. Gala Tea uses a sub-heap and this fix should handle
|
||
; their problem. The more general solution (multiple heap) is
|
||
; supposedly fixed in Figment. Thanks to Peter Hodie for providing
|
||
; this fix. I have rewritten it slightly.
|
||
; <SM10> 1/4/93 RB Put a dollar sign in front of the frame type check in
|
||
; DHBusErrorHandler, since it was supposed to be there !
|
||
; <SM9> 12/4/92 RB Rolled in changes to support NuKernel from Wayne Meretski and
|
||
; Russell Williams. Make ZCBusErrHandler and DHBusErrHandler
|
||
; compatible with NuKernel.
|
||
; <SM8> 11/12/92 PN Get rid of ≥ 020 conditionals
|
||
; <SM7> 10/26/92 CSS Remove cache flushing from memory manager.
|
||
; <SM6> 7/16/92 PN Fix a bug in A32SetSize that caused a dereference of NIL by
|
||
; re-rolling PatchIIciROM.a
|
||
; <SM5> 5/21/92 CSS Integrate Reality Changes: Apply patch from MemoryMgrPatches.a
|
||
; to MMHPrologue routine.
|
||
; <SM4> 5/17/92 kc Include PowerPrivEqu.a.
|
||
; <SM3> 4/22/92 TN Removed commented out code. Added StripAddress to AllocPtr in
|
||
; a24MakeSpace that was in MemoryMgrPatches.a
|
||
; <2> 3/4/92 kc Roll in axxSetSizePatch, axxActualSPatch, axxMaxLimitPatch and
|
||
; vxxPurgeSpacePatch from Terror.
|
||
; {4} 6/25/91 RP Patched to line align all blocks on 040 CPUs
|
||
; {7} 6/25/91 RP Disabled 24 bit line-align patches when VM is running
|
||
; <2> 12/21/91 RB Reverted the use of AllocPtr to the Terror equivalent. Otherwise
|
||
; the heap would be corrupted just after the welcome to Mac
|
||
; screen.
|
||
; <1> 10/2/91 JSM first checked in
|
||
; <0> 10/1/91 JSM Created from HeapGuts32.a.
|
||
;
|
||
; Modification history from HeapGuts32.a below:
|
||
;
|
||
; <11> 9/16/91 JSM Cleanup header.
|
||
; <10> 6/12/91 LN removed #include 'HardwareEqu.a'
|
||
; <9> 3/13/91 bbm &CCH; fix hard instruction cpusha to a call to jCacheFlush
|
||
; <8> 12/19/90 DFH Fixed use of AllocPtr. Was essentially ignored for NewPtr,
|
||
; ResrvMem, and MoreMasters.
|
||
; <7> 12/19/90 BG Removed conditionals from the 040 cache flushing in
|
||
; MMNoErrEpilogue.
|
||
; <6> 7/30/90 BG Removed CPU = 040 conditionals in preparation for moving from
|
||
; Mac040 to Mac32 build.
|
||
; <5> 6/22/90 CCH Added a cache push for 68040's to the prologue routine for some
|
||
; memory manager calls to avoid cache incoherency problems.
|
||
; <4> 1/25/90 BG Removed the AERRORs in ZCBusErrHandler, DHBusErrHandler,
|
||
; DerefHandle and ZoneCheck. Added ZC040BusErrHandler and
|
||
; DH040BusErrHandler, and modified DH and ZC to use the 040 bus
|
||
; error handlers.
|
||
; <3> 1/11/90 CCH Added include of “HardwarePrivateEqu.a”.
|
||
; <2> 1/3/90 BG Fix error messages produced by various BusErrHandlers regarding
|
||
; the 040 to use the correct quotes (single quotes, not double
|
||
; quotes). I'll be fixing the actual BusErrHandlers to do the
|
||
; right thing shortly.
|
||
; <1.9> 8/22/89 SES Removed references to nFiles.
|
||
; <1.8> 7/15/89 CSL Added additional check for non-rel. block in whichZone.
|
||
; <1.7> 6/15/89 CSL Added routine SubtractFree, this routine is to replace calls to
|
||
; AdjustFree with a negative D0.
|
||
; <1.6> 5/24/89 GGD Converted to feature based conditionals, added checks for 68040
|
||
; in places where changes will most likely be needed and generate
|
||
; assembly errors if assembling for a 68040. No code changes.
|
||
; <1.5> 4/17/89 CSL Added new routine MakeCBkf for freeing contiguous block
|
||
; <1.4> 3/30/89 CSL use A0 for pointer value in A32Setsize.
|
||
; <1.3> 3/22/89 CSL changed all Prologues to retry for different address mode if
|
||
; zone check fail.
|
||
; <1.2> 3/11/89 CSL replaced reference of minfree by minfree24 and minfree32 and
|
||
; also fixed problem
|
||
; <1.1> 2/28/89 CSL Added support for 24/32 bit memory manager. Most
|
||
; <1.0> 2/13/89 CCH Adding to EASE for first time from 24-Bit source.
|
||
; <C836> 2/20/87 JTC Tweak C636/C778 to correctly resote old handler in all cases.
|
||
; <C778> 2/10/87 JTC See Heap.a comment. Undo all C765 HiHeapMark nonsense and clean
|
||
; up bus error handlers.
|
||
; <C765> 2/5/87 JTC See Heap.a comment for full discussion. Change GrowZone here to
|
||
; extend HiHeapMark when heap is grown beyond current max.
|
||
; <C741> 2/2/87 JTC Undo C587. See Heap.a comment.
|
||
; <C636> 1/14/87 JTC Bus error handler in DerefHandle and ZoneCheck. See Heap.a
|
||
; <C587> 1/3/87 JTC Change MaxLimit and ToMaxLimit to avoid stack compare when
|
||
; SysZone=ApplZone. See Heap.a
|
||
; <C493> 12/9/86 JTC Reinstate C251. See Heap.a.
|
||
; <A415> 11/17/86 JTC Backed out C251 to accommodate Microsoft et al. See Heap.a
|
||
; <A305> 10/30/86 JTC Rolled in the last of the 28May86 patch above. See comment in
|
||
; Heap.a
|
||
; <C251> 10/24/86 JTC Changed to support longword alignment. See comment in Heap.a.
|
||
; <C206> 10/9/86 bbm Modified to mpw aincludes. Changed equate from mtAdjFre to
|
||
; negZcbFreeErr.
|
||
; 5/28/86 JTC Added code to MMHPrologue to handle case of Nil master ptr: if
|
||
; theZone is SysZone or ApplZone, set A6 ('theZone' throughout the
|
||
; call to MemMgr) to be the one of SysZone and ApplZone that makes
|
||
; more sense based on location of the master ptr.
|
||
; 4/14/86 JTC Fixed ptr-advance loop in MakePtrSpc, rolling in original 64K
|
||
; ROM patch stuff, with the added twist that space may be sought
|
||
; in a region started by a FREE block (not just an immovable)
|
||
; because of subtleties in SafeReloc/RelocRel.
|
||
; 2/19/86 BBM Made some modifications to work under MPW
|
||
; 5/21/85 JTC Check for carry-out in GrowZone when new heapEnd is computed.
|
||
; This is <21May85> place where 'negative' values of D0 will burn
|
||
; us. Need to distinguish empty handle and NIL in MMHPrologue, for
|
||
; sake of DisposeHandle.
|
||
; 5/20/85 JTC Change continuation code in MakePtrSpc from original ROM patch.
|
||
; Instead <20May85> of holding out till next fixed block after a
|
||
; failed try in MakeSpc, <20May85> just get to first thing after
|
||
; current block. This could be slower when <20May85> a raft of
|
||
; small relocs cannot be moved to make way, but this is rare!
|
||
; <20May85>
|
||
; 5/16/85 JTC In DerefHandle return 0 if 0 passed in from MMHPrologue
|
||
; <16May85>
|
||
; 5/13/85 JTC Patched ad nauseum. <13May85>
|
||
; 5/6/85 JTC Change to preserve high nibble information in RelocRel.
|
||
; <06May85>
|
||
; 4/27/85 JTC Add bogus label MemMgrEnd for RAM-based builds. <27Apr85> Fixed
|
||
; CompactHp to all free block to be first in zone. Changed
|
||
; ZoneCheck to look for free block at bkLim.
|
||
; 4/25/85 JTC Extend MMEpilogue to set MemErr -- except for RecoverHandle.
|
||
; <25Apr85>
|
||
; 4/24/85 JTC Pull out checking changes. <24Apr85 PULLOUT> But then
|
||
; reinstalled, same day...
|
||
; 4/23/85 JTC Change MMHPrologue and DerefHandle to watch for Nil passed as
|
||
; handle (along <23Apr85> with current checking for empty handles,
|
||
; themselves). It will return an error in D0, much like the
|
||
; obsolete Checking code.
|
||
; 4/23/85 LAK Fixed RelocRel to preserve block flags (for SafeReloc case).
|
||
; <23Apr85>
|
||
; 4/23/85 JTC Adjustments to keep roving ptr valid. <23Apr85>
|
||
; 4/18/85 JTC Change SetHandleSize algorithm to allow downward sliding to find
|
||
; free space <18Apr85>
|
||
; 4/17/85 JTC Added TotePurgeables utility to support PurgeSpace call.
|
||
; <17Apr85>
|
||
; 4/16/85 JTC Fix bug in BFindS: now checks against bkLim(A6) before
|
||
; Is-It-Free? test. <16Apr85>
|
||
; 4/14/85 JTC Added MakePtrSpc comment to GrowZone. <14Apr85> Modify
|
||
; MakePtrSpc so that if GrowDown is nonzero and zone is ApplZone,
|
||
; then run loop with OrgApplZone first, and then real ApplZone.
|
||
; BIG CHANGE to GrowZone to grow downward if no space upward.
|
||
; <14Apr85> Controlled by GrowDown conditional assembly flag.
|
||
; 4/13/85 JTC Add ZoneCheck call to prologues. <13Apr85>
|
||
; 4/10/85 JTC Move BClr/BSet of #Purge bit of block to be relocated from
|
||
; RelocRel to SetSize as per LAK's suggestion. Reason is, when
|
||
; called by SafeReloc, Purgeability doesn't matter. Saves code and
|
||
; time. <10Apr85> Alter EH to simply clear the MP of a ROZ.
|
||
; 3/4/85 JTC See comments in Heap.TEXT. Changes marked <04Mar85> to EH and
|
||
; SetSize.
|
||
; 1/29/85 JTC See comment in Heap.TEXT. Changes here are marked <29jan85> : 1)
|
||
; Modify CallGZProc to go to StdGZ in spare1(Zone) first. 2) Add
|
||
; StdGZ code from MSMiscFix file. 3) Add code to MakePtrSpc after
|
||
; call to MakeSpace.
|
||
; 9/12/83 LAK Added GZroot/move stuff for using the GZ handle/ pointer for
|
||
; notifying the GrowZone proc about forbidden blocks. This entails:
|
||
; Added ClearGZStuff for common clearing; Changed SetSize to set
|
||
; up/clearing root in > case; Changed RelocRel to "" "" "" "" move.
|
||
; Changed RelocRel for GZ purging object to be moved
|
||
; 9/10/83 LAK made MakePtrSpc look harder for space before giving up.
|
||
; 9/7/83 LAK simplified CallGZProc.
|
||
; 9/1/83 LAK made MakePtrSpc grow the zone if needed.
|
||
; 8/22/83 LAK fixed growZone interface (it's a Pascal function)
|
||
; 8/11/83 LAK Changed to save fewer regs when calling purge proc (assume Pascal
|
||
; regsave conventions are followed).
|
||
; 7/31/83 LAK Rover allocation, smart heap compact and purge now enabled by bits
|
||
; in zone Flags word.
|
||
; 7/30/83 LAK Added MakePtrSpace; changed GetSpaceAfter to MakeSpace; RelocRel
|
||
; now allocates an NRel block for the move to avoid invoking NewMaster;
|
||
; purge algorithm changed to do a roving minimal purge if possible;
|
||
; compact algorithm changed to compact only if it buys us success; AllocBk
|
||
; bug fixed (if handle offset=zone address value) and BFindS search
|
||
; algorithm changed to use a roving pointer.
|
||
; 7/19/83 LAK Added documentation (called by:); updated checking code interface;
|
||
; removed all trace of free list . . . removed DeleteBkF and all calls
|
||
; to it. Changed WhichZone to really return masked pointer.
|
||
; 6/21/83 MPH Put FreeList code under assembly switch: FList.
|
||
; 6/18/83 MPH Space Saving Changes: In MMHPrologue, saved D3-D7 instead of D1-D7,
|
||
; In MMFail, Tst.L (SP)+ => AddQ.L #4,SP, In MMExit, removed useless
|
||
; Tst.L D0, restore D3-D7 instead of D1-D7, In GetSize, saved code in
|
||
; delta field extract, In AdjustFree, maintain minCBFree only if
|
||
; Statistics is on, In BFindS, moved And.L MaskBC,D1 down,
|
||
; saved code in free block merge loop, In SetLogSize,
|
||
; And.L #$F,x => And.B #$F,x, In MakeBk, removed block type safety code,
|
||
; In BkFLow, rewrote inner loop per Steve Capps ideas to save code,
|
||
; In BlockMove, change to save only D0, In CompactHp, Removed unneeded
|
||
; Add.L D0,A1, added Label: CHNextRel, and added branch to it,
|
||
; In ZoneAdjustEnd, removed redundant Move.L D0,TagBC(A0), In GrowZone,
|
||
; And.L #x,y => And.W #x,y, In HMakeMoreMasters, changed safety checking
|
||
; code in MoreMasters, Changed HMLoop code to make it tighter, In FreeBk,
|
||
; repackaged Statistics code to make it smaller, In SetSize, changed MP
|
||
; flag save code to use Move.B (A1),-(SP), Changed all internal JSRs to BSRs.
|
||
; 6/17/83 MPH Space Saving Changes: Removed CallMoveProc definition, In WhichZone,
|
||
; used Tst.B TagBC(A0), In MMPrologue, saved D3-D7 instead of D1-D7,
|
||
; In MMPPrologue, saved D3-D7 instead of D1-D7.
|
||
; 6/16/83 MPH Removed unused .Defs from .Defs list, In AdjustFree, label AFTest
|
||
; unused, In AllocBk, label ABDone unused, In GetSpaceAfter, fixed
|
||
; error in PurgeBlock call, In RelocRel, fixed register bug involving
|
||
; use of A5 where A3 was intended.
|
||
; 6/10/83 MPH Included GrafTypes so that Nil is defined.
|
||
; 6/5/83 MPH Fixed InitApplZone by moving IAZCommon to module Heap.
|
||
; 6/2/83 MPH Fixed incorrect free list bug.
|
||
; 6/1/83 MPH Cleaned up comments and code.
|
||
; 4/12/83 MPH Revisions for final release.
|
||
; 3/20/83 MPH Fixed SetSize to return an error code. Added masking of ptrs and
|
||
; handles to MMPPrologue and MMHPrologue, respectively. Fixed
|
||
; HMakeMoreMasters to always create a new block.
|
||
; 2/15/83 MPH Changed BFindS algorithm.
|
||
; 2/10/83 MPH Moved Defs, Refs to front, changed WhichZone algorithm.
|
||
; 1/23/83 LAK Adapted for new equate files. Changed 'MoreMasters' to
|
||
; mAllocCnt.
|
||
; 1/17/83 MPH Fix broken GrowZone; fix broken HMakeMoreMasters
|
||
; 10/27/82 MPH Begin Zone refinement per suggestions of Andy J. Hertzfeld and
|
||
; Larry A. Kenyon
|
||
;
|
||
|
||
BLANKS ON
|
||
STRING ASIS
|
||
|
||
LOAD 'StandardEqu.d'
|
||
INCLUDE 'MemoryMgrPriv.a'
|
||
INCLUDE 'HardwarePrivateEqu.a'
|
||
INCLUDE 'PowerPrivEqu.a'
|
||
|
||
HeapGuts PROC EXPORT ; moved up here to contain equates
|
||
|
||
|
||
|
||
; In/Out Routines (external routines marked with *):
|
||
;
|
||
; DerefHandle <-------*MMHPrologue -----+--> MMFail
|
||
; |
|
||
; *MMPPrologue -----+--> WhichZone ---+--> ZoneCheck
|
||
; | |
|
||
; *MMRHPrologue ----+ | <A305>
|
||
; |
|
||
; *MMPrologue ------------------------+
|
||
;
|
||
; *MMEpilogue
|
||
; *MMNoErrEpilogue <25Apr85>
|
||
;
|
||
;
|
||
; Utility Routines (external routines marked with *):
|
||
;
|
||
; *MakeBkF: (MakeBk,PurgeBlock,MakeFree,ZoneAdjustEnd,MakeSpace,
|
||
; FreeBk,SetSize)
|
||
; SetLogSize: (AllocBk,SetSize) - set logical size of a block.
|
||
;
|
||
; HBlockMove: (CompactHp,RelocRel)
|
||
;
|
||
; *ReleaseMP: (HMakeMoreMasters,FreeBk)
|
||
;
|
||
; *ActualS: (CompactMem,PurgeMem,AllocBk,SetSize) - figures actual physical
|
||
; size needed for a block.
|
||
; *GetSize: (SafeReloc,RelocRel,SetSize(2))
|
||
;
|
||
; AdjustFree: (MakeBk,PurgeBlock,ZoneAdjustEnd,SafeReloc(2),FreeBk,SetSize(2))
|
||
;
|
||
; *TotePurgeables: called from PurgeSpace only. <17Apr85>
|
||
;
|
||
;
|
||
; Main Routines (external routines marked with *):
|
||
;
|
||
; *NextMaster
|
||
; |
|
||
; *HMakeMoreMasters
|
||
; |
|
||
; +-- *MakePtrSpc *SetSize ------+
|
||
; | | | |
|
||
; | +-------> MakeSpace |
|
||
; | | |
|
||
; | SafeReloc |
|
||
; | | |
|
||
; | |<--------+
|
||
; | |
|
||
; | RelocRel -->*FreeBk
|
||
; | |
|
||
; +---------------------->|
|
||
; *AllocBk --+--> BFindS
|
||
; | |
|
||
; | +--> MakeBk
|
||
; |
|
||
; *BkCompactS ---+--> GrowZone --+-->*ZoneAdjustEnd
|
||
; | |
|
||
; | +-->*MaxLimit
|
||
; +--> CallGZProc
|
||
; |
|
||
; +----------------->*CompactHp --+--> MakeFree
|
||
; | +-> |
|
||
; | | +--> BkFLow
|
||
; | |
|
||
; +-->*PurgeHeap -+-> PurgeBlock --> CallPurgePr
|
||
; +-->
|
||
; | +>
|
||
; *EH -------+ |
|
||
; |
|
||
; (MakeSpace)---------+
|
||
|
||
|
||
|
||
; index:
|
||
|
||
; DerefHandle
|
||
; WhichZone
|
||
; ZoneCheck
|
||
; MMPPrologue
|
||
; MMHPrologue
|
||
; MMFail
|
||
; MMPrologue
|
||
; MMRHPrologue <A305>
|
||
; MMNoErrEpilogue <25Apr85>
|
||
; MMEpilogue
|
||
|
||
; IncCntrs
|
||
; DecCntrs
|
||
; AdjCntrs
|
||
|
||
; MakeBkF
|
||
; EH
|
||
; CallPurgeProc
|
||
; PurgeBlock
|
||
; PurgeHeap
|
||
; TotePurgeables <17Apr85>
|
||
; CallGZProc
|
||
; BkCompactS
|
||
; BFindS
|
||
; AllocBK
|
||
|
||
; SetLogSize
|
||
; MakeBK
|
||
; BkfLow
|
||
; HBlockMove
|
||
; CompactHp
|
||
; MakeFree
|
||
|
||
; ToMaxLimit
|
||
; MaxLimit
|
||
; ZoneAdjustEnd
|
||
; GrowZone
|
||
; ActualS
|
||
; GetSize
|
||
; SetSize
|
||
; AdjustFree
|
||
; NextMaster
|
||
; HMakeMoreMasters
|
||
; ReleaseMP
|
||
; MakePtrSpc
|
||
; MakeSpace
|
||
; SafeReloc
|
||
; RelocRel
|
||
; FreeBk
|
||
; StdGZ ; new today <29jan85>
|
||
|
||
|
||
EXPORT MMPPrologue
|
||
EXPORT MMHPrologue
|
||
EXPORT MMPrologue
|
||
EXPORT MMRHPrologue ; <A305>
|
||
EXPORT MMNoErrEpilogue ; <25Apr85>
|
||
EXPORT MMEpilogue
|
||
EXPORT MMNoPrologue ; <v1.9>
|
||
EXPORT MMMMPrologue ; <v1.9>
|
||
|
||
EXPORT a24MakeBkF ; <v1.1>
|
||
EXPORT a32MakeBkF ; <v1.1>
|
||
EXPORT a24PurgeHeap ; <v1.1>
|
||
EXPORT a32PurgeHeap ; <v1.1>
|
||
EXPORT a24TotePurgeables ; <v1.1>
|
||
EXPORT a32TotePurgeables ; <v1.1>
|
||
EXPORT a24BkCompactS ; <v1.1>
|
||
EXPORT a32BkCompactS ; <v1.1>
|
||
EXPORT a24AllocBk ; <v1.1>
|
||
EXPORT a32AllocBk ; <v1.1>
|
||
|
||
EXPORT a24MaxLimit ; <v1.1>
|
||
EXPORT a32MaxLimit ; <v1.1>
|
||
EXPORT ToMaxLimit
|
||
EXPORT a24ZoneAdjustEnd ; <v1.1>
|
||
EXPORT a32ZoneAdjustEnd ; <v1.1>
|
||
EXPORT a24CompactHp ; <v1.1>
|
||
EXPORT a32CompactHp ; <v1.1>
|
||
|
||
EXPORT a24ActualS ; <v1.1>
|
||
EXPORT a32ActualS ; <v1.1>
|
||
EXPORT a24GetSize ; <v1.1>
|
||
EXPORT a32GetSize ; <v1.1>
|
||
EXPORT a24SetSize ; <v1.1>
|
||
EXPORT a32SetSize ; <v1.1>
|
||
EXPORT ClearGZStuff
|
||
EXPORT AdjustFree
|
||
EXPORT a24NextMaster ; <v1.1>
|
||
EXPORT a32NextMaster ; <v1.1>
|
||
EXPORT a24HMakeMoreMasters ; <v1.1>
|
||
EXPORT a32HMakeMoreMasters ; <v1.1>
|
||
EXPORT ReleaseMP
|
||
EXPORT a24MakePtrSpc ; <v1.1>
|
||
EXPORT a32MakePtrSpc ; <v1.1>
|
||
EXPORT a24FreeBk ; <v1.1>
|
||
EXPORT a32FreeBk ; <v1.1>
|
||
|
||
EXPORT a24EH ; <v1.1>
|
||
EXPORT a32EH ; <v1.1>
|
||
|
||
EXPORT StdGZ ; <29jan85>
|
||
EXPORT MemMgrEnd ; <27Apr85>
|
||
|
||
|
||
|
||
;---------------------------------------------------------------------- <SM9> rb, start <NK1>
|
||
; ZCBusErr -- bus error handler for ZoneCheck <NK1>
|
||
; A bus error in ZoneCheck causes ROMBase to be jammed for the relative handle. <NK1>
|
||
; Triggered by bus errors in Move.L (HeapData+handle32)(A6),D0 in ZoneCheck. <NK1>
|
||
; <NK1>
|
||
; Frame types 7 and B are handled. The PC is jammed with the instruction <NK1>
|
||
; following the bus error (it can't be incremented because the emulator <NK1>
|
||
; doesn't guarantee valid PC values) and A1 is jammed with ROMbase. The <NK1>
|
||
; frame is then mutated into a type 0 frame before RTE. This should work <NK1>
|
||
; with VM, NuKernel, and emulator environments. <NK1>
|
||
; <NK1>
|
||
; Output: D0 = 0 <NK1>
|
||
; Regs: A3 <NK1>
|
||
;---------------------------------------------------------------------- <NK1>
|
||
ZCBusErrHandler ; <NK1>
|
||
moveq #0,d0 ; stuff fake Nil value into dest. reg <NK1>
|
||
movea.w (sp),a3 ; <NK1>
|
||
cmpi.w #$7008,6(SP) ; type 7 frame? <NK1>
|
||
beq.s ZCBusErrType7 ; <NK1>
|
||
adda.w #(92-8),SP ; Leave space for type 0 frame <NK1>
|
||
bra.s ZCBusErrCommon ; <NK1>
|
||
ZCBusErrType7 ; <NK1>
|
||
adda.w #(60-8),SP ; Leave space for type 0 frame <NK1>
|
||
ZCBusErrCommon ; <NK1>
|
||
clr.w 6(SP) ; Make it a type 0 frame <NK1>
|
||
move.w a3,(sp) ; Return SR <NK1>
|
||
lea ZCFin,a3 ; <NK1>
|
||
move.l a3,2(SP) ; Return PC <NK1>
|
||
RTE ; <NK1>
|
||
|
||
;---------------------------------------------------------------------- <NK1>
|
||
; DHBusErr -- bus error handler for DerefHandle <NK1>
|
||
; A bus error in DerefHandle causes ROMBase to be jammed for the relative handle. <NK1>
|
||
; Triggered by bus errors in Move.L (A1),A0 in DerefHandle. <NK1>
|
||
; <NK1>
|
||
; Frame types 7 and B are handled. The PC is jammed with the instruction <NK1>
|
||
; following the bus error (it can't be incremented because the emulator <NK1>
|
||
; doesn't guarantee valid PC values) and A1 is jammed with ROMbase. The <NK1>
|
||
; frame is then mutated into a type 0 frame before RTE. This should work <NK1>
|
||
; with VM, NuKernel, and emulator environments. <NK1>
|
||
; <NK1>
|
||
; Output: D0 = -1 <NK1>
|
||
; Regs: A3 <NK1>
|
||
;---------------------------------------------------------------------- <NK1>
|
||
DHBusErrHandler
|
||
movea.l #-1,a0 ; stuff fake Nil value into dest. reg <NK1>
|
||
movea.w (sp),a3 ; <NK1>
|
||
cmpi.w #$7008,6(SP) ; type 7 frame? <NK1><SM10> rb
|
||
beq.s DHBusErrType7 ; <NK1>
|
||
adda.w #(92-8),SP ; Leave space for type 0 frame <NK1>
|
||
bra.s DHBusErrCommon ; <NK1>
|
||
DHBusErrType7 ; <NK1>
|
||
adda.w #(60-8),SP ; Leave space for type 0 frame <NK1>
|
||
DHBusErrCommon ; <NK1>
|
||
clr.w 6(SP) ; Make it a type 0 frame <NK1>
|
||
move.w a3,(sp) ; Return SR <NK1>
|
||
lea DHExit,a3 ; <NK1>
|
||
move.l a3,2(SP) ; Return PC <NK1>
|
||
RTE ; <NK1>
|
||
; <SM9> rb, end
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function DerefHandle(h: Handle): [p: RelPtr; h: Handle; ec: ErrCode];
|
||
;
|
||
; Dereferences a handle, safely. That is: mask the Handle, check
|
||
; that the address is good, and get the master pointer (MP) from
|
||
; that address.
|
||
; Check for Nil values passed in (as opposed to empty handles). <23Apr85>
|
||
; Watch that A1 is returned Nil when Nil passed in. <21May85>
|
||
; Add bus error check, returning A0=$FFFFFFFF. <C636>
|
||
;
|
||
; Argument:
|
||
; A0: h: handle for block.
|
||
;
|
||
; Results:
|
||
; D0: ec: error code.
|
||
; memAdrErr: Address is bad. (chking)
|
||
; nilHandleErr: Handle=0 passed. <23Apr85>
|
||
; 0: All is well, MP = Nil.
|
||
; #0: All is well, MP not Nil. (no chking)
|
||
; 1: All is well, MP not Nil. (chking)
|
||
; A0: p: de-referenced handle
|
||
; A1: h: masked handle
|
||
;
|
||
; Registers:
|
||
; D0: t: temporary
|
||
; D0: ec: error code
|
||
; A0: h: handle, masked handle
|
||
; A0: p: de-referenced handle
|
||
; A1: h: masked handle
|
||
; A2: saved bus error handler <C636>
|
||
; A3: new bus error handler <C636>
|
||
;
|
||
; Called By: MMHPrologue
|
||
|
||
DerefHandle
|
||
|
||
Move.L BusErrVct,A2 ;save current bus error handler <C636><1.6>
|
||
LEA DHBusErrHandler,A3 ;our DH version <C636>
|
||
Move.L A3,BusErrVct ; <C636><1.6>
|
||
|
||
BTST.B #MMStartMode,MMFlags ;is it 32 bit <v1.3>
|
||
Bne.S @10 ;branch if yes <v1.3>
|
||
Move.L A0,D0 ;Move h to D0
|
||
And.L MaskHandle,D0 ;Mask out high bits
|
||
Move.L D0,A0 ;Move masked h to A0
|
||
Move.L D0,A1 ;and to A1 right here, in case of error <21May85>
|
||
BEq.S DHExit ;Quit here sans error if 0 passed <16May85>
|
||
BRA.S @20 ;
|
||
@10 ; <v1.3>
|
||
Move.L A0,D0 ;Move h to D0
|
||
Move.L D0,A1 ;and to A1 right here, in case of error <21May85>
|
||
BEq.S DHExit ;Quit here sans error if 0 passed <16May85>
|
||
@20
|
||
Move.L (A1),A0 ;Move MP to A0, maybe NIL
|
||
DHExit
|
||
Move.L A2,BusErrVct ;restore old one after ALL done <C636><C836><1.6>
|
||
Move.L A0,D0 ;Test whether p is NIL, setting CCR <C836>
|
||
RTS ;Return to caller
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function WhichZone(p: Ptr; h: Handle): [z: Zone; ec: ErrCode];
|
||
;
|
||
; Returns the zone in which a memory block belongs. If the block
|
||
; is a Non-Relocatable block, the Handle field of the block header
|
||
; points directly at the zone object. If the block is a Relocatable
|
||
; block, the Handle field is the offset from the zone object to the
|
||
; Handle. Thus, for a Relocatable block, this offset is subtracted
|
||
; from the Handle used to find the block, in order to find the zone.
|
||
;
|
||
; Note that this routine clears the high byte of the pointer; this may
|
||
; appear to violate the convention that routines preserve this byte, but
|
||
; we are saved by the fact that the dispatcher has already saved the
|
||
; original argument (A0) in all cases except HandleZone and PtrZone which
|
||
; pass back the zone pointer in A0 anyways.
|
||
;
|
||
; Zone validity check added, via ZoneCheck. <13Apr85>
|
||
;
|
||
;
|
||
; Arguments:
|
||
; A0: p: points to block text region
|
||
; A1: h: handle for block or NIL
|
||
;
|
||
; Results:
|
||
; D0: ec: error code.
|
||
; memAdrErr: Address is bad. (chking)
|
||
; memWZErr: WhichZone failed, block is free!.
|
||
; 0: ok, A6 points to zone.
|
||
; A0: p: high byte of pointer has been cleared
|
||
; A6: z: zone in which block belongs
|
||
;
|
||
; Registers:
|
||
; D0: t: temporary
|
||
; D0: tag: tag from block
|
||
; D0: ec: error code
|
||
; A0: b: points to block header
|
||
;
|
||
; Called By: MMPPrologue,MMHPrologue
|
||
|
||
|
||
WhichZone
|
||
BTST.B #MMStartMode,MMFlags ;is it 32 bit or 24 bit <v1.2>
|
||
Bne.s WhZone32 ;branch for 32 bit zone <v1.2>
|
||
|
||
; for 24 bit zone
|
||
Move.L A0,D0 ;Move p to D0 for masking.
|
||
And.L MaskPtr,D0 ;Mask pointer.
|
||
Move.L D0,A0 ;Move masked p to A0.
|
||
|
||
SubQ.L #BlkData24,A0 ;Convert p to b (block pointer).
|
||
Tst.B TagBC24(A0) ;Test tag field.
|
||
BEq.S WZFail ;Tag = 0 => Free block, fail!
|
||
BMi.S WZRel ;Tag < 0 => Rel. block.
|
||
BTST.B #NRBbit,TagBC32(A0) ;is non-rel. block bit on? <v1.8>
|
||
BEQ.S WZFail ;branch, if it is not on. <v1.8>
|
||
|
||
Move.L Handle24(A0),A6 ;Actually points to zone
|
||
BrA.S WZCheck ;Checking exit path. <13Apr85>
|
||
|
||
WZRel
|
||
Move.L A1,A6 ;h to A6.
|
||
Sub.L Handle24(A0),A6 ;Offset back to zone pointer.
|
||
WZCheck ; <13Apr85>
|
||
BSR.S ZoneCheck ;leaving error code in D0 <13Apr85>
|
||
WZDone
|
||
AddQ.L #BlkData24,A0 ;Convert b to p (text pointer).
|
||
RTS ;Return.
|
||
WZFail
|
||
MoveQ #memWZErr,D0 ;WhichZone can't take a free
|
||
BrA.S WZDone ;block, fail return.
|
||
|
||
; 32 bit addressing version of the which zone
|
||
whZone32
|
||
Sub.L #BlkData32,A0 ;Convert p to b (block pointer). <v1.1>
|
||
Tst.B TagBC32(A0) ;Test tag field.
|
||
BEq.S @WZFail ;Tag = 0 => Free block, fail!
|
||
BMi.S @WZRel ;Tag < 0 => Rel. block.
|
||
BTST.B #NRBbit,TagBC32(A0) ;is non-rel. block bit on? <v1.8>
|
||
BEQ.S @WZFail ;branch, if it is not on. <v1.8>
|
||
|
||
Move.L Handle32(A0),A6 ;Actually points to zone
|
||
BrA.S @WZCheck ;Checking exit path. <13Apr85>
|
||
@WZRel
|
||
Move.L A1,A6 ;h to A6.
|
||
Sub.L Handle32(A0),A6 ;Offset back to zone pointer.
|
||
@WZCheck ; <13Apr85>
|
||
BSR.S ZoneCheck ;leaving error code in D0 <13Apr85>
|
||
@WZDone
|
||
Add.L #BlkData32,A0 ;Convert b to p (text pointer).
|
||
RTS ;Return.
|
||
@WZFail
|
||
MoveQ #memWZErr,D0 ;WhichZone can't take a free
|
||
BrA.S @WZDone ;block, fail return.
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function ZoneCheck(z: Zone): [ec: ErrCode]; <13Apr85>
|
||
;
|
||
; Checks whether z is valid by looking at block at first block in zone, which <16May85>
|
||
; should be an MP block. Note that this is incompatible with the GrowDown scheme! <16May85>
|
||
; Add bus error protection, returning MemAZErr via nil heap ptr. <C636>
|
||
; Also, removed save/restore of A0, which is no longer used. <C636>
|
||
;
|
||
; Arguments:
|
||
; A6: z: points to alleged heap zone
|
||
;
|
||
; Results:
|
||
; A6: z: stripped of high byte
|
||
; D0: ec: error code.
|
||
; memAZErr: Address of zone is bad.
|
||
; 0: ok, A6 points to zone.
|
||
; CCR: flags set according to ec in D0.
|
||
;
|
||
; Registers:
|
||
; D0: t: temporary
|
||
; A2: saved bus error handler <C636>
|
||
; A3: new bus error handler <C636>
|
||
;
|
||
; Called By: WhichZone, MMHPrologue (in case of NIL input handle), and MMPrologue.
|
||
|
||
ZoneCheck ; <13Apr85>
|
||
|
||
Move.L BusErrVct,A2 ;save current bus error handler <C636><1.6>
|
||
LEA ZCBusErrHandler,A3 ;our ZC version <C636>
|
||
Move.L A3,BusErrVct ; <C636><1.6>
|
||
|
||
BTST.B #MMStartMode,MMFlags ;is it 32 bit <v1.3>
|
||
Beq.S ZC24 ;Branch, if not <v1.1>
|
||
|
||
Move.L (HeapData+handle32)(A6),D0 ;relative handle of MP block <v1.1>
|
||
;possibly NIL on BusError <v1.1>
|
||
Bra.s ZCFin ;branch to rest of code <v1.1>
|
||
ZC24
|
||
Move.L A6,D0 ;Move z to D0 for masking.
|
||
And.L Lo3Bytes,D0 ;Mask pointer.
|
||
MoveA.L D0,A6 ;Return pointer
|
||
Move.L (HeapData+4)(A6),D0 ;relative handle of MP block <16May85>
|
||
;possibly NIL on BusError <C788>
|
||
|
||
ReturnFromZCBusErr ; <SM9> rb
|
||
And.L Lo3Bytes,D0 ;devoid of tag stuff <16May85>
|
||
ZCFin
|
||
Move.L A2,BusErrVct ;restore old one after danger <C636><1.6>
|
||
Sub.L A6,D0 ;if zero, that's our return code <16May85>
|
||
Beq.S ZCFini ;non-local label <C636>
|
||
|
||
MoveQ #memAZErr,D0
|
||
ZCFini ;non-local label <C636>
|
||
|
||
Rts
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function MMPPrologue(p: Ptr): [z: Zone; p: Ptr; h: Handle];
|
||
;
|
||
; Standard prefix for memory manager procedures using Pointers. Saves
|
||
; registers, sets z to the zone the block is in, sets h to Nil,
|
||
; checks the zone, checks the pointer, and returns to caller.
|
||
; If WhichZone fails, returns an error code. If ZC fails,
|
||
; invokes trouble alert.
|
||
;
|
||
; Argument:
|
||
; A0: p: points to block text.
|
||
;
|
||
; Results:
|
||
; A0: p: masked pointer to block text.
|
||
; A1: h: set to Nil.
|
||
; A6: z: zone in which block belongs.
|
||
;
|
||
; Registers:
|
||
; A0: p: points to block text
|
||
; A1: t1: temporary.
|
||
; A1: h: set to Nil.
|
||
; D2: t2: temporary.
|
||
;
|
||
; Called By: DisposePtr,GetPtrSize,SetPtrSize,PtrZone
|
||
|
||
MMPPrologue
|
||
Move.L (SP)+,A1 ; pop offset to vector
|
||
|
||
MoveM.L A2-A6/D3-D7,-(SP) ;Save Registers
|
||
Move.B MMFlags,-(SP) ;save Memory Mgr flags <v1.3>
|
||
Move.L A1,A4 ;Save offset to vector
|
||
Move.W #0,-(SP) ;set retry flag <v1.3>
|
||
Move.L D0,D2 ;Save D0
|
||
@again
|
||
Sub.L A1,A1 ;Set h to Nil.
|
||
BSR.S WhichZone ;Get zone from p.
|
||
BMi.S @retry ;WhichZone failed, retry <v1.3>
|
||
|
||
AddQ.L #2,SP ;get rid of retry flag <v1.3>
|
||
Move.L D2,D0 ;Restore D0.
|
||
|
||
Move.L ZoneJumpV(A6),D3 ; get jump vector table from zone <v1.9>
|
||
Bne.S @5 ; branch if not zero <v1.9>
|
||
Move.L #JMemMgr24,D3 ; if zero, assume 24 bit zone <v1.9>
|
||
@5
|
||
Add.L D3,A4 ; get address of vector <v1.9>
|
||
Move.L (A4),-(SP) ; get routine address
|
||
RTS ; proceed to routine
|
||
@retry
|
||
TST.W (SP)+ ;get retry flag <v1.3>
|
||
|
||
BNE MMFail
|
||
BCHG.B #MMStartMode,MMFlags ;invert Memory Mgr start Mode <v1.3>
|
||
Move.W #1,-(SP) ;no more retry <v1.3>
|
||
BRA.S @again ; <v1.3>
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Procedure MMHPrologue(h: Handle): [z: Zone; p: Ptr; h: Handle];
|
||
;
|
||
; Standard prefix for memory manager procedures using Handle. Saves
|
||
; registers, dereferences the Handle, which sets p to point to the
|
||
; block text, sets z to the zone the block is in,
|
||
; checks the zone, checks the handle, and returns to caller.
|
||
; If WhichZone or HC fails, returns an error code.
|
||
; If ZC fails, invokes trouble alert.
|
||
;
|
||
; If dereferenced handle turns out to be NIL, check default zone (theZone) via ZoneCheck. <13Apr85>
|
||
; If passed a Nil value for handle (otherwise known as 0!), return an error. <23Apr85>
|
||
;
|
||
; Tweak to adjust setting of A6 (the relevant zone) when master ptr is <16Apr86>
|
||
; Nil: if A6 (theZone, by default) is either SysZone or ApplZone,
|
||
; if (ApplZone < MP) then A6 := ApplZone
|
||
; else A6 := SysZone
|
||
; This is the least we can do to provide some sanity in ReallocHandle,
|
||
; DisposeHandle, HandleZone, and RecoverHandle. <28May86>
|
||
; when the MP is Nil; forcing A6 when theZone
|
||
; is neither SysZone nor ApplZone would be presumptuous of the progammer's
|
||
; intentions, so we don't do it!
|
||
; Add check for $FFFFFFFF coming back from DerefHandle via bus error. <C636>
|
||
;
|
||
; Argument:
|
||
; A0: h: handle for block.
|
||
;
|
||
; Results:
|
||
; cond. codes: Zero => handle is empty, Not Zero => handle in memory.
|
||
; A0: p: masked pointer for block or Nil.
|
||
; A1: h: masked handle for block.
|
||
; A6: z: zone in which block belongs.
|
||
;
|
||
; Registers:
|
||
; A0: p: points to block text.
|
||
; A1: t1: temporary.
|
||
; A1: h: handle for block.
|
||
; D2: t2: temporary.
|
||
; D7: t3: temporary.
|
||
;
|
||
; Called By: HLock,HUnLock,HPurge,HNoPurge,
|
||
; DsposeHandle,GetHandleSize,SetHandleSize,
|
||
; HandleZone,EmptyHandle,ReAllocHandle
|
||
|
||
MMHPrologue
|
||
Move.L (SP)+,A1 ;Pop ofset to vector
|
||
MoveM.L A2-A6/D3-D7,-(SP) ;Save Registers.
|
||
Move.B MMFlags,-(SP) ;save Memory Mgr flags <v1.3>
|
||
|
||
Move.L A1,A4 ;Save ofset to vector <v1.9>
|
||
|
||
BTST.B #MMStartMode,MMFlags ;is it 32 bit <v1.3>
|
||
BEQ.S @1 ;branch if not
|
||
MOVE.W #1,-(SP) ;set to not retry
|
||
Move.L D0,D2 ;Save D0.
|
||
BRA.S MMHagain ;perform the check
|
||
@1
|
||
Move.W #0,-(SP) ;set retry flag <v1.3>
|
||
Move.L D0,D2 ;Save D0.
|
||
MMHagain ; <v1.3>
|
||
Move.L theZone,A6 ;default to theZone.
|
||
|
||
BSR.S DerefHandle ;Dereference the Handle.
|
||
BEq.S MMHPDeflt ;No block, zone better be good. <13Apr85>
|
||
Cmp.L MinusOne,D0 ;Funny value stuffed on bus errors <v1.3> <C636>
|
||
BEq.S MMHRetry ;Exit quickly if bad value <C636>
|
||
|
||
BSR.S WhichZone ;Get zone from p, h.
|
||
MMHPCommon ;Common exit code for Nil and otherwise... <13Apr85>
|
||
BMi.S MMHRetry ;WhichZone or ZoneCheck failed <v1.3> <13Apr85>
|
||
|
||
AddQ.L #2,SP ;get rid of retry flag <v1.3>
|
||
Move.L D2,D0 ;Restore D0.
|
||
|
||
Move.L ZoneJumpV(A6),D3 ; get jump vector table from zone <v1.9>
|
||
Bne.S @1 ; branch if not zero <v1.9>
|
||
Move.L #JMemMgr24,D3 ; if zero, assume 24 bit zone <v1.9>
|
||
@1
|
||
Add.L D3,A4 ; get address of vector <v1.9>
|
||
Move.L (A4),-(SP) ; get routine address
|
||
|
||
Move.L A0,D7 ;Set condition codes
|
||
RTS ;Return to caller
|
||
|
||
MMHPDeflt ; <13Apr85>
|
||
; Check a6 (TheZone) against handle to determine which zone the handle is
|
||
; in. This works as long as there is not more than three working zones
|
||
; (i.e. TheZone, ApplZone, SysZone)
|
||
|
||
move.l A1,D0 ;EQ -> Handle is Nil <16Apr86>
|
||
beq.s @9 ;hopeless case <16Apr86>
|
||
|
||
; is the handle in TheZone?
|
||
cmp.l a6,a1 ; check zone start <SM11> CSS
|
||
blo.s @notTheZone ; below it <SM11> CSS
|
||
cmp.l (a6),a1 ; check zone end <SM11> CSS
|
||
blo.s @9 ; go for it <SM11> CSS
|
||
@notTheZone
|
||
; is the handle in the ApplZone?
|
||
move.l ApplZone,a6 ; try the ApplZone <SM11> CSS
|
||
cmp.l a6,a1 ; check zone start <SM11> CSS
|
||
blo.s @notApplZone ; below it <SM11> CSS
|
||
cmp.l (a6),a1 ; check zone end <SM11> CSS
|
||
blo.s @9 ; go for it <SM11> CSS
|
||
@notApplZone
|
||
; is the handle in the SysZone?
|
||
move.l SysZone,a6 ; try the SysZone <SM11> CSS
|
||
cmp.l a6,a1 ; check zone start <SM11> CSS
|
||
blo.s @punt ; below it <SM11> CSS
|
||
cmp.l (a6),a1 ; check zone end <SM11> CSS
|
||
blo.s @9 ; go for it <SM11> CSS
|
||
|
||
; <SM11> CSS if we got here, we must punt. We have three choices for the zone this handle is in
|
||
; (TheZone, ApplZone, SysZone). We just tested for all three of them and found that the
|
||
; handle is in none of the zones. So, we punt with TheZone. The only way that this should
|
||
; happen is if we have a zone which is not inside the application zone or the system zone.
|
||
|
||
@punt
|
||
move.l TheZone,A6 ; punt with TheZone <SM11> CSS
|
||
@9 ; <16Apr86>
|
||
BSR.S ZoneCheck ;Set D0 and CCR according to theZone in A6 <13Apr85>
|
||
BRA.S MMHPCommon ;And resume <13Apr85>
|
||
|
||
MMHRetry
|
||
TST.W (SP)+ ;get retry flag <v1.3>
|
||
|
||
BNE.S MMFail ;no more retry <v1.9>
|
||
Move.L A1,A0 ;reset A0 <v1.3>
|
||
BChg.B #MMStartMode,MMFlags ;invert Memory Mgr start Mode <v1.3>
|
||
Move.W #1,-(SP) ;no more retry <v1.3>
|
||
BRA.S MMHagain ; <v1.3>
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Entry MMFail;
|
||
;
|
||
; Standard entry point for fail returns from MMPrologue, MMPPrologue,
|
||
; and MMHPrologue. This pops the trap routine's return address from
|
||
; the stack, and then exits normally.
|
||
; Can be called from MMPrologue now that ZoneCheck is used. <13Apr85>
|
||
;
|
||
; Argument:
|
||
; D0: ec: Error Code.
|
||
;
|
||
; Result:
|
||
; None
|
||
;
|
||
; Register:
|
||
; D0: ec: Error Code.
|
||
;
|
||
; Called By: MMPPrologue,MMHPrologue,MMPrologue <13Apr85>
|
||
|
||
MMFail
|
||
BrA MMExit ;Restore regs, and return.
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
; PROCEDURE MMNoPrologue;
|
||
;
|
||
; This routine is called by routine that do not called either
|
||
; MMPrologue, MMHPrologue, MMPPrologue, MMRHPrologue.
|
||
|
||
|
||
MMNoPrologue
|
||
MOVE.L A0,-(SP) ; save A0 <v1.9>
|
||
MOVE.L 4(SP),A0 ; get offset to specific routine <v1.9>
|
||
BTST.B #MMStartMode,MMFlags ; is it 32 bit or 24 bit <v1.9>
|
||
BNE.S @1 ; branch if 32 bit <v1.9>
|
||
Add.L #JMemMgr24,A0 ; add in vector table adress <v1.9>
|
||
BRA.s @2 ; <v1.9>
|
||
@1
|
||
ADD.L #JMemMgr32,A0 ; add in vector table adress <v1.9>
|
||
@2
|
||
Move.L (A0),4(SP) ; get routine address onto stack <v1.9>
|
||
Move.L (SP)+,A0 ; restore A0 <v1.9>
|
||
RTS ; <v1.9>
|
||
;----------------------------------------------------------------------
|
||
; PROCEDURE MMMMPrologue;
|
||
;
|
||
; This routine is called by MoreMasters only
|
||
|
||
MMMMPrologue
|
||
Move.L (SP)+,A1 ; pop offset to vector <v1.9>
|
||
Move.L A6,-(SP) ; preserve A6
|
||
Move.L theZone,A6 ; use current zone
|
||
|
||
Move.L ZoneJumpV(A6),D0 ; get jump vector table from zone <v1.9>
|
||
Bne.S @1 ; branch if not zero <v1.9>
|
||
Move.L #JMemMgr24,D0 ; if zero, assume 24 bit zone <v1.9>
|
||
@1
|
||
Add.L D0,A1 ; get address of vector <v1.9>
|
||
Move.L (A1),-(SP) ; get vector onto stack <v1.9>
|
||
|
||
RTS ; go to routine directly
|
||
|
||
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function MMPrologue: [z: Zone];
|
||
;
|
||
; Standard prefix for memory manager procedures for which zone must
|
||
; be explicitly set before the call.
|
||
;
|
||
; A number of memory allocator functions use the System Global variable
|
||
; theZone to indicate which zone should be used for that function.
|
||
; It is often convenient for system programs to be able to specify that
|
||
; sysZone should be used for the current operation, whatever the current
|
||
; state of theZone is. On the other hand, most applications programs
|
||
; want to use whatever zone is currently specified by theZone. To
|
||
; permit this choice, the memory manager examines bit 10
|
||
; (the SysOrCurZone bit) of the OS trap. If this bit is clear
|
||
; (current zone), then A6 is set from theZone. If this bit is set
|
||
; (system zone), then A6 is set to sysZone.
|
||
;
|
||
; Once the registers have been saved, and the zone state has been set
|
||
; as desired, we call ZC, to ensure that the zone is
|
||
; internally consistent. We then return to the memory manager procedure
|
||
; which called us.
|
||
;
|
||
; ZoneCheck is used to verify the zone to be used. If it fails, off to MMFail. <13Apr85>
|
||
;
|
||
; Argument:
|
||
; D1 trap: value of trap instruction.
|
||
;
|
||
; Result:
|
||
; A6: z: zone for memory manager call.
|
||
;
|
||
; Registers:
|
||
; A1: t: temporary.
|
||
; D2: t: temporary copy of D0 (usually an argument to the caller). <13Apr85>
|
||
;
|
||
; Called By: NewPtr,NwHandle,RecoverHandle,CompactMem,PurgeMem,FreeMem,
|
||
; MaxMem,ResrvMem
|
||
|
||
|
||
MMPrologue
|
||
Move.L (SP)+,A1 ;Pop offset to vector
|
||
MoveM.L A2-A6/D3-D7,-(SP) ;Save Registers.
|
||
Move.B MMFlags,-(SP) ;save Memory Mgr flags <v1.3>
|
||
Move.L A1,A4 ;Save offset to vector <v1.9>
|
||
Move.W #0,-(SP) ;set retry flag <v1.3>
|
||
Move.L D0,D2 ;Save D0. <13Apr85>
|
||
@MMPagain ; <v1.3>
|
||
Move.L theZone,A6 ;Return current zone in A6.
|
||
BTst #TSysOrCurZone,D1 ;System or current zone?
|
||
BEq.S @1 ;Use current zone.
|
||
Move.L sysZone,A6 ;Use system zone.
|
||
@1
|
||
BSR ZoneCheck ;Is A6 kosher? <13Apr85>
|
||
BMi.S @MMPRetry ;Bail out if not. <13Apr85>
|
||
|
||
AddQ.L #2,SP ;get rid of retry flag <v1.3>
|
||
Move.L D2,D0 ;Restore D0. <13Apr85>
|
||
|
||
Move.L ZoneJumpV(A6),D3 ; get jump vector table from zone <v1.9>
|
||
Bne.S @5 ; branch if not zero <v1.9>
|
||
Move.L #JMemMgr24,D3 ; if zero, assume 24 bit zone <v1.9>
|
||
@5
|
||
Add.L D3,A4 ; get address of vector <v1.9>
|
||
Move.L (A4),-(SP) ; get vector onto stack <v1.9>
|
||
|
||
RTS ; go to routine directly
|
||
@MMPRetry
|
||
TST.W (SP)+ ;get retry flag <v1.3>
|
||
|
||
BNE.S MMFail ;no more retry <v1.9>
|
||
|
||
BCHG.B #MMStartMode,MMFlags ;invert Memory Mgr start Mode <v1.3>
|
||
Move.W #1,-(SP) ;no more retry <v1.3>
|
||
BRA.S @MMPagain ; <v1.3>
|
||
|
||
|
||
;---------------------------------------------------------------------- <A305>
|
||
; Function MMRHPrologue: [z: Zone]; <A305>
|
||
; MMRHPrologue -- a variant of MMPrologue called only by RecoverHandle. It gets TheZone into
|
||
; A6 as usual, but then checks that A6 is “sensible” in case TheZone is SysZone or ApplZone.
|
||
; More precisely, when TheZone is SysZone or ApplZone, force A6 to be ApplZone if the ptr
|
||
; to the given handle data is above ApplZone; else make A6 SysZone.
|
||
; See comments in MMRHPrologue for interface definition.
|
||
;
|
||
; Called by: RecoverHandle
|
||
|
||
MMRHPrologue ; <A305>
|
||
Move.L (SP)+,A1 ;Pop offset to vector.
|
||
MoveM.L A2-A6/D3-D7,-(SP) ;Save Registers.
|
||
Move.B MMFlags,-(SP) ;save Memory Mgr flags <v1.3>
|
||
Move.L A1,A4 ;Save offset to vector <v1.9>
|
||
Move.W #0,-(SP) ;set retry flag <v1.3>
|
||
Move.L D0,D2 ;Save D0
|
||
@MMRHagain ; <v1.3>
|
||
Move.L theZone,A6 ;Return current zone in A6.
|
||
BTst #TSysOrCurZone,D1 ;System or current zone?
|
||
|
||
;--------------------------- Start of difference from MMPrologue ------------- <A305>
|
||
BNE.S @forceSysZone ;
|
||
; When A6 is either SysZone or ApplZone, force A6 to be ApplZone
|
||
; if (ApplZone < Ptr), else force to be SysZone.
|
||
Cmp.L SysZone,A6 ;Eq --> force A6
|
||
BEq.S @forceA6 ;
|
||
Cmp.L ApplZone,A6 ;NE --> don't force A6
|
||
BNE.S @postForce ;
|
||
@forceSysZone ;
|
||
MoveA.L SysZone,A6 ;presume SysZone
|
||
@forceA6 ;
|
||
Move.L A0,D0 ;D0 := ptr to handle data
|
||
BTST.B #MMStartMode,MMFlags ;is it 32 bit <v1.3>
|
||
Bne.S @1 ;branch if yes <v1.1>
|
||
And.L Lo3Bytes,D0 ;true 24-bit ptr, devoid of state bits
|
||
@1
|
||
Cmp.L ApplZone,D0 ;ApplZone < D0 --> use ApplZone
|
||
BLS.S @postForce ;ApplZone >= D0 --> Lower or Same --> SysZone
|
||
MoveA.L ApplZone,A6 ;
|
||
@postForce ;
|
||
;------------------------- End of difference from MMPrologue --------------- <A305>
|
||
|
||
BSR ZoneCheck ;Is A6 kosher? <13Apr85>
|
||
BMi.S @MMRHRetry ;Bail out if not. <v1.3> <13Apr85>
|
||
|
||
AddQ.L #2,SP ;get rid of retry flag <v1.3>
|
||
Move.L D2,D0 ;Restore D0. <13Apr85>
|
||
|
||
Move.L ZoneJumpV(A6),D3 ; get jump vector table from zone <v1.9>
|
||
Bne.S @5 ; branch if not zero <v1.9>
|
||
Move.L #JMemMgr24,D3 ; if zero, assume 24 bit zone <v1.9>
|
||
@5
|
||
Add.L D3,A4 ; get address of vector <v1.9>
|
||
Move.L (A4),-(SP) ; get routine address <v1.9>
|
||
|
||
RTS ;Return to caller. End of <A305>
|
||
|
||
@MMRHRetry
|
||
TST.W (SP)+ ;get retry flag <v1.3>
|
||
BNE.S MMFail ;no more retry <v1.9>
|
||
BCHG.B #MMStartMode,MMFlags ;invert Memory Mgr start Mode <v1.3>
|
||
Move.W #1,-(SP) ;no more retry <v1.3>
|
||
BRA.S @MMRHagain ; <v1.3>
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Entry MMEpilogue;
|
||
;
|
||
; Standard Epilogue for many memory allocator entry points.
|
||
; This routine does a number of services for those memory allocator
|
||
; entry points which use it: it checks that the zone is still
|
||
; consistent restores the registers, and returns to caller of
|
||
; the entry point.
|
||
;
|
||
; Amended to stuff error code in global MemErr. There are three classes of routines: <25Apr85>
|
||
; 1) Typical -- long error code <= 0 in D0 <25Apr85>
|
||
; 2) GetHandleSize, etc. -- long result >= 0 or error code <= in D0 <25Apr85>
|
||
; 3) Bizarre RecoverHandle -- preserved, irrelevant value in D0, but error code = 0 <25Apr85>
|
||
; First two may be handled by simple Tst.L; in latter case just stuff MemErr. <25Apr85>
|
||
;
|
||
; Argument:
|
||
; D0: ec: error code, or 0 for success, or, possibly,
|
||
; a byte count or other + result.
|
||
;
|
||
; Result:
|
||
; None
|
||
;
|
||
; Register:
|
||
; D0: ec: error code.
|
||
;
|
||
; MMEpilogue called By: HLock,HUnLock,HPurge,HNoPurge,NewPtr,NwHandle,
|
||
; DisposePtr,GetPtrSize,SetPtrSize,PtrZone
|
||
; DsposeHandle,GetHandleSize,SetHandleSize,
|
||
; HandleZone, ** not RecoverHandle ** ,EmptyHandle,ReAllocHandle <25Apr85>
|
||
; CompactMem,PurgeMem,FreeMem,MaxMem ,ResrvMem
|
||
; MMNoErrEpilogue called by: RecoverHandle <25Apr85>
|
||
|
||
MMEpilogue
|
||
Clr.W MemErr
|
||
Tst.L D0
|
||
BGE.S MMNoErrEpilogue
|
||
MMExit ;get here from failed prologue <25Apr85>
|
||
Move.W D0,MemErr
|
||
MMNoErrEpilogue
|
||
Move.B (SP)+,MMFlags ;restore Memory Mgr. Flags <v1.3>
|
||
MoveM.L (SP)+,A2-A6/D3-D7 ;Restore Registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Procedure MakeBkf(b: Block; s: Size);
|
||
;
|
||
; Makes block b into a free block s bytes long.
|
||
; S must be even, and already includes the block overhead bytes.
|
||
;
|
||
; Arguments:
|
||
; D0: s: size of new free block.
|
||
; A0: b: points to block header of block
|
||
; A6: z: zone for block.
|
||
;
|
||
; Result:
|
||
; None.
|
||
;
|
||
; Registers:
|
||
; D0: s: size of new free block.
|
||
; D0: t: temporary, used for masking b.
|
||
; A1: bFirst: first block on free list.
|
||
; A1: bPrev: block before one being added.
|
||
; A1: bFirst: first block on free list.
|
||
;
|
||
; Called By: InitZone,MakeBk,MakeFree,ZoneAdjustEnd,MakeSpace,SetSize,Purgeblock
|
||
|
||
a24MakeBkF
|
||
Move.L D0,TagBC24(A0) ;Set tag and byte count.
|
||
Clr.B TagBC24(A0) ;Clear tag and offset.
|
||
|
||
RTS ;Return to caller.
|
||
|
||
a32MakeBkF
|
||
Move.L D0,BlkSize32(A0) ;save size of free block <v1.1>
|
||
Clr.L TagBC32(A0) ;clear first long word <v1.1>
|
||
|
||
RTS ;Return to caller.
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Procedure MakeCBkf(b: Block; s: Size);
|
||
;
|
||
; Makes block b into a free block s bytes long, also check next block
|
||
; if next block is a free block, combined both free block, repeat until
|
||
; next block is not a free block.
|
||
; S must be even, and already includes the block overhead bytes.
|
||
;
|
||
; Arguments:
|
||
; D0: s: size of new free space.
|
||
; A0: b: points to block header of block
|
||
; A6: z: zone for block.
|
||
;
|
||
; Result:
|
||
; None.
|
||
;
|
||
; Registers:
|
||
; D0: s: size of new free space.
|
||
; D0: t: temporary, used for new free block size.
|
||
;
|
||
; Called By: FreeBk
|
||
|
||
a24MakeCBkF
|
||
Movem.L A1/D0,-(SP) ;save A1, D0 <v1.5>
|
||
Move.L A0,A1 ;get start of free block address <v1.5>
|
||
Add.L D0,A1 ;get beginning of next block <v1.5>
|
||
@tryNext ; <v1.5>
|
||
Tst.B TagBC24(A1) ;is next block free <v1.5>
|
||
Bne.S @notFree ;branch if not a free block <v1.5>
|
||
CmpA.L BkLim(A6),A1 ;is it the last free block <v1.5>
|
||
Bcc.S @notFree ;branch, if yes <v1.5>
|
||
|
||
Cmp.L AllocPtr(A6),A1 ;is the rover at a disappearing block? <SM12> kc
|
||
Bne.S @1 ;NotEqual => no... <SM12> kc
|
||
Move.L A0,AllocPtr(A6) ;don't let allocptr pt to nonexistent block <SM12> kc
|
||
@1 ; <SM12> kc
|
||
Add.L TagBC24(A1),D0 ;add size of next free block <v1.5>
|
||
AddA.L TagBC24(A1),A1 ;advance A1 to next block <v1.5>
|
||
Bra.S @trynext ;check next block <v1.5>
|
||
@notFree ; <v1.5>
|
||
Move.L D0,TagBC24(A0) ;Set tag and byte count.
|
||
Clr.B TagBC24(A0) ;Clear tag and offset.
|
||
;<SM12> kc Move.L A0,AllocPtr(A6) ;update allocPtr to point here <v1.5>
|
||
Movem.L (SP)+,A1/D0 ;restore A1 ,D0 <v1.5>
|
||
RTS ;Return to caller.
|
||
|
||
;--- 32 bit version ---
|
||
|
||
a32MakeCBkF
|
||
Movem.L A1/D0,-(SP) ;save A1, D0 <v1.5>
|
||
Move.L A0,A1 ;get start of free block address <v1.5>
|
||
Add.L D0,A1 ;get beginning of next block <v1.5>
|
||
@tryNext ; <v1.5>
|
||
Tst.B TagBC32(A1) ;is next block free <v1.5>
|
||
Bne.S @notFree ;branch if not a free block <v1.5>
|
||
CmpA.L BkLim(A6),A1 ;is it the last free block <v1.5>
|
||
Bcc.S @notFree ;branch, if yes <v1.5>
|
||
|
||
Cmp.L AllocPtr(A6),A1 ;is the rover at a disappearing block? <SM12> kc
|
||
Bne.S @1 ;NotEqual => no... <SM12> kc
|
||
Move.L A0,AllocPtr(A6) ;don't let allocptr pt to nonexistent block <SM12> kc
|
||
@1 ; <SM12> kc
|
||
Add.L BlkSize32(A1),D0 ;add size of next free block <v1.5>
|
||
AddA.L BlkSize32(A1),A1 ;advance A1 to next block <v1.5>
|
||
Bra.S @trynext ;check next block <v1.5>
|
||
@notFree ; <v1.5>
|
||
Move.L D0,BlkSize32(A0) ;save size of free block <v1.1>
|
||
Clr.L TagBC32(A0) ;clear first long word <v1.1>
|
||
|
||
;<SM12> kc Move.L A0,AllocPtr(A6) ;update allocPtr to point here <v1.5>
|
||
Movem.L (SP)+,A1/D0 ;restore A1, D0 <v1.5>
|
||
RTS ;Return to caller.
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function EH(p: Ptr; h: Handle): ErrCode;
|
||
;
|
||
; Tests whether block is locked. If it is, then returns with an error.
|
||
; Otherwise, the block is purged.
|
||
;
|
||
; Arguments:
|
||
; A0: p: pointer for block.
|
||
; A1: h: handle for block.
|
||
; A6: z: zone containing block.
|
||
;
|
||
; Result:
|
||
; D0: ec: error code.
|
||
; memPurErr: Block is locked.
|
||
; 0: Success.
|
||
;
|
||
; Register:
|
||
; A0: b: points to block header.
|
||
;
|
||
; Called By: EmptyHandle,ReAllocHandle
|
||
|
||
a24EH ; 24 bit version <v1.1>
|
||
BTst #Lock,(A1) ; Handle locked?
|
||
BNE.S @EHNoPurge ; Yes, fail.
|
||
|
||
BTst #ROZ,flags(A6) ; just clear the MP if ROZ <10Apr85>
|
||
BNE.S @EHSkip ; <10Apr85>
|
||
|
||
SubQ.L #BlkData24,A0 ; Adjust to point to block head.
|
||
BSR.S a24PurgeBlock ; Purge this block.
|
||
AddQ.L #BlkData24,A0 ; Point again to block text.
|
||
@EHOK
|
||
MoveQ #0,D0 ; Success result.
|
||
@EHExit
|
||
RTS ; Return to caller.
|
||
@EHNoPurge
|
||
MoveQ #memPurErr,D0 ; Block is locked, can't purge.
|
||
BrA.S @EHExit ; Use common exit code.
|
||
@EHSkip
|
||
CLR.L (A1) ; Wipe out the (bogus) MP <10Apr85>
|
||
BRA.S @EHOK ; error-free exit <10Apr85>
|
||
|
||
;------- 32 bit version --------
|
||
a32EH ; 32 bit version <v1.1>
|
||
Move.L A2,-(SP) ; save register <v1.1>
|
||
Move.L (A1),A2 ; get start of data in block <v1.1>
|
||
BTst #Lock,MPtag32-blkData32(A2) ;handle locked? <v1.1>
|
||
BNE.S @EHNoPurge ; Yes, fail.
|
||
|
||
BTst #ROZ,flags(A6) ; just clear the MP if ROZ <10Apr85>
|
||
BNE.S @EHSkip ; <10Apr85>
|
||
|
||
Sub.L #BlkData32,A0 ; Adjust to point to block head.
|
||
BSR.S a32PurgeBlock ; Purge this block.
|
||
Add.L #BlkData32,A0 ; Point again to block text.
|
||
@EHOK
|
||
MoveQ #0,D0 ; Success result.
|
||
@EHExit
|
||
Move.L (SP)+,A2 ; restore register <v1.1>
|
||
RTS ; Return to caller.
|
||
@EHNoPurge
|
||
MoveQ #memPurErr,D0 ; Block is locked, can't purge.
|
||
BrA.S @EHExit ; Use common exit code.
|
||
@EHSkip
|
||
CLR.L (A1) ; Wipe out the (bogus) MP <10Apr85>
|
||
BRA.S @EHOK ; error-free exit <10Apr85>
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Procedure CallPurgeProc(h: Handle);
|
||
;
|
||
; Calls the zone's Purge Warning Procedure. This procedure is called
|
||
; by the memory manager routines just before a block is purged.
|
||
;
|
||
; Arguments:
|
||
; A1: h: Handle for block about to be purged.
|
||
; A6: z: Zone containing block to be purged.
|
||
;
|
||
; Result:
|
||
; None.
|
||
;
|
||
; Registers:
|
||
; A1: prPur: Address of Purge Warning Procedure.
|
||
;
|
||
; Called By: PurgeBlock
|
||
|
||
CallPurgeProc
|
||
Tst.L purgeProc(A6) ;PurgeProc defined?
|
||
BEq.S CPgReturn ;No, return directly.
|
||
|
||
MoveM.L D0-D2/A0-A1,-(SP) ;Save registers.
|
||
Move.L A1,-(SP) ;Push h as argument.
|
||
Move.L purgeProc(A6),A1 ;Points to Purge Warning proc.
|
||
JSR (A1) ;Call Purge Warning proc.
|
||
MoveM.L (SP)+,D0-D2/A0-A1 ;Restore registers.
|
||
CPgReturn
|
||
RTS ;Return to caller.
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Procedure PurgeBlock(p: Ptr; h: Handle);
|
||
;
|
||
; Purge the referenced block and adjust counters.
|
||
;
|
||
; Arguments:
|
||
; A0: p: points to block.
|
||
; A1: h: handle for block.
|
||
; A6: z: Zone to be searched.
|
||
;
|
||
; Result:
|
||
; None.
|
||
;
|
||
; Registers:
|
||
; D0: s: Physical size of block being purged.
|
||
;
|
||
; Called By: PurgeHeap,MakeSpace,EH
|
||
|
||
a24PurgeBlock
|
||
Move.L D0,-(SP) ;Save register.
|
||
Move.L TagBC24(A0),D0 ;Get block header.
|
||
And.L MaskBC,D0 ;Extract physical block size.
|
||
BSR CallPurgeProc ;Invoke the purge warning.
|
||
Clr.L (A1) ;Set the Master Pointer to Nil.
|
||
BSR.S a24MakeBkF ;Make a free block.
|
||
BSR AdjustFree ;Increase zone free count.
|
||
Move.L (SP)+,D0 ;Restore register.
|
||
RTS ;Return to caller.
|
||
|
||
a32PurgeBlock
|
||
Move.L D0,-(SP) ;Save register.
|
||
Move.L BlkSize32(A0),D0 ;get block size <v1.1>
|
||
BSR CallPurgeProc ;Invoke the purge warning.
|
||
Clr.L (A1) ;Set the Master Pointer to Nil.
|
||
BSR.S a32MakeBkF ;Make a free block.
|
||
BSR AdjustFree ;Increase zone free count.
|
||
Move.L (SP)+,D0 ;Restore register.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function PurgeHeap(s: Size): Ptr;
|
||
;
|
||
; This procedure first scans the heap for a region containing unlocked
|
||
; relocatables (purgeable and non-purgeable) and free blocks with enough
|
||
; free and purgeable space to satisfy the request. This is done using
|
||
; a roving purge pointer so that the first blocks are not always purged.
|
||
; If no region satisfying the request is found, all purgeable blocks in
|
||
; the heap are purged; otherwise, only those purgeable blocks within the
|
||
; identified region are purged. After purging the heap is compacted.
|
||
;
|
||
; Arguments:
|
||
; D0: s: Number of adjacent bytes needed by caller.
|
||
; A6: z: Zone to be purged.
|
||
;
|
||
; Result:
|
||
; A0: b: points to available free space, or Nil if none found.
|
||
; D1: contains largest free space found.
|
||
;
|
||
; Registers:
|
||
; D0: s: Size needed.
|
||
; D1: temporary
|
||
; D2: sRgn: cumulative count of bytes in current region.
|
||
; A0: bPrg: points to purge start
|
||
; A1: h: handle for block, temporary.
|
||
; A2: bNxt: points to next block, purge end.
|
||
; A3: bLim: points to last block in zone
|
||
; A4: bCur: points to current block.
|
||
;
|
||
; Called By: BkCompactS,PurgeMem
|
||
|
||
a24PurgeHeap ; 24 bit version of PurgeHeap
|
||
MoveM.L D2/A1-A4,-(SP) ;Save registers.
|
||
@PurgeScan Move.L BkLim(A6),A3 ;Last block in zone
|
||
LEA HeapData(A6),A0 ;First block in zone.
|
||
BTst #FNSelPurge,Flags(A6) ;Use non-selective purge?
|
||
BNE.S @PHPrgAll ;Br if so.
|
||
Move.L A0,A2 ;bPrg := first zone block ptr.
|
||
MoveQ #0,D2 ;sRgn := 0.
|
||
@PrgScanLoop
|
||
Move.L TagBC24(A2),D1 ;Block header
|
||
And.L MaskBC,D1 ;Byte count only
|
||
Move.L A2,A4 ;Current block ptr.
|
||
Add.L D1,A2 ;Next block ptr.
|
||
|
||
Tst.B TagBC24(A4) ;Is this block free?
|
||
Beq.S @PrgSFree ;Br if so (add to region)
|
||
Bpl.S @PrgSNRel ;Br if non-rel (start next region)
|
||
|
||
Move.L Handle24(A4),A1 ;Handle offset.
|
||
Add.L A6,A1 ;Handle
|
||
Tst.B (A1) ;Is block locked?
|
||
BMi.S @PrgSNRel ;Br if so (start next region)
|
||
BTst #Purge,(A1) ;Unlocked, test purge flag.
|
||
BEq.S @PrgSEnd ;Not purgeable, don't purge.
|
||
Cmp.L PurgePtr(A6),A4 ;Past the purge rover yet?
|
||
BCS.S @PrgSAdv ;Br if not (advance purge start)
|
||
@PrgSFree Add.L D1,D2 ;Add to sRgn
|
||
Cmp.L D0,D2 ;Do we have enough?
|
||
BCS.S @PrgSEnd ;Br if not
|
||
BrA.S @PHLoop ;Purge purgeable blocks between
|
||
; A0 and A2, then compact . . .
|
||
@PrgSNRel MoveQ #0,D2 ;sRgn := 0. (next region)
|
||
@PrgSAdv Move.L A2,A0 ;Advance purge start ptr.
|
||
|
||
@PrgSEnd Cmp.L A3,A2 ;End of zone reached?
|
||
BCS.S @PrgScanLoop ;Loop if not
|
||
|
||
LEA HeapData(A6),A0
|
||
Cmp.L PurgePtr(A6),A0 ;Did rover start at heap start?
|
||
BEq.S @PHPrgAll ;Br if so.
|
||
Move.L A0,PurgePtr(A6) ;Otherwise, set the rover back
|
||
BrA.S @PurgeScan ;And scan again.
|
||
|
||
@PHPrgAll Move.L A3,A2 ;No luck. So purge all purgables.
|
||
|
||
; now that we've pre-scanned, it's time to do the actual purging; we purge all
|
||
; purgeable blocks from (A0) up to but not including (A2). We have to test for
|
||
; locked relocatables and non-relocatables because of the case in which we are
|
||
; purging all purgeables in the heap.
|
||
|
||
@PHLoop
|
||
Move.L TagBC24(A0),D1 ;Block header
|
||
And.L MaskBC,D1 ;Byte count only
|
||
|
||
Tst.B TagBC24(A0) ;Is this block free?
|
||
Bpl.S @PHSkip ;Br if Free or Non-Rel
|
||
|
||
Move.L Handle24(A0),A1 ;Handle offset for rel. block.
|
||
Add.L A6,A1 ;Convert to true handle.
|
||
Tst.B (A1) ;Test lock, purge flags byte.
|
||
BMi.S @PHSkip ;Locked, can't purge it.
|
||
BTst #Purge,(A1) ;Unlocked, test purge flag.
|
||
BEq.S @PHSkip ;Not purgeable, don't purge.
|
||
|
||
BSR.S a24PurgeBlock ;Go ahead and purge this one.
|
||
Cmp.L D0,D1 ;Is sBlock >= s? check for
|
||
BCC.S @PHDone ; standard purge scheme . . .
|
||
|
||
@PHSkip
|
||
Add.L D1,A0 ;Point to next block.
|
||
Move.L A0,PurgePtr(A6) ;Advance purge rover.
|
||
Cmp.L A2,A0 ;At end of purge zone?
|
||
BCS.S @PHLoop ;No, do next block.
|
||
|
||
@PHDone
|
||
BSR a24CompactHp ;Compact the heap.
|
||
|
||
MoveM.L (SP)+,D2/A1-A4 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
a32PurgeHeap ; 32 bit version of PurgeHeap
|
||
MoveM.L D2/A1-A4,-(SP) ;Save registers.
|
||
@PurgeScan Move.L BkLim(A6),A3 ;Last block in zone
|
||
LEA HeapData(A6),A0 ;First block in zone.
|
||
BTst #FNSelPurge,Flags(A6) ;Use non-selective purge?
|
||
BNE.S @PHPrgAll ;Br if so.
|
||
Move.L A0,A2 ;bPrg := first zone block ptr.
|
||
MoveQ #0,D2 ;sRgn := 0.
|
||
@PrgScanLoop
|
||
Move.L BlkSize32(A2),D1 ;get byte count <v1.1>
|
||
Move.L A2,A4 ;Current block ptr.
|
||
Add.L D1,A2 ;Next block ptr.
|
||
|
||
Tst.B TagBC32(A4) ;Is this block free?
|
||
Beq.S @PrgSFree ;Br if so (add to region)
|
||
Bpl.S @PrgSNRel ;Br if non-rel (start next region)
|
||
|
||
Tst.B MPtag32(A4) ;is block locked? <v1.1>
|
||
BMi.S @PrgSNRel ;Br if so (start next region) <v1.1>
|
||
BTst #Purge,MPtag32(A4) ;Unlocked, test purge flag. <v1.1>
|
||
|
||
BEq.S @PrgSEnd ;Not purgeable, don't purge.
|
||
Cmp.L PurgePtr(A6),A4 ;Past the purge rover yet?
|
||
BCS.S @PrgSAdv ;Br if not (advance purge start)
|
||
@PrgSFree Add.L D1,D2 ;Add to sRgn
|
||
Cmp.L D0,D2 ;Do we have enough?
|
||
BCS.S @PrgSEnd ;Br if not
|
||
BrA.S @PHLoop ;Purge purgeable blocks between
|
||
; A0 and A2, then compact . . .
|
||
@PrgSNRel MoveQ #0,D2 ;sRgn := 0. (next region)
|
||
@PrgSAdv Move.L A2,A0 ;Advance purge start ptr.
|
||
|
||
@PrgSEnd Cmp.L A3,A2 ;End of zone reached?
|
||
BCS.S @PrgScanLoop ;Loop if not
|
||
|
||
LEA HeapData(A6),A0
|
||
Cmp.L PurgePtr(A6),A0 ;Did rover start at heap start?
|
||
BEq.S @PHPrgAll ;Br if so.
|
||
Move.L A0,PurgePtr(A6) ;Otherwise, set the rover back
|
||
BrA.S @PurgeScan ;And scan again.
|
||
|
||
@PHPrgAll Move.L A3,A2 ;No luck. So purge all purgables.
|
||
|
||
; now that we've pre-scanned, it's time to do the actual purging; we purge all
|
||
; purgeable blocks from (A0) up to but not including (A2). We have to test for
|
||
; locked relocatables and non-relocatables because of the case in which we are
|
||
; purging all purgeables in the heap.
|
||
|
||
@PHLoop
|
||
Move.L Blksize32(A0),D1 ;get byte count <v1.1>
|
||
|
||
Tst.B TagBC32(A0) ;Is this block free?
|
||
Bpl.S @PHSkip ;Br if Free or Non-Rel
|
||
|
||
Move.L Handle32(A0),A1 ;Handle offset for rel. block.
|
||
Add.L A6,A1 ;Convert to true handle.
|
||
Tst.B MPtag32(A0) ;Test lock, purge flags byte. <v1.1>
|
||
BMi.S @PHSkip ;Locked, can't purge it. <v1.1>
|
||
BTst #Purge,MPtag32(A0) ;Unlocked, test purge flag. <v1.1>
|
||
BEq.S @PHSkip ;Not purgeable, don't purge.
|
||
|
||
BSR.S a32PurgeBlock ;Go ahead and purge this one.
|
||
Cmp.L D0,D1 ;Is sBlock >= s? check for
|
||
BCC.S @PHDone ; standard purge scheme . . .
|
||
|
||
@PHSkip
|
||
Add.L D1,A0 ;Point to next block.
|
||
Move.L A0,PurgePtr(A6) ;Advance purge rover.
|
||
Cmp.L A2,A0 ;At end of purge zone?
|
||
BCS.S @PHLoop ;No, do next block.
|
||
|
||
@PHDone
|
||
BSR a32CompactHp ;Compact the heap.
|
||
|
||
MoveM.L (SP)+,D2/A1-A4 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function TotePurgeables: [totFreeAndPurge, contigFreeAndPurge : LongInt]; <17Apr85>
|
||
; <17Apr85>
|
||
; Scan each region (between successive ptrs and locked relocatables) for the free <17Apr85>
|
||
; and purgeable space. Accumulate the total for the zone and the max region within <17Apr85>
|
||
; the zone. <17Apr85>
|
||
;
|
||
; Argument:
|
||
; A6: z: Zone to be totaled..
|
||
;
|
||
; Result:
|
||
; A0: maximum free plus purge space in any one region
|
||
; D0: total free plus purge space in zone
|
||
;
|
||
; Registers:
|
||
; D0: accumulate total free and purge
|
||
; D1: accumulate total free and purge by region
|
||
; D2: length of current block
|
||
; A0: save max region so far
|
||
; A1: ptr to current block
|
||
; A2: handle to current block, if relocatable
|
||
;
|
||
; Trashes D1-D2/A1-A2.
|
||
; Called By: PurgeSpace (outer-level routine)
|
||
|
||
a24TotePurgeables ; 24 bit version <17Apr85>
|
||
MoveQ #0,D0 ;init total
|
||
Move.L D0,D1 ;init region count
|
||
MoveA.L D0,A0 ;init max so far
|
||
LEA heapData(A6),A1 ;pt to first data block
|
||
@PMLoop
|
||
CmpA.L bkLim(A6),A1 ;Carry Clear if beyond end
|
||
BCC.S @PMExit ;...in which case exit loop
|
||
Move.L tagBC24(A1),D2
|
||
And.L Lo3Bytes,D2 ;isolate block size
|
||
Tst.B (A1) ;check tags nibble
|
||
BEq.S @PMGotSome ;Eq => free, so got some space
|
||
BPl.S @PMSandBar ;Pl => ptr, a sandbar
|
||
MoveA.L handle24(A1),A2 ;relative handle from beginning of zone
|
||
AddA.L A6,A2 ;true handle to block pointed to by A1
|
||
Tst.B (A2)
|
||
BMi.S @PMSandBar ;locked handle is like a pointer here
|
||
BTst #Purge,(A2)
|
||
BEq.S @PMLEnd ;Eq => slider, which doesn't affect totals
|
||
@PMGotSome
|
||
Add.L D2,D1 ;add block size into region total
|
||
@PMLEnd
|
||
AddA.L D2,A1 ;bump A1 to next block in zone
|
||
BrA.S @PMLoop ;and keep looking
|
||
|
||
; There are two ways to end a region: ptr/locked block and zone end. The following subroutine
|
||
; accommodates both needs. When branched to as PMSandBar it effects a BrA.S back to PMLend.
|
||
; When branched to as PMExit, it does the final totals and exits TotPurgeables!
|
||
@PMSandBar
|
||
PEA @PMLEnd ;we'll RtS to the loop end code
|
||
@PMExit
|
||
Add.L D1,D0 ;accumulate grand total by adding this region's space <2> kc.start
|
||
CmpA.L D1,A0 ;Carry Clear => max is still max!
|
||
BCC.S @0
|
||
MoveA.L D1,A0
|
||
|
||
@0 Cmpi.b #cpu68040,CPUFlag ; Are we on an 040 or greater?
|
||
Blt.s @1 ; No? Then no alignment.
|
||
Tst.l pVMGlobals ; VM running?
|
||
Bpl.s @1 ; Yea? Then no alignment.
|
||
|
||
Move.l A0,D1 ; Largest contig block.
|
||
AndI.W #$FFF0,D1 ; Line align result.
|
||
Move.l D1,A0 ; Set result. <2> kc.end
|
||
@1
|
||
MoveQ #0,D1 ;clear out the region total -- we're starting a new one
|
||
RtS
|
||
|
||
|
||
a32TotePurgeables ; 32 bit version <17Apr85>
|
||
MoveQ #0,D0 ;init total
|
||
Move.L D0,D1 ;init region count
|
||
MoveA.L D0,A0 ;init max so far
|
||
LEA heapData(A6),A1 ;pt to first data block
|
||
@PMLoop
|
||
CmpA.L bkLim(A6),A1 ;Carry Clear if beyond end
|
||
BCC.S @PMExit ;...in which case exit loop
|
||
Move.L BlkSize32(A1),D2 ;get block size <v1.1>
|
||
Tst.B (A1) ;check tags nibble
|
||
BEq.S @PMGotSome ;Eq => free, so got some space
|
||
BPl.S @PMSandBar ;Pl => ptr, a sandbar
|
||
Tst.B MPtag32(A1) ;check lock, purge flag <C883>
|
||
BMi.S @PMSandBar ;locked handle is like a pointer here <C883>
|
||
BTst #Purge,MPtag32(A1) ; <C883>
|
||
BEq.S @PMLEnd ;Eq => slider, which doesn't affect totals
|
||
@PMGotSome
|
||
Add.L D2,D1 ;add block size into region total
|
||
@PMLEnd
|
||
AddA.L D2,A1 ;bump A1 to next block in zone
|
||
BrA.S @PMLoop ;and keep looking
|
||
|
||
; There are two ways to end a region: ptr/locked block and zone end. The following subroutine
|
||
; accommodates both needs. When branched to as PMSandBar it effects a BrA.S back to PMLend.
|
||
; When branched to as PMExit, it does the final totals and exits TotPurgeables!
|
||
@PMSandBar
|
||
PEA @PMLEnd ;we'll RtS to the loop end code
|
||
@PMExit
|
||
Add.L D1,D0 ;accumulate grand total by adding this region's space <2> kc.start
|
||
CmpA.L D1,A0 ;Carry Clear => max is still max!
|
||
BCC.S @0
|
||
MoveA.L D1,A0
|
||
|
||
@0 Cmpi.b #cpu68040,CPUFlag ; Are we on an 040 or greater?
|
||
Blt.s @1 ; No? Then no alignment.
|
||
|
||
Move.l A0,D1 ; Largest contig block.
|
||
AndI.W #$FFF0,D1 ; Line align result.
|
||
Move.l D1,A0 ; Set result. <2> kc.end
|
||
@1
|
||
MoveQ #0,D1 ;clear out the region total -- we're starting a new one
|
||
RtS
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function CallGZProc(s: Size): Size;
|
||
;
|
||
; Calls the system GrowZone Function in spare1(Zone). ;<29jan85>
|
||
;
|
||
; Arguments:
|
||
; D0: s: Number of contiguous bytes needed.
|
||
; A6: z: Zone in which block will be made.
|
||
;
|
||
; Result:
|
||
; D2: dSize: Number of bytes added to zone by GrowZone Function.
|
||
;
|
||
; Registers:
|
||
; A1: prGZ: Address of GrowZone Function.
|
||
;
|
||
; Called By: BkCompactS
|
||
|
||
CallGZProc
|
||
Move.L spare1(A6),D2 ;system GrowZone function defined? <29jan85>
|
||
BEq.S CGZReturn ;No, return dSize of 0.
|
||
|
||
CGZCall
|
||
MoveM.L D0-D1/D3-D7/A0-A6,-(SP) ;Save registers.
|
||
|
||
Move.L spare1(A6),A1 ;Get system GrowZone Fun. address. <29jan85>
|
||
|
||
Clr.L -(SP) ;we're not hackers! (function result)
|
||
Move.L D0,-(SP) ;Push s as argument.
|
||
JSR (A1) ;Call GrowZone Function.
|
||
Move.L (SP)+,D2 ;Get GrowZone result.
|
||
|
||
MoveM.L (SP)+,D0-D1/D3-D7/A0-A6 ;Restore registers.
|
||
|
||
CGZReturn
|
||
RTS ;Return to caller.
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function BkCompactS(s: Size; tryGrw: Boolean):
|
||
; [sMax: Size; b: Block];
|
||
;
|
||
; Compacts the zone until room is made for a block s bytes long. If
|
||
; it is not possible to make enough room by compaction, the tryGrow
|
||
; flag is true, and the zone is the application zone, then the
|
||
; GrowZone procedure is called to make more space in the zone.
|
||
; BkCompactS returns a pointer to a block at least s bytes long,
|
||
; or Nil, if it is impossible to create room for one. sMax is
|
||
; returned with the size of the largest block found during
|
||
; compaction.
|
||
;
|
||
; Arguments:
|
||
; D0: s: Size of free block needed.
|
||
; D2: tryGrw: Indicates whether to try growing the zone.
|
||
; A6: z: Zone which might experience heap motion.
|
||
;
|
||
; Results:
|
||
; A0: b: Address of block s bytes long, or Nil.
|
||
; D1: sMax: Size of largest free block found.
|
||
;
|
||
; Registers:
|
||
; D1: sMax: Size of largest free block found.
|
||
; D2: dSize: Number of bytes added to zone by User's GrowZone proc.
|
||
;
|
||
; Called By: MaxMem,AllocBk
|
||
|
||
|
||
a24BkCompactS ; 24 bit version
|
||
MoveM.L D0/D2,-(SP) ;Save registers.
|
||
BSR a24CompactHp ;Compact the Heap.
|
||
Cmp.L D1,D0 ;Did we find enough space?
|
||
BLS.S @BCCDone ;Yes, return.
|
||
Cmp.L applZone,A6 ;Is this the application zone?
|
||
BNE.S @BCCPurge ;No, don't try to grow it.
|
||
Tst.L D2 ;May we grow the zone?
|
||
BEq.S @BCCPurge ;No, try purging the heap.
|
||
BSR a24GrowZone ;Grow the zone.
|
||
BSR a24CompactHp ;Compact the heap again.
|
||
Cmp.L D1,D0 ;Enough room for block?
|
||
BLS.S @BCCDone ;Yes, return.
|
||
@BCCPurge
|
||
BSR.S a24PurgeHeap ;Purge heap to make room.
|
||
Cmp.L D1,D0 ;Enough room for block?
|
||
BLS.S @BCCDone ;Yes, return.
|
||
Tst.L D2 ;Is tryGrw false?
|
||
BEq.S @BCCDone ;Yes, MaxMem must be calling.
|
||
@BCCCallGZ
|
||
BSR.S CallGZProc ;Call the Grow Zone procedure.
|
||
BSR a24CompactHp ;Compact the heap again.
|
||
Cmp.L D1,D0 ;Enough room for block?
|
||
BLS.S @BCCDone ;Yes, return.
|
||
Tst.L D2 ;Did Grow Zone add room last time?
|
||
BNE.S @BCCCallGZ ;Yes, call it again.
|
||
Sub.L A0,A0 ;No joy, fail return.
|
||
@BCCDone
|
||
Move.L A0,D2 ;Set Condition Codes.
|
||
MoveM.L (SP)+,D0/D2 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
a32BkCompactS ; 32 bit version
|
||
MoveM.L D0/D2,-(SP) ;Save registers.
|
||
BSR a32CompactHp ;Compact the Heap.
|
||
Cmp.L D1,D0 ;Did we find enough space?
|
||
BLS.S @BCCDone ;Yes, return.
|
||
Cmp.L applZone,A6 ;Is this the application zone?
|
||
BNE.S @BCCPurge ;No, don't try to grow it.
|
||
Tst.L D2 ;May we grow the zone?
|
||
BEq.S @BCCPurge ;No, try purging the heap.
|
||
BSR a32GrowZone ;Grow the zone.
|
||
BSR a32CompactHp ;Compact the heap again.
|
||
Cmp.L D1,D0 ;Enough room for block?
|
||
BLS.S @BCCDone ;Yes, return.
|
||
@BCCPurge
|
||
BSR.S a32PurgeHeap ;Purge heap to make room.
|
||
Cmp.L D1,D0 ;Enough room for block?
|
||
BLS.S @BCCDone ;Yes, return.
|
||
Tst.L D2 ;Is tryGrw false?
|
||
BEq.S @BCCDone ;Yes, MaxMem must be calling.
|
||
@BCCCallGZ
|
||
BSR.S CallGZProc ;Call the Grow Zone procedure.
|
||
BSR a32CompactHp ;Compact the heap again.
|
||
Cmp.L D1,D0 ;Enough room for block?
|
||
BLS.S @BCCDone ;Yes, return.
|
||
Tst.L D2 ;Did Grow Zone add room last time?
|
||
BNE.S @BCCCallGZ ;Yes, call it again.
|
||
Sub.L A0,A0 ;No joy, fail return.
|
||
@BCCDone
|
||
Move.L A0,D2 ;Set Condition Codes.
|
||
MoveM.L (SP)+,D0/D2 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function BFindS(s: Size): Block;
|
||
;
|
||
; Finds the next free block in the zone with size >= s. Searches
|
||
; through zone from the alloc rover, merging adjacent free blocks,
|
||
; until the entire zone has been searched or a free block large enough
|
||
; to hold s bytes is found. Returns Nil if no free block large enough
|
||
; can be found.
|
||
; Changed to check A1 against bkLim(A6) at BFSLoop, rather than after check for free. <16Apr85>
|
||
;
|
||
; Arguments:
|
||
; D0: s: size of free block needed.
|
||
; A6: z: zone to be searched for the free block.
|
||
;
|
||
; Result:
|
||
; A0: b: points to block >= s bytes long, or Nil if
|
||
; none big enough found.
|
||
;
|
||
; Registers:
|
||
; D0: s: size of free block needed.
|
||
; D1: sCur: size of current block.
|
||
; D2: mBC: mask for byte count field of header only.
|
||
; A0: bSrch: Address of block after bMerge.
|
||
; A1: bMerge: Address of free block used for merges.
|
||
; A2: APtr: Address of roving allocation pointer.
|
||
;
|
||
; Called By: AllocBk
|
||
|
||
a24BFindS ; 24 bit version
|
||
MoveM.L D1-D2/A1-A2,-(SP) ;Save registers.
|
||
Move.L MaskBC,D2 ;We will need this soon.
|
||
LEA AllocPtr(A6),A2
|
||
BTst #FNoRvrAlloc,Flags(A6) ;Use rover?
|
||
BEq.S @BFindSS ;Br if so.
|
||
Clr.L (A2) ;Invalidate it otherwise.
|
||
@BFindSS Move.L (A2),D1 ;Is rover valid?
|
||
Move.L D1,A1
|
||
BNE.S @BFSLoop ;Br if so.
|
||
LEA HeapData(A6),A1 ;Start from beginning if not.
|
||
@BFSLoop ;Skip allocated blocks.
|
||
Cmp.L BkLim(A6),A1 ;Past or at limit block? <16Apr85>
|
||
BCC.S @BFSFail ;Br if so. <16Apr85>
|
||
Move.L TagBC24(A1),D1 ;Get byte count.
|
||
Tst.B TagBC24(A1) ;Is this block free?
|
||
BEq.S @BFSFLoop ;Yes, start building onto it. <16Apr85>
|
||
@BFSNext
|
||
And.L D2,D1 ;Extract only byte count.
|
||
Add.L D1,A1 ;Address of next block.
|
||
BrA.S @BFSLoop ;Look for free block.
|
||
|
||
; This loop used to have a header that checked agains bkLim(A6). That check is at BFSLoop. <16Apr85>
|
||
@BFSFLoop
|
||
Move.L A1,A0 ;Address of current block.
|
||
Add.L D1,A0 ;Point to next block.
|
||
Tst.B TagBC24(A0) ;Is next block free?
|
||
BNE.S @1 ;Skip if not free.
|
||
Cmp.L BkLim(A6),A0 ;Past limit block?
|
||
BCC.S @1 ;Yes, skip.
|
||
Add.L TagBC24(A0),D1 ;Merge next with current block.
|
||
Move.L D1,TagBC24(A1) ;Length of new block at bMerge.
|
||
BrA.S @BFSFLoop ;And loop, to do more blocks.
|
||
@1
|
||
Cmp.L D0,D1 ;Free bytes >= s?
|
||
BCS.S @BFSNext ;No, skip.
|
||
Move.L A1,A0 ;Else return bMerge.
|
||
BrA.S @BFSDone ;Success return.
|
||
@BFSFail
|
||
Tst.L (A2) ;Did we start at the beginning?
|
||
BEq.S @2 ;Br if so (searched entire heap)
|
||
Clr.L (A2) ;Otherwise, go again.
|
||
BrA.S @BFindSS
|
||
@2 Sub.L A0,A0 ;Return Nil.
|
||
@BFSDone
|
||
Move.L A0,(A2) ;Set condition codes and
|
||
; update allocation rover.
|
||
MoveM.L (SP)+,D1-D2/A1-A2 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
; ---- 32 bit version ----
|
||
a32BFindS ; 32 bit version
|
||
MoveM.L D1-D2/A1-A2,-(SP) ;Save registers.
|
||
Move.L MaskBC,D2 ;We will need this soon.
|
||
LEA AllocPtr(A6),A2
|
||
BTst #FNoRvrAlloc,Flags(A6) ;Use rover?
|
||
BEq.S @BFindSS ;Br if so.
|
||
Clr.L (A2) ;Invalidate it otherwise.
|
||
@BFindSS Move.L (A2),D1 ;Is rover valid?
|
||
Move.L D1,A1
|
||
BNE.S @BFSLoop ;Br if so.
|
||
LEA HeapData(A6),A1 ;Start from beginning if not.
|
||
@BFSLoop ;Skip allocated blocks.
|
||
Cmp.L BkLim(A6),A1 ;Past or at limit block? <16Apr85>
|
||
BCC.S @BFSFail ;Br if so. <16Apr85>
|
||
Move.L BlkSize32(A1),D1 ;get byte count. <v1.1>
|
||
Tst.B TagBC32(A1) ;Is this block free?
|
||
BEq.S @BFSFLoop ;Yes, start building onto it. <16Apr85>
|
||
@BFSNext
|
||
Add.L D1,A1 ;Address of next block.
|
||
BrA.S @BFSLoop ;Look for free block.
|
||
|
||
; This loop used to have a header that checked agains bkLim(A6). That check is at BFSLoop. <16Apr85>
|
||
@BFSFLoop
|
||
Move.L A1,A0 ;Address of current block.
|
||
Add.L D1,A0 ;Point to next block.
|
||
Tst.B TagBC32(A0) ;Is next block free?
|
||
BNE.S @1 ;Skip if not free.
|
||
Cmp.L BkLim(A6),A0 ;Past limit block?
|
||
BCC.S @1 ;Yes, skip.
|
||
Add.L BlkSize32(A0),D1 ;Merge next with current block. <v1.1>
|
||
Move.L D1,BlkSize32(A1) ;Length of new block at bMerge. <v1.1>
|
||
Clr.L TagBC32(A1) ;set free block <C883><25Oct87>
|
||
BrA.S @BFSFLoop ;And loop, to do more blocks.
|
||
@1
|
||
Cmp.L D0,D1 ;Free bytes >= s?
|
||
BCS.S @BFSNext ;No, skip.
|
||
Move.L A1,A0 ;Else return bMerge.
|
||
BrA.S @BFSDone ;Success return.
|
||
@BFSFail
|
||
Tst.L (A2) ;Did we start at the beginning?
|
||
BEq.S @2 ;Br if so (searched entire heap)
|
||
Clr.L (A2) ;Otherwise, go again.
|
||
BrA.S @BFindSS
|
||
@2 Sub.L A0,A0 ;Return Nil.
|
||
@BFSDone
|
||
Move.L A0,(A2) ;Set condition codes and
|
||
; update allocation rover.
|
||
MoveM.L (SP)+,D1-D2/A1-A2 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function AllocBk(h: Handle; s: Size): Ptr;
|
||
;
|
||
; Finds and allocates a block of size s. If h is not Nil, then
|
||
; the block will be a relocatable block, and h^ will be filled in
|
||
; to point to the allocated block. If s is less than minFree, a
|
||
; block minFree long will be allocated, and the offset field will
|
||
; be correctly filled in.
|
||
;
|
||
; Arguments:
|
||
; D0: s: size of block desired.
|
||
; A1: h: handle for block, or Nil.
|
||
;
|
||
; Result:
|
||
; A0: p: points to new block, or Nil if no room for block.
|
||
;
|
||
; Registers:
|
||
; D1: tyBk: Block type for MakeBk.
|
||
; D2: tryGrw: Allows heap to grow in order to make space.
|
||
; D3: endPck: True => Put block at end of free space.
|
||
; D4: s: Size of block desired.
|
||
; D5: Zone pointer (nrel) or handle offset (rel)
|
||
; A1: relH: Relative handle.
|
||
;
|
||
; Called By: HMakeMoreMasters,RelocRel
|
||
; NewPtr,NwHandle,ReallocHandle(Heap)
|
||
|
||
a24AllocBK ; 24 bit version of AllocBk
|
||
MoveM.L D0-D5,-(SP) ;Save Registers.
|
||
Move.L D0,D4 ;Save size.
|
||
BSR a24ActualS ;Returns real sAct.
|
||
|
||
BSR.S a24BFindS ;Find a free block sAct long.
|
||
BNE.S @ABFound ;Found one.
|
||
|
||
MoveQ #-1,D2 ;No luck, allow heap to grow.
|
||
BSR.S a24BkCompactS ;Compact the heap.
|
||
BNE.S @ABFound ;Space found, continue.
|
||
|
||
Sub.L A0,A0 ;Nil result => failed.
|
||
BrA.S @ABExit ;Use common exit path.
|
||
@ABFound
|
||
Move.L D0,D2 ;Copy sAct
|
||
Move.L TagBC24(A0),D0 ;Get block header
|
||
; And.L MaskBC,D0 ;Extract only byte count.
|
||
Move.L A1,D5 ;Make Relocatable block?
|
||
BEq.S @ABNRel ;No, take Non-Rel path.
|
||
|
||
Sub.L A6,D5 ;Make D5 a handle offset.
|
||
MoveQ #tybkRel,D1 ;Set up Rel block type.
|
||
MoveQ #-1,D3 ;Set endPck true.
|
||
|
||
BrA.S @ABMake ;Go make the block.
|
||
@ABNRel
|
||
Move.L A6,D5 ;Points to zone.
|
||
MoveQ #tybkNRel,D1 ;Set up Non-Rel block type.
|
||
MoveQ #0,D3 ;Set endPck false.
|
||
@ABMake
|
||
BSR a24MakeBk ;Split the free space.
|
||
|
||
Move.L D5,Handle24(A0) ;Save handle offset or
|
||
; zone pointer in block.
|
||
Move.L D4,D0 ;Desired size.
|
||
BSR.S a24SetLogSize ;Set the logical size.
|
||
|
||
AddQ.L #BlkData24,A0 ;Point to data portion.
|
||
Move.L A1,D5 ;Nrel block?
|
||
BEq.S @ABExit ;Yes, no MP.
|
||
Move.L A0,(A1) ;Store block pointer in MP.
|
||
@ABExit
|
||
Move.L A0,D0 ;Set condition codes.
|
||
MoveM.L (SP)+,D0-D5 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
a32AllocBK ; 32 bit version of AllocBk
|
||
MoveM.L D0-D5,-(SP) ;Save Registers.
|
||
Move.L D0,D4 ;Save size.
|
||
BSR a32ActualS ;Returns real sAct.
|
||
|
||
BSR.S a32BFindS ;Find a free block sAct long.
|
||
BNE.S @ABFound ;Found one.
|
||
|
||
MoveQ #-1,D2 ;No luck, allow heap to grow.
|
||
BSR.S a32BkCompactS ;Compact the heap.
|
||
BNE.S @ABFound ;Space found, continue.
|
||
|
||
Sub.L A0,A0 ;Nil result => failed.
|
||
BrA.S @ABExit ;Use common exit path.
|
||
@ABFound
|
||
Move.L D0,D2 ;Copy sAct
|
||
Move.L BlkSize32(A0),D0 ;Get block size <v1.1>
|
||
; And.L MaskBC,D0 ;Extract only byte count.
|
||
Move.L A1,D5 ;Make Relocatable block?
|
||
BEq.S @ABNRel ;No, take Non-Rel path.
|
||
|
||
Sub.L A6,D5 ;Make D5 a handle offset.
|
||
MoveQ #tybkRel,D1 ;Set up Rel block type.
|
||
MoveQ #-1,D3 ;Set endPck true.
|
||
|
||
BrA.S @ABMake ;Go make the block.
|
||
@ABNRel
|
||
Move.L A6,D5 ;Points to zone.
|
||
MoveQ #tybkNRel,D1 ;Set up Non-Rel block type.
|
||
MoveQ #0,D3 ;Set endPck false.
|
||
@ABMake
|
||
BSR a32MakeBk ;Split the free space.
|
||
|
||
Move.L D5,Handle32(A0) ;Save handle offset or
|
||
; zone pointer in block.
|
||
Move.L D4,D0 ;Desired size.
|
||
BSR.S a32SetLogSize ;Set the logical size.
|
||
|
||
Add.L #BlkData32,A0 ;Point to data portion.
|
||
Move.L A1,D5 ;Nrel block?
|
||
BEq.S @ABExit ;Yes, no MP.
|
||
Move.L A0,(A1) ;Store block pointer in MP.
|
||
@ABExit
|
||
Move.L A0,D0 ;Set condition codes.
|
||
MoveM.L (SP)+,D0-D5 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Procedure SetLogSize(b: Block; s: Size);
|
||
;
|
||
; Sets the logical size of block b to s. Invokes deep trouble manager
|
||
; if trying to set the logical size of the block too small (more than
|
||
; 23 bytes shorter than physical size). The logical size is always
|
||
; at least 8 bytes less than the physical size.
|
||
;
|
||
; Arguments:
|
||
; A0: b: points to block header of block whose logical
|
||
; size will be set.
|
||
; D0: s: logical size for block b.
|
||
;
|
||
; Result:
|
||
; None.
|
||
;
|
||
; Registers:
|
||
; A0: b: block whose logical size is being set.
|
||
; D1: s: physical size.
|
||
; D1: s': adjusted physical size.
|
||
; D1: dSize: delta size between adjusted physical and logical sizes.
|
||
;
|
||
; Called By: AllocBk,SetSize
|
||
|
||
a24SetLogSize ; 24 bit version of SetLogSize
|
||
Move.L D1,-(SP) ;Save register.
|
||
Move.L TagBC24(A0),D1 ;Get block header.
|
||
And.L MaskBC,D1 ;Strip to byte count only.
|
||
SubQ.L #BlkData24,D1 ;Adjust to rough logical size.
|
||
Sub.L D0,D1 ;Subtract logical size desired.
|
||
And.B #$F,D1 ;Mask to triply insure range.
|
||
And.B #$C0,TagBC24(A0) ;Clear offset field in header.
|
||
Or.B D1,TagBC24(A0) ;Merge in new offset.
|
||
Move.L (SP)+,D1 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
a32SetLogSize ; 32 bit version of SetLogSize
|
||
Move.L D1,-(SP) ;Save register.
|
||
Move.L BlkSize32(A0),D1 ;Get byte count. <v1.1>
|
||
Sub.L #BlkData32,D1 ;Adjust to rough logical size. <v1.1>
|
||
Sub.L D0,D1 ;Subtract logical size desired. <v1.1>
|
||
Move.B D1,SizeCor32(A0) ;set size correction <v1.1>
|
||
Move.L (SP)+,D1 ;Rstore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function MakeBk(Var bk: Block; s: Size; ty: TyBk; sFree: Size;
|
||
; endPck: Boolean): Block;
|
||
;
|
||
; Makes a block of type ty and length s in empty space sFree long
|
||
; pointed to by b. That is, it splits free space sFree long at
|
||
; b into a free block (sFree-s) long and an allocated block s long.
|
||
; Where (sFree-s) is too small, only one block is made.
|
||
; Upon return, b points to the allocated block.
|
||
; The left-over space is returned as a free block. If endPack is
|
||
; true, and bit FRelAtEnd of the zone flags byte is non-zero,
|
||
; the block is packed against the high end of the empty space.
|
||
;
|
||
; Arguments:
|
||
; A0: b: free block from which new block is to be made.
|
||
; A6: z: zone in which block is being made.
|
||
; D0: sFree: number of bytes in current free block.
|
||
; D1: ty: Block type (1 = Non-Rel; 2 = Rel).
|
||
; D2: s: number of bytes needed.
|
||
; D3: endPck: boolean (t=>pack at end of free block)
|
||
;
|
||
; Result:
|
||
; A0: b: points to newly made block.
|
||
;
|
||
; Registers:
|
||
; A0: b: points to block being split.
|
||
; A0: bFree: points to block which will be freed.
|
||
; A1: b': copy of pointer to block being split.
|
||
; A1: b: pointer to new block being split.
|
||
; D0: sFree: number of bytes in free block.
|
||
; D0: sRem: physical size of remaining free block.
|
||
; D1: ty: Block type (1 = Non-Rel; 2 = Rel).
|
||
; D1: tag: Block tag.
|
||
; D2: s: physical size.
|
||
; D3: endPck: boolean (t=>pack at end of free block)
|
||
; D4: sFree': copy of number of bytes in free block.
|
||
;
|
||
; Called By: AllocBk
|
||
|
||
a24MakeBK ; 24 bit version
|
||
MoveM.L D0-D2/D4/A1,-(SP) ;Save registers.
|
||
Move.L D0,D4 ;Copy sFree.
|
||
Sub.L D2,D0 ;D0 := sFree-s (= bytes to reclaim).
|
||
Move.L A0,A1 ;Points to free block.
|
||
Cmp.L #MinFree24,D0 ;Enough to reclaim? <v1.2>
|
||
BCS.S @MBUseAll ;No, skip.
|
||
Tst.W D3 ;Make block at end of free?
|
||
BEq.S @1 ;No, skip.
|
||
Tst.B Flags(A6) ;Also check FRelAtEnd of flags
|
||
BPl.S @1 ; for non-zero . . .
|
||
Add.L D0,A1 ;Offset by reclaim bytes.
|
||
BrA.S @MBFree ;Go make free block.
|
||
@1
|
||
Add.L D2,A0 ;Place free block at end (at b + s).
|
||
@MBFree
|
||
BSR.S a24MakeBkF ;Byte count in D0.
|
||
BrA.S @MBDone ;Create allocated block.
|
||
@MBUseAll
|
||
Move.L D4,D2 ;s := sFree (Use all of the block).
|
||
@MBDone
|
||
Move.L D2,D0 ;s = size of block.
|
||
; Neg.L D0 ;Decrease zone free space.
|
||
; BSR AdjustFree ;Adjust zone free space by D0.
|
||
BSR SubtractFree ;Adjust zone free space by D0. <v1.7>.
|
||
Move.L A1,A0 ;Move b pointer to result reg.
|
||
RoR.L #2,D1 ;Move type to tag bits.
|
||
Add.L D2,D1 ;And add in block length.
|
||
Move.L D1,TagBC24(A0) ;Set up block header.
|
||
MoveM.L (SP)+,D0-D2/D4/A1 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
a32MakeBK ; 32 bit version
|
||
MoveM.L D0-D2/D4/A1,-(SP) ;Save registers.
|
||
Move.L D0,D4 ;Copy sFree.
|
||
Sub.L D2,D0 ;D0 := sFree-s (= bytes to reclaim).
|
||
Move.L A0,A1 ;Points to free block.
|
||
Cmp.L #MinFree32,D0 ;Enough to reclaim? <v1.2>
|
||
BCS.S @MBUseAll ;No, skip.
|
||
Tst.W D3 ;Make block at end of free?
|
||
BEq.S @1 ;No, skip.
|
||
Tst.B Flags(A6) ;Also check FRelAtEnd of flags
|
||
BPl.S @1 ; for non-zero . . .
|
||
Add.L D0,A1 ;Offset by reclaim bytes.
|
||
BrA.S @MBFree ;Go make free block.
|
||
@1
|
||
Add.L D2,A0 ;Place free block at end (at b + s).
|
||
@MBFree
|
||
BSR.S a32MakeBkF ;Byte count in D0.
|
||
BrA.S @MBDone ;Create allocated block.
|
||
@MBUseAll
|
||
Move.L D4,D2 ;s := sFree (Use all of the block).
|
||
@MBDone
|
||
Move.L D2,D0 ;s = size of block.
|
||
; Neg.L D0 ;Decrease zone free space.
|
||
; BSR AdjustFree ;Adjust zone free space by D0.
|
||
BSR SubtractFree ;Adjust zone free space by D0. <v1.7>
|
||
Move.L A1,A0 ;Move b pointer to result reg.
|
||
RoR.L #2,D1 ;Move type to tag bits.
|
||
Move.L D2,BlkSize32(A0) ;set block length <v1.1>
|
||
Move.L D1,TagBC32(A0) ;Set up block header.
|
||
MoveM.L (SP)+,D0-D2/D4/A1 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Procedure HBlockMove;
|
||
;
|
||
; Calls OS BlockMove to move stuff around.
|
||
;
|
||
; Arguments:
|
||
; D0: s: Number of bytes to be moved.
|
||
; A0: pSrc: points to source block.
|
||
; A1: pDst: points to destination block.
|
||
;
|
||
; Result:
|
||
; None.
|
||
;
|
||
; Registers:
|
||
; None.
|
||
;
|
||
; Called By: CompactHp,RelocRel
|
||
;
|
||
|
||
HBlockMove
|
||
MoveM.L D0-D2/A0-A2,-(SP) ;Save registers
|
||
bclr #noQueueBit,d1 ;Clear bit so we flush the cache <LW4>
|
||
MOVE.L JBlockMove,A2
|
||
JSR (A2)
|
||
MoveM.L (SP)+,D0-D2/A0-A2 ;Restore register.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function CompactHp(s: Size): [bFree: Block; sMax: Size];
|
||
;
|
||
; Compacts heap by moving relocatable blocks downwards until a
|
||
; contiguous free region at least s bytes long is found or until
|
||
; the end of the heap is reached. Returns a pointer to the free
|
||
; block, or Nil if no free block large enough was found. Also
|
||
; returns size of largest free block found so far.
|
||
; Change start code to accommodate (unlikely) case that first block in zone <27Apr85>
|
||
; is free. Used to just skip over initial MP block.
|
||
;
|
||
; Called by BkCompactS: 1) initially
|
||
; 2) after growing zone
|
||
; 3) after purging (actually by PurgeHeap)
|
||
; 4) in loop, each time after calling growzone proc
|
||
;
|
||
; Arguments:
|
||
; D0: s: Amount of space needed by caller.
|
||
; A6: z: Zone to be purged.
|
||
;
|
||
; Result:
|
||
; A0: bFree: points to available free space, or Nil.
|
||
; D1: sMax: size of largest free block found in search (even if
|
||
; A0 is nil).
|
||
;
|
||
; Registers:
|
||
; D0: sThis: Physical size of current block.
|
||
; D1: sMax: Size to date of largest free block found.
|
||
; D2: sFree: Cumulative size of this free block.
|
||
; D3: s: Amount of space needed by caller.
|
||
; D4: t: Temporary holds flags byte of Master Pointer.
|
||
; D5: fScan: Scan flag.
|
||
; A0: bSrc: Source address for compacting moves.
|
||
; A1: bDst: Destination address for compacting moves.
|
||
; A2: bScan: Block scan last started from.
|
||
; A3: h: Handle for relocatable block being moved.
|
||
; A4: pNew: New Pointer for relocatable block being moved.
|
||
;
|
||
; Called By: CompactMem,BkCompactS,PurgeHeap
|
||
|
||
a24CompactHp ; 24 bit version of CompactHp
|
||
MoveM.L D0/D2-D5/A1-A4,-(SP) ;Save registers.
|
||
Move.L D0,D3 ;Amount of space needed.
|
||
MoveQ #0,D1 ;sMax := 0.
|
||
LEA HeapData(A6),A0 ;bDst := first block in zone.
|
||
BrA.S @CHStart ;...just in case first block is free <27Apr85>
|
||
|
||
@CHNextRgn ;Check each region.
|
||
@CHSeekFree
|
||
Move.L TagBC24(A0),D4 ;Block header.
|
||
And.L MaskBC,D4 ;Byte count only.
|
||
Add.L D4,A0 ;Point to next block.
|
||
Cmp.L BkLim(A6),A0 ;At End of Zone?
|
||
BCC.S @CHFndFree ;Yes, quit.
|
||
@CHStart ;entry point to grand loop <27Apr85>
|
||
Tst.B TagBC24(A0) ;Is this block free?
|
||
BNE.S @CHSeekFree ;No, try next one.
|
||
@CHFndFree
|
||
BTst #FNSelCompct,Flags(A6) ;use non-selective compact?
|
||
SEq D5 ;fScan := true if not.
|
||
Move.L A0,A2 ;Remember region start
|
||
|
||
@CHNR2 Move.L A0,A1 ;bDst := bSrc.
|
||
MoveQ #0,D2 ;sFree := 0.
|
||
@CHNextBlock ;Compact each block in region.
|
||
Cmp.L BkLim(A6),A0 ;Done with all blocks in zone ?
|
||
BCC.S @CHRtsFail ;Yes, Fail return.
|
||
|
||
Move.L TagBC24(A0),D0 ;Get block header.
|
||
And.L MaskBC,D0 ;Extract byte count.
|
||
Tst.B TagBC24(A0) ;What kind of block here?
|
||
BEq.S @CHFreeBlock ;Free Block.
|
||
BPl.S @CHNextFree ;Non-Relocatable Block.
|
||
;Process relocatable block.
|
||
Move.L Handle24(A0),A3 ;Handle offset.
|
||
Add.L A6,A3 ;Convert to handle reference.
|
||
Tst.B (A3) ;Is block locked?
|
||
BMi.S @CHNextFree ;Yes, don't move it.
|
||
|
||
Tst.B D5 ;Scanning?
|
||
BNE.S @CHNextRel ;Then don't move any blocks.
|
||
|
||
LEA BlkData24(A1),A4 ;Point to bDst data.
|
||
Move.B (A3),D4 ;Save old purge flag.
|
||
Move.L A4,(A3) ;Update master pointer.
|
||
Move.B D4,(A3) ;Restore purge flag.
|
||
|
||
BSR.S HBlockMove ;Move block from bSrc to bDst.
|
||
Add.L D0,A1 ;Update bDst.
|
||
BrA.S @CHNextRel ;Do next block.
|
||
@CHFreeBlock ;Process Free block.
|
||
Add.L D0,D2 ;Update sFree.
|
||
|
||
Move.L A1,A3 ;In case we're done!
|
||
Cmp.L D3,D2 ;sFree >= s?
|
||
BCS.S @CHNextRel ;br if we haven't found enough.
|
||
Tst.B D5 ;were we scanning?
|
||
BEq.S @CHRts ;Br if not (we're done).
|
||
Clr.B D5 ;Do it 4 real this time . . .
|
||
Move.L A2,A0 ;Reset to scan start.
|
||
BrA.S @CHNR2 ;And do it 4 real this time.
|
||
@CHNextRel
|
||
Add.L D0,A0 ;Else update bSrc.
|
||
BrA.S @CHNextBlock ;Do next block.
|
||
@CHNextFree ;We hit a sandbar.
|
||
BSR a24MakeFree ;Make a Free block.
|
||
BrA.S @CHNextRgn ;Do next region.
|
||
@CHRtsFail
|
||
Sub.L A3,A3 ;Return Nil if not found.
|
||
@CHRts
|
||
BSR a24MakeFree ;Free up last block.
|
||
Move.L A3,A0 ;Return pointer to free space.
|
||
Move.L A0,AllocPtr(A6) ;Set rover here.
|
||
MoveM.L (SP)+,D0/D2-D5/A1-A4 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
;---- 32 bit version of compactHp
|
||
|
||
a32CompactHp ; 32 bit version of CompactHp
|
||
MoveM.L D0/D2-D5/A1-A4,-(SP) ;Save registers.
|
||
Move.L D0,D3 ;Amount of space needed.
|
||
MoveQ #0,D1 ;sMax := 0.
|
||
LEA HeapData(A6),A0 ;bDst := first block in zone.
|
||
BrA.S @CHStart ;...just in case first block is free <27Apr85>
|
||
|
||
@CHNextRgn ;Check each region.
|
||
@CHSeekFree
|
||
Move.L BlkSize32(A0),D4 ;get byte count <v1.1>
|
||
Add.L D4,A0 ;Point to next block.
|
||
Cmp.L BkLim(A6),A0 ;At End of Zone?
|
||
BCC.S @CHFndFree ;Yes, quit.
|
||
@CHStart ;entry point to grand loop <27Apr85>
|
||
Tst.B TagBC32(A0) ;Is this block free?
|
||
BNE.S @CHSeekFree ;No, try next one.
|
||
@CHFndFree
|
||
BTst #FNSelCompct,Flags(A6) ;use non-selective compact?
|
||
SEq D5 ;fScan := true if not.
|
||
Move.L A0,A2 ;Remember region start
|
||
|
||
@CHNR2 Move.L A0,A1 ;bDst := bSrc.
|
||
MoveQ #0,D2 ;sFree := 0.
|
||
@CHNextBlock ;Compact each block in region.
|
||
Cmp.L BkLim(A6),A0 ;Done with all blocks in zone ?
|
||
BCC.S @CHRtsFail ;Yes, Fail return.
|
||
|
||
Move.L BlkSize32(A0),D0 ;Get byte count. <v1.1>
|
||
Tst.B TagBC32(A0) ;What kind of block here?
|
||
BEq.S @CHFreeBlock ;Free Block.
|
||
BPl.S @CHNextFree ;Non-Relocatable Block.
|
||
;Process relocatable block.
|
||
Move.L Handle32(A0),A3 ;Handle offset.
|
||
Add.L A6,A3 ;Convert to handle reference.
|
||
Tst.B MPtag32(A0) ;is block locked? <v1.1>
|
||
BMi.S @CHNextFree ;Yes, don't move it.
|
||
|
||
Tst.B D5 ;Scanning?
|
||
BNE.S @CHNextRel ;Then don't move any blocks.
|
||
|
||
LEA BlkData32(A1),A4 ;Point to bDst data.
|
||
Move.L A4,(A3) ;Update master pointer. <v1.1>
|
||
|
||
BSR.S HBlockMove ;Move block from bSrc to bDst.
|
||
Add.L D0,A1 ;Update bDst.
|
||
BrA.S @CHNextRel ;Do next block.
|
||
@CHFreeBlock ;Process Free block.
|
||
Add.L D0,D2 ;Update sFree.
|
||
|
||
Move.L A1,A3 ;In case we're done!
|
||
Cmp.L D3,D2 ;sFree >= s?
|
||
BCS.S @CHNextRel ;br if we haven't found enough.
|
||
Tst.B D5 ;were we scanning?
|
||
BEq.S @CHRts ;Br if not (we're done).
|
||
Clr.B D5 ;Do it 4 real this time . . .
|
||
Move.L A2,A0 ;Reset to scan start.
|
||
BrA.S @CHNR2 ;And do it 4 real this time.
|
||
@CHNextRel
|
||
Add.L D0,A0 ;Else update bSrc.
|
||
BrA.S @CHNextBlock ;Do next block.
|
||
@CHNextFree ;We hit a sandbar.
|
||
BSR a32MakeFree ;Make a Free block.
|
||
BrA.S @CHNextRgn ;Do next region.
|
||
@CHRtsFail
|
||
Sub.L A3,A3 ;Return Nil if not found.
|
||
@CHRts
|
||
BSR.S a32MakeFree ;Free up last block.
|
||
Move.L A3,A0 ;Return pointer to free space.
|
||
Move.L A0,AllocPtr(A6) ;Set rover here.
|
||
MoveM.L (SP)+,D0/D2-D5/A1-A4 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
a24MakeFree
|
||
Tst.L D2 ;sFree = 0?
|
||
BEq.S @2 ;Yes, do nothing here.
|
||
Tst.B D5 ;Scanning only?
|
||
BNE.S @1 ;Br if so.
|
||
Move.L D2,TagBC24(A1)
|
||
@1 Cmp.L D2,D1 ;sMax >= sFree?
|
||
BCC.S @2 ;Yes, leave sMax untouched.
|
||
Move.L D2,D1 ;sMax := sFree.
|
||
@2 RTS ;Return to caller.
|
||
|
||
|
||
a32MakeFree
|
||
Tst.L D2 ;sFree = 0?
|
||
BEq.S @2 ;Yes, do nothing here.
|
||
Tst.B D5 ;Scanning only?
|
||
BNE.S @1 ;Br if so.
|
||
Clr.L TagBC32(A1) ;free block <v1.1>
|
||
Move.L D2,BlkSize32(A1) ;set block size <v1.1>
|
||
@1 Cmp.L D2,D1 ;sMax >= sFree?
|
||
BCC.S @2 ;Yes, leave sMax untouched.
|
||
Move.L D2,D1 ;sMax := sFree.
|
||
@2 RTS ;Return to caller.
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function MaxLimit(adrLim: Adr): Adr;
|
||
;
|
||
; Returns a safe value for growing applZone, dynamically based on the
|
||
; current stack pointer. Both values are forced to be multiples of 4. <C251>
|
||
; ToMaxLimit: MIN( (BufPtr-DefltStack), (SP-MinStack) )
|
||
; MaxLimit: MIN( (proposed limit), (SP-MinStack) )
|
||
; When SP < bkLim(SysZone), as is the case when booting and the stack is in a nonstandard <C587>
|
||
; place, then the value returned is just the first of the two arguments to MIN() above. <C587>
|
||
;
|
||
; Argument:
|
||
; D2: adrLim: Proposed Appl Limit value.
|
||
;
|
||
; Result:
|
||
; D1: adrLim: New Appl Limit value.
|
||
; D2: BufPtr-DefltStack
|
||
;
|
||
; Register:
|
||
; D1: adrCei: Temporary limit value ceiling.
|
||
;
|
||
; Called By: SetApplBase(ToMaxLimit),InitApplZone(ToMaxLimit),GrowZone
|
||
;
|
||
|
||
ToMaxLimit Move.L BufPtr,D2 ;stack bottom, beginning of time
|
||
Sub.L DefltStack,D2 ;useful static value
|
||
a24MaxLimit
|
||
AndI.W #$FFFC,D2 ; D2 := 4X <2> kc.start
|
||
Cmpi.b #cpu68040,CPUFlag ; Are we on an 040 or greater?
|
||
Blt.s @0 ; No? Then long align is good enough.
|
||
Tst.l pVMGlobals ; VM running? <T7>
|
||
Bpl.s @0 ; Yea? Then just long align.<T7>
|
||
Andi.w #$FFF0,D2 ; No? Then line align.
|
||
|
||
@0 Move.L SP,D1 ;D1 := SP, possibly with high bits set
|
||
And.L MaskPtr,D1 ;D1 := SP, stripped
|
||
Sub.L MinStack,D1 ;Allow some stack margin.
|
||
AndI.W #$FFFC,D1 ;D1 := 4X
|
||
Cmpi.b #cpu68040,CPUFlag ; Are we on an 040 or greater?
|
||
Blt.s @1 ; No? Then long align is good enough.
|
||
Tst.l pVMGlobals ; VM running? <T7>
|
||
Bpl.s @1 ; Yea? Then just long align.<T7>
|
||
Andi.w #$FFF0,D1 ; No? Then line align.
|
||
|
||
@1 Cmp.L D2,D1 ;adrCei < adrLim?
|
||
BCS.S @2 ;Yes, return adrCei as adrLim.
|
||
@skipStack ;
|
||
Move.L D2,D1 ;No, return adrLim as adrLim.
|
||
@2
|
||
RTS ;Return to caller.
|
||
|
||
a32MaxLimit
|
||
AndI.W #$FFFC,D2 ; D2 := 4X
|
||
Cmpi.b #cpu68040,CPUFlag ; Are we on an 040 or greater?
|
||
Blt.s @0 ; No? Then long align is good enough.
|
||
Andi.w #$FFF0,D2 ; Yes? Then line align.
|
||
|
||
@0 Move.L SP,D1 ;D1 := SP, possibly with high bits set
|
||
Sub.L MinStack,D1 ;Allow some stack margin.
|
||
AndI.W #$FFFC,D1 ;D1 := 4X
|
||
Cmpi.b #cpu68040,CPUFlag ; Are we on an 040 or greater?
|
||
Blt.s @1 ; No? Then long align is good enough.
|
||
Andi.w #$FFF0,D1 ; Yes? Then line align.
|
||
|
||
@1 Cmp.L D2,D1 ;adrCei < adrLim?
|
||
BCS.S @2 ;Yes, return adrCei as adrLim.
|
||
@skipStack ;
|
||
Move.L D2,D1 ;No, return adrLim as adrLim.
|
||
@2
|
||
RTS ;Return to caller. <2> kc.end
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Procedure ZoneAdjustEnd;
|
||
;
|
||
; Adjusts the end of the specified zone to the address provided in A0.
|
||
; It is only safe to call this on the System Zone when the Application
|
||
; Zone is about to be initialized.
|
||
;
|
||
; Arguments:
|
||
; A0: adrEnd: New heap end address.
|
||
; A6: z: Zone whose end will be adjusted.
|
||
;
|
||
; Result:
|
||
; None.
|
||
;
|
||
; Registers:
|
||
; D0: dSize: Amount zone will be grown by.
|
||
; A0: adrOld: Old heap end address.
|
||
; A2: adrT: address temporary.
|
||
; A3: adrEnd: New heap end address.
|
||
;
|
||
; Called By: SetApplBase,GrowZone
|
||
|
||
a24ZoneAdjustEnd
|
||
MoveM.L D0/A0/A2-A3,-(SP) ;Save registers.
|
||
Move.L A0,A3 ;New Heap End.
|
||
Move.L BkLim(A6),A0 ;Current Heap End.
|
||
Move.L A3,D0 ;New Heap End.
|
||
Sub.L A0,D0 ;Compute size increase.
|
||
|
||
Move.L #MinFree24,TagBC24(A3) ;Size of new end block. <v1.2>
|
||
|
||
BSR a24MakeBkf ;make it a free block
|
||
BSR AdjustFree ;Adjust zone free count.
|
||
|
||
Move.L A3,BkLim(A6) ;Point zone obj. at new end block.
|
||
|
||
MoveM.L (SP)+,D0/A0/A2-A3 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
a32ZoneAdjustEnd
|
||
MoveM.L D0/A0/A2-A3,-(SP) ;Save registers.
|
||
Move.L A0,A3 ;New Heap End.
|
||
Move.L BkLim(A6),A0 ;Current Heap End.
|
||
Move.L A3,D0 ;New Heap End.
|
||
Sub.L A0,D0 ;Compute size increase.
|
||
|
||
CLR.L TagBC32(A3) ;clear header <C883>
|
||
Move.L #MinFree32,BlkSize32(A3);Size of new end block. <v1.2>
|
||
|
||
BSR a32MakeBkf ;make it a free block
|
||
BSR AdjustFree ;Adjust zone free count.
|
||
|
||
Move.L A3,BkLim(A6) ;Point zone obj. at new end block.
|
||
|
||
MoveM.L (SP)+,D0/A0/A2-A3 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Procedure GrowZone(s: Size);
|
||
;
|
||
; GrowZone tries to grow the application heap by (s rounded up to next
|
||
; 1024 byte boundary). If not successful, tries to grow it at least
|
||
; up to (SP-MinStack) boundary. HeapEnd is set up in INitZone and can only be
|
||
; changed here.
|
||
;
|
||
; This is one of the few locations where arithmetic is done on an input size request. <21May85>
|
||
; Watch for carry out when size is added to current zone, as is the case when the
|
||
; requested size is 'negative'.
|
||
;
|
||
; Massive change: Across 'historical' upward GrowZone, D3 records how much of <14Apr85>
|
||
; the request is actually met. If it's nonzero at GZClnUp, and the conditional
|
||
; assembly permits, then try growing downward. Round any growth up to next 4K to
|
||
; make it worth the trouble, but bound the ApplZone below by SysZone, of course,
|
||
; and don't allow an increase smaller than minFree. The change is simple. Move
|
||
; the header down; make a free block of the space between the header and what was
|
||
; the first block; and then update the relative handles of the pointers (decrementing
|
||
; by the delta) and of the handles (incrementing by the delta).
|
||
;
|
||
; When jamming HeapEnd with new value, there’s no need to check HiHeapMark since in <C765><C778>
|
||
; principle it was pinned to ApplLimit. <C778>
|
||
;
|
||
; Arguments:
|
||
; D0: s: Number of bytes to add to the zone.
|
||
; A6: z: Zone to be grown. Must only point to ApplZone.
|
||
;
|
||
; Result:
|
||
; None.
|
||
;
|
||
; Registers:
|
||
; D0: s: Amount of zone size increase.
|
||
; D1: adrLim: New ApplLimit.
|
||
; D2: adrEnd: Heap End; then temp <14Apr85>
|
||
; D3: amount satisfied upward; then flag for TheZone=ApplZone <14Apr85>
|
||
; A0: adrEnd: New Heap End; then temp <14Apr85>
|
||
; A1: temp. <14Apr85>
|
||
; A2: temp. <14Apr85>
|
||
;
|
||
; Called By: BkCompactS, MakePtrSpc <14Apr85>
|
||
|
||
;------ 24 bit version--------
|
||
a24GrowZone
|
||
MoveM.L D0-D3/A0-A2,-(SP) ;Save registers. <14Apr85>
|
||
|
||
Add.L #$400,D0 ;Add 1024 bytes to size.
|
||
And.W #$FC00,D0 ;Round it down.
|
||
Move.L D0,D3 ;This is how much we need. <14Apr85>
|
||
|
||
Move.L ApplLimit,D2 ;Current ApplLimit.
|
||
BSR.S a24MaxLimit ;Compute new ApplLimit value. <v1.1>
|
||
|
||
Move.L HeapEnd,D2 ;Current HeapEnd.
|
||
Cmp.L D2,D1 ;New ApplLimit <= HeapEnd?
|
||
BLS.S @GZClnUp ;Yes, can't grow heap.
|
||
|
||
Add.L D0,D2 ;Projected HeapEnd. This may carry-out. <21May85>
|
||
BCS.S @GZClnUp ;CarrySet => D0 looks negative. Retreat! <21May85>
|
||
Cmp.L D2,D1 ;New ApplLimit <= New HeapEnd?
|
||
BCS.S @GZPartGrow ;Yes, just grow as much as we can.
|
||
|
||
Move.L D2,D1 ;Set HeapEnd to new value.
|
||
MoveQ #0,D3 ;We won't need any more after that. <14Apr85>
|
||
BrA.S @GZAdjFree ;Go move end block, etc.
|
||
@GZPartGrow
|
||
Move.L D1,D0 ;Use ApplLimit as new HeapEnd.
|
||
Sub.L HeapEnd,D0 ;Compute number of bytes grown.
|
||
Cmp.L #MinFree24,D0 ;Bytes grown < MinFree? <v1.2>
|
||
BCS.S @GZClnUp ;Yes, just don't grow at all.
|
||
; We need contiguous space -- so don't bother splitting high and low.
|
||
; Sub.L D0,D3 ;Diminish need by amount to be grown. <14Apr85>
|
||
@GZAdjFree
|
||
Move.L D1,HeapEnd ;Set HeapEnd.
|
||
;presume HeapEnd <= ApplLimit == HiHeapMark <C778>
|
||
Move.L D1,A0 ;Pass HeapEnd to ZoneAdjustEnd.
|
||
BSR.S a24ZoneAdjustEnd ;Move end of zone to HeapEnd.
|
||
@GZClnUp
|
||
|
||
MoveM.L (SP)+,D0-D3/A0-A2 ;Restore registers. <14Apr85>
|
||
RTS ;Sole exit point from GrowZone. <14Apr85>
|
||
|
||
;------ 32 bit version--------
|
||
a32GrowZone
|
||
MoveM.L D0-D3/A0-A2,-(SP) ;Save registers. <14Apr85>
|
||
|
||
Add.L #$400,D0 ;Add 1024 bytes to size.
|
||
And.W #$FC00,D0 ;Round it down.
|
||
Move.L D0,D3 ;This is how much we need. <14Apr85>
|
||
|
||
Move.L ApplLimit,D2 ;Current ApplLimit.
|
||
BSR.S a32MaxLimit ;Compute new ApplLimit value. <v1.1>
|
||
|
||
Move.L HeapEnd,D2 ;Current HeapEnd.
|
||
Cmp.L D2,D1 ;New ApplLimit <= HeapEnd?
|
||
BLS.S @GZClnUp ;Yes, can't grow heap.
|
||
|
||
Add.L D0,D2 ;Projected HeapEnd. This may carry-out. <21May85>
|
||
BCS.S @GZClnUp ;CarrySet => D0 looks negative. Retreat! <21May85>
|
||
Cmp.L D2,D1 ;New ApplLimit <= New HeapEnd?
|
||
BCS.S @GZPartGrow ;Yes, just grow as much as we can.
|
||
|
||
Move.L D2,D1 ;Set HeapEnd to new value.
|
||
MoveQ #0,D3 ;We won't need any more after that. <14Apr85>
|
||
BrA.S @GZAdjFree ;Go move end block, etc.
|
||
@GZPartGrow
|
||
Move.L D1,D0 ;Use ApplLimit as new HeapEnd.
|
||
Sub.L HeapEnd,D0 ;Compute number of bytes grown.
|
||
Cmp.L #MinFree32,D0 ;Bytes grown < MinFree? <v1.2>
|
||
BCS.S @GZClnUp ;Yes, just don't grow at all.
|
||
; We need contiguous space -- so don't bother splitting high and low.
|
||
; Sub.L D0,D3 ;Diminish need by amount to be grown. <14Apr85>
|
||
@GZAdjFree
|
||
Move.L D1,HeapEnd ;Set HeapEnd.
|
||
;presume HeapEnd <= ApplLimit == HiHeapMark <C778>
|
||
Move.L D1,A0 ;Pass HeapEnd to ZoneAdjustEnd.
|
||
BSR.S a32ZoneAdjustEnd ;Move end of zone to HeapEnd.
|
||
@GZClnUp
|
||
|
||
MoveM.L (SP)+,D0-D3/A0-A2 ;Restore registers. <14Apr85>
|
||
RTS ;Sole exit point from GrowZone. <14Apr85>
|
||
|
||
|
||
;---------------------------------------------------------------------- {4}
|
||
;
|
||
; Function ActualS(s: Size): Size;
|
||
;
|
||
; Takes a user-supplied size and converts it to an actual block size
|
||
; by adding the overhead length and making sure the block is at
|
||
; least minimum size. Also ensures that size is a multiple of 16 on 040s.
|
||
; Change <C251> of the previous line is backed out, that is, blocks <A415>
|
||
; are permitted to have the form 2(2n+1).
|
||
; And now we forego compatibility in favor of speed.
|
||
;
|
||
; Argument:
|
||
; D0: s: logical size.
|
||
;
|
||
; Result:
|
||
; D0: sAct: actual physical size needed for block.
|
||
;
|
||
; Registers:
|
||
; D0: sTemp: size undergoing computation.
|
||
;
|
||
; Called By: CompactMem,PurgeMem,AllocBk,SetSize
|
||
|
||
a24ActualS
|
||
Cmpi.b #cpu68040,CPUFlag ; Are we on an 040 or greater? <2> kc.start
|
||
Blt.s @0 ; No? Then long align.
|
||
Tst.l pVMGlobals ; VM running? <T7>
|
||
Bpl.s @0 ; Yea? Then don't patch.<T7>
|
||
|
||
Add.L #BlkData24+15,D0 ;Add Block overhead.
|
||
And.W #$FFF0,D0 ;
|
||
Cmp.L #MinFree24+4,D0 ;sAct >= minFree?
|
||
BCC.S @1 ;Yes, skip.
|
||
MoveQ #MinFree24+4,D0 ;No, guarantee minimum size.
|
||
Bra.s @1
|
||
|
||
@0 AddQ.L #BlkData24,D0 ;Add Block overhead.
|
||
AddQ.L #3,D0 ;round up to 4x
|
||
And.W #$FFFC,D0 ;
|
||
Cmp.L #MinFree24,D0 ;sAct >= minFree?
|
||
BCC.S @1 ;Yes, skip.
|
||
MoveQ #MinFree24,D0 ;No, guarantee minimum size.
|
||
|
||
@1 Rts
|
||
|
||
a32ActualS
|
||
Cmpi.b #cpu68040,CPUFlag ; Are we on an 040 or greater?
|
||
Blt.s @0 ; No? Then long align.
|
||
|
||
Add.L #BlkData32+15,D0 ;Add Block overhead.
|
||
And.W #$FFF0,D0 ;
|
||
Cmp.L #MinFree32,D0 ;sAct >= minFree?
|
||
BCC.S @1 ;Yes, skip.
|
||
MoveQ #MinFree32,D0 ;No, guarantee minimum size.
|
||
Bra.s @1
|
||
|
||
@0 Add.L #BlkData32,D0 ;Add Block overhead.
|
||
AddQ.L #3,D0 ;round up to 4x
|
||
And.W #$FFFC,D0 ;
|
||
Cmp.L #MinFree32,D0 ;sAct >= minFree?
|
||
BCC.S @1 ;Yes, skip.
|
||
MoveQ #MinFree32,D0 ;No, guarantee minimum size.
|
||
|
||
@1 RTS ;Return to caller. <2> kc.end
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function GetSize(p: Ptr): Size;
|
||
;
|
||
; Returns the actual data size of a memory manager block.
|
||
;
|
||
; Argument:
|
||
; A0: p: points to block text region
|
||
;
|
||
; Result:
|
||
; D0: s: size in bytes
|
||
;
|
||
; Registers:
|
||
; D0: s: size.
|
||
; D1: dSize: delta size.
|
||
; A0: p: points to block text.
|
||
; A0: b: points to block header.
|
||
;
|
||
; Called By: GetPtrSize,GetHandleSize,SafeReloc,RelocRel,SetSize(2)
|
||
|
||
a24GetSize
|
||
Move.L D1,-(SP) ;Save register.
|
||
SubQ.L #BlkData24,A0 ;Point to block header.
|
||
MoveQ #$F,D1 ;Mask for delta field.
|
||
And.B (A0),D1 ;Logical size difference.
|
||
Move.L TagBC24(A0),D0 ;Get size of block.
|
||
And.L MaskBC,D0 ;Discard tag and delta.
|
||
SubQ.L #BlkData24,D0 ;Adjust for header length.
|
||
Sub.L D1,D0 ;Subtract size difference.
|
||
AddQ.L #BlkData24,A0 ;Point to block text.
|
||
Move.L (SP)+,D1 ;Restore register.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
a32GetSize
|
||
Move.L D1,-(SP) ;Save register.
|
||
Sub.L #BlkData32,A0 ;Point to block header. <v1.1>
|
||
MoveQ #0,D1 ;clear out D1 <v1.1>
|
||
Move.B SizeCor32(A0),D1 ;Get size correction. <v1.1>
|
||
Move.L BlkSize32(A0),D0 ;Get size of block. <v1.1>
|
||
Sub.L #BlkData32,D0 ;Adjust for header length. <v1.1>
|
||
Sub.L D1,D0 ;Subtract size difference. <v1.1>
|
||
Add.L #BlkData32,A0 ;Point to block text. <v1.1>
|
||
Move.L (SP)+,D1 ;Restore register.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Procedure ClearGZStuff
|
||
;
|
||
; Clears out the grow zone handle/pointer for the root flavor only
|
||
;
|
||
; Arguments: None
|
||
;
|
||
; Called by: SetSize,ReallocHandle
|
||
;
|
||
;----------------------------------------------------------------------
|
||
;
|
||
ClearGZStuff
|
||
CLR.L GZRootHnd ; clear 'em out
|
||
CLR.L GZRootPtr
|
||
|
||
RTS
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function SetSize(p: Ptr; h: Handle; s: Size): ErrCode;
|
||
;
|
||
; This routine is used to set the size of memory blocks -- except shrinking ROZ blocks. <04Mar85>
|
||
; Before call is made to RelocRel, block is marked nonpurgeable, though user's growZone <10Apr85>
|
||
; may go ahead and blitz it anyway. <10Apr85>
|
||
;
|
||
; New strategy for handles: If there is sufficient free space beyond block, proceed as usual. <18Apr85>
|
||
; If not unlocked relocatable, proceed as usual. Look for free space below growing block, <18Apr85>
|
||
; coalescing free space from beginning of zone. If there is free space of SUFFICIENT size, <18Apr85>
|
||
; then slide block down, but no further than required to grow the block, including space beyond <18Apr85>
|
||
; the end. Else (sliding doesn't help) check the relative sizes of the growing block and its <18Apr85>
|
||
; successor in the heap; if the latter is larger, skip the MakeSpace call, and go right on to <18Apr85>
|
||
; relocate and grow the growing block. <18Apr85>
|
||
; Code is conditionally assembled according to SmartSetSize flag. <18Apr85>
|
||
;
|
||
; Arguments:
|
||
; D0: s: New logical size for block.
|
||
; A0: p: Pointer to block
|
||
; A1: h: Handle for block, or Nil if Non-Relocatable.
|
||
; A6: z: Zone holding block.
|
||
;
|
||
; Result:
|
||
; D0: ec: error code.
|
||
; memFullErr: Not enough room to grow.
|
||
; 0: Success.
|
||
;
|
||
; Registers:
|
||
; A0: p: Pointer to block.
|
||
; A0: b: Points to block header.
|
||
; A2: b: Points to block header.
|
||
; A2: bFree: Points to header of following free block.
|
||
; D0: sCur: Current size of block.
|
||
; D0: SNew: Sometime, number of bytes in new block.
|
||
; D1: sNew: Number of bytes in new block.
|
||
; D2: sCAct: Physical size of current block.
|
||
; D3: sNAct: Physical size of new block.
|
||
; D4: sCAct: Copy of physical size of current block.
|
||
; D4: t: Temporary.
|
||
;
|
||
; Called By: SetPtrSize,SetHandleSize
|
||
|
||
; ----- 24 bit version -----
|
||
a24SetSize
|
||
MoveM.L D1-D6/A0-A3,-(SP) ;Save registers. <18Apr85>
|
||
Move.B (A1),-(SP) ;Save flags of block
|
||
|
||
;---------------------------------------------------------------------- <2> kc.start
|
||
; Patch to SetSize to intercept size changes to the first Master Pointer block since
|
||
; this is the block that gets additional padding to force all following blocks to be
|
||
; line aligned on 040 cpus.
|
||
|
||
@a24SetSizePatch
|
||
Move.L D0,D1 ;Save desired logical size.
|
||
Lea heapData+BlkData24(A6),A2 ; First MP block.
|
||
Cmpa.l A0,A2 ; Resizing it?
|
||
Bne.s @noPadding ; No? Then get normal size.
|
||
Cmpi.b #cpu68040,CPUFlag ; Are we on an 040 or greater?
|
||
Blt.s @noPadding ; No? Then no extra padding.
|
||
Tst.l pVMGlobals ; VM running? {7}
|
||
Bpl.s @noPadding ; Yea? Then don't patch.{7}
|
||
|
||
Add.l #BlkData24,D0
|
||
Move.l A2,D2 ; Start of block.
|
||
Add.l D0,D2 ; End of block.
|
||
And.l #$F,D2
|
||
Beq.s @aligned ; Already aligned?
|
||
Not.b D2 ; Get remainder.
|
||
And.b #$F,D2 ; Only care about bottom 4 bits.
|
||
Addq.b #1,D2 ; Add in 1.
|
||
Add.l D2,D0 ; New physical size.
|
||
Bra.s @aligned
|
||
|
||
@noPadding BSR.S a24ActualS ;Adjust D0 to new physical size.
|
||
|
||
@aligned Move.L D0,D3 ;New physical size. <2> kc.end
|
||
|
||
BSR.S a24GetSize ;Get current logical size in D0.
|
||
Cmp.L D0,D1 ;sNew = sCur?
|
||
BEq @SSDone ;Yes, return to caller.
|
||
|
||
Move.L A0,A2 ;Points to block text.
|
||
SubQ.L #BlkData24,A2 ;Point to block header.
|
||
Move.L TagBC24(A2),D2 ;Get block header.
|
||
And.L MaskBC,D2 ;Extract physical size.
|
||
|
||
Move.L D2,D4 ;Old physical size.
|
||
|
||
Cmp.L D2,D3 ;sNAct = sCAct?
|
||
BEq @SSLogical ;Yes, just set logical size.
|
||
BCS @SSShrink ;sNAct < sCAct, shrink the block.
|
||
|
||
******************************** Start conditional block. ******************************** <18Apr85>
|
||
IF SmartSetSize THEN
|
||
|
||
; The block must be grown. <18Apr85>
|
||
; Registers: D0=D3=new phys size; D1=new log size; D2=D4=phys size; D5=?? <18Apr85>
|
||
; A0=text ptr; A1=handle; A2=block ptr; A3=?? <18Apr85>
|
||
; Across the code use registers: <18Apr85>
|
||
; D0=tmp; D1=new log size; D2=D4=phys size; D3=new phys size; D5=delta size <18Apr85>
|
||
; A0=tmp; A1=handle; A2=block ptr; A3=tmp <18Apr85>
|
||
; <18Apr85>
|
||
; First, set up some registers and the GZ's. <18Apr85>
|
||
Move.L D3,D5
|
||
Sub.L D2,D5 ;delta physical size
|
||
Move.L A1,GZRootHnd ;record handle being sized
|
||
Move.L A0,GZRootPtr ;record pointer " "
|
||
|
||
; In this loop, A3 steps across the blocks and D6 accumulates free space. <18Apr85>
|
||
MoveA.L A2,A3
|
||
AddA.L D4,A3 ;next block after growing
|
||
MoveQ #0,D6 ;initial accumulation
|
||
@SSAftFree
|
||
CmpA.L bkLim(A6),A3 ;have we reached the heap end?
|
||
BCC.S @SSAFEnd ;Carry Clear => beyond the end
|
||
|
||
Tst.B (A3) ;Eq => free block
|
||
BNE.S @SSAFEnd
|
||
Add.L TagBC24(A3),D6 ;accumulate free space
|
||
AddA.L TagBC24(A3),A3 ;bump on to next block
|
||
BrA.S @SSAftFree ;and continue looping
|
||
@SSAFEnd
|
||
; Detail: be sure to go on if exactly enough space is there -- for no sliding will be done! <18Apr85>
|
||
Sub.L D6,D5 ;D5 := amount unrequited by free space at end
|
||
BLS @SSAsUsual ;Lower or Same => enough space for easy growth!
|
||
|
||
; Provided the block is unlocked, relocatable, try coalescing free space from below, remembering <18Apr85>
|
||
; the 'last' block to give a backward peek when A2 is reached. The logic follows BFindS farily <18Apr85>
|
||
; closely. Starting at the heap's beginning, outer loop skips over allocated blocks (watching <18Apr85>
|
||
; for the one being grown); when a free block is hit, the inner loop starts coalescing until <18Apr85>
|
||
; allocated block (or growing one) is found. The loop terminates with A0 pointing to the last <18Apr85>
|
||
; free block found, and D0 equal to the amount of free space immmediately before the growing block. <18Apr85>
|
||
Move.L A1,D0
|
||
BEq @SSAsUsual ;Eq => it's a ptr, cannot move
|
||
Tst.B (SP) ;remember, the flags were saved earlier
|
||
BMi @SSAsUsual ;Mi => locked, cannot move
|
||
|
||
LEA heapData(A6),A3 ;start with the first block
|
||
@CoalLoop
|
||
CmpA.L A2,A3
|
||
BCC.S @CoalFini ;Carry Clear => beyond growing pointer
|
||
|
||
Move.L TagBC24(A3),D0
|
||
Tst.B TagBC24(A3)
|
||
BEq.S @CoalFree ;Eq => free block found
|
||
And.L Lo3Bytes,D0 ;isolate current block length
|
||
AddA.L D0,A3 ;bump up to next block
|
||
MoveQ #0,D0 ;mark 'no immediately preceeding free space'
|
||
BrA.S @CoalLoop
|
||
@CoalFree
|
||
MoveA.L A3,A0 ;start of free space
|
||
MoveQ #0,D0 ;init accumulated free space
|
||
@CoalFLoop
|
||
CmpA.L allocPtr(A6),A3 ;is the rover at a disappearing block? <23Apr85>
|
||
BNE.S @1 ;NotEqual => no... <23Apr85>
|
||
Move.L A0,allocPtr(A6) ;don't let allocptr pt to nonexistent block <23Apr85>
|
||
@1 ; <23Apr85>
|
||
Add.L TagBC24(A3),D0 ;accumulate the free space
|
||
AddA.L TagBC24(A3),A3 ;bump to next block
|
||
Tst.B TagBC24(A3)
|
||
BEq.S @CoalFLoop ;Eq => more free space!
|
||
|
||
Move.L D0,TagBC24(A0) ;update size of coalesced block
|
||
BrA.S @CoalLoop ;continue with this non-free block
|
||
@CoalFini
|
||
|
||
; We exit the above loop with D0=free space immediately below growing block, A0 pointing <18Apr85>
|
||
; to it. If at least 1/4 of the unrequited space can be made up by sliding, DO IT. <18Apr85>
|
||
; In case of a slide: if the free space is within a few minFree's of the needed space, <18Apr85>
|
||
; go the whole way, otherwise slide just enough to meet the needs. <18Apr85>
|
||
; A special case arises: when D5 is tiny, a fourth is zero, and this is BAD news if D0 is <18Apr85>
|
||
; also zero! The test BLS (as opposed to BCS) catches this case along with tinies. <18Apr85>
|
||
; Yet another goof -- must bound unrequited size by minFree, since that's the size of block <18Apr85>
|
||
; of free block we'll make at the end. <18Apr85>
|
||
Move.L D5,D6 ;unrequited space
|
||
LSR.L #2,D6 ;1/4 of it
|
||
Cmp.L D6,D0
|
||
BLS.S @SSNoSlide ;Lower or Same => too little space free (or none available)
|
||
|
||
|
||
MoveQ #minFree24,D6 ;Lower bound for unrequited <v1.2>
|
||
Cmp.L D5,D6
|
||
BLS.S @5 ;Lower or Same => D5 big enough for slide
|
||
Move.L D6,D5 ;Make at least minFree space...
|
||
@5
|
||
MoveQ #minFree24+minFree24,D6 ;unscientific slop <v1.2>
|
||
Add.L D5,D6 ;unrequited space + slop
|
||
Cmp.L D6,D0
|
||
BCS.S @SSFullSlide ;Carry Set => not enough extra to split free space
|
||
|
||
; To do a partial slide, decrement the size of the lower block by the amount we'll slide. <18Apr85>
|
||
Sub.L D5,D0 ;Size minus amount of slide
|
||
Move.L D0,TagBC24(A0) ;Force size of free block (don't need A0 now)
|
||
AddA.L D0,A0 ;Target slot for growing block
|
||
Move.L D5,D0 ;Size of slide, for 'sliding' into FullSlide
|
||
|
||
; Full slide code: D0=amt of slide; D4=size of sliding block; D6=tmp; A0=dst of slide; <18Apr85>
|
||
; A1=handle to sliding block; A2=ptr to sliding block. Be sure to update the handle! <18Apr85>
|
||
; And after the block is moved, update GZRootPtr and allocPtr, since the latter may point <18Apr85>
|
||
; to a nonexistent free block. <18Apr85>
|
||
@SSFullSlide
|
||
Move.L A0,(A1) ;new location for sliding/growing block
|
||
AddQ.L #blkData24,(A1) ;be sure handle points to text of block!!!! (you idiot)
|
||
Move.B (SP),(A1) ;restore the tags from home on the stack
|
||
MoveM.L D0/A1,-(SP) ;save amt of slide and handle
|
||
|
||
CmpA.L allocPtr(A6),A2 ;is the rover at the block we're moving? <23Apr85>
|
||
BNE.S @10 ;NotEqual => rover is elsewhere... <23Apr85>
|
||
Move.L A0,allocPtr(A6) ;point rover at new location <23Apr85>
|
||
@10 ; <23Apr85>
|
||
Exg A0,A2 ;A0=src of growing block, A1=dst
|
||
MoveA.L A2,A1 ;dst, for blockmove
|
||
Move.L D4,D0 ;current phys length is length of move!
|
||
BSr HBlockMove
|
||
|
||
MoveA.L A2,A0 ;ptr to moved block
|
||
AddA.L D4,A0 ;ptr just beyond -- to new free block
|
||
Move.L (SP)+,TagBC24(A0) ;stuff size of new free block
|
||
MoveA.L (SP)+,A1 ;restore handle
|
||
|
||
LEA blkData24(A2),A0 ;text ptr to growing block
|
||
Move.L A0,GZRootPtr
|
||
BrA.S @SSAsUsual
|
||
|
||
; Our last resort: check the block following ours; if it's larger and allocated, don't even <18Apr85>
|
||
; bother trying to move it. <18Apr85>
|
||
@SSNoSlide
|
||
MoveA.L A2,A0
|
||
AddA.L D4,A0 ;ptr to following block
|
||
Move.L TagBC24(A0),D0
|
||
And.L Lo3Bytes,D0 ;isolate size
|
||
Cmp.L D0,D3
|
||
BCC.S @SSAsUsual ;Carry Clear => new size is large, so go the normal route
|
||
Tst.B TagBC24(A0)
|
||
BNE.S @SSDoReloc ;Not Equal => larger, alloc block following
|
||
|
||
********************************* End conditional block. ******************************** <18Apr85>
|
||
ENDIF ; SmartSetSize
|
||
|
||
; This resumes the original SetSize growth code. The register setup must be adjusted to: <18Apr85>
|
||
; D0=??; D1=new log size; D2=D4=phys size; D3=new phys size; D4=phy size; D5=??; D6=?? <18Apr85>
|
||
; A0=??; A1=handle; A2=block ptr; A3=?? <18Apr85>
|
||
@SSAsUsual
|
||
Move.L A2,A0 ;Points to block header.
|
||
Move.L D3,D0 ;New physical size.
|
||
Sub.L D2,D0 ;Compute delta bytes.
|
||
Add.L D2,A2 ;Point to where space is needed
|
||
|
||
BSet #Lock,(A1) ;Lock block so that MakeSpace
|
||
; doesn't move it by accident.
|
||
BSR a24MakeSpace ;Try making room after this block.
|
||
BClr #Lock,(A1) ;Unlock the block.
|
||
Move.L A2,D4 ;Did we succeed?
|
||
BNE.S @SSEnough ;Yes, keep going
|
||
|
||
; New entry point to bypass MakeSpace when following block is bigger than one we're growing. <18Apr85>
|
||
@SSDoReloc
|
||
Move.L A1,D4 ;No, maybe we can relocate block.
|
||
BEq.S @SSFail ;No, block is Non-Relocatable.
|
||
Tst.B (SP) ;Can we move the growing block?
|
||
BMi.S @SSFail ;No, block is locked.
|
||
Move.L D1,D0 ;Desired new logical size.
|
||
|
||
; Try to grow the (unlocked) block by relocating&growing simultaneously. Across the call <10Apr85>
|
||
; mark it nonpurgeable, since we WANT it! Note must retrieve previous state from stack <10Apr85>
|
||
; unlike the BSet/BClr pair bracketing MakeSpace above. To get here, the Lock bit must be <10Apr85>
|
||
; clear, so the blithe BClr above jibes with our restoration from the stack. <10Apr85>
|
||
BClr #Purge,(A1) ;Try not to purge it while moving it! <10Apr85>
|
||
BSR a24RelocRel ;Relocate the old block into a new.
|
||
MOVE.B (SP),(A1) ;Restore previous state. <10Apr85>
|
||
BSR.S ClearGZStuff ;mark gz stuff as done
|
||
BrA.S @SSExit ;Return to caller.
|
||
@SSFail ;Unable to find space.
|
||
BSR.S ClearGZStuff ;mark gz stuff as done
|
||
MoveQ #memFullErr,D0 ;Not enough room to reloc. block.
|
||
BrA.S @SSExit ;Return to caller.
|
||
@SSEnough ;Enough room has been found.
|
||
BSR.S ClearGZStuff ;mark gz stuff as done
|
||
Move.L TagBC24(A2),D0 ;Length of free space after.
|
||
; <SM12> kc
|
||
AndI.l #$00FFFFFF,AllocPtr(A6) ; <SM12> kc
|
||
Cmp.L AllocPtr(A6),A2 ;Does the rover point here? <SM12> kc
|
||
BNE.S @NotRover ;Skip if not . . . <SM12> kc
|
||
And.L Lo3Bytes,D0 ; <SM12> kc
|
||
Add.L D0,AllocPtr(A6) ;Point to next block instead <SM12> kc
|
||
@NotRover ; <SM12> kc
|
||
Move.L D0,D4 ;Physical size of free space.
|
||
Add.L D2,D4 ;Physical size of new combined blk.
|
||
Move.L A0,A2 ;Points to block.
|
||
Move.B TagBC24(A2),D5 ;Save tag, delta size.
|
||
Move.L D4,TagBC24(A2) ;Set block physical size.
|
||
Move.B D5,TagBC24(A2) ;Restore tag, delta size fields.
|
||
; Neg.L D0 ;Minus size of new space.
|
||
; BSR AdjustFree ;Account for less free space.
|
||
BSR SubtractFree ;Account for less free space. <v1.7>
|
||
@SSShrink ;Shrink the block.
|
||
Sub.L D3,D4 ;Number of bytes to shrink block.
|
||
Cmp.L #MinFree24,D4 ;sFree < MinFree? <v1.2>
|
||
BCS.S @SSLogical ;Yes, set logical size only.
|
||
BTST #ROZ,flags(A6) ;don't shrink ROZ blocks <04Mar85>
|
||
BNE.S @SSSkip ; <04Mar85>
|
||
|
||
Move.L A2,A0 ;Points to block.
|
||
Add.L D3,A0 ;Point to new free block.
|
||
Move.B TagBC24(A2),D5 ;Save tag, delta size.
|
||
Move.L D3,TagBC24(A2) ;Set block physical size.
|
||
Move.B D5,TagBC24(A2) ;Restore tag, delta size fields.
|
||
Move.L D4,D0 ;Size of new free block.
|
||
BSR.S a24MakeBkF ;Release free space.
|
||
BSR AdjustFree ;And account for new free space.
|
||
@SSLogical ;Set the logical size of the block.
|
||
Move.L A2,A0 ;Points to block.
|
||
Move.L D1,D0 ;New logical size.
|
||
BSR.S a24SetLogSize ;Set logical size.
|
||
@SSDone
|
||
MoveQ #0,D0 ;Success result code.
|
||
@SSExit
|
||
Move.B (SP)+,(A1) ;Restore MP flag byte.
|
||
MoveM.L (SP)+,D1-D6/A0-A3 ;Restore registers. <18Apr85>
|
||
RTS ;Return to caller.
|
||
@SSSkip
|
||
MoveQ #memROZWarn,D0 ; <04Mar85>
|
||
BRA.S @SSExit ; <04Mar85>
|
||
|
||
|
||
; ----- 32 bit version -----
|
||
a32SetSize
|
||
MoveM.L D1-D6/A0-A3,-(SP) ;Save registers. <18Apr85>
|
||
Move.L A0,A2 ;Points to block text. <v1.4>
|
||
Move.B MPtag32-BlkData32(A2),-(SP) ;save flags of block <v1.1>
|
||
|
||
@SetSizePatch Move.L D0,D1 ;Save desired logical size. <2> kc.start
|
||
Lea heapData+BlkData32(A6),A2 ; First MP block.
|
||
Cmpa.l A0,A2 ; Resizing it?
|
||
Bne.s @noPadding ; No? Then get normal size.
|
||
Cmpi.b #cpu68040,CPUFlag ; Are we on an 040 or greater?
|
||
Blt.s @noPadding ; No? Then no extra padding.
|
||
|
||
Add.l #BlkData32,D0
|
||
Move.l A2,D2 ; Start of block.
|
||
Add.l D0,D2 ; End of block.
|
||
And.l #$F,D2
|
||
Beq.s @aligned ; Already aligned?
|
||
Not.b D2 ; Get remainder.
|
||
And.b #$F,D2 ; Only care about bottom 4 bits.
|
||
Addq.b #1,D2 ; Add in 1.
|
||
Add.l D2,D0 ; New physical size.
|
||
Bra.s @aligned
|
||
|
||
@noPadding BSR.S a32ActualS ;Adjust D0 to new physical size.
|
||
|
||
@aligned Move.L D0,D3 ;New physical size. <2> kc.end
|
||
|
||
BSR.S a32GetSize ;Get current logical size in D0.
|
||
Cmp.L D0,D1 ;sNew = sCur?
|
||
BEq @SSEqual ;Yes, return to caller. <SM6>
|
||
|
||
Move.L A0,A2 ;Points to block text.
|
||
Sub.L #BlkData32,A2 ;Point to block header. <v1.1>
|
||
Move.L BlkSize32(A2),D2 ;Get physical size. <v1.1>
|
||
|
||
Move.L D2,D4 ;Old physical size.
|
||
|
||
Cmp.L D2,D3 ;sNAct = sCAct?
|
||
BEq @SSLogical ;Yes, just set logical size.
|
||
BCS @SSShrink ;sNAct < sCAct, shrink the block.
|
||
|
||
******************************** Start conditional block. ******************************** <18Apr85>
|
||
IF SmartSetSize THEN
|
||
|
||
; The block must be grown. <18Apr85>
|
||
; Registers: D0=D3=new phys size; D1=new log size; D2=D4=phys size; D5=?? <18Apr85>
|
||
; A0=text ptr; A1=handle; A2=block ptr; A3=?? <18Apr85>
|
||
; Across the code use registers: <18Apr85>
|
||
; D0=tmp; D1=new log size; D2=D4=phys size; D3=new phys size; D5=delta size <18Apr85>
|
||
; A0=tmp; A1=handle; A2=block ptr; A3=tmp <18Apr85>
|
||
; <18Apr85>
|
||
; First, set up some registers and the GZ's. <18Apr85>
|
||
Move.L D3,D5
|
||
Sub.L D2,D5 ;delta physical size
|
||
Move.L A1,GZRootHnd ;record handle being sized
|
||
Move.L A0,GZRootPtr ;record pointer " "
|
||
|
||
; In this loop, A3 steps across the blocks and D6 accumulates free space. <18Apr85>
|
||
MoveA.L A2,A3
|
||
AddA.L D4,A3 ;next block after growing
|
||
MoveQ #0,D6 ;initial accumulation
|
||
@SSAftFree
|
||
CmpA.L bkLim(A6),A3 ;have we reached the heap end?
|
||
BCC.S @SSAFEnd ;Carry Clear => beyond the end
|
||
|
||
Tst.B (A3) ;Eq => free block
|
||
BNE.S @SSAFEnd
|
||
Add.L BlkSize32(A3),D6 ;accumulate free space <v1.1>
|
||
AddA.L BlkSize32(A3),A3 ;bump on to next block <v1.1>
|
||
BrA.S @SSAftFree ;and continue looping
|
||
@SSAFEnd
|
||
; Detail: be sure to go on if exactly enough space is there -- for no sliding will be done! <18Apr85>
|
||
Sub.L D6,D5 ;D5 := amount unrequited by free space at end
|
||
BLS @SSAsUsual ;Lower or Same => enough space for easy growth!
|
||
|
||
; Provided the block is unlocked, relocatable, try coalescing free space from below, remembering <18Apr85>
|
||
; the 'last' block to give a backward peek when A2 is reached. The logic follows BFindS farily <18Apr85>
|
||
; closely. Starting at the heap's beginning, outer loop skips over allocated blocks (watching <18Apr85>
|
||
; for the one being grown); when a free block is hit, the inner loop starts coalescing until <18Apr85>
|
||
; allocated block (or growing one) is found. The loop terminates with A0 pointing to the last <18Apr85>
|
||
; free block found, and D0 equal to the amount of free space immmediately before the growing block. <18Apr85>
|
||
Move.L A1,D0
|
||
BEq @SSAsUsual ;Eq => it's a ptr, cannot move
|
||
Tst.B (SP) ;remember, the flags were saved earlier
|
||
BMi @SSAsUsual ;Mi => locked, cannot move
|
||
|
||
LEA heapData(A6),A3 ;start with the first block
|
||
@CoalLoop
|
||
CmpA.L A2,A3
|
||
BCC.S @CoalFini ;Carry Clear => beyond growing pointer
|
||
|
||
Tst.B TagBC32(A3) ; <v1.1>
|
||
BEq.S @CoalFree ;Eq => free block found <v1.1>
|
||
Move.L BlkSize32(A3),D0 ;get block size <v1.1>
|
||
AddA.L D0,A3 ;bump up to next block
|
||
MoveQ #0,D0 ;mark 'no immediately preceeding free space'
|
||
BrA.S @CoalLoop
|
||
@CoalFree
|
||
MoveA.L A3,A0 ;start of free space
|
||
MoveQ #0,D0 ;init accumulated free space
|
||
@CoalFLoop
|
||
CmpA.L allocPtr(A6),A3 ;is the rover at a disappearing block? <23Apr85>
|
||
BNE.S @1 ;NotEqual => no... <23Apr85>
|
||
Move.L A0,allocPtr(A6) ;don't let allocptr pt to nonexistent block <23Apr85>
|
||
@1 ; <23Apr85>
|
||
Add.L BlkSize32(A3),D0 ;accumulate free space <v1.1>
|
||
AddA.L BlkSize32(A3),A3 ;bump on to next block <v1.1>
|
||
Tst.B TagBC32(A3)
|
||
BEq.S @CoalFLoop ;Eq => more free space!
|
||
|
||
Clr.L TagBC32(A0) ;clear 1st long word of block <v1.1>
|
||
Move.L D0,BlkSize32(A0) ;update size of coalesced block <v1.1>
|
||
BrA.S @CoalLoop ;continue with this non-free block
|
||
@CoalFini
|
||
|
||
; We exit the above loop with D0=free space immediately below growing block, A0 pointing <18Apr85>
|
||
; to it. If at least 1/4 of the unrequited space can be made up by sliding, DO IT. <18Apr85>
|
||
; In case of a slide: if the free space is within a few minFree's of the needed space, <18Apr85>
|
||
; go the whole way, otherwise slide just enough to meet the needs. <18Apr85>
|
||
; A special case arises: when D5 is tiny, a fourth is zero, and this is BAD news if D0 is <18Apr85>
|
||
; also zero! The test BLS (as opposed to BCS) catches this case along with tinies. <18Apr85>
|
||
; Yet another goof -- must bound unrequited size by minFree, since that's the size of block <18Apr85>
|
||
; of free block we'll make at the end. <18Apr85>
|
||
Move.L D5,D6 ;unrequited space
|
||
LSR.L #2,D6 ;1/4 of it
|
||
Cmp.L D6,D0
|
||
BLS.S @SSNoSlide ;Lower or Same => too little space free (or none available)
|
||
|
||
|
||
MoveQ #minFree32,D6 ;Lower bound for unrequited <v1.2>
|
||
Cmp.L D5,D6
|
||
BLS.S @5 ;Lower or Same => D5 big enough for slide
|
||
Move.L D6,D5 ;Make at least minFree space...
|
||
@5
|
||
MoveQ #minFree32+minFree32,D6 ;unscientific slop <v1.2>
|
||
Add.L D5,D6 ;unrequited space + slop
|
||
Cmp.L D6,D0
|
||
BCS.S @SSFullSlide ;Carry Set => not enough extra to split free space
|
||
|
||
; To do a partial slide, decrement the size of the lower block by the amount we'll slide. <18Apr85>
|
||
Sub.L D5,D0 ;Size minus amount of slide <v1.1>
|
||
Clr.L TagBC32(A0) ;set free block <v1.1>
|
||
Move.L D0,BlkSize32(A0) ;Force size of free block (don't need A0 now)<C883>
|
||
AddA.L D0,A0 ;Target slot for growing block
|
||
Move.L D5,D0 ;Size of slide, for 'sliding' into FullSlide
|
||
|
||
; Full slide code: D0=amt of slide; D4=size of sliding block; D6=tmp; A0=dst of slide; <18Apr85>
|
||
; A1=handle to sliding block; A2=ptr to sliding block. Be sure to update the handle! <18Apr85>
|
||
; And after the block is moved, update GZRootPtr and allocPtr, since the latter may point <18Apr85>
|
||
; to a nonexistent free block. <18Apr85>
|
||
@SSFullSlide
|
||
Move.L A0,(A1) ;new location for sliding/growing block
|
||
Add.L #blkData32,(A1) ;be sure handle points to text of block!!!! <v1.1>
|
||
Move.B (SP),MPtag32(A0) ;restore the tags from home on the stack <v1.1>
|
||
MoveM.L D0/A1,-(SP) ;save amt of slide and handle
|
||
|
||
CmpA.L allocPtr(A6),A2 ;is the rover at the block we're moving? <23Apr85>
|
||
BNE.S @10 ;NotEqual => rover is elsewhere... <23Apr85>
|
||
Move.L A0,allocPtr(A6) ;point rover at new location <23Apr85>
|
||
@10 ; <23Apr85>
|
||
Exg A0,A2 ;A0=src of growing block, A1=dst
|
||
MoveA.L A2,A1 ;dst, for blockmove
|
||
Move.L D4,D0 ;current phys length is length of move!
|
||
BSr HBlockMove
|
||
|
||
MoveA.L A2,A0 ;ptr to moved block
|
||
AddA.L D4,A0 ;ptr just beyond -- to new free block
|
||
Move.L (SP)+,BlkSize32(A0) ;stuff size of new free block <v1.1>
|
||
Clr.L TagBC32(A0) ;free block <v1.1>
|
||
MoveA.L (SP)+,A1 ;restore handle
|
||
|
||
LEA blkData32(A2),A0 ;text ptr to growing block
|
||
Move.L A0,GZRootPtr
|
||
BrA.S @SSAsUsual
|
||
|
||
; Our last resort: check the block following ours; if it's larger and allocated, don't even <18Apr85>
|
||
; bother trying to move it. <18Apr85>
|
||
@SSNoSlide
|
||
MoveA.L A2,A0
|
||
AddA.L D4,A0 ;ptr to following block
|
||
Move.L BlkSize32(A0),D0 ;get size <v1.1>
|
||
Cmp.L D0,D3
|
||
BCC.S @SSAsUsual ;Carry Clear => new size is large, so go the normal route
|
||
Tst.B TagBC32(A0)
|
||
BNE.S @SSDoReloc ;Not Equal => larger, alloc block following
|
||
|
||
********************************* End conditional block. ******************************** <18Apr85>
|
||
ENDIF ; SmartSetSize
|
||
|
||
; This resumes the original SetSize growth code. The register setup must be adjusted to: <18Apr85>
|
||
; D0=??; D1=new log size; D2=D4=phys size; D3=new phys size; D4=phy size; D5=??; D6=?? <18Apr85>
|
||
; A0=??; A1=handle; A2=block ptr; A3=?? <18Apr85>
|
||
@SSAsUsual
|
||
Move.L A2,A0 ;Points to block header.
|
||
Move.L D3,D0 ;New physical size.
|
||
Sub.L D2,D0 ;Compute delta bytes.
|
||
Add.L D2,A2 ;Point to where space is needed
|
||
|
||
BSet #Lock,MPtag32(A0) ;lock block <SM6> <v1.1>
|
||
; doesn't move it by accident.
|
||
BSR a32MakeSpace ;Try making room after this block.
|
||
BClr #Lock,MPtag32(A0) ;Unlock block <SM6> <v1.1>
|
||
Move.L A2,D4 ;Did we succeed?
|
||
BNE.S @SSEnough ;Yes, keep going
|
||
|
||
; New entry point to bypass MakeSpace when following block is bigger than one we're growing. <18Apr85>
|
||
@SSDoReloc
|
||
Move.L A1,D4 ;No, maybe we can relocate block.
|
||
BEq.S @SSFail ;No, block is Non-Relocatable.
|
||
Tst.B (SP) ;Can we move the growing block?
|
||
BMi.S @SSFail ;No, block is locked.
|
||
Move.L D1,D0 ;Desired new logical size.
|
||
|
||
; Try to grow the (unlocked) block by relocating&growing simultaneously. Across the call <10Apr85>
|
||
; mark it nonpurgeable, since we WANT it! Note must retrieve previous state from stack <10Apr85>
|
||
; unlike the BSet/BClr pair bracketing MakeSpace above. To get here, the Lock bit must be <10Apr85>
|
||
; clear, so the blithe BClr above jibes with our restoration from the stack. <10Apr85>
|
||
Move.L (A1),A3 ;dereference handle <v1.1>
|
||
BClr #Purge,MPtag32-BlkData32(A3);Unlock block <v1.1>
|
||
BSR a32RelocRel ;Relocate the old block into a new.
|
||
|
||
Move.L (A1),A0 ; get new address of block header <SM6> <121>
|
||
Sub.L #BlkData32,A0 ;Point to block header. <SM6> <121>
|
||
|
||
BSR.S ClearGZStuff ;mark gz stuff as done
|
||
BrA.S @SSExit ;Return to caller.
|
||
@SSFail ;Unable to find space.
|
||
BSR.S ClearGZStuff ;mark gz stuff as done
|
||
MoveQ #memFullErr,D0 ;Not enough room to reloc. block.
|
||
BrA.S @SSExit ;Return to caller.
|
||
@SSEnough ;Enough room has been found.
|
||
BSR.S ClearGZStuff ;mark gz stuff as done
|
||
Move.L BlkSize32(A2),D0 ;Length of free space after. <v1.1>
|
||
; <SM12> kc
|
||
Cmp.L AllocPtr(A6),A2 ;Does the rover point here? <SM12> kc
|
||
BNE.S @NotRover ;Skip if not . . . <SM12> kc
|
||
Add.L D0,AllocPtr(A6) ;Point to next block instead <SM12> kc
|
||
@NotRover ; <SM12> kc
|
||
Move.L D0,D4 ;Physical size of free space.
|
||
Add.L D2,D4 ;Physical size of new combined blk.
|
||
Move.L A0,A2 ;Points to block.
|
||
Move.L D4,BlkSize32(A2) ;set block physical size. <v1.1>
|
||
BSR.S SubtractFree ;Account for less free space. <v1.7>
|
||
@SSShrink ;Shrink the block.
|
||
Sub.L D3,D4 ;Number of bytes to shrink block.
|
||
Cmp.L #MinFree32,D4 ;sFree < MinFree? <v1.2>
|
||
BCS.S @SSLogical ;Yes, set logical size only.
|
||
BTST #ROZ,flags(A6) ;don't shrink ROZ blocks <04Mar85>
|
||
BNE.S @SSSkip ; <04Mar85>
|
||
|
||
Move.L A2,A0 ;Points to block.
|
||
Add.L D3,A0 ;Point to new free block.
|
||
Move.L D3,BlkSize32(A2) ;set block physical size. <v1.1>
|
||
Move.L D4,D0 ;Size of new free block.
|
||
BSR.S a32MakeBkF ;Release free space.
|
||
BSR.S AdjustFree ;And account for new free space.
|
||
@SSLogical ;Set the logical size of the block.
|
||
Move.L A2,A0 ;Points to block.
|
||
Move.L D1,D0 ;New logical size.
|
||
BSR.S a32SetLogSize ;Set logical size.
|
||
@SSDone
|
||
MoveQ #0,D0 ;Success result code.
|
||
@SSExit
|
||
|
||
Move.B (SP)+,MPtag32(A0) ;Restore MP flag byte. <SM6> <v1.1>
|
||
@SSFin
|
||
MoveM.L (SP)+,D1-D6/A0-A3 ;Restore registers. <18Apr85>
|
||
RTS ;Return to caller.
|
||
@SSSkip
|
||
MoveQ #memROZWarn,D0 ; <04Mar85>
|
||
BRA.S @SSExit ; <04Mar85>
|
||
@SSEqual
|
||
Move.B (SP)+,D0 ; Don't care about saved MP flag <SM6> <121>
|
||
MoveQ #0,D0 ;Success result code. <SM6> <121>
|
||
Bra.S @SSFin ; <SM6> <121>
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Procedure AdjustFree(dSize: Size);
|
||
;
|
||
; Adjusts the free byte count of the zone by dCB. System fatal error
|
||
; if an attempt is made to decrease the zone byte count to less than
|
||
; zero.
|
||
;
|
||
; Arguments:
|
||
; D0: dSize: delta in size.
|
||
; A6: z: zone whose free byte count will be adjusted.
|
||
;
|
||
; Result:
|
||
; None.
|
||
;
|
||
; Registers:
|
||
; D0: dSize: delta in size.
|
||
; D0: CB: new free byte count.
|
||
;
|
||
; Called By: MakeBk,PurgeBlock,ZoneAdjustEnd,SafeReloc(2),FreeBk,
|
||
; SetSize(2)
|
||
|
||
AdjustFree
|
||
Add.L D0,ZCBFree(A6) ; New ZCBFree.
|
||
BCS.S @AdjFail ; Can never get carry set.
|
||
RTS ; Return.
|
||
@AdjFail
|
||
MoveQ #negZcbFreeErr,D0 ; Trouble Code (over 4 Gbyte). <C206>
|
||
_SysError ; Invoke trouble manager.
|
||
RTS ; Return.
|
||
;
|
||
; SubtractFree is derived from AdjustFree, routines who used to call
|
||
; AdjustFree to substract free space now calls SubtractFree
|
||
;
|
||
; Arguments:
|
||
; D0: dSize: delta in size.
|
||
; A6: z: zone whose free byte count will be adjusted.
|
||
;
|
||
; Result:
|
||
; None. unless free block becomes negative
|
||
;
|
||
SubtractFree
|
||
Sub.L D0,ZCBFree(A6) ; New ZCBFree.
|
||
BCS.S @SubFail ; Can never get carry set.
|
||
RTS ; Return.
|
||
@SubFail
|
||
MoveQ #negZcbFreeErr,D0 ; Trouble Code. <C206>
|
||
_SysError ; Invoke trouble manager.
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function NextMaster: Handle;
|
||
;
|
||
; Gets a fresh master pointer, and returns a handle to it. If none
|
||
; are available, calls on HMakeMoreMasters to create more. Returns
|
||
; Nil if HMakeMoreMasters fails.
|
||
;
|
||
; Argument:
|
||
; A6: z: Zone from which fresh master is to be gotten.
|
||
;
|
||
; Result:
|
||
; A1: h: Handle for new master pointer, or Nil.
|
||
;
|
||
; Registers:
|
||
; D0: t: Temporary, used to test handle for Nil.
|
||
; A1: h: Handle for next master pointer.
|
||
;
|
||
; Called By: NwHandle
|
||
|
||
; ----- 24 bit version -------
|
||
a24NextMaster
|
||
MoveM.L A0/D0,-(SP) ;Save registers.
|
||
Move.L HFstFree(A6),A1 ;Get next handle.
|
||
Move.L A1,D0 ;Are any left?
|
||
BNE.S @NMSuccess ;Yes, return this handle.
|
||
|
||
BSR.S a24HMakeMoreMasters ;No, go make more. <v1.1>
|
||
BEq.S @NMExit ;No luck, no room for more.
|
||
|
||
@NMSuccess
|
||
Move.L (A1),HFstFree(A6) ;Remove handle from list.
|
||
Move.L A1,D0 ;Set condition codes.
|
||
|
||
@NMExit
|
||
MoveM.L (SP)+,A0/D0 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
; ----- 32 bit version -------
|
||
a32NextMaster
|
||
MoveM.L A0/D0,-(SP) ;Save registers.
|
||
Move.L HFstFree(A6),A1 ;Get next handle.
|
||
Move.L A1,D0 ;Are any left?
|
||
BNE.S @NMSuccess ;Yes, return this handle.
|
||
|
||
BSR.S a32HMakeMoreMasters ;No, go make more. <v1.1>
|
||
BEq.S @NMExit ;No luck, no room for more.
|
||
|
||
@NMSuccess
|
||
Move.L (A1),HFstFree(A6) ;Remove handle from list.
|
||
Move.L A1,D0 ;Set condition codes.
|
||
|
||
@NMExit
|
||
MoveM.L (SP)+,A0/D0 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function HMakeMoreMasters: Handle;
|
||
;
|
||
; Makes more Master Pointers (MPs) by allocating a new non-relocatable
|
||
; block, and then linking the contents of the block onto the free
|
||
; handle list.
|
||
;
|
||
; Argument:
|
||
; A6: z: Zone in which new MPs are to be made.
|
||
;
|
||
; Result:
|
||
; A1: h: Handle for first MP on free list, or Nil.
|
||
;
|
||
; Registers:
|
||
; D0: cMast: Number of masters to make.
|
||
; D0: sMast: Size of block to allocate.
|
||
; D0: t: Temporary used to set condition codes.
|
||
; D1: cMast: Number of master pointers made.
|
||
; A0: p: Points to new space for MPs.
|
||
; A1: h: Nil handle for Non-Rel allocation.
|
||
; A1: h: Handle being released to pool.
|
||
;
|
||
; Called By: InitZone,NextMaster,MoreMasters <29jan85>
|
||
|
||
; ----- 24 bit version ------
|
||
a24HMakeMoreMasters
|
||
MoveM.L A0/D0-D1,-(SP) ;Save registers.
|
||
|
||
Move mAllocCnt(A6),D0 ;Number of masters to make.
|
||
Ext.L D0
|
||
BGT.S @1 ;Make sure count is > 0
|
||
|
||
MoveQ #DfltMasters,D0 ;If not, use default number.
|
||
@1
|
||
Move.L D0,D1 ;Count of master pointers.
|
||
ASL.L #2,D0 ;Convert MP count to byte count.
|
||
|
||
BSR.S a24MakePtrSpc ;Clear some room at the low end.
|
||
Sub.L A1,A1 ;Set handle for this block to Nil.
|
||
BSR.S a24AllocBk ;Allocate a Non-Relocatable.
|
||
BEq.S @HMExit ;Didn't find any space!
|
||
|
||
Move.L A0,A1 ;Points to fresh block.
|
||
@HMLoop
|
||
BSR.S ReleaseMP ;Return new MP to list.
|
||
AddQ.L #4,A1 ;Point to next MP.
|
||
SubQ #1,D1 ;Loop counter.
|
||
BNE.S @HMLoop ;Do all fresh handles.
|
||
|
||
SubQ.L #4,A1 ;Point to first MP on list.
|
||
@HMExit
|
||
Move.L A1,D0 ;Set condition codes.
|
||
MoveM.L (SP)+,A0/D0-D1 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
; ----- 32 bit version ------
|
||
a32HMakeMoreMasters
|
||
MoveM.L A0/D0-D1,-(SP) ;Save registers.
|
||
|
||
Move mAllocCnt(A6),D0 ;Number of masters to make.
|
||
Ext.L D0
|
||
BGT.S @1 ;Make sure count is > 0
|
||
|
||
MoveQ #DfltMasters,D0 ;If not, use default number.
|
||
@1
|
||
Move.L D0,D1 ;Count of master pointers.
|
||
ASL.L #2,D0 ;Convert MP count to byte count.
|
||
|
||
BSR a32MakePtrSpc ;Clear some room at the low end.
|
||
Sub.L A1,A1 ;Set handle for this block to Nil.
|
||
BSR.S a32AllocBk ;Allocate a Non-Relocatable.
|
||
BEq.S @HMExit ;Didn't find any space!
|
||
|
||
Move.L A0,A1 ;Points to fresh block.
|
||
@HMLoop
|
||
BSR.S ReleaseMP ;Return new MP to list.
|
||
AddQ.L #4,A1 ;Point to next MP.
|
||
SubQ #1,D1 ;Loop counter.
|
||
BNE.S @HMLoop ;Do all fresh handles.
|
||
|
||
SubQ.L #4,A1 ;Point to first MP on list.
|
||
@HMExit
|
||
Move.L A1,D0 ;Set condition codes.
|
||
MoveM.L (SP)+,A0/D0-D1 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Procedure ReleaseMP(h: Handle);
|
||
;
|
||
; Releases a master pointer to the master pointer pool.
|
||
;
|
||
; Arguments:
|
||
; A1: h: handle for master pointer being released.
|
||
; A6: z: Zone into which MP will be released.
|
||
;
|
||
; Result:
|
||
; None.
|
||
;
|
||
; Registers:
|
||
; None.
|
||
;
|
||
; Called By: HMakeMoreMasters,FreeBk
|
||
; DsposeHandle(Heap)
|
||
|
||
ReleaseMP
|
||
Move.L HFstFree(A6),(A1) ;Move old list head to MP.
|
||
Move.L A1,HFstFree(A6) ;Move handle to new list head.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Procedure MakePtrSpc(s: Size);
|
||
;
|
||
; Tries to create a free space of size s as low in the heap as possible
|
||
; by locating the first possible region and then calling MakeSpace.
|
||
;
|
||
; Added patch code from MSMiscFix after call to MakeSpace. It used to be <29jan85>
|
||
; patched in when the call chain got all the way to growZone. The reasoning
|
||
; here is that the code is only executed when the return value in A2 is NIL,
|
||
; in which case, growZone MUST HAVE BEEN CALLED.
|
||
;
|
||
; Change the patch code to just pass on to the next block strictly after that which <20May85>
|
||
; couldn't be relocated.
|
||
;
|
||
; Add code to run outer loop with OrgApplZone and then ApplZone in case GrowDown <14Apr85>
|
||
; is nonzero and zone is ApplZone. Saves new registers D4,A4.
|
||
; In order to keep ptrs as localized as possible, start trying to place them where the
|
||
; first was located, namely just after OrgApplZone. If that fails, then look down where
|
||
; heap may subsequently have grown. SUBTLETY -- since first block of original zone is
|
||
; a pointer full of MP's, it's OK to start search midstream at OrgApplZone+bkLim.
|
||
; The moral is: once an MP block, always an MP block!!
|
||
;
|
||
; Arguments:
|
||
; D0: s: size of block desired.
|
||
;
|
||
; Result:
|
||
; A2: bRgn: points to block header for reserved block, or Nil.
|
||
;
|
||
; Registers:
|
||
; D0: s: Size needed.
|
||
; D1: temporary
|
||
; D2: sRgn: cumulative count of bytes in current region.
|
||
; D3: temp flag for is-it-ApplZone in inner loop. <14Apr85>
|
||
; D4: temp flag for is-it-ApplZone in outer loop. <14Apr85>
|
||
; A0: bCur: points to current block.
|
||
; A1: temporary
|
||
; A2: bRgn: points to region start
|
||
; A3: bLim: points to last block in zone
|
||
; A4: points to 'apparent' start of zone in inner loop. <14Apr85>
|
||
;
|
||
; Called By: HMakeMoreMasters
|
||
; NewPtr,ResrvMem(Heap)
|
||
|
||
; ----- 24 bit version -----
|
||
a24MakePtrSpc
|
||
MoveM.L D0-D4/A0-A1/A3-A4,-(SP) ;Preserve registers, nowadays D4,A4, too. <14Apr85>
|
||
BSR a24ActualS ;Returns real sAct.
|
||
MoveA.l A6,A4 ;Presume it's not ApplZone case <14Apr85>
|
||
CmpA.L ApplZone,A6 ;If EQ & GrowDown then must fix A4 <14Apr85>
|
||
SEq D3 ;$FF if so (i.e. we can grow) <14Apr85>
|
||
|
||
; search for good region
|
||
|
||
@MPSpc1 ; <14Apr85>
|
||
LEA HeapData(A4),A0 ;Start at first block in 'heap' <14Apr85>
|
||
Move.L BkLim(A6),A3 ;Last block in zone
|
||
Move.L A0,A2 ;bRgn := first zone block ptr.
|
||
MoveQ #0,D2 ;sRgn := 0.
|
||
@RegionLoop
|
||
Move.L TagBC24(A0),D1 ;Block header
|
||
And.L MaskBC,D1 ;Byte count only
|
||
Tst.B TagBC24(A0) ;Is this block free?
|
||
BEq.S @1 ;Br if so (add to region)
|
||
BPl.S @2 ;Br if non-rel
|
||
Move.L Handle24(A0),A1 ;Handle offset.
|
||
Add.L A6,A1 ;Handle
|
||
Tst.B (A1) ;Is block locked?
|
||
BMi.S @2 ;Br if so
|
||
@1 Add.L D1,D2 ;Add to sRgn
|
||
Add.L D1,A0 ;Point to next block
|
||
Cmp.L D0,D2 ;Do we have enough?
|
||
BCS.S @4 ;Br if not
|
||
BSR a24MakeSpace ;MakeSpace(bRgn,s)
|
||
;
|
||
; Loop to relocate search in case growZone purged starting point. <29jan85>
|
||
; Labels offset by 90, to protect the innocent. <29jan85>
|
||
; Just relocate at next block beyond current end ptr in A0. <20May85>
|
||
@91 MOVE.L A2,D2 ; get the space? <29jan85>
|
||
BNE.S @96 ; br if so <29jan85>
|
||
LEA HeapData(A4),A2 ; start where the original search did <14Apr85>
|
||
@92 ; <29jan85>
|
||
MOVE.L TagBC24(A2),D1 ; get size of current block <29jan85>
|
||
AND.L MaskBC,D1
|
||
ADD.L D1,A2 ; point to next block <29jan85>
|
||
; <29jan85>
|
||
; The following snippet of code was foolishly omitted <14Apr86>
|
||
; from the Mac+ ROM. It turns out that RelocRel depends
|
||
; on there being an immovable block just below the handle
|
||
; being moved, so we skip ahead to the next FREE or
|
||
; IMMOVABLE, the point of the FREE being that SafeReloc
|
||
; will lock any leading free space down before calling RelocRel,
|
||
; thus effectively starting the painful process at a locked
|
||
; place.
|
||
TST.B TagBC24(A2) ; is this block free or locked? <14apr86>
|
||
BPL.S @93 ; free & non-rel blocks OK <14apr86>
|
||
MOVE.L Handle24(A2),A1 ; recover master pointer <14apr86>
|
||
ADD.L A6,A1 ; <14apr86>
|
||
TST.B (A1) ; is block locked? <14apr86>
|
||
BPL.S @94 ; skip if movable <14apr86>
|
||
@93 ; <14apr86>
|
||
CMP.L A0,A2 ; past or equal to current checkpt? <29jan85>
|
||
BHI.S @95 ; want HIgher, not CarryClear as before <20May85>
|
||
@94 ; <29jan85>
|
||
CMP.L A3,A2 ; end of heap reached? <29jan85>
|
||
BCS.S @92 ; br if not <29jan85>
|
||
@95 ; <29jan85>
|
||
MOVE.L A2,A0 ; A0 should now be cool <29jan85>
|
||
SUB.L A2,A2 ; restore A2 <29jan85>
|
||
@96 ; <29jan85>
|
||
; Now continue with the original MakePtrSpc code... <29jan85>
|
||
;
|
||
Move.L A2,D2 ;Did we find it?
|
||
BNE.S @MPSExit ;Exit if so
|
||
BRA.S @3 ;Otherwise, look some more.
|
||
@2 Add.L D1,A0 ;Point to next block
|
||
@3 Move.L A0,A2 ;bRgn := next block ptr.
|
||
MoveQ #0,D2 ;sRgn := 0. (next region)
|
||
@4 Cmp.L A3,A0 ;End of zone reached?
|
||
BCS.S @RegionLoop ;Loop if not
|
||
AddQ.B #1,D3 ;Try to grow zone?
|
||
BNE.S @MPSOuter ;Exit if not possible <14Apr85>
|
||
BSR a24GrowZone ;Do it
|
||
;
|
||
; EXCRUCIATING SUBTLETY HERE: Two cases can arise, A4 is OrgApplZone (which is <14Apr85>
|
||
; always a cool place to start searching, or A4 is an incarnation of ApplZone. <14Apr85>
|
||
; In the latter case, ApplZone may have changed as a result of the recent call to <14Apr85>
|
||
; GrowZone. Even though A4 may now be in the midst of a big new free block, <14Apr85>
|
||
; bkLim(A4) should nonetheless be the same block it was last time through the loop, <14Apr85>
|
||
; since no coalescing is done in GrowZone. <14Apr85>
|
||
; The following sequence would fix the problem by adjusting A4 if it turned out that<14Apr85>
|
||
; the first block after the previous ApplZone header could be coalesced. <14Apr85>
|
||
;
|
||
|
||
BrA.S @MPSpc1
|
||
|
||
@MPSOuter ;inner loop failed <14Apr85>
|
||
Sub.L A2,A2 ;No luck.
|
||
@MPSExit
|
||
MoveM.L (SP)+,D0-D4/A0-A1/A3-A4 ;Restore registers, D4&A4,too <14Apr85>
|
||
RTS ;Return to caller.
|
||
|
||
|
||
; ----- 32 bit version -----
|
||
a32MakePtrSpc
|
||
MoveM.L D0-D4/A0-A1/A3-A4,-(SP) ;Preserve registers, nowadays D4,A4, too. <14Apr85>
|
||
BSR a32ActualS ;Returns real sAct.
|
||
MoveA.l A6,A4 ;Presume it's not ApplZone case <14Apr85>
|
||
CmpA.L ApplZone,A6 ;If EQ & GrowDown then must fix A4 <14Apr85>
|
||
SEq D3 ;$FF if so (i.e. we can grow) <14Apr85>
|
||
|
||
; search for good region
|
||
|
||
@MPSpc1 ; <14Apr85>
|
||
LEA HeapData(A4),A0 ;Start at first block in 'heap' <14Apr85>
|
||
Move.L BkLim(A6),A3 ;Last block in zone
|
||
Move.L A0,A2 ;bRgn := first zone block ptr.
|
||
MoveQ #0,D2 ;sRgn := 0.
|
||
@RegionLoop
|
||
Move.L Blksize32(A0),D1 ;Block byte count <v1.1>
|
||
Tst.B TagBC32(A0) ;Is this block free?
|
||
BEq.S @1 ;Br if so (add to region)
|
||
BPl.S @2 ;Br if non-rel
|
||
|
||
Tst.B MPtag32(A0) ;is block locked? <v1.1>
|
||
BMi.S @2 ;Br if so
|
||
|
||
@1 Add.L D1,D2 ;Add to sRgn
|
||
Add.L D1,A0 ;Point to next block
|
||
Cmp.L D0,D2 ;Do we have enough?
|
||
BCS.S @4 ;Br if not
|
||
BSR a32MakeSpace ;MakeSpace(bRgn,s)
|
||
;
|
||
; Loop to relocate search in case growZone purged starting point. <29jan85>
|
||
; Labels offset by 90, to protect the innocent. <29jan85>
|
||
; Just relocate at next block beyond current end ptr in A0. <20May85>
|
||
@91 MOVE.L A2,D2 ; get the space? <29jan85>
|
||
BNE.S @96 ; br if so <29jan85>
|
||
LEA HeapData(A4),A2 ; start where the original search did <14Apr85>
|
||
@92 ; <29jan85>
|
||
MOVE.L BlkSize32(A2),D1 ; get size of current block <v1.1>
|
||
ADD.L D1,A2 ; point to next block <29jan85>
|
||
; <29jan85>
|
||
; The following snippet of code was foolishly omitted <14Apr86>
|
||
; from the Mac+ ROM. It turns out that RelocRel depends
|
||
; on there being an immovable block just below the handle
|
||
; being moved, so we skip ahead to the next FREE or
|
||
; IMMOVABLE, the point of the FREE being that SafeReloc
|
||
; will lock any leading free space down before calling RelocRel,
|
||
; thus effectively starting the painful process at a locked
|
||
; place.
|
||
TST.B TagBC32(A2) ; is this block free or locked? <v1.1>
|
||
BPL.S @93 ; free & non-rel blocks OK <14apr86>
|
||
|
||
TST.B MPtag32(A2) ; is block locked? <v1.1>
|
||
BPL.S @94 ; skip if movable <14apr86>
|
||
@93 ; <14apr86>
|
||
CMP.L A0,A2 ; past or equal to current checkpt? <29jan85>
|
||
BHI.S @95 ; want HIgher, not CarryClear as before <20May85>
|
||
@94 ; <29jan85>
|
||
CMP.L A3,A2 ; end of heap reached? <29jan85>
|
||
BCS.S @92 ; br if not <29jan85>
|
||
@95 ; <29jan85>
|
||
MOVE.L A2,A0 ; A0 should now be cool <29jan85>
|
||
SUB.L A2,A2 ; restore A2 <29jan85>
|
||
@96 ; <29jan85>
|
||
; Now continue with the original MakePtrSpc code... <29jan85>
|
||
;
|
||
Move.L A2,D2 ;Did we find it?
|
||
BNE.S @MPSExit ;Exit if so
|
||
BRA.S @3 ;Otherwise, look some more.
|
||
@2 Add.L D1,A0 ;Point to next block
|
||
@3 Move.L A0,A2 ;bRgn := next block ptr.
|
||
MoveQ #0,D2 ;sRgn := 0. (next region)
|
||
@4 Cmp.L A3,A0 ;End of zone reached?
|
||
BCS.S @RegionLoop ;Loop if not
|
||
AddQ.B #1,D3 ;Try to grow zone?
|
||
BNE.S @MPSOuter ;Exit if not possible <14Apr85>
|
||
BSR a32GrowZone ;Do it
|
||
;
|
||
; EXCRUCIATING SUBTLETY HERE: Two cases can arise, A4 is OrgApplZone (which is <14Apr85>
|
||
; always a cool place to start searching, or A4 is an incarnation of ApplZone. <14Apr85>
|
||
; In the latter case, ApplZone may have changed as a result of the recent call to <14Apr85>
|
||
; GrowZone. Even though A4 may now be in the midst of a big new free block, <14Apr85>
|
||
; bkLim(A4) should nonetheless be the same block it was last time through the loop, <14Apr85>
|
||
; since no coalescing is done in GrowZone. <14Apr85>
|
||
; The following sequence would fix the problem by adjusting A4 if it turned out that<14Apr85>
|
||
; the first block after the previous ApplZone header could be coalesced. <14Apr85>
|
||
;
|
||
|
||
BrA.S @MPSpc1
|
||
|
||
@MPSOuter ;inner loop failed <14Apr85>
|
||
Sub.L A2,A2 ;No luck.
|
||
@MPSExit
|
||
MoveM.L (SP)+,D0-D4/A0-A1/A3-A4 ;Restore registers, D4&A4,too <14Apr85>
|
||
RTS ;Return to caller.
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function MakeSpace(b: Block; dSize: Size): Block;
|
||
;
|
||
; Try to make a free block of size dSize starting at
|
||
; block b, and return a pointer to it.
|
||
;
|
||
; Changed exit code to set AllocPtr to be first block of OrgApplZone, so that search for <27Apr85>
|
||
; newly freed space will begin at correct place.
|
||
;
|
||
; Arguments:
|
||
; D0: dSize: amount of space needed at this address.
|
||
; A2: b: points to block header of first block in region.
|
||
;
|
||
; Result:
|
||
; A2: bAft: points to block header for succeeding block, or Nil.
|
||
;
|
||
; Registers:
|
||
; D0: s,t: Size needed, temp.
|
||
; D1: s: Size needed.
|
||
; D2: t: Temporary byte, used for flags byte of handle.
|
||
; D3: sCum: Cumulative free byte count.
|
||
; A0: bPur: points to block being purged.
|
||
; A0: bFree: points to block being freed.
|
||
; A1: bAft: points to block header for succeeding block.
|
||
; A1: h: Handle for block being purged, or otherwise munched.
|
||
; A2: bAft: points to block header for succeeding block.
|
||
; A3: bCur: points to block header of block currently being moved.
|
||
;
|
||
; Called By: SetSize,MakePtrSpc
|
||
|
||
; ----- 24 bit version -----
|
||
a24MakeSpace
|
||
MoveM.L A0-A1/A3/D0-D3,-(SP) ;Save registers.
|
||
|
||
Move.L D0,D1 ;Size needed.
|
||
Move.L A2,A3 ;Advances through following blks.
|
||
MoveQ #0,D3 ;Cumulative free byte count.
|
||
@MSpLoop
|
||
Cmp.L D1,D3 ;Enough room yet?
|
||
BCC.S @MSpDone ;Yes, exit loop.
|
||
|
||
Cmp.L BkLim(A6),A3 ;At end of zone?
|
||
BCC.S @MSpDone ;Yes, give up search.
|
||
|
||
Tst.B TagBC24(A3) ;Is this block free?
|
||
BEq.S @MSpFree ;Yes, let's grab it!
|
||
BPl.S @MSpDone ;Can't move a Non-Rel block.
|
||
|
||
Move.L Handle24(A3),A1 ;Get relative handle.
|
||
Add.L A6,A1 ;Convert to absolute handle.
|
||
Move.B (A1),D2 ;This block locked?
|
||
BMi.S @MSpDone ;Yes, give up.
|
||
|
||
BSR a24SafeReloc ;Move this block safely.
|
||
BEq.S @MSpFree ;All is well.
|
||
|
||
BTst #Purge,D2 ;Can we purge this block?
|
||
BEq.S @MSpDone ;No, give up.
|
||
|
||
Move.L (A1),A0 ;Set up pointer to purgeable.
|
||
SubQ.L #BlkData24,A0 ;Point to block text field.
|
||
BSR.S a24PurgeBlock ;Purge this block.
|
||
@MSpFree
|
||
Move.L A3,A0 ;Address of block being released.
|
||
Move.L TagBC24(A0),D0 ;Size of block
|
||
AndI.l #$00FFFFFF,AllocPtr(A6) ;<SM3> tcn
|
||
Cmp.L AllocPtr(A6),A0 ;Does the rover point here?
|
||
BNE.S @MSpNext ;Skip if not . . .
|
||
And.L Lo3Bytes,D0 ;isolate byte count
|
||
Add.L D0,AllocPtr(A6) ; <SM12> kc
|
||
@MSpNext
|
||
Add.L D0,D3 ;Inc. amount of space found.
|
||
Add.L D0,A3 ;Inc. base address of block.
|
||
BrA.S @MSpLoop ;Release or move next block.
|
||
@MSpDone
|
||
And.L MaskBC,D3 ;Extract only byte count.
|
||
BEq.S @1 ;No space found.
|
||
|
||
Move.L D3,TagBC24(A2) ;Set free block size.
|
||
@1
|
||
Cmp.L D1,D3 ;sFnd >= s?
|
||
BCC.S @MSpExit ;Yes, success return.
|
||
|
||
Sub.L A2,A2 ;reason to call MakeBkf . . .
|
||
@MSpExit
|
||
Move.l A2,AllocPtr(A6) ; let our children learn from us <SM12> kc
|
||
|
||
MoveM.L (SP)+,A0-A1/A3/D0-D3 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
; ----- 32 bit version -----
|
||
a32MakeSpace
|
||
MoveM.L A0-A1/A3/D0-D3,-(SP) ;Save registers.
|
||
|
||
Move.L D0,D1 ;Size needed.
|
||
Move.L A2,A3 ;Advances through following blks.
|
||
MoveQ #0,D3 ;Cumulative free byte count.
|
||
@MSpLoop
|
||
Cmp.L D1,D3 ;Enough room yet?
|
||
BCC.S @MSpDone ;Yes, exit loop.
|
||
|
||
Cmp.L BkLim(A6),A3 ;At end of zone?
|
||
BCC.S @MSpDone ;Yes, give up search.
|
||
|
||
Tst.B TagBC32(A3) ;Is this block free?
|
||
BEq.S @MSpFree ;Yes, let's grab it!
|
||
BPl.S @MSpDone ;Can't move a Non-Rel block.
|
||
|
||
Move.L Handle32(A3),A1 ;Get relative handle.
|
||
Add.L A6,A1 ;Convert to absolute handle.
|
||
Move.B MPtag32(A3),D2 ;Get master pointer tag byte <v1.1>
|
||
BMi.S @MSpDone ;Yes, give up.
|
||
|
||
BSR.S a32SafeReloc ;Move this block safely.
|
||
BEq.S @MSpFree ;All is well.
|
||
|
||
BTst #Purge,D2 ;Can we purge this block?
|
||
BEq.S @MSpDone ;No, give up.
|
||
|
||
Move.L (A1),A0 ;Set up pointer to purgeable.
|
||
Sub.L #BlkData32,A0 ;Point to block text field. <v1.1>
|
||
BSR.S a32PurgeBlock ;Purge this block.
|
||
@MSpFree
|
||
Move.L A3,A0 ;Address of block being released.
|
||
Move.L BlkSize32(A0),D0 ;Size of block <v1.1>
|
||
Cmp.L AllocPtr(A6),A0 ;Does the rover point here?
|
||
BNE.S @MSpNext ;Skip if not . . .
|
||
Add.L D0,AllocPtr(A6) ;Point to next block instead <SM12> kc
|
||
@MSpNext
|
||
Add.L D0,D3 ;Inc. amount of space found.
|
||
Add.L D0,A3 ;Inc. base address of block.
|
||
BrA.S @MSpLoop ;Release or move next block.
|
||
@MSpDone
|
||
Tst.L D3 ;is byte count zero <v1.1>
|
||
BEq.S @1 ;No space found.
|
||
|
||
Clr.L TagBC32(A2) ;set free block <v1.1>
|
||
Move.L D3,BlkSize32(A2) ;Set free block size. <v1.1>
|
||
@1
|
||
Cmp.L D1,D3 ;sFnd >= s?
|
||
BCC.S @MSpExit ;Yes, success return.
|
||
|
||
Sub.L A2,A2 ; reason to call MakeBkf . . . <SM12> kc
|
||
@MSpExit ; <SM12> kc
|
||
Move.L A2,AllocPtr(A6) ;let our children learn from us <SM12> kc
|
||
|
||
MoveM.L (SP)+,A0-A1/A3/D0-D3 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function SafeReloc(sCum: Size; h: Handle; bAft: Block): ErrCode;
|
||
;
|
||
; Safely relocates a relocatable block.
|
||
;
|
||
; Arguments:
|
||
; D3: sCum: cumulative free byte count.
|
||
; A1: h: Handle for block to be moved.
|
||
; A2: bAft: points to block header for block being built.
|
||
; A6: z: Zone holding block to be moved.
|
||
;
|
||
; Result:
|
||
; D0: ec: error code.
|
||
; memFullErr: No room to relocate block.
|
||
; 0: Success.
|
||
;
|
||
; Registers:
|
||
; D0: s: Size of block being built.
|
||
; A0: p: Pointer to block being moved.
|
||
; A0: ec: Saved error code.
|
||
;
|
||
; Called By: MakeSpace
|
||
|
||
; ----- 24 bit version -----
|
||
a24SafeReloc
|
||
Move.L A0,-(SP) ;Save register.
|
||
Move.L D3,D0 ;Is there a free block yet?
|
||
BEq.S @1 ;No, skip consistency code.
|
||
|
||
Move.L D3,TagBC24(A2) ;Set free block length.
|
||
Or.L #NRelTag,TagBC24(A2) ;Fake Non-Rel block.
|
||
Move.L A6,Handle24(A2) ;Including zone reference.
|
||
BSR.S SubtractFree ;Adjust free space for Non-Rel blk. <v1.7>
|
||
@1
|
||
Move.L (A1),A0 ;Get pointer to block from handle.
|
||
BSR.S a24GetSize ;Get logical size of block.
|
||
BSR.S a24RelocRel ;Move the block.
|
||
Move.L D0,A0 ;Save error code.
|
||
Move.L D3,D0 ;Cumulative free space.
|
||
BEq.S @2 ;Nothing so far, skip magic.
|
||
|
||
Move.L D3,TagBC24(A2) ;Make the block free again.
|
||
BSR.S AdjustFree ;Return space to space pool.
|
||
@2
|
||
Move.L A0,D0 ;Return error code and set cond.
|
||
Move.L (SP)+,A0 ;Restore register.
|
||
RTS ;Return to caller.
|
||
|
||
; ----- 32 bit version -----
|
||
a32SafeReloc
|
||
Move.L A0,-(SP) ;Save register.
|
||
Move.L D3,D0 ;Is there a free block yet?
|
||
BEq.S @1 ;No, skip consistency code.
|
||
|
||
Move.L D3,BlkSize32(A2) ;Set free block length. <v1.1>
|
||
Move.L #NRelTag,TagBC32(A2) ;Fake Non-Rel block. <v1.1>
|
||
Move.L A6,Handle32(A2) ;Including zone reference.
|
||
BSR.S SubtractFree ;Adjust free space for Non-Rel blk. <v1.7>
|
||
@1
|
||
Move.L (A1),A0 ;Get pointer to block from handle.
|
||
BSR.S a32GetSize ;Get logical size of block.
|
||
BSR.S a32RelocRel ;Move the block.
|
||
Move.L D0,A0 ;Save error code.
|
||
Move.L D3,D0 ;Cumulative free space.
|
||
BEq.S @2 ;Nothing so far, skip magic.
|
||
|
||
Clr.L TagBC32(A2) ;make free block <v1.1>
|
||
Move.L D3,BlkSize32(A2) ;Make the block free again. <v1.1>
|
||
BSR.S AdjustFree ;Return space to space pool.
|
||
@2
|
||
Move.L A0,D0 ;Return error code and set cond.
|
||
Move.L (SP)+,A0 ;Restore register.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function RelocRel(h: Handle; s: Size)
|
||
;
|
||
; RelocRel is used to relocate unlocked relocatables. It moves
|
||
; the text of the source block referred to by h to a new non relocatable
|
||
; block s long. Then it swaps data with the destination block,
|
||
; swaps block types (making the new block a relocatable and the old
|
||
; block a non-relocatable, and updating the master pointer), and
|
||
; releases the source block as a nonrelocatable.
|
||
;
|
||
; SetSize calls here to grow a relocatable block; the destination block size
|
||
; (used to allocate a new block) is therefore greater than the source data
|
||
; size (used as the number of bytes to move . . .). SafeReloc calls here
|
||
; simply to move a block out of the way: the desired new logical size, in this
|
||
; case is the same as the old . . . Since only SetSize cares whether block to
|
||
; be moved gets purged (which is still OK), change of purge bit is moved from here <10Apr85>
|
||
; to SetSize.
|
||
;
|
||
; This guy should set up(and release) GZMoveHnd for notifying the grow zone
|
||
; proc about the handle being moved.
|
||
;
|
||
; Grow zone IS allowed to purge the moving target, if not equal to GZRootHnd, BUT
|
||
; it is NEVER allowed to Dispose of it. (A reboot is in order if so...)
|
||
;
|
||
;
|
||
; Arguments:
|
||
; D0: s: Desired new logical size of block being moved.
|
||
; A1: h: Handle for block being moved.
|
||
; A6: z: Zone containing block being moved.
|
||
;
|
||
; Results:
|
||
; D0: ec: error code. (CCR doesn't reflect err code)
|
||
; memFullErr: No room to relocate block.
|
||
; 0: Success.
|
||
;
|
||
;
|
||
; Registers:
|
||
; D0: s: logical size of source, destination blocks; temp <06May85>
|
||
; D1: t: Temporary used to save flags byte.
|
||
; D2: Temporary while swapping tags fields. <06May85>
|
||
; A0: p: Points to source or destination blocks.
|
||
; A1: hNew: Handle for destination block.
|
||
; A1: pDst: Points to destination for blockmove.
|
||
; A2: hOld: Handle for block being moved.
|
||
;
|
||
; Called By: SafeReloc,SetSize
|
||
|
||
; ----- 24 bit version -----
|
||
a24RelocRel
|
||
MoveM.L D1-D2/A0-A2,-(SP) ;Save registers. <06May85>
|
||
Move.L A1,A2 ;Handle being moved
|
||
Move.L A1,GZMoveHnd ;record the moving target
|
||
; Don't mess with purge bit here -- let caller (SetSize) do it. <10Apr85>
|
||
|
||
Move.B (A2),D1 ;Save flags byte (for SafeReloc case) <23Apr85>
|
||
Sub.L A1,A1 ;get a nonrelocatable
|
||
BSR a24AllocBk ;Get a dest block, if we can.
|
||
BEq.S @RRFail ;No luck, restore flags and exit
|
||
|
||
; Note... if the object was purged,
|
||
; by GZ, by definition, there must
|
||
; be enough space to reallocate it
|
||
; (esp. if the size is the same -
|
||
; MakeSpace case), So A2 is valid
|
||
; for the exit through RRFail
|
||
|
||
Tst.L (A2) ;was object handle purged?
|
||
BEq.S @RRFree ;assume success
|
||
Move.L A0,A1 ;Points to destination block.
|
||
; <SM12> kc
|
||
Move.L (A2),D0 ;Points to source block <SM12> kc
|
||
And.L Lo3Bytes,D0 ;don't store the naughty bits <SM12> kc
|
||
Move.L D0,A0 ;Points to source block <SM12> kc
|
||
; <SM12> kc
|
||
BSR.S a24GetSize ;Get original size (for SetSize)
|
||
BSR HBlockMove ;Copy source to destination.
|
||
; (only logical bytes)
|
||
|
||
; Make the new nrel a rel, and vice versa. Do so preserving the leading nibble of tag <06May85>
|
||
; information and but not messing up the logical blocksize in the low nibble. <06May85>
|
||
; It's ugly, but someone has to do it.
|
||
; It's really ugly: $F0 is -$10, not -$F as first attempted. <13May85>
|
||
SubQ.L #8,A0 ;Source reloc block
|
||
SubQ.L #8,A1 ;Dest nrel block
|
||
MoveQ #-$10,D0 ;nibble mask = -$10 = $EF+1 = $F0 UGH! <13May85>
|
||
And.B (A0),D0 ;Source high nibble <06May85>
|
||
EOr.B D0,(A0) ;Clear high nibble <06May85>
|
||
MoveQ #-$10,D2 ;Mask for high nibble. <13May85>
|
||
And.B (A1),D2 ;Dest high nibble <06May85>
|
||
EOr.B D2,(A1) ;Clear high nibble <06May85>
|
||
Or.B D0,(A1) ;Dest becomes reloc <06May85>
|
||
Or.B D2,(A0) ;Source becomes nonreloc <06May85>
|
||
AddQ.L #4,A0 ;relative handle of original reloc <06May85>
|
||
AddQ.L #4,A1 ;relative handle of new nonreloc <06May85>
|
||
Move.L (A0),(A1)+ ;complete transformation of new block <06May85>
|
||
Move.L A1,(A2) ;point the master pointer here <06May85>
|
||
Move.B D1,(A2) ;Restore flags byte. <23Apr85>
|
||
Move.L A6,(A0)+ ;Source block is nrel now
|
||
@RRFree
|
||
BSR.S a24FreeBk ;Discard source block as nrel.
|
||
MoveQ #0,D0 ;Success return.
|
||
@RRExit
|
||
Clr.L GZMoveHnd ;clear the moving target
|
||
MoveM.L (SP)+,D1-D2/A0-A2 ;Restore registers. <06May85>
|
||
RTS ;Return to caller.
|
||
@RRFail
|
||
Move.B D1,(A2) ;Restore flags byte. <23Apr85>
|
||
MoveQ #memFullErr,D0 ;No room in memory to move block.
|
||
BrA.S @RRExit ;Common exit code.
|
||
|
||
|
||
; ----- 32 bit version -----
|
||
a32RelocRel
|
||
MoveM.L D1-D2/A0-A2,-(SP) ;Save registers. <06May85>
|
||
Move.L A1,A2 ;Handle being moved
|
||
Move.L A1,GZMoveHnd ;record the moving target
|
||
; Don't mess with purge bit here -- let caller (SetSize) do it. <10Apr85>
|
||
|
||
Sub.L A1,A1 ;get a nonrelocatable
|
||
BSR a32AllocBk ;Get a dest block, if we can.
|
||
BEq.S @RRFail ;No luck, restore flags and exit
|
||
|
||
; Note... if the object was purged,
|
||
; by GZ, by definition, there must
|
||
; be enough space to reallocate it
|
||
; (esp. if the size is the same -
|
||
; MakeSpace case), So A2 is valid
|
||
; for the exit through RRFail
|
||
|
||
Tst.L (A2) ;was object handle purged?
|
||
BEq.S @RRFree ;assume success
|
||
Move.L A0,A1 ;Points to destination block.
|
||
Move.L (A2),A0 ;Points to source block
|
||
BSR.S a32GetSize ;Get original size (for SetSize)
|
||
BSR HBlockMove ;Copy source to destination.
|
||
; (only logical bytes)
|
||
|
||
; Make the new nrel a rel, and vice versa. Do so preserving the leading nibble of tag <06May85>
|
||
; information and but not messing up the logical blocksize in the low nibble. <06May85>
|
||
; It's ugly, but someone has to do it.
|
||
; It's really ugly: $F0 is -$10, not -$F as first attempted. <13May85>
|
||
Sub.L #blkData32,A0 ;Source reloc block <v1.1>
|
||
Sub.L #blkData32,A1 ;Dest nrel block <v1.1>
|
||
Move.B tagBC32(A0),D0 ;get source tag <v1.1>
|
||
Move.B tagBc32(A1),D2 ;get dest tag <v1.1>
|
||
Move.B D0,tagBc32(A1) ;Dest becomes reloc <v1.1>
|
||
Move.B D2,tagBc32(A0) ;Source becomes nonreloc <v1.1>
|
||
Move.B MPtag32(A0),MPtag32(A1) ;copy master pointer tag <v1.1>
|
||
|
||
AddQ.L #handle32,A0 ;relative handle of original reloc <v1.1>
|
||
AddQ.L #handle32,A1 ;relative handle of new nonreloc <v1.1>
|
||
Move.L (A0),(A1)+ ;complete transformation of new block <06May85>
|
||
Move.L A1,(A2) ;point the master pointer here <06May85>
|
||
Move.L A6,(A0)+ ;Source block is nrel now
|
||
@RRFree
|
||
BSR a32FreeBk ;Discard source block as nrel.
|
||
MoveQ #0,D0 ;Success return.
|
||
@RRExit
|
||
Clr.L GZMoveHnd ;clear the moving target
|
||
MoveM.L (SP)+,D1-D2/A0-A2 ;Restore registers. <06May85>
|
||
RTS ;Return to caller.
|
||
@RRFail
|
||
MoveQ #memFullErr,D0 ;No room in memory to move block.
|
||
BrA.S @RRExit ;Common exit code.
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Procedure FreeBk(p: Ptr);
|
||
;
|
||
; Release block. If it is a relocatable block, release its master
|
||
; pointer as well.
|
||
;
|
||
; Arguments:
|
||
; A0: p: points to block to be freed.
|
||
; A6: z: zone in which block belongs.
|
||
;
|
||
; Results:
|
||
; None.
|
||
;
|
||
; Registers:
|
||
; D0: s: Size of block.
|
||
; D1: tag: Tag field of block.
|
||
; A0: b: Points to block header.
|
||
; A1: h: Handle for block.
|
||
;
|
||
; Called By: DisposePtr,DsposeHandle,RelocRel
|
||
|
||
|
||
; ----- 24 bit version -----
|
||
a24FreeBk
|
||
MoveM.L A0-A1/D0-D1,-(SP) ;Save registers.
|
||
|
||
SubQ.L #BlkData24,A0 ;Point to block header.
|
||
Move.L TagBC24(A0),D0 ;Tag and byte count.
|
||
Move.L D0,D1 ;Make a copy.
|
||
And.L MaskBC,D0 ;Extract byte count
|
||
EOr.L D0,D1 ;Tag, size delta only.
|
||
BEq.S @FBDone ;Free block, do nothing.
|
||
BPl.S @FBNRel ;Non-relocatable block.
|
||
|
||
Move.L Handle24(A0),A1 ;Handle offset.
|
||
Add.L A6,A1 ;Add base to make handle.
|
||
BSR.S ReleaseMP ;Release handle.
|
||
@FBNRel
|
||
BSR.S a24MakeCBkF ;Free block. <v1.5>
|
||
BSR.S AdjustFree ;Increase free space.
|
||
@FBDone
|
||
MoveM.L (SP)+,A0-A1/D0-D1 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
; ----- 32 bit version -----
|
||
a32FreeBk
|
||
MoveM.L A0-A1/D0-D1,-(SP) ;Save registers.
|
||
|
||
Sub.L #BlkData32,A0 ;Point to block header. <v1.1>
|
||
Move.L BlkSize32(A0),D0 ;get byte count. <v1.1>
|
||
Tst.B TagBC32(A0) ;test block <v1.1>
|
||
BEq.S @FBDone ;Free block, do nothing.
|
||
BPl.S @FBNRel ;Non-relocatable block.
|
||
|
||
Move.L Handle32(A0),A1 ;Handle offset.
|
||
Add.L A6,A1 ;Add base to make handle.
|
||
BSR.S ReleaseMP ;Release handle.
|
||
@FBNRel
|
||
BSR.S a32MakeCBkF ;Free block. <v1.5>
|
||
BSR.S AdjustFree ;Increase free space.
|
||
@FBDone
|
||
MoveM.L (SP)+,A0-A1/D0-D1 ;Restore registers.
|
||
RTS ;Return to caller.
|
||
|
||
|
||
|
||
;----------------------------------------------------------------------
|
||
;
|
||
; Function StdGZ(s: Size): Size; added <29jan85>
|
||
;
|
||
; Try to make space, and spare the user's GZProc in non-critical cases.
|
||
; Code lifted from MSMiscFix, our old patch file. Changes marked <29jan85> :
|
||
; 1) Labels prefixed by SGZ.
|
||
; 2) Pull MakePtrSpc patch stuff out.
|
||
;
|
||
; Arguments:
|
||
; 4(SP) s: Number of contiguous bytes needed.
|
||
;
|
||
; Result:
|
||
; (SP) dSize: Number of bytes added to zone by GrowZone Function.
|
||
;
|
||
; Registers:
|
||
; A1: return address
|
||
; A2: ptr to GZRootHnd, GZRootPtr, GZMoveHnd
|
||
; D3-D5: 3 temp GZxxx values (A2)
|
||
;
|
||
; Called By: CallGZProc
|
||
;
|
||
|
||
StdGZ
|
||
MOVE.L (SP)+,A1 ; return address <29jan85>
|
||
LEA GZRootHnd,A2
|
||
MOVEM.L (A2),D3-D5 ; D3=GZRootHnd, D4=GZRootPtr, D5=GZMoveHnd <29jan85>
|
||
TST.L D5 ; separate critical from non-critical . . .
|
||
BEQ.S SGZCritCase ; <29jan85>
|
||
CMP.L D3,D5 ; <29jan85>
|
||
BNE.S SGZPatchGPS ; <29jan85>
|
||
|
||
SGZCritCase BTST #FNGZResrv,Flags(A6) ; go directly to user growzone? <29jan85>
|
||
BNE.S SGZtoUserGZ ; br if so <29jan85>
|
||
|
||
MOVE.L (SP),D0 ; requested amount <29jan85>
|
||
CLR.L (A2)+ ; zero these locs for ResrvMem call <29jan85>
|
||
CLR.L (A2)+ ; (ResrvMem must be a non-critical <29jan85>
|
||
CLR.L (A2)+ ; case to prevent reentering) <29jan85>
|
||
MOVE.L TheZone,-(SP) ; save current zone <29jan85>
|
||
MOVE.L A6,TheZone
|
||
_ResrvMem ; try for memory this way . . . <29jan85>
|
||
MOVE.L (SP)+,TheZone ; restore current zone <29jan85>
|
||
MOVEM.L D3-D5,-(A2) ; restore GZRootHnd, GZRootPtr, GZMoveHnd <29jan85>
|
||
TST.L D0 ; did we get it? <29jan85>
|
||
BMI.S SGZtoUserGZ ; br if not (try user GZ proc) <29jan85>
|
||
@0 MOVE.L (SP)+,(SP) ; must be amount we got <29jan85>
|
||
JMP (A1) ; so return <29jan85>
|
||
|
||
; come here in all non-critical cases . . . <29jan85>
|
||
SGZPatchGPS ; <29jan85>
|
||
BTST #FGZAlways,Flags(A6) ; always call user GZ proc? <29jan85>
|
||
BNE.S SGZtoUserGZ ; br if so <29jan85>
|
||
; otherwise do our non-critical trip <29jan85>
|
||
SGZNonCrit ADDQ #4,SP ; remove requested amount from stack <29jan85>
|
||
JMP (A1)
|
||
|
||
; Set up call to user's proc, because the above failed. <29jan85>
|
||
SGZtoUserGZ ; <29jan85>
|
||
MOVE.L GZProc(A6),D2 ; user growzone proc <29jan85>
|
||
BEQ.S SGZNonCrit ; exit if none <29jan85>
|
||
MOVE.L A1,-(SP) ; restore memory manager return address <29jan85>
|
||
MOVE.L D2,-(SP) ; user proc <29jan85>
|
||
RTS ; go via user growzone <29jan85>
|
||
|
||
|
||
MemMgrEnd ; the last hurrah -- for build process <27Apr85>
|
||
|
||
|
||
END
|