sys7.1-doc-wip/OS/MemoryMgr/MemoryMgrExtensions.a
2019-07-27 22:37:48 +08:00

453 lines
18 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; File: MemoryMgrExtensions.a
;
; Contains: New routines for the Memory Mgr.
;
; Written by: A bunch of people. Merged into this file by Tim Nichols
;
; Copyright: © 1990-1993 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <SM4> 6/14/93 kc Roll in Ludwig.
; <LW2> 5/11/93 chp MoveHLow was depending on the CCR to indicate error conditions
; reported by _RecoverHandle. This weirdass trap only returns its
; result in MemErr, so insert an explicit test to avoid crashing
; in the subsequent _HGetState. Partial fix for RADAR #1081681.
; <SM3> 10/22/92 CSS Change some branch short instructions to word branches.
; <SM2> 7/10/92 RLM add CycloneTranslate24To32
; <1> 4/8/92 tcn New today. Code from MemoryMgrPatches.a
;
load 'StandardEqu.d'
MACHINE MC68020 ;<SM2> RLM
; ——————————————————————————————————————————————————————————————————————————————————————————————————
;
; MoveHLow
;
; entry:
; A0 - handle requested
; exit:
; D0 - error (word)
; internal:
; A4 - (long) handle to original block
; A3 - (long) pointer to new block
; D3 - (long) size of block
; D4 - (long) offset to block tags (24 = -8; 32 = -12)
; info:
; This code does the opposite in principle to MoveHHi. The handle input
; is moved as low as possible in the heap that it belongs. This call works
; with 24 and 32 bit zones.
; to do:
; • roving pointer point at newly freed block (is this good?)
myError EQU nsStackErr ;QuickDraw error meaning not enough stack
blkSize EQU -8 ;note that this offset is the same for 24/32 bit zones
StackSlop EQU (3*1024) ;3k slop for interupts and our minimal buffer
BlockTagBits EQU $C0 ;
MakeBlocksNonPurgeableStack record {a6Link},decr
startParams equ *
paramSize equ startParams-*
return ds.l 1
a6Link ds.l 1
HPurgeAddress ds.l 1 ;trap address for HPurge
hNoPurgeAddress ds.l 1 ;trap address for HNoPurge
RecoverHAddress ds.l 1 ;trap address for RecoverHandle
HGetStateAddress ds.l 1 ;trap address for HGetState
largestFreeSpace ds.l 1 ;size of largest free space available
freeSpaceAccumulator ds.l 1 ;a place to add up free space
keepCheckingFreeSpace ds.w 1 ;should we keep checking free space?
passedOurBlock ds.w 1 ;are we past our block yet?
localSize equ * ;size of all the local variables
endR
MoveHLow Proc Export
@Regs REG a3-a6/d3-d7
movem.l @Regs,-(sp) ;save regs
move.l theZone,-(sp) ;save theZone
move.l a0,a4 ;save callers A0,
; original MoveHHi did this
;check for nil master pointer
move.w #nilHandleErr,MemErr ;
move.l (a0),d0 ;check for nil MP
beq @RestoreZoneStateAndExit ;
;check for locked handle passed in, and save the state of the handle
;move.l a4,a0 ;get handle to original block
_HGetState ;
move.b d0,d2 ;save handle state of original block
move.w #memLockedErr,MemErr ;
btst #lock,d0 ;
bne @RestoreZoneStateAndExit ; <SM3> CSS
;set theZone to zone that this handle lives in
move.l a4,a0 ;get handle to original block
_HandleZone ;
tst.w d0 ;
bne @RestoreZoneStateAndExit ; <SM3> CSS
move.l a0,theZone ;temporarily set theZone to contain block
;set up offset in d4 to MemMgr Block tags (be 24/32 bit zone friendly)
moveq #-8,d4 ;-8 offset MemMgr Block tags in 24 zone
move.l Lo3Bytes,d6 ;setup mask for MakeBlocksNonPurgeable
tst.b maxNRel(a0) ;check if 32 zone
beq.s @not32bitzone ;
add.l #-4,d4 ;-12 offset MemMgr Block tags in 32 zone
moveq #-1,d6 ;setup mask for MakeBlocksNonPurgeable
@not32bitzone
;mark all purgeable blocks as non-purgeable when/if we call Newptr
;mark our block as non-purgeable
move.l a4,a0 ;get handle to original block
_HNoPurge
;always allocate a buffer on the stack
link A6,#MakeBlocksNonPurgeableStack.localSize ;Unlk A6 happens in RestorePurgeableBlocks
clr.l -(sp) ;ensure end of handle list is a nil
bsr MakeBlocksNonPurgeable ; <SM3> CSS
bne.s @DoCommonExit ;condition codes are set for failure
;allocate block of same size in lower in this heap. (first get size of handle)
move.l a4,a0 ;get handle to original block
_GetHandleSize ;
move.l d0,d3 ;save size of block and check for error
bmi.s @DoCommonExit ;
_NewPtr ;d0 from _GetHandleSize
bne.s @DoCommonExit ;check for error
move.l a0,a3 ;save pointer to new block
;the result from NewPtr may actually be higher in memory than Handle passed in
;check for this and leave handle where it is
move.l (a4),d0 ;get pointer to old block
_StripAddress ;in 24 bit world, this call needed
cmp.l a0,d0 ;is new block higher in memory than old?
blt.s @DisposeBlock ;yes, go dispose the new block
;copy junk from old handle to new pointer
move.l a0,a1 ;set up destination for blockmove
move.l (a4),a0 ;set up source for blockmove
move.l d3,d0 ;set up size for blockmove
_BlockMove
;make the handle point at the new block, and make the old block a pointer block
;fix relhandle
;move.l (a4),a0 ;point a0 at old block
move.l -(a0),-4(a3) ;fix relhandle for new block
move.l theZone,(a0)+ ;change relhandle to pointer block info
;change master pointer to point at new
move.l a3,(a4) ;no more references to old block
;mark old block as pointer block, and new block as relocateable
eori.b #BlockTagBits,(a3,d4) ;toggle new block from nonrel to rel
eori.b #BlockTagBits,(a0,d4) ;toggle old block from rel to nonrel
;Dispose of the old block (this frees the block)
@DisposeBlock
_DisposePtr
;fall through to exit code (ResoreHandleStateAndExit)
@DoCommonExit ;
;walk the heap to restore Purgeable Blocks and cleanup the stack
bsr RestorePurgeableBlocks ;
move.l (sp)+,d0 ;remove the nil marker
unlk a6 ;distroy stack buffer
;restore the master pointer flags
move.w MemErr,d3 ;preserve MemErr across _HSetState call
move.l a4,a0 ;get handle to new block
move.b d2,d0 ;restore handle state of original block
_HSetState ;
move.w d3,MemErr ;restore MemErr after _HSetState call
;set up D0, fall through to exit code (RemoveStackBuffer)
moveq #0,d0 ;
@RestoreZoneStateAndExit
move.l (sp)+,theZone ;restore theZone
move.l a4,a0 ;preserve handle across MoveHHi
move.w MemErr,d0 ;make d0 agree with MemErr
movem.l (sp)+,@Regs ;restore regs, leave cc's unchanged
rts ;return without calling through
; ——————————————————————————————————————————————————————————————————————————————————————————————————
;
; MakeBlocksNonPurgeable
;
; entry:
; theZone - the zone we will walk
; d4 - negative size of heapblock header.
; exit :
; a0-a1 - trashed
; a2-a3 - unchanged
; a4 - unchanged; handle of block passed to MoveHLow
; a5 - trashed, used to jump through as return address
; a6 - should be used to unlink buffer on stack
; a7,sp - points to buffer on stack (first long is number of entries)
; d0 - error (long) (0 means no error, else bail; leave buffer on stack)
; d1 - trashed
; d2 - unchanged
; d3 - address of block passed to MoveHLow
; d4-d6 - unchanged
; d7 - trashed
;
; info:
; Walk the heap and mark purgeable blocks Non-purgeable. The problem is that
; the original MoveHHi did not purge any blocks. We need to save all purgeable
; handles, make a NewPtr call, and then restore them. Remember which
; blocks we change by putting the master pointers in a buffer on the stack.
; Warning! This routine leaves a buffer on the stack, which will be
; removed by calling RestorePurgeableBlocks. That means this routine
; cant save anything on the stack except master pointers.
;
; todo:
; ——————————————————————————————————————————————————————————————————————————————————————————————————
with MakeBlocksNonPurgeableStack
MakeBlocksNonPurgeable
move.l a3,d1 ;preserve a3 across call
move.l (sp)+,a5 ;get return address
;see if we can make a buffer with storage for at least entry
_StackSpace ;
sub.l #StackSlop,d0 ;need some slop on stack for interupts
bmi @ErrorExit ;
;initialize regs for @loop
;clear free space counters
;clear flags to see if we should check free space and if weve passed our block
;set up our block address for free space counter
;A1 points at end of stack buffer
;A3 points at first block in heap
;D7 points at end of heap
clr.l largestFreeSpace(a6) ;start with zero as the largest free space
clr.l freeSpaceAccumulator(a6) ;and the accumulator starts out empty, too
clr.w keepCheckingFreeSpace(a6) ;clear the flag for free space checks
clr.w passedOurBlock(a6) ;clear the flag for our block in the heap
move.l sp,a1 ;pointer to stack buffer
sub.l d0,a1 ;point to the end of the stack buffer
move.l (a4),d0 ;get address of our block
_StripAddress ;shave off nasty bits, cause were gonna compare against it
move.l d0,d3 ;keep block address in d3
move.l theZone,a3 ;get pointer to start of this zone
move.l bkLim(a3),d7 ;save end of heap
add.l #heapData,a3 ;skip past zone header
sub.l d4,a3 ;skip past heap block header
;this loop walks the heap, and marks all purgeable blocks non-purgeable
@loop
cmp.l a1,sp ;check if stack buffer is full
ble @ErrorExit ;no more room in buffer, signal error
cmp.l a3,d7 ;check if end of heap
blt @NormalExit ;successfull, exit loop
cmp.l a3,d3 ;check if were to our block
bgt.s @pastCheckForOurBlock ;if were not there, then move on
move.w #-1, passedOurBlock(a6) ;otherwise, set the flag that says were past our block
;now treat block passed in as a special case terminator for free space checks
cmp.l a3,d3
beq.s @resetFreeSpaceAccumulator
@pastCheckForOurBlock
;low two bits in d0 will be the block type
move.b (a3,d4),d0 ;get the blocktype
lsr.b #6,d0 ;only use the tag bits
;if free d0 = 0
beq.s @addToFreeSpaceAccumulator
@notFreeBlock
;bail if pointer block
cmp.b #tybkNRel,d0 ;check if pointer block
beq.s @resetFreeSpaceAccumulator ;advance to next block
;we are sure it is a relocateable block now, but check just in case.
cmp.b #tybkRel,d0 ;check if relocateable block
bne.s @resetFreeSpaceAccumulator ;if not relocatateable, error, go next?
;we have a pointer to the relocatable block, we need a handle to mark it non-purgeable
move.l a3,a0 ;set up pointer to block
_RecoverHandle ;if this fails, then this block is
;orphaned, and we can move it at will
tst.w MemErr ;(RecoverHandle result in MemErr only!) <LW2>
bmi.s @pastFreeSpaceChecks ;
;if already locked, we dont need to change its state
_HGetState ;
btst #lock,d0 ;check if handle is locked
bne.s @resetFreeSpaceAccumulator ;is locked, go to nextBlock
;last test, is it a purgeable block?
btst #purge,d0 ;check if handle is purgeable
beq.s @pastFreeSpaceChecks ;if not purgable go to nextBlock
;change its state, and save a handle to this block in our buffer.
_HNoPurge ;keep this block from purgeing
move.l a0,-(sp) ;save handle to this block on stack
bra.s @pastFreeSpaceChecks
;we found a relocatable or free block, so add this block to the possible space for our ptr
@addToFreeSpaceAccumulator
move.l blkSize(a3),d0 ;get size of this block
and.l d6,d0 ;strip off tags 24 bit world (32 is ok)
tst.w keepCheckingFreeSpace(a6) ;should we bother (have we passed our block)
bmi.s @endOfLoop ;dont bother if weve passed our block
add.l d0, freeSpaceAccumulator(a6) ;and add the size to the free space for this island
bra.s @endOfLoop
;we ran across an immovable block, so reset our counter and update the largest free area weve found
@resetFreeSpaceAccumulator
tst.w keepCheckingFreeSpace(a6) ;should we bother with this? (past our block?)
bmi.s @pastFreeSpaceChecks ;if the flag is set, skip the free space stuff
tst.w passedOurBlock(a6) ;have we (just now) passed our block in the heap
beq.s @pastPreflightCheck ;if the flag is not set, keep checking free spaces
;now comes the good part... should we bail out early because there isnt sufficient free space
;lower that our block in the heap?
move.l a3, -(sp) ;save block pointer, cause we need an address register
move.l d3,a3 ;put block passed in here
move.l blkSize(a3),d0 ;get size of our block
and.l d6,d0 ;strip off tags 24 bit world (32 is ok)
cmp.l largestFreeSpace(a6),d0 ;do we have room for our block lower in the heap?
move.l (sp)+, a3 ;put old block pointer back, dont affect cc
bgt.s @ErrorExit ;no room in heap, bail out!
move.w #-1,keepCheckingFreeSpace(a6) ;now that we have good news, stop checking free space
bra.s @pastFreeSpaceChecks
@pastPreflightCheck
move.l freeSpaceAccumulator(a6), d0 ;get the space we counted this time
cmp.l largestFreeSpace(a6), d0 ;see if the largest is still king of the hill
ble.s @pastFreeSpaceChecks ;if so, move on
move.l d0, largestFreeSpace(a6) ;else make a new king
clr.l freeSpaceAccumulator(a6) ;and clear the accumulator
@pastFreeSpaceChecks
move.l blkSize(a3),d0 ;get size of this block
and.l d6,d0 ;strip off tags 24 bit world (32 is ok)
;end of @loop, bump a3 to point at next block
@endOfLoop
add.l d0,a3 ;point at next block
bra @loop ;loop back for more
;if error occured, we must signal error by putting a zero count into stack buffer
@ErrorExit
move.w #myError,d0 ;signal an error to the main routine
move.w d0,MemErr ;set MemErr
bra.s @CommonExit ;exit through CommonExit
@NormalExit
moveq #0,d0 ;signal no error to the main routine
@CommonExit
;condition codes must be set at this point, caller depends on this
movea.l d1,a3 ;preserve a3 across call
jmp (a5) ;rts
endwith
; ——————————————————————————————————————————————————————————————————————————————————————————————————
;
; RestorePurgeableBlocks
;
; entry:
; A6 - should be used to unlink buffer on stack
; exit :
; D1 - trashed
; A5 - trashed
; A6 - restored
;
; info:
; Traverse the stack buffer and restore the saved handles to their purgeable
; state. Deallocate the stack buffer.
; Warning! This routine removes the buffer on the stack. This buffer was
; allocated by MakeBlocksNonPurgeable.
; todo:
; ——————————————————————————————————————————————————————————————————————————————————————————————————
RestorePurgeableBlocks
move.l (sp)+,a5 ;get return address
@loop
tst.l (sp) ;check for end of list
beq.s @ExitRestorePurgeableBlocks ;nil meant end of list
move.l (sp)+,a0 ;get handle
_HPurge ;mark as purgeable, ignore any error
bra.s @loop ;check if anymore
@ExitRestorePurgeableBlocks
jmp (a5) ;return to caller
EndProc
; ——————————————————————————————————————————————————————————————————————————————————————————————————
; •••••••••••••••••••••••••• Patch for CycloneTranslate24To32 •••••••••••••••••••••••••• <P8> RMP
;
; FUNCTION CycloneTranslate24To32(Addr24: long): Addr32;
;
; Translate an Cyclone 24-bit address to a valid Cyclone 32-bit address.
;
; INPUT D0=Addr24;
; OUTPUT D0=Addr32;
;
; All other registers preserved
;
; Translation algorithm from Cyclone Hardware ERS:
;
; Old first 3 nibbles New first 3 nibbles
; ------------------- -------------------
; xx0 000
; : :
; xx7 007
; xx8 400-->408 for safety in 24 bit mode; also since the emulator doesn't alias
; xx9 409 second meg of ROM is in tradional slot 9 space.
; xxA FA0
; : :
; xxE FE0
; xxF 500
;
;
;
; NOTE: Unlike _StripAddress, this routine does not necessarily
; return an address which can also be used in 24 bit mode.
; Furthermore, Translate24To32 can not be called meaningfully
; with the result of a previous translation.
;
;
;
CycloneTranslate24To32 Proc Export
AND.L Lo3Bytes,D0 ;Clean high byte for fast exit
BCLR #23,D0 ;Is the address in RAM?
BNE.S @NotRam ;no, go patch up address
RTS ;quick exit
@NotRam MOVE.W D1,-(SP) ;save a work register
SWAP D0 ;get relevant nibbles into low word
MOVE.W D0,D1 ;...and into index register
LSR.W #4,D1 ;move nibble 3 to use as index
AND.W (@TABLE+2,PC,D1.W*4),D0 ;mask off bits that will be added.
ADD.W (@TABLE,PC,D1.W*4),D0 ;translate by adding table value
SWAP D0 ;move translated nibbles back to high word
MOVE.W (SP)+,D1 ;restore work register
RTS
@TABLE
DC.W $4080,$FFFF ; 008x -> 408x
Dc.w $4080,$FFFF ; 009x -> 409x
Dc.w $FA00,$000F ; 00Ax -> FA0x
Dc.w $FB00,$000F ; 00Bx -> FB0x
Dc.w $FC00,$000F ; 00Cx -> FC0x
Dc.w $FD00,$000F ; 00Dx -> FD0x
Dc.w $FE00,$000F ; 00Ex -> FE0x
Dc.w $5000,$000F ; 00Fx -> 500x
ENDPROC
end