mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2026-01-23 13:20:49 +00:00
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.
928 lines
38 KiB
Plaintext
928 lines
38 KiB
Plaintext
;
|
|
; File: SegmentLoader.a
|
|
;
|
|
; Contains: Segment Loader for Macintosh Operating System
|
|
;
|
|
; Written by: Andy Hertzfeld 09-May-83
|
|
;
|
|
; Copyright: © 1983-1992 by Apple Computer, Inc. All rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM10> 11/12/92 PN Get rid of ³ 020 conditionals for ROM builds
|
|
; <SM9> 11/3/92 SWC Changed PaletteEqu.a->Palettes.a.
|
|
; <SM8> 10/22/92 CSS Change some branch short instructions to word branches.
|
|
; <SM7> 6/26/92 kc ReRoll in Terror SegLoad Patch. From Terror OverPatch.a:
|
|
; <T13> 7/10/91 RP Removed MPW SegLoad fix. Fix was made in FlushCacheRange.
|
|
; <T10> 6/26/91 RP Patched LoadSeg & UnloadSeg to use FlushCacheRange.
|
|
; <SM6> 5/16/92 kc Remove onHcMac code and conditional.
|
|
; <SM5> 4/14/92 stb change process mgr CODE segment fetches to 'scod'
|
|
; <4> 3/27/92 JSM Moved this file to SegmentLoader folder, keeping all the old
|
|
; revisions, to reflect current Reality structure.
|
|
; <3> 3/9/92 PN Adding machine MC68020 directive
|
|
; <2> 3/6/92 RB Flush Cache range inside LoadSeg and UnloadSeg instead of just
|
|
; invalidating the caches.
|
|
; <7> 9/27/91 JSM Cleanup header, donÕt use hasCQD conditional since all future
|
|
; ROMs will have color QuickDraw.
|
|
; <6> 6/12/91 LN removed #include 'HardwareEqu.a'
|
|
; <5> 3/12/91 CCH Removed the cache flush at the beginning of LoadSeg, since we
|
|
; flush it at the end. Also moved cache flush in UnLoadSeg to the
|
|
; end of the routine.
|
|
; <4> 8/27/90 CCH Modified <3> to make sure it only gets done on 040s. Also
|
|
; removed the -eclipseDebug- conditional since it will always
|
|
; apply to 040s.
|
|
; <3> 6/22/90 CCH Added cache push for 68040 machines after jump table is created
|
|
; to avoid cache incoherency problems.
|
|
; <2> 1/12/90 CCH Added include of ÒHardwarePrivateEqu.aÓ.
|
|
; <1.7> 7/12/89 GGD Added conditional hasCQD around call to PMgrExit, to fix non-CQD
|
|
; machines.
|
|
; <1.6> 7/8/89 BAL <dvb> Added PMgrExit call to ExitToShell.
|
|
; 7/8/89 dvb Added call to PMgrExit in ExitToShell.
|
|
; <1.5> 4/11/89 GGD Changed FPUin to the proper equate hwCbFPU to clean up
|
|
; HardwareEqu.a, deleted usage of nequ.d.
|
|
; <1.4> 3/20/89 MSH Fixed a conditional.
|
|
; <1.3> 2/20/89 rwh changed to feature-based conditionals.
|
|
; <1.2> 1/30/89 GGD Added unconditional call to CacheFlush in _LoadSeg/_UnloadSeg,
|
|
; to allow better support for 68020/030s in the 68000 ROMs.
|
|
; <1.1> 11/10/88 CCH Fixed Header.
|
|
; <1.0> 11/9/88 CCH Adding to EASE.
|
|
; <¥1.1> 9/23/88 CCH Got rid of inc.sum.d and empty nFiles
|
|
; <1.0> 2/10/88 BBM Adding file for the first time into EASEÉ
|
|
; <C914> 10/29/87 rwh Port to Modern Victorian (onMvMac)
|
|
; <C800> 2/12/87 JTC Clear (a5) on launch in case someone (like old MacWrites) goes
|
|
; snooping for QD globals before InitGraf time. Also, adjust C741
|
|
; alignment to just AFTER the Òabove A5Ó amount has been taken
|
|
; from SP.
|
|
; <C749> 2/3/87 bbm changed the way the 68881 is inited on launch.
|
|
; <C741> 2/2/87 JTC Try to longword align the A5 world.
|
|
; <C707> 1/27/87 RDC Removed check for debugger installed in Launch code
|
|
; <C681> 1/24/87 JTC Moved init stuff in Launch to InitApplZone, where it may
|
|
; actually belong. Made last-minute app start-up code subject to
|
|
; new vector jLaunchInit.
|
|
; <C668> 1/22/87 bbm added a vector to flush the cache in LoadSeg and UnLoadSeg. For
|
|
; overkill, and because the vCacheFlush trashes D1, we preserve D1
|
|
; across call.
|
|
; <C548> 12/19/86 bbm kill all outstanding sounds on Launch
|
|
; <C490> 12/8/86 EMT Launch & Chain now put ROMBase+64K in address 0 if debugger is
|
|
; not installed
|
|
; <C482> 12/4/86 bbm The code to flush the cache in loadseg and unloadseg needed to
|
|
; be set in conditionals for onNuMac.
|
|
; <C456> 11/22/86 bbm moved the code to flush the cache into blockmove, loadseg,
|
|
; unloadseg, and read. this might improve performance.
|
|
; <A284> 10/28/86 LAK Copy launch parameters before resetting the stack (could have
|
|
; been passed on stack). Set CurMap to CurApRefNum when loading a
|
|
; code resource (but preserve setting of both Resload and Curmap).
|
|
; Use StripAddress trap for FlushApplVbls, InstallRDrivers via new
|
|
; routine ApZoneAddr which is also more selective about what's in
|
|
; the application world (specifically excludes above BufPtr). Use
|
|
; launch trap at ExitToShell so we have a hook there.
|
|
; <C206> 10/9/86 bbm Modified to mpw aincludes.
|
|
; <C192> 10/1/86 JDT Added call to script manager during launch.
|
|
; <C169> 9/23/86 JTC Use HLock/HUnlock rather than bset/bclr and use HGetState to
|
|
; check lockedness.
|
|
; <C141> 9/4/86 RDC Added code to init FPU chip for NuMac
|
|
; <C54> 6/24/86 WRL Changed access to ROMBase to make it survive a 32 bit value.
|
|
; 2/19/86 BBM Made some modifications to work under MPW
|
|
; 1/13/86 JTC Patch for InstallRDrivers to correctly kill DCtlStorage of
|
|
; drivers with storage in the app heap.
|
|
; 11/2/85 JTC Check global SegHiEnable before MoveHHi in LoadSeg.
|
|
; 10/28/85 JTC Changed Launch and Chain to check for extended param block,
|
|
; calling OpenRFPerm with desired permissions. Also added vector
|
|
; for vSegStack.
|
|
; 9/10/85 BBM fix bug - if ExitToShell with ResLoad false, then LoadCode
|
|
; wouldn't load the code.
|
|
; 8/18/85 LAK Removed call to MakeStkPB and placed that code in-line (moved
|
|
; this file to TBLink so had to remove the .Ref). A file system
|
|
; call should be added to flush all volumes soon.
|
|
; 7/26/85 RDC Added include statement for HWequ file (needed for DiagROM
|
|
; reference)
|
|
; 7/8/85 LAK Zero D0-D7 and init A0-A2 to DiagROM addr at launch; fixed bug
|
|
; in InstallRDrivers to preserve DCtlStorage handle if it's in the
|
|
; system heap.
|
|
; 5/23/85 JTC Do a MoveHHi on all segments that come in unlocked.
|
|
; 5/22/85 LAK Set location 0 to DiagROM at launch (in case Finder doesn't FOBJ
|
|
; it).
|
|
; 5/21/85 JTC Fix bug in check for "already loaded" seg in LoadSeg.
|
|
; 3/27/85 JTC Add loop in Launch to remove appl zone vbl tasks from loop
|
|
; before trashing appl zone.
|
|
; 1/30/85 LAK Added ram patch after ExitToShell to LodeScrap and prefix to
|
|
; BootDrive. Moved ExitToShell label (before ram patch).
|
|
; CloseResFile skipped here to avoid bug in driver goodbye kiss
|
|
; (where driver came from app file), esp. since it appears to be
|
|
; called in Launch anyways.
|
|
; 1/29/85 EHB Made Launch and Chain give goodbye calls to drivers that want
|
|
; 'em
|
|
; 1/29/85 EHB Fix odd stack bug in Launch/Chain
|
|
; 9/10/83 AJH Fixed bug -- it wasn't releasing segment 0!
|
|
; 9/6/83 AJH BadOpen now deep shits
|
|
; 8/19/83 LAK Now inits StkLowPt.
|
|
; 8/18/83 SC Changed theScrap to scrapHandle and changed BEQ to BLE
|
|
; 8/16/83 AJH Compute screen sound address relative to memTop (instead of
|
|
; ScreenBase)
|
|
; 8/13/83 SC Dropped flushevents
|
|
; 8/12/83 AJH moved globals to SysEqu; use deepShit alert in SysErr made
|
|
; ExitToShell use a low memory pBlock save parameters in lomem
|
|
; earlier
|
|
; 8/11/83 AJH made it preserve scrap by moving it to stack
|
|
; 8/10/83 AJH moved LoadTrap to LoadSeg; loader calls SetApplLimit
|
|
; 8/9/83 SC Fixed bug in scrap stuff(D0 lost through NewHandle)
|
|
; 8/8/83 AJH removed compact before locking (now rMgr does it!)
|
|
; 8/6/83 BLH Added initialization of DragHook, DeskHook, CloseOrnHook,
|
|
; restProc, saveProc, saveSP, taskLock, fScaleDisable, resErrHook
|
|
; right after InitApplZone. These all used to be in InitWindows
|
|
; (except fScaleDisable).
|
|
; 6/17/83 AJH fixed bug (no InitApplZone) introduced yesterday
|
|
; 6/16/83 AJH made it compact before locking code segments
|
|
; 6/16/83 AJH made it InitApplZone early so it only opens once
|
|
; 6/11/83 AJH cleaned up BadOpen error exit stuff
|
|
; 6/8/83 AJH increased size of appName; made it use AppParmHandle
|
|
; 6/4/83 AJH made Launch clear D7 & 20(A5) for stupid Lisa Pascal
|
|
; 6/2/83 AJH fixed bug in ExitToShell to push page 2 word
|
|
; 6/1/83 AJH preserved theScrap; added page two options
|
|
; 5/29/83 AJH Changed jumptable from 10 bytes/entry to 8 bytes/entry
|
|
; 1/23/83 LAK Adapted for new equate files.
|
|
;
|
|
;---------------------------------------------------
|
|
;
|
|
; Really old comments which probably make no sense:
|
|
;
|
|
; Here is the new resource-based segment loader. It
|
|
; is capable of loading multiple Lisa-style code segments
|
|
; using a jump table scheme similar to the Lisa "physical
|
|
; executable" format.
|
|
;
|
|
; The loader is also the part of the system that cuts back
|
|
; the application heap and builds an "A5 world" for the
|
|
; application.
|
|
;
|
|
; The loader will preserve the handle in low memory called
|
|
; "theScrap" across world swaps.
|
|
;
|
|
;
|
|
; To Do:
|
|
; - Move FlushApplVBLs, RDrvrInit, etc. to some more sensible place.
|
|
; - why is lodescrap called at exittoshell?
|
|
; - recover earlier on launches if file is bad . . .
|
|
; - remove hardwired constant for 2nd screen delta to memtop.?? for Reno?? <A284>
|
|
;
|
|
; Problems with incorporating 'Q' init here:
|
|
; - hardwired name 'miniFinder'
|
|
; - 'Q' code still in flux (should set up launch flags, Finder should reset the
|
|
; sublaunch stack since it deallocates WDCBs. We should really use DirIDs and
|
|
; VRefNums in 'Q', as well as allocate a WDCB if needed).
|
|
; - need this for MacPlus and Mac512 also; why not keep all the code in the
|
|
; same place?
|
|
;_______________________________________________________________________
|
|
|
|
|
|
BLANKS ON
|
|
STRING ASIS
|
|
|
|
LOAD 'StandardEqu.d'
|
|
INCLUDE 'HardwarePrivateEqu.a'
|
|
INCLUDE 'Palettes.a'
|
|
|
|
machine mc68020
|
|
|
|
Loader PROC EXPORT
|
|
|
|
EXPORT Launch,Chain,ExitToShell
|
|
EXPORT InstallRDrivers
|
|
EXPORT LoadSeg,UnloadSeg
|
|
EXPORT GetAppParms
|
|
EXPORT vSegStack ; <28Oct85>
|
|
EXPORT SgLdrEnd
|
|
EXPORT vLaunchInit ; to be used by InitApplZone <C681>
|
|
EXPORT FlushApplVBLs ; to be used by InitApplZone <C681>
|
|
EXPORT AppZoneAddr ; to be used by InitApplZone <C699>
|
|
|
|
; IMPORT LaunchScript ; during switch-launch (C192)
|
|
IMPORT FlushCRange ; <SM2> rb
|
|
|
|
|
|
; segment header definitions
|
|
|
|
SegJTOffset EQU 0 ; offset of 1st jumpTable entry
|
|
SegJTEntries EQU 2 ; number of jumpTable entries
|
|
SegHdrSize EQU 4 ; the header is four bytes long
|
|
|
|
; misc definitions
|
|
|
|
SegLoadTrap EQU $A9F0 ; LoadSeg trap ID
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
;
|
|
; PROCEDURE LoadSeg(segID: INTEGER);
|
|
;
|
|
; LoadSeg is used to load a segment and patch all the jump table entries for
|
|
; that segment. It is usually called from the jump table entry and almost
|
|
; never called directly by the application. It then transfers control
|
|
; to the newly loaded code.
|
|
;
|
|
; All registers are preserved until the newly loaded code is launched.
|
|
; If the segment can't be found, a deep shit alert is posted.
|
|
;
|
|
;------------------------------------------------------------------------------
|
|
|
|
LoadSeg
|
|
MOVEM.L D0-D2/A0-A1,-(SP) ;all registers must be preserved
|
|
|
|
MOVE.W 24(SP),D0 ; get the segment ID
|
|
BSR LoadCode ; A0=D0=segment handle <SM8> CSS
|
|
BEQ SegError ; if none, give up <SM8> CSS
|
|
|
|
_HGetState ; D0 <- master ptr state bits <C169>
|
|
BTST #Lock,D0 ; NE => locked <C169>
|
|
BNE.S NoMoveHHi ; NotEqual => don't move it <23May85>
|
|
TST.B SegHiEnable ; = 0 to disable use of (dubious) MoveHHi <02Nov85> JTC
|
|
BEQ.S @37 ; <02Nov85> JTC
|
|
|
|
_MoveHHi ;Move it to highest possible point <23May85>
|
|
@37 ;Aren't we slick and tight? <02Nov85> JTC
|
|
_HLock ; <23May85><C169>
|
|
NoMoveHHi
|
|
MOVE.L (A0),D0 ; handle -> dirty pointer <C169>
|
|
_StripAddress ; D0 <- clean ptr <C169>
|
|
MOVE.L D0,A0 ; <C169>
|
|
|
|
MOVE.L A5,A1 ;copy world base address
|
|
ADD.W CurJTOffset,A1 ;offset by the current offset
|
|
ADD.W SegJTOffset(A0),A1 ;compute address of 1st entry
|
|
|
|
CMP.W #$4EF9,2(A1) ;is it already loaded? (was 4(A1)) <21May85>
|
|
BEQ.S GoLaunch ;if so, don't bother to load
|
|
|
|
; we must patch the jump table to point to the newly loaded segment. At this
|
|
; point A1 points to the first jump table entry.
|
|
|
|
MOVE.W SegJTEntries(A0),D0 ;get the number of entries
|
|
BEQ.S GoLaunch ;if none, just go launch it
|
|
MOVE.W 24(SP),D1 ;get the segment ID
|
|
MOVEQ #0,D2 ;clear out high part of D2
|
|
|
|
; LoadSegPatch from Terror overpatch.a
|
|
Move.l A2,-(Sp) ; Save A2.
|
|
Move.l A1,A2 ; Save starting address.
|
|
PatchJTLoop
|
|
MOVE.W (A1)+,D2 ;pick up the offset
|
|
MOVE.W D1,-2(A1) ;remember the segment ID in entry
|
|
MOVE.W #$4EF9,(A1)+ ;patch in the "JMP.L" opcode
|
|
PEA SegHdrSize(A0,D2.L) ;compute the entry point address
|
|
MOVE.L (SP)+,(A1)+ ;move in the entry point address
|
|
|
|
SUBQ #1,D0 ;more entries to do?
|
|
BNE.S PatchJTLoop ;loop till done
|
|
|
|
Suba.l A2,A1 ; Length of changes.
|
|
Move.l A2,A0 ; Starting address. <T13>
|
|
BSR.l FlushCRange ; Flush the Caches. <T10>
|
|
Move.l (Sp)+,A2 ; Restore A2.
|
|
|
|
; now we can transfer control to the newly loaded code at the proper entry point
|
|
|
|
GoLaunch
|
|
MOVE.L 20(SP),A1 ;get the return address from the trap
|
|
SUBQ.L #6,A1 ;back up to the JMP.L opcode
|
|
MOVE.L A1,22(SP) ;patch the return address
|
|
|
|
MOVEM.L (SP)+,D0-D2/A0-A1 ;restore the registers
|
|
ADDQ #2,SP ;strip parameter
|
|
|
|
TST.B LoadTrap ;debugging on?
|
|
BEQ.S @1 ;go launch if its not
|
|
DC.W $A9FF ;invoke debugger
|
|
@1
|
|
RTS ;launch the code!
|
|
|
|
; here is the error handler for when we couldnt load a segment we need. Its
|
|
; a deep shit alert.
|
|
|
|
SegError
|
|
MOVEQ #DSLoadErr,D0 ;get deep shit ID
|
|
_SysError ;invoke deep shit - dont come back
|
|
DC.W $A9FF ;trap to debugger, just in case
|
|
|
|
; LoadCode is a code saving utility that loads the segment with the resource ID
|
|
; specified in D0. It returns the segment handle in A0
|
|
|
|
LoadCode
|
|
ST ResLoad ; force a load of code segment <10sep85> BBM
|
|
|
|
SUBQ #4,SP ; make room for function result
|
|
|
|
; <sm 5>stb Imported for SuperMario from SegmentLoaderPatches 3/30/92
|
|
; Force system code to load as 'scod' resources. The Process Mgr. is our distinguished first guest
|
|
; of this mechanism. If the id is in the reserved range [$BFFF,$BF00] it loads a ÔscodÕ instead
|
|
; of a ÔCODEÕ.
|
|
cmp.w #$BFFF,D0 ; Is it in the BFFF - BF00 range reserved for sys code?
|
|
bgt.s @normalCODE
|
|
cmp.w #$BF00,D0 ; is it really in the BFFF - BF00 range?
|
|
blt.s @normalCODE
|
|
move.l #'scod',-(SP) ; load a system-code (ÔscodÕ) resource
|
|
bra.s @systemCode
|
|
@normalCODE
|
|
MOVE.L #'CODE',-(SP) ; load a regular CODE resource
|
|
@systemCode
|
|
MOVE.W D0,-(SP) ; push the segment ID
|
|
_GetResource ; load it
|
|
MOVE.L (SP)+,A0 ; get result in A0
|
|
|
|
MOVE.L A0,D0 ; better set Z-flag based on result
|
|
RTS ; return to caller
|
|
|
|
;------------------------------------------------------------------------------
|
|
;
|
|
; PROCEDURE UnloadSeg(routineAddr: Ptr);
|
|
;
|
|
; UnLoadSeg is used to unload a segment when the application feels its no
|
|
; longer needed for a while. It patches all of the segment's jump table
|
|
; entries back to the "load me" state. The parameter is the address of any
|
|
; routine within the segment.
|
|
;
|
|
;------------------------------------------------------------------------------
|
|
|
|
UnloadSeg MOVE.L 4(SP),A0 ;get the address of the routine
|
|
CMP.W #$4EF9,(A0) ;is it already unloaded?
|
|
BNE.S DoneUnload ;if so, we're done
|
|
|
|
; the first thing we must do is figure out the handle of the segment
|
|
|
|
MOVE.W -2(A0),D0 ;get the segment ID
|
|
BSR.S LoadCode ;get the segment handle
|
|
_HUnlock ;let it roam
|
|
MOVE.L (A0),A0 ;handle -> pointer
|
|
MOVE.L A5,A1 ;copy world base address
|
|
ADD.W CurJTOffset,A1 ;offset by current offset
|
|
ADD.W SegJTOffset(A0),A1 ;compute address of 1st entry
|
|
MOVE.W SegJTEntries(A0),D0 ;get the number of entries
|
|
BEQ.S DoneUnload ;if zero, we're all done
|
|
|
|
; loop through each jump table entry, patching it back to the "load me" state
|
|
|
|
Movem.l D1/A2,-(Sp) ; Save registers. <T10>
|
|
Move.l A1,A2 ; Save starting address. <T10>
|
|
|
|
UnpatchLoop
|
|
MOVE.W (A1),D1 ;remember the segment ID
|
|
MOVE.L 4(A1),D2 ;get the current address
|
|
SUB.L A0,D2 ;subtract the segment base address
|
|
SUBQ.L #SegHdrSize,D2 ;subtract the header size
|
|
|
|
MOVE.W D2,(A1)+ ;move in the offset
|
|
MOVE.W #$3F3C,(A1)+ ;move in the "push immediate" opcode
|
|
MOVE.W D1,(A1)+ ;move in the segment ID
|
|
MOVE.W #SegLoadTrap,(A1)+ ;move in the "SegLoad" trap
|
|
|
|
SUBQ #1,D0 ;more to do?
|
|
BNE.S UnpatchLoop ;loop until done
|
|
|
|
; we're all done with unloading the segment so strip the parameter and
|
|
; return to the caller
|
|
|
|
Suba.l A2,A1 ; Length of changes. <T10>
|
|
Move.l A2,A0 ; Starting address. <T10>
|
|
BSR.l FlushCRange ; Flush the Caches. <T10>
|
|
|
|
Movem.L (Sp)+,D1/A2 ; Restore registers <T10>
|
|
|
|
DoneUnload
|
|
MOVE.L (SP)+,(SP) ;strip the parameter
|
|
RTS ;return to caller
|
|
|
|
;------------------------------------------------------------------------------
|
|
; PROCEDURE AppZoneAddr <A284>
|
|
;
|
|
; Purpose: Strips any garbage off D0 address and sets D0=0 if in app zone.
|
|
; Aguments: D0 is the unstripped address on input, stripped or zeroed on output.
|
|
; CCR is set according to D0 value.
|
|
; Special case -- always say ÒdonÕt nukeÓ when SysZone==ApplZone. <C699>
|
|
; Registers: D0.
|
|
; Called by: FlushApplVbls, InstallRDrivers.
|
|
;------------------------------------------------------------------------------
|
|
|
|
AppZoneAddr
|
|
_StripAddress ;<A284> D0 <- clean ptr
|
|
MOVE.L ApplZone,-(SP) ;get two zone ptrs where we can compare them <C699>
|
|
MOVE.L SysZone,-(SP) ;two zones poised for compare <C699>
|
|
CMP.L (SP)+,(SP)+ ;if appl==sys get out with D0!=0 <C699>
|
|
BEQ.S @notInApplZone ;donÕt nuke sys zone stuff at start time <C699>
|
|
CMP.L ApplZone,D0 ;<A284> Carry is set if below ApplZone, i.e. SysZone
|
|
BCS.S @notInApplZone ;<A284> in system zone, so leave D1 <C699>
|
|
CMP.L BufPtr,D0 ;<A284> Carry is clear if above the application space
|
|
BCC.S @notInApplZone ;<A284> (some other system zone? or BufPtr permanent <C699>
|
|
;<A284> allocation).
|
|
MOVEQ #0,D0 ;<A284> otherwise, return 0.
|
|
RTS
|
|
@notInApplZone
|
|
MOVEQ #-1,D0 ;really nonzero <C699>
|
|
RTS ;exit with CCR set <C699>
|
|
|
|
;------------------------------------------------------------------------------
|
|
; PROCEDURE FlushApplVbls
|
|
;
|
|
; Purpose: Remove from VBL queue any tasks based in applzone.
|
|
; Aguments: None.
|
|
; Registers: D0,A0-A1
|
|
; Called by: InitApplZone <C681>
|
|
;------------------------------------------------------------------------------
|
|
|
|
FlushApplVbls
|
|
MOVEA.L VBLQueue+qHead,A1 ; point to queue header <27Mar85>
|
|
fAVLoop ; <27Mar85>
|
|
MOVE.L A1,D0 ; is there a next element? <27Mar85>
|
|
BEQ.S fAVDone ; if not, just quit <27Mar85>
|
|
|
|
MOVEA.L A1,A0 ; line up element pointer for possible remove <27Mar85>
|
|
MOVEA.L vbLink(A0),A1 ; get next element for looping <27Mar85>
|
|
MOVE.L vblAddr(A0),D0 ; task pointer <27Mar85>
|
|
BSR.S AppZoneAddr ;<A284> in application area (or zero)?
|
|
BNE.S fAVLoop ;<A284> br if not
|
|
|
|
_VRemove ; <27Mar85>
|
|
BRA.S fAVLoop ; <27Mar85>
|
|
fAVDone ; <27Mar85>
|
|
RTS ; <27Mar85>
|
|
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
;
|
|
; PROCEDUREs Launch, Chain, ExitToShell:
|
|
;
|
|
; Here is the main part of the segment loader that actually launches
|
|
; an application. It opens the resource file specified by the input name,
|
|
; loads segment 0 to get the jumptable and global size information, optionally
|
|
; cuts back the application heap and kicks off the application by invoking
|
|
; its first jump table entry.
|
|
;
|
|
; Warning -- LAUNCH obliterates the application heap so if an error occurs
|
|
; (like the file isn't executable) the code that called us is no longer
|
|
; "in the zone". Callers of LAUNCH should be very careful...(they probably
|
|
; should use a deep shit alert to put up a message and then re-launch themselves)
|
|
;
|
|
; New format parameter block to Launch and Chain has form:
|
|
; (a0) = (long) file name ptr
|
|
; (word) sounc and screen page option flag
|
|
; (word) 'LC' -- Charles Dodgeson's initials mark extended block
|
|
; (long) length of param block extension in bytes, past this long
|
|
; (word) finder file flags, bit #6 of low byte is 1 for read-only access
|
|
;
|
|
;------------------------------------------------------------------------------
|
|
|
|
|
|
; This part of the code is here so it can be accessible by short branches.
|
|
; Compute the address of sound page 2 and go modify the stackBase if
|
|
; neccessary.
|
|
|
|
SoundPage2
|
|
MOVE.L MemTop,D0 ;get address of top of RAM
|
|
SUB.L #$00005F00,D0 ;compute address of sound page 2
|
|
BRA SetNewStack ;modify stackBase if necessary
|
|
|
|
|
|
; First we have some an alternate entry point "Chain" which is just like
|
|
; launch except it doesn't cut back the heap.
|
|
|
|
Chain
|
|
CLR.W LaunchFlag ;flag not to cut back heap
|
|
BRA.S LaunchCom ;fall into common code
|
|
|
|
; Here is the main entry point for launch
|
|
|
|
Launch
|
|
ST LaunchFlag ;flag that we should cut back the heap
|
|
|
|
; first, send a doGoodBye call to all drivers that want one
|
|
|
|
MOVEM.L D0-D1/A0-A1,-(SP) ; save registers <EHB 29-Jan-85>
|
|
SUB #IOQElSize,SP ; allocate pBlock <EHB 29-Jan-85>
|
|
MOVE #-1,CSCode(SP) ; set up control code <EHB 29-Jan-85>
|
|
MOVE.L UTableBase,A1 ; point to unit table <EHB 29-Jan-85>
|
|
MOVE.W UnitNtryCnt,D1 ; get # entries in unit table <EHB 29-Jan-85>
|
|
GoodByeLoop
|
|
MOVE.L (A1)+,D0 ; get the DCE handle <EHB 29-Jan-85>
|
|
BEQ.S NextGoodBye ; if NIL, try next one <EHB 29-Jan-85>
|
|
|
|
MOVE.L D0,A0 ; get the DCE handle <EHB 29-Jan-85>
|
|
MOVE.L (A0),A0 ; get the DCE pointer <EHB 29-Jan-85>
|
|
BTST #DNeedGoodbye,DCtlFlags(A0) ; need a goodbye kiss? <EHB 29-Jan-85>
|
|
BEQ.S NextGoodbye ; not tonight dear <EHB 29-Jan-85>
|
|
|
|
; we found one that needs a goodbye call so issue the control call
|
|
|
|
MOVE.W DCtlRefNum(A0),IORefNum(SP) ; set up the refNum <EHB 29-Jan-85>
|
|
MOVE.L SP,A0 ; point to the DCE <EHB 29-Jan-85>
|
|
_Control ; kiss it goodbye... <EHB 29-Jan-85>
|
|
NextGoodBye
|
|
SUBQ #1,D1 ; check next entry <EHB 29-Jan-85>
|
|
BNE.S GoodByeLoop ; if so, loop <EHB 29-Jan-85>
|
|
|
|
ADD #IOQElSize,SP ; deallocate pBlock <EHB 29-Jan-85>
|
|
MOVEM.L (SP)+,D0-D1/A0-A1 ; restore registers <EHB 29-Jan-85>
|
|
|
|
LaunchCom
|
|
|
|
; preserve application name, and which sound and screen pages to use
|
|
|
|
movea.l a0,a3 ; save pblock ptr in a3 until actual launch <28Oct85>
|
|
movea.l (a3)+,a0 ; file name ptr <28Oct85>
|
|
move.w (a3)+,CurPageOption ; <28Oct85>
|
|
LEA CurApName,A1 ;get address to stuff the name
|
|
MOVEQ #32,D0 ;move 32 bytes worth
|
|
_BlockMove ;move it in
|
|
|
|
MOVEQ #0,D3 ;<A284> assume all flags are zero
|
|
CMP.W #'LC',(A3)+ ;<A284> extension code around?
|
|
BNE.S @closeOld ;<A284> br if not
|
|
ADDQ #4,A3 ;<A284> skip over length
|
|
MOVE.W (A3)+,D3 ;<A284> save flags for later test
|
|
|
|
; close any previously open application, if any
|
|
|
|
@closeOld
|
|
MOVE CurApRefNum,D0 ;get refnum of current application
|
|
BLE.S SkipClose ;if none, skip the close
|
|
MOVE.W D0,-(SP) ;push the refNum
|
|
_CloseResFile ;close it
|
|
CLR.W CurApRefNum ;flag that no application is open
|
|
|
|
; now initialize the application heapZone, if we're launching
|
|
|
|
SkipClose
|
|
MOVE.L BufPtr,SP ;start stack under screen/debugger
|
|
CLR.L StkLowPt ;keep VBL task out
|
|
|
|
TST.W LaunchFlag ;is it a launch?
|
|
BEQ.S OpenApp ;if not, skip
|
|
|
|
; before obliterating the heap, save the scrap on the stack
|
|
|
|
MOVE.L scrapHandle,D0 ;get the scrap handle
|
|
BLE.S GoInitAZone ;if none, skip
|
|
|
|
MOVE.L D0,A0 ;get the handle
|
|
_GetHandleSize ;get its size
|
|
|
|
ADDQ.L #1,D0 ; make sure it's even <EHB 29-Jan-85>
|
|
BCLR #0,D0 ; because that's how SP likes it! <EHB 29-Jan-85>
|
|
SUB.L D0,SP ;allocate space for it
|
|
MOVE.L SP,A1 ;set up destination for move
|
|
MOVE.L (A0),A0 ;set up source for move
|
|
MOVE.L D0,-(SP) ;remember the size
|
|
_BlockMove ;move it!
|
|
|
|
; re-init the application heap zone, destroying the world...
|
|
; ...but just before, flush any vbl tasks executing out of that doomed land! <27Mar85>
|
|
|
|
GoInitAZone
|
|
; Code move to InitApplZone, where it might actually belong. <C681>
|
|
; Moved here from LaunchCom -- only reinitialize if heap will be trashed. <24Apr85>
|
|
;;;CLR.L DragHook ;No drag hook yet
|
|
;;;CLR.L DeskHook ;No desk hook for hit-testing desk.
|
|
;;;LEA CloseOrnHook, A0 ; Point to closeOrnHook
|
|
;;;CLR.L (A0)+ ;clear closeOrnHook
|
|
;;;CLR.L (A0)+ ;clear RestProc
|
|
;;;CLR.L (A0)+ ;clear saveProc
|
|
;;;CLR.W TaskLock ;clear taskLock, fScaleDisable.
|
|
;;;CLR.L ResErrProc ;and resource error proc.
|
|
;;;CLR.L EjectNotify ;moved here from InitApplZone (from patches) <24Apr85>
|
|
;;;BSR SndAppDead ;kill all current channels <C548>
|
|
;;;BSR.S FlushApplVbls ;kill off doomed vbl tasks <27Mar85>
|
|
_InitApplZone ;cut back the heap
|
|
;;;CLR.W CurApRefNum ;InitApplZone closes resource files
|
|
|
|
;allocate a new handle for the scrap to be copied into, if necessary.
|
|
|
|
TST.L scrapHandle ;did we have a scrap?
|
|
BLE.S SkipScrap ;if none, skip
|
|
|
|
; we had a scrap so better allocate a new handle for it and rescue its contents
|
|
; from the stack
|
|
|
|
MOVE.L (SP)+,D1 ;get the size of the scrap
|
|
MOVE.L D1,D0 ;set up size for NewHandle
|
|
_NewHandle ;allocate a handle for it
|
|
MOVE.L A0,scrapHandle ;remember the handle
|
|
|
|
MOVE.L D1,D0 ;get size for blockMove
|
|
MOVE.L (A0),A1 ;get destination pointer
|
|
MOVE.L SP,A0 ;get source pointer
|
|
_BlockMove ;move it in!
|
|
|
|
ADD.L D1,SP ;deallocate scrap save buffer
|
|
|
|
SkipScrap
|
|
;;;_RDrvrInstall ;fix up ram based drivers -- moved to InitApplZone <C681>
|
|
; JSR LaunchScript ;fix up scripts (C192)
|
|
|
|
; now that the heap's in good shape, open the new application file after reiniting
|
|
; some important hooks and globals
|
|
|
|
; Open the app res file (preloading the most desirable resources). Use the call <28Oct85>
|
|
; FUNCTION _OpenResFile(f : Str255) : integer; with RMGRPerm set for read-only access. <30Oct85>
|
|
; This ugly implicit param to RMGR supports Finder's need to trap out OpenResFile. <30Oct85>
|
|
|
|
OpenApp
|
|
SUBQ #2,SP ;<A284> space for result
|
|
PEA CurApName ;<A284> launchee
|
|
|
|
MOVEQ #0,D0 ;<A284> assume r/w or r/o if already open
|
|
BTST #6,D3 ;<A284> 1 => read-only
|
|
BEQ.S @1 ;<A284> br if not
|
|
MOVEQ #1,D0 ;<A284> r/o permission
|
|
@1 MOVE.B D0,RMGRPerm ;<A284> use implicit READ-ONLY boolean for RMGR
|
|
|
|
_OpenResFile ;<A284> open resfile with appropriate permissions
|
|
MOVE.W (SP)+,CurApRefNum ;<A284> remember it in low memory
|
|
BLE BadOpen ;<A284> branch if open wasn't successful
|
|
|
|
; now load in segment 0, which has the A5 world information as well as the
|
|
; jump table
|
|
|
|
MOVEQ #0,D0 ;get ID for segment 0
|
|
BSR LoadCode ;load it in =>seg handle in A0
|
|
BEQ BadOpen ;if we failed, report error
|
|
MOVE.L A0,SaveSegHandle ;remember code 0 handle in loMem
|
|
|
|
; set up A5 and A7 for this application
|
|
|
|
MOVE.L (A0),A0 ;point to seg 0 info
|
|
|
|
; adjust the stack base according to the page 2 options word
|
|
|
|
TST.W CurPageOption ;are any page 2 options requested?
|
|
BEQ.S SetA5 ;if not, go build A5 world
|
|
BPL.S SoundPage2 ;if so, go handle sound page 2
|
|
|
|
MOVE.L MemTop,D0 ;start at memTop
|
|
SUB.L #$0000D900,D0 ;compute video page 2 address
|
|
|
|
SetNewStack
|
|
CMP.L SP,D0 ;should we move down the stack
|
|
BGE.S SetA5 ;if not, skip
|
|
MOVE.L D0,SP ;move it down
|
|
|
|
SetA5
|
|
|
|
; Give the world a chance to mess with the stack before committing to an a5 world. <28Oct85>
|
|
movea.l jSegStack,a3 ; get vector to continue stack computation <28Oct85>
|
|
jmp (a3) ; <28Oct85>
|
|
vSegStack ; <28Oct85>
|
|
SUB.L (A0)+,SP ;allocate "above A5" space
|
|
; Before jamming A5 for the app, chop down to ensure long alignment, leaving either 0 <C800>
|
|
; or 2 dead bytes between the A5 and BufPtr worlds. After that itÕs up to CODE=0 to <C800>
|
|
; to keep things lined up. <C800>
|
|
MOVE.L SP,D0 ; get stack where we can trim it <C800>
|
|
ANDI.W #$FFFC,D0 ; keep all but low 2 bits <C800>
|
|
MOVE.L D0,SP ; new, empty stack is 4*N <C800>
|
|
MOVE.L SP,A5 ;set up A5
|
|
|
|
SUB.L (A0)+,SP ;allocate "below A5" space
|
|
MOVE.L A5,CurrentA5 ;remember A5 for this application
|
|
MOVE.L SP,CurStackBase ;remember stack for this one, too
|
|
MOVE.L SP,StkLowPt ;for heap-stack crashes
|
|
|
|
; move in the jump table to where it belongs
|
|
|
|
MOVE.L (A0)+,D0 ;get the jump table size
|
|
MOVE.L (A0)+,A1 ;get the load offset
|
|
MOVE.W A1,CurJTOffset ;remember the offset
|
|
ADD.L A5,A1 ;add in the base address
|
|
LEA 2(A1),A3 ;remember the launch address
|
|
_BlockMove ;move it in
|
|
|
|
; now that things are set up, we can release segment 0
|
|
|
|
MOVE.L SaveSegHandle,-(SP) ;push the segment 0 handle
|
|
_ReleaseResource ;de-allocate it
|
|
|
|
; set up the parameters to the application
|
|
|
|
LEA 8(A5),A0 ;point to parameter area
|
|
CLR.L (A0)+ ;standard input
|
|
CLR.L (A0)+ ;standard output
|
|
MOVE.L AppParmHandle,(A0)+ ;parameter pointer
|
|
CLR.W (A0)+ ;physExec flag for stupid Lisa Pascal
|
|
|
|
; set the default application heap zone limit based on the current stack
|
|
|
|
MOVE.L SP,A0 ;get the stack
|
|
SUB.L DefltStack,A0 ;subtract buffer zone
|
|
_SetApplLimit ;set the new limit
|
|
|
|
MOVE.L jLaunchInit,A0 ; address of init routine <C681>
|
|
JSR (A0) ; vectors aweigh! <C681>
|
|
JSR (A3) ;launch the application:
|
|
; A4,A6 unchanged <08Jul85>
|
|
; A5,A7 initialized <08Jul85>
|
|
; D0-D7 zeroed <08Jul85>
|
|
; A0-A2 set to DiagROM <08Jul85>
|
|
|
|
; If we reached this point, the application must have successfully terminated.
|
|
; Close its resource file and chain back to the finder.
|
|
|
|
ExitToShell ; <30Jan85>
|
|
|
|
; MOVE.W CurApRefNum,-(SP) ; push the app's refnum (THIS IS DONE IN LAUNCH!)
|
|
; _CloseResFile
|
|
; CLR.W CurApRefNum
|
|
|
|
_PMgrExit ; Empty out the palette manager < 7Jul89>
|
|
SUB.L A0,A0 ; clear out A0 <30Jan85>
|
|
_SetGrowZone ; disable application's growZone handler <30Jan85>
|
|
|
|
SUBQ #4,SP ; load the scrap into memory <30Jan85>
|
|
_LodeScrap ; <30Jan85>
|
|
ADDQ #4,SP ; trashes pascal regs <30Jan85>
|
|
|
|
MOVEQ #(IOVQElSize/2)-1,D0 ; <18Aug85>
|
|
@1 CLR.W -(SP) ; get IO param block off stack <18Aug85>
|
|
DBRA D0,@1 ; (with IOFileName zeroed) <18Aug85>
|
|
MOVE.L SP,A0 ; <18Aug85>
|
|
|
|
MOVE.W BootDrive,IOVRefNum(A0) ; prefix to 'boot' drive <30Jan85>
|
|
_SetVol ; <30Jan85>
|
|
ADD #IOVQElSize,SP ; clean up stack <30Jan85>
|
|
|
|
LEA LoaderPBlock,A0 ;point to lomem param block
|
|
MOVE.L A0,A1 ;copy to A1
|
|
PEA FinderName ;get finder name pointer
|
|
MOVE.L (SP)+,(A1)+ ;put finder name ptr in pBlock
|
|
CLR.L (A1)+ ;no page 2 usage
|
|
_Launch ;<A284> launch it!
|
|
|
|
; here is the error handler for when we can't open the file. We've already
|
|
; obliterated the world (possibly) so just deep shit
|
|
|
|
BadOpen
|
|
MOVEQ #DSBadLaunch,D0
|
|
_SysError ;post the error
|
|
DC.W $A9FF ;invoke debugger
|
|
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
; PROCEDURE vLaunchInit; new <C681>
|
|
;
|
|
; Vectored utility to set up application world just before launching the app.
|
|
; Historically set $0 to be diag ROM rather than even more historical 'FOBJ'
|
|
; from early Finders. Much experimentation is being done with different values
|
|
; to get as many apps as possible to work despite their love of Nil ptrs and handles.
|
|
; Input: a3=app address, a4-a7 preinitialized above.
|
|
; Registers: d0-d7/a0-a2
|
|
; Called by: Launch&Chain through vector jLaunchInit.
|
|
;------------------------------------------------------------------------------
|
|
vLaunchInit
|
|
|
|
; First do init of 68881 (FPU) if present
|
|
|
|
BTST #hwCbFPU,HWCfgFlags ;FPU installed? <C141><1.5>
|
|
BEQ.S @2 ;skip if not <C141>
|
|
|
|
MC68881 ; <C749>
|
|
CLR.L -(SP) ; Place null state frame on stack <C749>
|
|
FRESTORE (SP)+ ; É and use it to reset all FPU regs<C749>
|
|
|
|
|
|
; Next do init of A and D regs
|
|
|
|
@2 MOVEQ #0,D7 ;clear D7 for stupid Pascal
|
|
MOVEQ #0,D6 ;set up a fairly constant world <08Jul85>
|
|
MOVEQ #0,D5 ; <08Jul85>
|
|
MOVEQ #0,D4 ; <08Jul85>
|
|
MOVEQ #0,D3 ; <08Jul85>
|
|
MOVEQ #0,D2 ; <08Jul85>
|
|
MOVEQ #0,D1 ; <08Jul85>
|
|
MOVEQ #0,D0 ; <08Jul85>
|
|
|
|
; deleted check for debugger - always put safe value in location 0 for those <C707>
|
|
; NIL handle apps!! <C707>
|
|
MOVE.L ROMBase, A2 ; <C490/08Dec86>
|
|
ADD.L #$10000, A2 ; <C490/08Dec86>
|
|
|
|
MOVE.L A2,A1 ; <08Jul85>
|
|
MOVE.L A2,A0 ; <08Jul85>
|
|
|
|
MOVE.L A2,0 ;keep everything constant <08Jul85>
|
|
CLR.L (A5) ;fake nil QD world for rude apps <C800>
|
|
RTS ; <C681>
|
|
|
|
|
|
|
|
;------------------------------------------------------------------------------
|
|
;
|
|
; PROCEDURE GetAppParms(VAR apName: Str255;
|
|
; VAR apRefNum: INTEGER;
|
|
; VAR apParam: Ptr)
|
|
;
|
|
; GetAppParms is a utility routine that returns some information about the
|
|
; currently executing application. It returns its name (the first 24
|
|
; characters, anyway), its resource refNum and a pointer to the parameter
|
|
; block passed by the finder.
|
|
;
|
|
;------------------------------------------------------------------------------
|
|
|
|
GetAppParms
|
|
MOVE.L (SP)+,A0 ;pull off the return address
|
|
MOVE.L (SP)+,A1 ;get pointer to apParam
|
|
MOVE.L 16(A5),(A1) ;return a pointer to finder pBlock
|
|
|
|
MOVE.L (SP)+,A1 ;get pointer to apRefNum
|
|
MOVE.W CurApRefNum,(A1) ;pass back the refNum
|
|
|
|
MOVE.L (SP)+,A1 ;point to place to stuff name string
|
|
MOVE.L A0,-(SP) ;replace return address
|
|
|
|
LEA CurApName,A0 ;point to name in low memory
|
|
MOVEQ #32,D0 ;move 32 bytes
|
|
_BlockMove ;move it!
|
|
|
|
RTS ;return to caller (params already stripped)
|
|
|
|
;------------------------------------------------------------------------------
|
|
;
|
|
; InstallRDrivers fixes up the unit table after the application heap
|
|
; is obliterated between applications.
|
|
;
|
|
;------------------------------------------------------------------------------
|
|
|
|
InstallRDrivers
|
|
|
|
MOVEM.L D0-D4/A0-A3,-(SP)
|
|
|
|
; loop through the unit table, checking for drivers in the application heap
|
|
|
|
MOVE.L UTableBase,A3 ; get pointer to unit table
|
|
MOVE.W UnitNtryCnt,D3 ; get # of entries in unit table
|
|
MOVEQ #-1,D4 ; the first unit is refNum -1
|
|
IRDLoop
|
|
MOVE.L (A3)+,D0 ; get the DCE handle
|
|
BEQ.S NextIRD ; if NIL, skip
|
|
|
|
MOVE.L D0,A1 ; get handle in A-reg
|
|
MOVE.L (A1),D0 ; <08Jul85>
|
|
BEQ.S NextIRD ; br if DCE purged (shouldn't be) <08Jul85>
|
|
|
|
MOVE.L D0,A1 ; get DCE ptr
|
|
BTST #DRamBased,DCtlFlags+1(A1) ;is it ROM-based?
|
|
BEQ.S NextIRD ; if so, skip
|
|
|
|
MOVE.L DCtlDriver(A1),D0 ; get driver handle in D0
|
|
BEQ.S NextIRD ; if none, skip
|
|
|
|
MOVE.L DCtlStorage(A1),D1 ; preserve its storage handle <08Jul85>
|
|
|
|
BSR AppZoneAddr ;<A284> in application area?
|
|
BNE.S DoSysZDriver ;<A284> br if not - handle special
|
|
|
|
; we got a driver in the application heap, so re-init its DCE
|
|
|
|
MOVEQ #DCtlEntrySize-1,D0 ; get size in bytes
|
|
MOVE.L A1,A0 ; point to DCE start
|
|
|
|
@1 CLR.B (A0)+ ; clear a byte
|
|
DBRA D0,@1 ; loop till cleared
|
|
|
|
; flag it as RAM-based, set up the refNum, restore DCtlStorage
|
|
|
|
BSET #DRamBased,DCtlFlags+1(A1)
|
|
MOVE.W D4,DCtlRefNum(A1) ; set up the refNum (queue inited to 0s)
|
|
|
|
; At this point, A1 = DCE ptr and D1 = DCtlStorage(A1) (before possible zeroing above). <13Jan86 JTC>
|
|
; Clear the DCtlWindow field in any case and, if the storage is in the appl zone,
|
|
; clear the DCtlStorage field, too. If the storage is in the system zone, restore
|
|
; the DCtlStorage field from saved value in D1.
|
|
; Prior to this fix, DCtlStorage(A1) (which was just set to zero) would be checked against
|
|
; ApplZone. Since it would appear lower, D1 would be left untouched, so that the DCE would
|
|
; have a bogus handle replaced in the DCtlStorage field.
|
|
; Note that the window field must be cleared for ALL drivers since the window list is about
|
|
; to be trashed as the ApplZone is wiped out. Since the driver has previously been called
|
|
; to Close, the window should be nonexistant anyway. In the case of system-resident drivers,
|
|
; the storage should be checked for appropriate size on entry, in case FDAMover replaced one
|
|
; with another.
|
|
DoSysZDriver ; <08Jul85>
|
|
CLR.L DCtlWindow(A1) ; zero its window <08Jul85>
|
|
|
|
MOVE.L D1,D0 ;<A284> storage ptr
|
|
BSR AppZoneAddr ;<A284> in application area?
|
|
BNE.S @1 ;<A284> if not, leave D1
|
|
MOVEQ #0,D1 ; otherwise, zero it before killing app heap <13Jan86 JTC>
|
|
@1
|
|
MOVE.L D1,DCtlStorage(A1) ; restore or zero DCtlStorage <08Jul85>
|
|
|
|
; inspect the next table entry
|
|
|
|
NextIRD
|
|
SUBQ #1,D4 ;decrement refNum
|
|
SUBQ #1,D3 ;more to do?
|
|
BNE.S IRDLoop ;loop until done
|
|
|
|
MOVEM.L (SP)+,D0-D4/A0-A3
|
|
RTS ; all done!
|
|
|
|
SgLdrEnd
|
|
END
|
|
|
|
|