mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-29 07:29:15 +00:00
0ba83392d4
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
314 lines
12 KiB
Plaintext
314 lines
12 KiB
Plaintext
;
|
|
; File: DispatchHelper.a
|
|
;
|
|
; Written by: Jeff Miller
|
|
;
|
|
; Contains: Code implementing the generic dispatcher (DispatchHelper) and generic procedure
|
|
; dispatcher (ProcHelper). Both are installed as OSTraps, but they should always
|
|
; be called from the low memory vector rather than through the trap mechanism.
|
|
;
|
|
; Copyright: © 1990-1991 by Apple Computer, Inc., all rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <8> 8/29/91 JSM Cleanup header.
|
|
; <7> 10/22/90 JSM <dba> Use dispatchFlags equates and DispatchUnimplementedRoutine
|
|
; macro, add support for more efficient linked patch dispatching
|
|
; with absolute addresses, don't support NULL dispatch table
|
|
; entries anymore for more efficient dispatching, misc. other
|
|
; optimizations.
|
|
; <6> 9/25/90 KIP Change it back to a linked patch.
|
|
; <5> 8/9/90 gbm LinkPatch REALLY hates main modules...
|
|
; <4> 8/8/90 SAM Making DispatchHelper & ProcHelper load as an old style ptch.
|
|
; ¥¥¥---> Temporary <---¥¥¥ remove this when the Sound Mgr code is
|
|
; converted to a linked patch (as it should be).
|
|
; <3> 7/12/90 STB Moved _ProcHelper & _DispatchHelper patch installation code from
|
|
; MiscPatches.a to here.
|
|
; <2> 7/8/90 JSM ProcHelper takes a pointer to use count instead of an offset
|
|
; now.
|
|
; <1> 7/7/90 JSM First checked in.
|
|
;
|
|
|
|
LOAD 'StandardEqu.d'
|
|
INCLUDE 'DispatchHelperPriv.a'
|
|
INCLUDE 'LinkedPatchMacros.a'
|
|
|
|
;___________________________________________________________________________________
|
|
; These linked patches are installed on all ROM families
|
|
;
|
|
ROMs Plus,SE,II,Portable,IIci
|
|
|
|
;___________________________________________________________________________________
|
|
; DispatchHelper
|
|
;
|
|
; A generic dispatcher. Assumes all routines it dispatches to are
|
|
; Pascal functions returning an OSErr. Installed as OS trap $A0EC, but
|
|
; should always be called directly through the vector at $7B0.
|
|
;
|
|
; Selectors are in D0.W, with the low byte containing the actual selector
|
|
; and the high byte containing the number of words of parameters on the
|
|
; stack.
|
|
;
|
|
; Uses a standard DispatchHelperTable specifying the valid selector range and
|
|
; offsets to each routine.
|
|
;
|
|
; If the low byte of D0 is out of range, DispatchHelper strips the parameters
|
|
; off the stack and returns paramErr.
|
|
;
|
|
; If bit 1 (dhAbsoluteEntries) of dispatchFlags in the DispatchHelperTable is set,
|
|
; DispatchHelper assumes that the entries in the dispatch table are 4 byte absolute
|
|
; addresses (used mainly in linked patches). Otherwise, entries in the dispatch
|
|
; table are 2 byte offsets from the beginning of the table to the actual routine.
|
|
;
|
|
; If bit 0 (dhSelectorsEven) of dispatchFlags in the DispatchHelperTable is set,
|
|
; DispatchHelper assumes that the selector in D0 is already even and doesn't multiply
|
|
; it by two to get to the offset. Note that all even selectors are currently unsupported
|
|
; for absolute address dispatch tables.
|
|
;
|
|
; General implementation strategy: since absolute addresses are used by linked patches in
|
|
; some very common cases (for example: dialogs, windows, and menus), we want that case to
|
|
; execute the fastest (i.e. with the fewest branches). Note that trying to overload
|
|
; dispatchFlags too much goes against the original intent of DispatchHelper, which is
|
|
; speed.
|
|
;
|
|
; Inputs:
|
|
; A0 Pointer to DispatchHelperTable.
|
|
; D0.W Low byte is selector, high byte is number of words of parameters.
|
|
;
|
|
; Outputs:
|
|
; D0.W untouched
|
|
;
|
|
; Destroys:
|
|
; D1, A0
|
|
;
|
|
;___________________________________________________________________________________
|
|
DispatchHelper PatchProc _DispatchHelperTrap
|
|
|
|
WITH DispatchHelperTable
|
|
MOVE.W D0,D1 ; get selector in D1 so we don't touch D0
|
|
;
|
|
; Make sure the selector is in range
|
|
;
|
|
CMP.B lastSelector(A0),D1 ; is selector too large?
|
|
BGT.S DispatchHelperBadSelector ; yes, cleanup and return
|
|
SUB.B firstSelector(A0),D1 ; get absolute zero-based selector
|
|
BLT.S DispatchHelperBadSelector ; if too small, cleanup and return
|
|
;
|
|
; Selector is in range, now dispatch
|
|
; Since we only support dhAbsoluteEntries or dhSelectorsEven, but never both
|
|
; at the same time, we can do a CMP, which is faster than a BTST.
|
|
;
|
|
EXT.W D1 ; selector OK, make it a word
|
|
CMP.W #(1<<dhAbsoluteEntries),dispatchFlags(A0) ; are entries absolute addresses?
|
|
BNE.S @offsetEntries ; no, they're word offsets
|
|
|
|
;
|
|
; Entries in DispatchHelperTable are absolute addresses (used in linked patches)
|
|
;
|
|
ASL.W #2,D1 ; convert to offset from firstAddress
|
|
MOVE.L firstAddress(A0,D1.W),A0 ; A0 = absolute address of routine entry point
|
|
JMP (A0) ; jump to entry point
|
|
|
|
;
|
|
; Entries in DispatchHelperTable are word offsets from beginning
|
|
;
|
|
@offsetEntries
|
|
CMP.W #(1<<dhSelectorsEven),dispatchFlags(A0) ; are selectors even?
|
|
BEQ.S @D1IsOffset ; yes, no need to double D1
|
|
ADD.W D1,D1 ; convert to offset from firstOffset
|
|
@D1IsOffset
|
|
MOVE.W firstOffset(A0,D1.W),D1 ; D1.W = routine offset from DispatchHelperTable
|
|
ADD.W D1,A0 ; A0 = actual routine entry point
|
|
JMP (A0) ; jump to entry point
|
|
|
|
ENDWITH ; DispatchHelperTable
|
|
|
|
;
|
|
; Selector is out of range, clean up stack and return paramErr
|
|
;
|
|
EXPORT DispatchHelperBadSelector ; so Dispatcher linked patch macro can reference it
|
|
DispatchHelperBadSelector
|
|
DispatchUnimplementedRoutine ; cleans up stack and returns to caller
|
|
|
|
ENDPROC ; DispatchHelper
|
|
|
|
;___________________________________________________________________________________
|
|
; ProcHelper
|
|
;
|
|
; A resource-based procedure dispatcher. Assumes all routines it dispatches
|
|
; to are Pascal functions returning an OSErr. Originally designed for
|
|
; use with PACKs, but will work with all resource-based code of the correct
|
|
; format. Installed as OS trap $A09A, but should always be called directly
|
|
; through the vector at $668.
|
|
;
|
|
; Uses DispatchHelper, so selectors are in D0.W, with the low byte containing
|
|
; the actual selector and the high byte containing the number of words of
|
|
; parameters on the stack.
|
|
;
|
|
; A0 should be a handle to the procedure resource ('PACK', 'proc', or
|
|
; whatever) that begins with a ProcHelperHeader. If the handle is NIL,
|
|
; returns memFullErr. If the handle has been purged, and LoadResource fails,
|
|
; returns ResError. In either case, the parameters are stripped of the stack
|
|
; before returning.
|
|
;
|
|
; For maximum memory usage benefits, procedure resources should be purgeable.
|
|
;
|
|
; A1 should be a pointer to a word of globals ProcHelper can use to store a
|
|
; use count for this resource. The word should be initialized to 0 before
|
|
; ProcHelper is called the first time for a resource. ProcHelper uses this
|
|
; count to handle locking and unlocking the resource. ProcHelper updates
|
|
; this use count be changing the return address to always come back through
|
|
; ProcHelperReturn. See the ERS for more details on the stack manipulation
|
|
; used to do this, but here is an example of what happens to the stack
|
|
; when there are three words of parameters:
|
|
;
|
|
; On entry to called routine
|
|
;
|
|
; +--------+--------+
|
|
; | ProcHelperReturn|
|
|
; +--------+--------+
|
|
; | param3 | param2 |
|
|
; On entry to ProcHelper +--------+--------+
|
|
; | param1 | OSErr |
|
|
; +--------+--------+ +--------+--------+
|
|
; | return address | | return address |
|
|
; +--------+--------+ +--------+--------+
|
|
; | param3 | param2 | | use count ptr |
|
|
; +--------+--------+ +--------+--------+
|
|
; | param1 | OSErr | | proc handle |
|
|
; +--------+--------+ +--------+--------+
|
|
;
|
|
; Inputs:
|
|
; D0.W Low byte is selector, high byte is number of words of parameters.
|
|
; A1 Pointer to the use count global for this procedure
|
|
; A0 Handle to procedure resource
|
|
;
|
|
; Outputs:
|
|
; When branching to DispatchHelper:
|
|
; A0 Pointer to DispatchHelperTable.
|
|
; D0.W Low byte is selector, high byte is number of words of parameters.
|
|
;
|
|
; When returning to application:
|
|
; None
|
|
;
|
|
; Destroys:
|
|
; When branching to DispatchHelper:
|
|
; D1, D2, A1
|
|
;
|
|
;___________________________________________________________________________________
|
|
|
|
ProcHelper PatchProc _ProcHelperTrap
|
|
|
|
;
|
|
; Reload procedure resource, if necessary
|
|
;
|
|
MOVE.L A0,D1 ; is the procedure handle NIL?
|
|
BEQ.S ResHandleNil ; no handle -> resource gone
|
|
TST.L (A0) ; is procedure pointer NIL?
|
|
BNE.S @resLoaded ; no, we're OK
|
|
|
|
MOVE.L A0,-(SP) ; push handle for LoadResource
|
|
MOVE.W #MapTrue,ROMMapInsert ; use ROM map as well ???
|
|
_LoadResource ; Note: preserves ALL registers
|
|
|
|
TST.L (A0) ; Did load fail?
|
|
BEQ.S ResNotLoaded ; NIL handle -> could not load
|
|
|
|
@resLoaded
|
|
;
|
|
; Check use count to see if there is already a call in progress
|
|
;
|
|
TST.W (A1) ; is there a call in process (count <> 0)?
|
|
BNE.S @procNowLocked ; yes, not first time through
|
|
|
|
;
|
|
; This is the first call, so lock down the procedure resource
|
|
;
|
|
MOVE.W D0,-(SP) ; save selector on stack across HLock
|
|
_HLock ; lock down resource
|
|
MOVE.W (SP)+,D0 ; restore selector
|
|
|
|
@procNowLocked
|
|
ADDQ.W #1,(A1) ; increment use count
|
|
MOVE.L A1,D2 ; save ptr to use count
|
|
|
|
;
|
|
; Make space on stack for moving parameters down and saving of
|
|
; old return address, use count pointer, and resource handle
|
|
;
|
|
SUBQ #8,SP ; need two longs for use count ptr and proc handle
|
|
PEA ProcHelperReturn ; return to this address after call
|
|
MOVE.L 12(SP),-(SP) ; save off real return address
|
|
|
|
;
|
|
; Loop through number of words of parameters, moving them down each time
|
|
;
|
|
|
|
MOVE.W D0,D1 ; D1.W = selector
|
|
LSR.W #8,D1 ; D1.W = words of parameters
|
|
LEA 8(SP),A1 ; get ptr to place to put parameters
|
|
@moveLoop
|
|
MOVE.W 12(A1),(A1)+ ; D0.W = current parameter
|
|
DBRA D1,@moveLoop ; continue moving parameters
|
|
|
|
;
|
|
; Save off needed values underneath the parameters we just moved
|
|
;
|
|
MOVE.L (SP)+,(A1)+ ; save real return address
|
|
MOVE.L D2,(A1)+ ; save ptr to use count
|
|
MOVE.L A0,(A1)+ ; save handle to proc
|
|
|
|
;
|
|
; Set up A0 to point to DispatchTable, then branch to dispatcher
|
|
;
|
|
MOVE.L (A0),A0 ; A0 = pointer to proc header
|
|
ADD.L #ProcHelperHeader.ProcDispTable,A0 ; A0 = pointer to start of dispatch table
|
|
_DispatchHelper ; call DispatchHelper through vector
|
|
|
|
;
|
|
; Procedure called through DispatchHelper returns to here
|
|
;
|
|
ProcHelperReturn
|
|
MOVE.W (SP)+,D1 ; D1.W = returned OSErr
|
|
MOVE.L (SP)+,A1 ; get real return address
|
|
MOVE.L (SP)+,A0 ; get pointer to use count
|
|
SUBQ.W #1,(A0) ; decrement use count
|
|
MOVE.L (SP)+,A0 ; get handle to procedure resource
|
|
BNE.S @stillInUse ; if use count not zero, still calls processing
|
|
_HUnlock ; unlock procedure resorce in A0
|
|
@stillInUse
|
|
MOVE.W D1,-(SP) ; restore returned OSErr
|
|
JMP (A1) ; return to proc caller
|
|
|
|
|
|
ResHandleNil
|
|
;
|
|
; No handle for procedure, return memFullErr
|
|
;
|
|
MOVE.W #memFullErr,D1 ; put error in D1.W
|
|
BRA.S ProcHelperError ; and return
|
|
|
|
ResNotLoaded
|
|
;
|
|
; Could not reload the procedure resource, return ResError
|
|
;
|
|
MOVE.W ResErr,D1 ; get ResError() in D1.W
|
|
;BRA.S ProcHelperError ; fall through to ProcHelperError
|
|
|
|
;
|
|
; An error occurred before the dispatch could happen.
|
|
; Clean up the stack, and return to caller with error code in D1.W.
|
|
;
|
|
|
|
ProcHelperError
|
|
MOVE.L (SP)+,A0 ; get caller's return address
|
|
LSR.W #8,D0 ; D0.W = words of parameters
|
|
LSL.W #1,D0 ; D0.W = bytes of parameters
|
|
ADD.W D0,SP ; strip off parameters
|
|
MOVE.W D1,(SP) ; return error in D1.W
|
|
JMP (A0) ; return to caller
|
|
|
|
ENDPROC ; ProcHelper
|
|
|
|
END
|