mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-25 09:30:50 +00:00
1843 lines
45 KiB
Plaintext
1843 lines
45 KiB
Plaintext
|
;
|
|||
|
; File: LinkedPatchMacros.a
|
|||
|
;
|
|||
|
; Contains: macros for use in linked patch source
|
|||
|
;
|
|||
|
; Note that the code generated by the macros in this file is closely tied to the
|
|||
|
; patch loader and to the patch linker. Use care in changing one of these three
|
|||
|
; without looking at the others.
|
|||
|
;
|
|||
|
; This file also contains ROM versions of many macros. This is so that the same
|
|||
|
; code can be used in ROM and in a patch without lots of conditionals throughout.
|
|||
|
;
|
|||
|
; Symbols and macros that end with a '$' symbol are for internal use of the system
|
|||
|
; that links patches.
|
|||
|
;
|
|||
|
; Written by: Darin Adler
|
|||
|
;
|
|||
|
; Copyright: © 1990-1992 by Apple Computer, Inc., all rights reserved.
|
|||
|
;
|
|||
|
; Change History (most recent first):
|
|||
|
;
|
|||
|
; <49> 1/31/92 JSM Add new SuperMario ROM version. This has the effect of creating
|
|||
|
; two new 'lpch' resources in the System. 'lpch' 63 is the new
|
|||
|
; universal patch resource, it contains the extra universal
|
|||
|
; information formerly put in 'lpch' 31, which was the universal
|
|||
|
; resource when there were only 5 ROMs. The actual patches all
|
|||
|
; remain in 'lpch' 31, since none of them apply to SuperMario.
|
|||
|
; 'lpch' 32 is the patch resource for only the SuperMario ROM.
|
|||
|
; Neither of these 'lpch' resources currently contain any code,
|
|||
|
; since SuperMario doesn’t have any patches.
|
|||
|
; <48> 1/20/92 PN Nullify the cmpROM for ROM build
|
|||
|
; <47> 1/11/92 JSM Add MakeDispatcherTable macro so we can go back to defining a
|
|||
|
; common EndDispatcher for both the ROM and patch versions, get
|
|||
|
; rid of the selectorNum global array which was never really used
|
|||
|
; by the Dispatcher macros.
|
|||
|
; <46> 1/8/92 RB (JSM really). Created ROM versions of the EndDispatch macro and
|
|||
|
; dummy versions of jsrOld, jmpOld, etc. So that the ROM build
|
|||
|
; can use files used in LinkedPatches.
|
|||
|
; <45> 10/28/91 SAM/KSM Rolled in Regatta file.
|
|||
|
; Added hasC96 and hasPwrMgr conditionals.
|
|||
|
; Added hasTERROR and notTERROR conditionals to identify the
|
|||
|
; TERROR $067C overpatch ROM.
|
|||
|
; <44> 8/19/91 FM Remove obsolete LPFilename code. LPFileName is now passed in as
|
|||
|
; a -d parameter from the build scripts.
|
|||
|
; <43> 8/17/91 FM Added Comment records that will allow the LinkPatch tool to
|
|||
|
; generate object file information about patch entries. Also fixed
|
|||
|
; a couple of off by 2 errors that Darin pointed out.
|
|||
|
; <42> 5/28/91 FM Simplified dcOld
|
|||
|
; <41> 5/28/91 FM Added new dcOLD macro for use in building dispatch tables
|
|||
|
; <40> 4/2/91 dba KIP: add hasEricksonSoundMgr, since the newer Sound Mgr. is on
|
|||
|
; some machines that have the overpatch mistake fixed
|
|||
|
; <39> 1/30/91 gbm sab, #38: Change the ‘already including this file’ variable to
|
|||
|
; all uppercase (for security reasons)
|
|||
|
; <38> 1/27/91 PKE bbm: (also dba) fixed optimization of jsrROM, since it was
|
|||
|
; bogus. Fix was deleting LastJMP$&name parameter from Try$ call
|
|||
|
; in JsrROM, which caused it to BSR to another nearby BSR instead
|
|||
|
; of to the JMP into ROM. Whiteboard bug, no BRC #.
|
|||
|
; <37> 1/15/91 stb & dba; Fix the scratchRegister feature of the xxxROM macros.
|
|||
|
; They were broken, once again proving that nothing works until
|
|||
|
; you test it.
|
|||
|
; <36> 1/14/91 JDR (dba) Add .far option to peaROM, jsrROM, and jmpROM, as long as
|
|||
|
; you provide a scratch register.
|
|||
|
; <35> 1/14/91 JDR (dba) Changed the leaROM macro to support absolute addresses.
|
|||
|
; <34> 12/18/90 gbm (dba) Add new condition noPatchProtector and introduce the
|
|||
|
; concept of constant values for conditions.
|
|||
|
; <33> 12/14/90 BBM (dba) add two conditionals for linked patching, using24BitHeaps,
|
|||
|
; using32BitHeaps. Added support for vectors in
|
|||
|
; ComeFromPatchProc.
|
|||
|
; <32> 12/8/90 dba <gbm> create symbols for the ROM versions
|
|||
|
; <31> 12/4/90 dba <BBM> Add the ComeFromAfterPatchProc macro for Kevin and Brian.
|
|||
|
; Went nuts and added rejoinROM, too. Allow # signs in cmpROM. Put
|
|||
|
; markers in the file.
|
|||
|
; <30> 10/22/90 JSM <dba> Change Dispatcher macro to take advantage of new absolute
|
|||
|
; address support in DispatchHelper, don't optimize for all even
|
|||
|
; selectors for now.
|
|||
|
; <29> 10/8/90 JDR get rid of hasPMMUNoVM and add hasPMMU and notVM
|
|||
|
; <28> 9/25/90 KIP (really dba) Added new conditional noEricksonSoundMgr.
|
|||
|
; <27> 8/21/90 csd Added a condition which excludes the Elsie: hasMemoryDispatch.
|
|||
|
; <26> 8/19/90 dba add six new loading conditions that were needed for Sony and MMU
|
|||
|
; patching
|
|||
|
; <25> 8/10/90 DTY Make PatchProc take offsets into ExpandMem.
|
|||
|
; <24> 7/23/90 dba put some checks in for some common errors
|
|||
|
; <23> 7/20/90 CCH Unfixed the fix below.
|
|||
|
; <22> 7/17/90 CCH Fixed dcImport macro so that the patch linker recognizes it.
|
|||
|
; <21> 7/16/90 DTY (Really Darin.) Added conditional in cmpROM so TRY$ is only
|
|||
|
; executed when &operand is a register.
|
|||
|
; <20> 7/11/90 dba add dcROM, dcImport, and dcImportResident
|
|||
|
; <19> 7/11/90 dba fix bug from last check-in
|
|||
|
; <18> 7/10/90 dba turn off the DefineConditions$ for ROM builds
|
|||
|
; <17> 7/10/90 gbm Fix undefined SysVers to SYSVERS, because butt-head Darin turns
|
|||
|
; CASE ON in LInkPatch.a
|
|||
|
; <16> 7/10/90 DTY Added not32BitCQD conditional for System 6 builds.
|
|||
|
; <15> 7/7/90 JSM Include DispatchHelperPriv.a and use _DispatchHelper.
|
|||
|
; <14> 6/22/90 DTY Fix forROM case.
|
|||
|
; <13> 6/11/90 JSM Fix calculation of ReturnAddressDepth.
|
|||
|
; <12> 6/8/90 JSM Fix cmpROM macro.
|
|||
|
; <11> 6/8/90 dba fix all macros that use offsets from the PC (e.g., *+xxx); this
|
|||
|
; gets rid of bugs with complicated effective addresses
|
|||
|
; <10> 5/30/90 dba allow ROM lists on MakePatch/MakeInstall; make trap numbers work
|
|||
|
; without TrapNumbers.a; split dispatcher handling to support
|
|||
|
; dispatchers with huge numbers of traps; fix ComeFromPatchProc to
|
|||
|
; support all kinds of OS traps, ones that save A0 and ones that
|
|||
|
; do not save A0
|
|||
|
; <8> 4/20/90 KSM Modified the Dispatcher macro to allow the routine selector
|
|||
|
; number to be defaulted. The default symbol generated for a
|
|||
|
; routine named “MyProc” is “selectMyProc” (how easy can this
|
|||
|
; get?).
|
|||
|
; <7> 4/19/90 dba make the Dispatcher macro with Kevin; improve error messages and
|
|||
|
; some of the looping logic
|
|||
|
; <6> 4/17/90 dba get rid of LastJSROld$ which was never used; fix bugs in some of
|
|||
|
; the optimizations in ROM calls
|
|||
|
; <5> 4/4/90 dba fix so it complains when patching for no ROMs
|
|||
|
; <4> 3/21/90 dba fix ROM version number for the SE
|
|||
|
; <3> 3/9/90 KSM Now INCLUDES TrapNames.d -- TrapNames.a is too huge!
|
|||
|
; <2> 3/9/90 KSM Now includes “TrapNames.a.”
|
|||
|
; <1> 2/20/90 KSM First checked in.
|
|||
|
; 2/12/90 dba use the real opcode for xxxROM macros instead of NOPs
|
|||
|
; 1/27/90 dba added branches to ROM addresses
|
|||
|
; 1/25/90 dba added a header
|
|||
|
;
|
|||
|
; To Do:
|
|||
|
; make ROM versions of more macros
|
|||
|
; optimize for 020 (especially the ROM versions of the macros)
|
|||
|
;
|
|||
|
|
|||
|
if &type('__INCLUDINGLINKEDPATCHMACROS__') = 'UNDEFINED' then
|
|||
|
__IncludingLinkedPatchMacros__: set 1
|
|||
|
|
|||
|
include 'DispatchHelperPriv.a'
|
|||
|
|
|||
|
; ——————————————————————————————————————————————————————————————————————————————————————————————————
|
|||
|
; equates
|
|||
|
|
|||
|
; this file is for patches by default
|
|||
|
|
|||
|
if &type('forROM') = 'UNDEFINED' then
|
|||
|
forROM: equ 0
|
|||
|
endif
|
|||
|
|
|||
|
; This magic cookie is used to do fixups for jmpOld, jsrOld, etc.
|
|||
|
|
|||
|
OldTrapAddressMagicCookie: equ $ACBDADFB ; these two words must never occur in normal code
|
|||
|
|
|||
|
; ——————————————————————————————————————————————————————————————————————————————————————————————————
|
|||
|
; some macros that are the same for ROM or patches; more of these at the end of the file
|
|||
|
|
|||
|
; OptimizeFor sets up so that the macros will try to generate small code or fast code.
|
|||
|
|
|||
|
macro
|
|||
|
OptimizeFor &sizeOrSpeed
|
|||
|
gbla &optimizeForSpeed
|
|||
|
|
|||
|
if &lowcase(&sizeOrSpeed) = 'size' then
|
|||
|
&optimizeForSpeed: seta 0
|
|||
|
elseif &lowcase(&sizeOrSpeed) = 'speed' then
|
|||
|
&optimizeForSpeed: seta 1
|
|||
|
else
|
|||
|
aerror &concat('only “size” or “speed” allowed, not “',&sizeOrSpeed,'”')
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; ExportSymbol$ exports a symbol.
|
|||
|
|
|||
|
macro
|
|||
|
ExportSymbol$ &symbol
|
|||
|
; make a proc to put the symbol in if the the module name is empty
|
|||
|
; *** this won’t work for unnamed modules, but I can’t figure out a better way
|
|||
|
|
|||
|
lcla &makeProc
|
|||
|
&makeProc: seta &sysmod = ''
|
|||
|
if &makeProc then
|
|||
|
proc
|
|||
|
endif
|
|||
|
export &symbol
|
|||
|
&symbol: equ *
|
|||
|
if &makeProc then
|
|||
|
endproc
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; Try$ tries an optimize for space case out and is used by many macros below.
|
|||
|
|
|||
|
macro
|
|||
|
Try$ &trySymbol,&distance,&opcode,&operand,&defineSymbol
|
|||
|
gbla &optimizeForSpeed
|
|||
|
gbla &noCodeYet
|
|||
|
|
|||
|
; try this case
|
|||
|
|
|||
|
if &noCodeYet and (not &optimizeForSpeed) and (&type(&trySymbol) = 'CODE LABEL') then
|
|||
|
if * - &eval(&trySymbol) <= &eval(&distance) then
|
|||
|
if &operand = '' then
|
|||
|
@where: &opcode &trySymbol
|
|||
|
else
|
|||
|
@where: &opcode &trySymbol,&operand
|
|||
|
endif
|
|||
|
&noCodeYet: seta 0
|
|||
|
if &defineSymbol ≠ '' then
|
|||
|
&defineSymbol: set @where
|
|||
|
endif
|
|||
|
endif
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; ——————————————————————————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|||
|
if forROM then
|
|||
|
|
|||
|
; ——————————————————————————————————————————————————————————————————————————————————————————————————
|
|||
|
; macros for ROM (so we don’t have to heavily conditionalize code used both in ROM and patches)
|
|||
|
|
|||
|
macro
|
|||
|
ROMs
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
leaROM.&size &name,®ister
|
|||
|
import &name
|
|||
|
if &upcase(&size) = 'FAR' then
|
|||
|
if &setting('MACHINE') = 'MC68000' then
|
|||
|
@local: lea (&name-@local).L,®ister
|
|||
|
lea @local(pc,®ister..L),®ister
|
|||
|
else
|
|||
|
lea ((&name).l,pc),®ister
|
|||
|
endif
|
|||
|
else
|
|||
|
lea &name,®ister
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
peaROM.&size &name,&scratchRegister
|
|||
|
import &name
|
|||
|
if &upcase(&size) = 'FAR' then
|
|||
|
if &setting('MACHINE') = 'MC68000' then
|
|||
|
if &substr(&type(&scratchRegister),1,5) = 'REG A' then
|
|||
|
@local: lea (&name-@local).L,&scratchRegister
|
|||
|
pea @local(pc,&scratchRegister..L)
|
|||
|
else
|
|||
|
aerror 'must specify address register to use peaROM.far on a 68000'
|
|||
|
endif
|
|||
|
else
|
|||
|
pea ((&name).l,pc)
|
|||
|
endif
|
|||
|
else
|
|||
|
pea &name
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
jmpROM.&size &name,&scratchRegister
|
|||
|
gbla &noCodeYet
|
|||
|
&noCodeYet: seta 1
|
|||
|
|
|||
|
; try optimal case
|
|||
|
|
|||
|
Try$ LastRealJMP$&name,128-2,bra.s,,LastJMP$&name
|
|||
|
Try$ LastJMP$&name,128-2,bra.s,,LastJMP$&name
|
|||
|
|
|||
|
; if optimized cases didn’t kick in, generate a JMP for the patch linker
|
|||
|
|
|||
|
if &noCodeYet then
|
|||
|
import &name
|
|||
|
if &upcase(&size) = 'FAR' then
|
|||
|
if &setting('MACHINE') = 'MC68000' then
|
|||
|
if &substr(&type(&scratchRegister),1,5) = 'REG A' then
|
|||
|
@local: lea (&name-@local).L,&scratchRegister
|
|||
|
jmp @local(pc,&scratchRegister..L)
|
|||
|
else
|
|||
|
aerror 'must specify address register to use jmpROM.far on a 68000'
|
|||
|
endif
|
|||
|
else
|
|||
|
jmp ((&name).l,pc)
|
|||
|
endif
|
|||
|
else
|
|||
|
@where: jmp &name
|
|||
|
LastJMP$&name: set @where
|
|||
|
LastRealJMP$&name: set LastJMP$&name
|
|||
|
endif
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
jsrROM.&size &name,&scratchRegister
|
|||
|
gbla &noCodeYet
|
|||
|
&noCodeYet: seta 1
|
|||
|
|
|||
|
; try optimal case
|
|||
|
|
|||
|
Try$ LastRealJMP$&name,128-2,bsr.s
|
|||
|
Try$ LastJMP$&name,128-2,bsr.s
|
|||
|
|
|||
|
; if optimized cases didn’t kick in, generate a JSR for the patch linker
|
|||
|
|
|||
|
if &noCodeYet then
|
|||
|
import &name
|
|||
|
if &upcase(&size) = 'FAR' then
|
|||
|
if &setting('MACHINE') = 'MC68000' then
|
|||
|
if &substr(&type(&scratchRegister),1,5) = 'REG A' then
|
|||
|
@local: lea (&name-@local).L,&scratchRegister
|
|||
|
jsr @local(pc,&scratchRegister..L)
|
|||
|
else
|
|||
|
aerror 'must specify address register to use jsrROM.far on a 68000'
|
|||
|
endif
|
|||
|
else
|
|||
|
jsr ((&name).l,pc)
|
|||
|
endif
|
|||
|
else
|
|||
|
jsr &name
|
|||
|
endif
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
BranchROM$ &name,&condition,&oppositeCondition
|
|||
|
gbla &noCodeYet
|
|||
|
&noCodeYet: seta 1
|
|||
|
|
|||
|
; try optimal case
|
|||
|
|
|||
|
Try$ LastRealJMP$&name,128-2,b&condition..s
|
|||
|
Try$ LastJMP$&name,128-2,b&condition..s
|
|||
|
|
|||
|
; if optimized cases didn’t kick in, generate a JMP for the patch linker
|
|||
|
|
|||
|
if &noCodeYet then
|
|||
|
b&oppositeCondition..s @skip
|
|||
|
import &name
|
|||
|
@where: jmp &name
|
|||
|
@skip:
|
|||
|
LastJMP$&name: set @where
|
|||
|
LastRealJMP$&name: set LastJMP$&name
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
leaResident &name,®ister
|
|||
|
import &name
|
|||
|
lea &name,®ister
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
peaResident &name
|
|||
|
import &name
|
|||
|
pea &name
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
&name: ROMBind
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
DefineConditions$
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
MakePatch
|
|||
|
endm
|
|||
|
|
|||
|
; MakeDispatcherTable
|
|||
|
; Called by EndDispatcher to generate the dispatch table for _DispatchHelper
|
|||
|
; Unlike the version for patches, we don't use absolute addresses in the dispatch table
|
|||
|
; since the ROM may move in memory. Instead, we use word offsets from the beginning
|
|||
|
; of the table.
|
|||
|
|
|||
|
macro
|
|||
|
MakeDispatcherTable
|
|||
|
gbla &firstSelector
|
|||
|
gbla &lastSelector
|
|||
|
gbla &allSelectorsEven
|
|||
|
|
|||
|
gblc &selectorName[256]
|
|||
|
gbla &selectorIndex[256]
|
|||
|
|
|||
|
; make table header
|
|||
|
|
|||
|
DispatchTable:
|
|||
|
|
|||
|
if &allSelectorsEven then
|
|||
|
dc.w (1<<dhSelectorsEven)
|
|||
|
else
|
|||
|
dc.w 0 ; dispatch table entries are offsets from the start of the table
|
|||
|
endif
|
|||
|
|
|||
|
dc.b &firstSelector
|
|||
|
dc.b &lastSelector
|
|||
|
|
|||
|
; make table
|
|||
|
|
|||
|
lclc &name
|
|||
|
lcla &num
|
|||
|
lcla &index
|
|||
|
|
|||
|
&num: seta &firstSelector
|
|||
|
while &num <= &lastSelector do
|
|||
|
&index: seta &selectorIndex[&num + 129]
|
|||
|
if &index = 0 then
|
|||
|
; *** could be a problem if DispatchHelperBadSelector is too far away in ROM
|
|||
|
import DispatchHelperBadSelector
|
|||
|
dc.w DispatchHelperBadSelector-DispatchTable ; unused entry, set it to unimplemented routine in DispatchHelper.a
|
|||
|
else
|
|||
|
import &selectorName[&index]
|
|||
|
dc.w &selectorName[&index]-DispatchTable ; get address of entry
|
|||
|
endif
|
|||
|
if &allSelectorsEven then
|
|||
|
&num: seta &num + 2
|
|||
|
else
|
|||
|
&num: seta &num + 1
|
|||
|
endif
|
|||
|
endwhile
|
|||
|
endm
|
|||
|
|
|||
|
; ComeFromPatchProc doesn't work for ROMs, but we need to have it compile
|
|||
|
|
|||
|
macro
|
|||
|
&module: ComeFromPatchProc
|
|||
|
&module: proc export
|
|||
|
endm
|
|||
|
|
|||
|
; xxxOld macros don't work for ROM either, but like ComeFromPatchProc we need them to compile
|
|||
|
|
|||
|
macro
|
|||
|
leaOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
peaOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
jmpOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
jsrOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bccOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bcsOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
beqOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bgeOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bgtOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bhiOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bhsOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bleOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bloOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
blsOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bltOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bmiOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bneOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bnzOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bplOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
braOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bvcOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bvsOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
bzOld
|
|||
|
endm
|
|||
|
|
|||
|
macro
|
|||
|
cmpROM
|
|||
|
endm
|
|||
|
|
|||
|
; ——————————————————————————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|||
|
else ; not forROM
|
|||
|
|
|||
|
; ——————————————————————————————————————————————————————————————————————————————————————————————————
|
|||
|
; macros for use in patches
|
|||
|
|
|||
|
; DefineConditions$ defines all of the conditions, including ROM versions and other conditions.
|
|||
|
; Each ROM version is an ordered pair of the ROM name and the ROM version number.
|
|||
|
; Each other condition is a name.
|
|||
|
|
|||
|
macro
|
|||
|
DefineConditions$
|
|||
|
lcla &numConditions
|
|||
|
lcla &index
|
|||
|
|
|||
|
; define a condition bit and ROM version for each ROM (e.g., $0075)
|
|||
|
|
|||
|
&numConditions: seta 0
|
|||
|
|
|||
|
&index: seta 0
|
|||
|
while &index < &nbr(&syslist) do
|
|||
|
&index: seta &index + 1
|
|||
|
if &nbr(&syslist[&index]) = 2 then
|
|||
|
Condition$&syslist[&index,1]: equ &numConditions
|
|||
|
ROMVersion$&numConditions: equ &syslist[&index,2]
|
|||
|
kROMVersion&syslist[&index,1]: equ &syslist[&index,2]
|
|||
|
&numConditions: seta &numConditions + 1
|
|||
|
endif
|
|||
|
endwhile
|
|||
|
|
|||
|
NumROMs$: equ &numConditions
|
|||
|
|
|||
|
; check to see that we can use resource IDs to express ROM combinations
|
|||
|
|
|||
|
if NumROMs$ > 15 then
|
|||
|
aerror 'too many ROMs; up to 15 allowed'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
; define a condition bit numberfor each non-ROM condition
|
|||
|
|
|||
|
&index: seta 0
|
|||
|
while &index < &nbr(&syslist) do
|
|||
|
&index: seta &index + 1
|
|||
|
if &nbr(&syslist[&index]) ≠ 2 then
|
|||
|
Condition$&syslist[&index]: equ &numConditions
|
|||
|
&numConditions: seta &numConditions + 1
|
|||
|
endif
|
|||
|
endwhile
|
|||
|
|
|||
|
NumConditions$: equ &numConditions
|
|||
|
|
|||
|
; check to see that a mask with 1 bit per condition will fit in 31 bits
|
|||
|
|
|||
|
if NumConditions$ > 31 then
|
|||
|
aerror 'too many conditions; up to 31 allowed'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
; make masks
|
|||
|
|
|||
|
ROMsMask$: equ (1 << NumROMs$) - 1
|
|||
|
NonROMConditionsMask$: equ (1 << NumConditions$) - 1 - ROMsMask$
|
|||
|
endm
|
|||
|
|
|||
|
; ParseLoadConditions$ parses a list of conditions.
|
|||
|
; It gets passed a string containing '(condition,condition,...)'.
|
|||
|
|
|||
|
macro
|
|||
|
ParseLoadConditions$ &conditions
|
|||
|
gbla &loadConditions
|
|||
|
&loadConditions: seta 0
|
|||
|
|
|||
|
; parse string passed with conditions into a list
|
|||
|
|
|||
|
if (&substr(&conditions,1,1) ≠ '(') or (&substr(&conditions,&len(&conditions),1) ≠ ')') then
|
|||
|
aerror 'missing parentheses'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
lclc &conditionList[NumConditions$]
|
|||
|
lcla &numConditions
|
|||
|
&numConditions: seta &list(&substr(&conditions,2,&len(&conditions)-2),'&conditionList')
|
|||
|
|
|||
|
; for each condition, set the appropriate bit in &loadConditions
|
|||
|
|
|||
|
lcla &index
|
|||
|
&index: seta 0
|
|||
|
lclc &conditionName
|
|||
|
lclc &symbol
|
|||
|
lcla &mask
|
|||
|
while &index < &numConditions do
|
|||
|
&index: seta &index + 1
|
|||
|
&conditionName: setc &conditionList[&index]
|
|||
|
&symbol: setc &concat('Condition$',&conditionName)
|
|||
|
if &type(&symbol) = 'EQU' then
|
|||
|
&mask: seta 1 << &eval(&symbol)
|
|||
|
if (&mask and &loadConditions) ≠ 0 then
|
|||
|
aerror &concat('ROM “',&conditionName,'” mentioned twice')
|
|||
|
else
|
|||
|
&loadConditions: seta &loadConditions or &mask
|
|||
|
endif
|
|||
|
else
|
|||
|
aerror &concat('never heard of ROM named “',&conditionName,'”')
|
|||
|
endif
|
|||
|
endwhile
|
|||
|
|
|||
|
; at least one ROM must be mentioned
|
|||
|
|
|||
|
if (&loadConditions and ROMsMask$) = 0 then
|
|||
|
aerror 'no ROMs mentioned'
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; ROMs defines which ROM versions apply as a default from this point on.
|
|||
|
|
|||
|
macro
|
|||
|
ROMs
|
|||
|
gbla &loadConditions,&defaultLoadConditions
|
|||
|
|
|||
|
; build a string out of the ROMs passed
|
|||
|
|
|||
|
lclc &roms
|
|||
|
&roms: setc ''
|
|||
|
lcla &index
|
|||
|
&index: seta 0
|
|||
|
while &index < &nbr(&syslist) do
|
|||
|
&index: seta &index + 1
|
|||
|
&roms: setc &concat(&roms,',',&syslist[&index])
|
|||
|
endwhile
|
|||
|
|
|||
|
; now parse the list, and set the conditions scope
|
|||
|
|
|||
|
ParseLoadConditions$ (&substr(&roms,2,32767))
|
|||
|
&defaultLoadConditions: seta &loadConditions
|
|||
|
endm
|
|||
|
|
|||
|
; ROMBind binds pairs of ROM versions and addresses.
|
|||
|
|
|||
|
macro
|
|||
|
&name: ROMBind
|
|||
|
; go through each pair, checking that the ROM name is good, and making table entries
|
|||
|
|
|||
|
lcla &seenMask
|
|||
|
&seenMask: seta 0
|
|||
|
|
|||
|
lcla &index
|
|||
|
&index: seta 0
|
|||
|
lclc &romName
|
|||
|
lclc &symbol
|
|||
|
lcla &romNum
|
|||
|
lcla &mask
|
|||
|
while &index < &nbr(&syslist) do
|
|||
|
&index: seta &index + 1
|
|||
|
&romName: setc &syslist[&index,1]
|
|||
|
&symbol: setc &concat('Condition$',&romName)
|
|||
|
if &type(&symbol) = 'EQU' then
|
|||
|
&romNum: seta &eval(&symbol)
|
|||
|
&mask: seta 1 << &romNum
|
|||
|
if (&mask and ROMsMask$) = 0 then
|
|||
|
aerror &concat('can’t bind with a condition like “',&romName,'”, only a ROM')
|
|||
|
elseif (&mask and &seenMask) ≠ 0 then
|
|||
|
aerror &concat('“',&romName,'” mentioned twice')
|
|||
|
else
|
|||
|
ExportSymbol$ BIND$&name.$&romNum.$&eval(&syslist[&index,2])$
|
|||
|
&seenMask: seta &seenMask or &mask
|
|||
|
endif
|
|||
|
else
|
|||
|
aerror &concat('never heard of ROM named “',&romName,'”')
|
|||
|
endif
|
|||
|
endwhile
|
|||
|
endm
|
|||
|
|
|||
|
; leaOld loads the old address of a trap into a register.
|
|||
|
|
|||
|
macro
|
|||
|
leaOld ®ister
|
|||
|
gbla &noCodeYet
|
|||
|
&noCodeYet: seta 1
|
|||
|
|
|||
|
; try optimal case
|
|||
|
|
|||
|
Try$ LastOld$,32768-4,move.l,®ister
|
|||
|
|
|||
|
; if optimized cases didn’t kick in, generate a MOVE.L with the magic cookie
|
|||
|
|
|||
|
if &noCodeYet then
|
|||
|
if &type('InComeFrom$') = 'UNDEFINED' then
|
|||
|
@where: move.l #OldTrapAddressMagicCookie,®ister
|
|||
|
LastOld$: set @where + 2
|
|||
|
else
|
|||
|
aerror 'old reference too far in come-from patch'
|
|||
|
endif
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; peaOld pushes the old address of a trap onto the stack.
|
|||
|
|
|||
|
macro
|
|||
|
peaOld
|
|||
|
gbla &noCodeYet
|
|||
|
&noCodeYet: seta 1
|
|||
|
|
|||
|
; try optimal case
|
|||
|
|
|||
|
Try$ LastOld$,32768-4,move.l,-(sp)
|
|||
|
|
|||
|
; if optimized cases didn’t kick in, generate a MOVE.L with the magic cookie
|
|||
|
|
|||
|
if &noCodeYet then
|
|||
|
if &type('InComeFrom$') = 'UNDEFINED' then
|
|||
|
@where: move.l #OldTrapAddressMagicCookie,-(sp)
|
|||
|
LastOld$: set @where + 2
|
|||
|
else
|
|||
|
aerror 'old reference too far in come-from patch'
|
|||
|
endif
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; jmpOld jumps to the old implementation of a trap.
|
|||
|
; If we are set to OptimizeFor size, then branch to a previous jmpOld.
|
|||
|
|
|||
|
macro
|
|||
|
jmpOld
|
|||
|
gbla &noCodeYet
|
|||
|
&noCodeYet: seta 1
|
|||
|
|
|||
|
; try optimal case
|
|||
|
|
|||
|
Try$ LastRealJMPOld$,128-2,bra.s,,LastJMPOld$
|
|||
|
Try$ LastJMPOld$,128-2,bra.s,,LastJMPOld$
|
|||
|
Try$ LastRealJMPOld$,32768-4,bra.w,,LastJMPOld$
|
|||
|
Try$ LastJMPOld$,32768-4,bra.w,,LastJMPOld$
|
|||
|
|
|||
|
; if optimized cases didn’t kick in, generate a JMP.L with the magic cookie
|
|||
|
|
|||
|
if &noCodeYet then
|
|||
|
if &type('InComeFrom$') = 'UNDEFINED' then
|
|||
|
@where: jmp (OldTrapAddressMagicCookie).L
|
|||
|
LastJMPOld$: set @where
|
|||
|
LastRealJMPOld$: set LastJMPOld$
|
|||
|
LastOld$: set LastJMPOld$ + 2
|
|||
|
else
|
|||
|
aerror 'old reference too far in come-from patch'
|
|||
|
endif
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; jsrOld calls the old implementation of a trap.
|
|||
|
; If we are set to OptimizeFor size, then branch to a previous jmpOld or jsrOld.
|
|||
|
|
|||
|
macro
|
|||
|
jsrOld
|
|||
|
gbla &noCodeYet
|
|||
|
&noCodeYet: seta 1
|
|||
|
|
|||
|
; try optimal case
|
|||
|
|
|||
|
Try$ LastRealJMPOld$,128-2,bsr.s
|
|||
|
Try$ LastJMPOld$,128-2,bsr.s
|
|||
|
Try$ LastRealJMPOld$,32768-4,bsr.w
|
|||
|
Try$ LastJMPOld$,32768-4,bsr.w
|
|||
|
|
|||
|
; if optimized cases didn’t kick in, generate a JSR.L with the magic cookie
|
|||
|
|
|||
|
if &noCodeYet then
|
|||
|
if &type('InComeFrom$') = 'UNDEFINED' then
|
|||
|
@where: jsr (OldTrapAddressMagicCookie).L
|
|||
|
LastOld$: set @where + 2
|
|||
|
else
|
|||
|
aerror 'old reference too far in come-from patch'
|
|||
|
endif
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; BranchOld$ branches to the old implementation of a trap.
|
|||
|
; It is used by the specific branch macros to build a variety of branches.
|
|||
|
|
|||
|
macro
|
|||
|
BranchOld$ &condition,&oppositeCondition
|
|||
|
gbla &noCodeYet
|
|||
|
&noCodeYet: seta 1
|
|||
|
|
|||
|
; try optimal case
|
|||
|
|
|||
|
Try$ LastRealJMPOld$,128-2,b&condition..s
|
|||
|
Try$ LastJMPOld$,128-2,b&condition..s
|
|||
|
Try$ LastRealJMPOld$,32768-4,b&condition..w
|
|||
|
Try$ LastJMPOld$,32768-4,b&condition..w
|
|||
|
|
|||
|
; if optimized cases didn’t kick in, generate a JMP.L with the magic cookie
|
|||
|
|
|||
|
if &noCodeYet then
|
|||
|
if &type('InComeFrom$') = 'UNDEFINED' then
|
|||
|
b&oppositeCondition..s @skip
|
|||
|
@where: jmp (OldTrapAddressMagicCookie).L
|
|||
|
@skip:
|
|||
|
LastJMPOld$: set @where
|
|||
|
LastRealJMPOld$: set LastJMPOld$
|
|||
|
LastOld$: set LastJMPOld$ + 2
|
|||
|
else
|
|||
|
aerror 'old reference too far in come-from patch'
|
|||
|
endif
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; bccOld
|
|||
|
|
|||
|
macro
|
|||
|
bccOld
|
|||
|
BranchOld$ cc,cs
|
|||
|
endm
|
|||
|
|
|||
|
; bcsOld
|
|||
|
|
|||
|
macro
|
|||
|
bcsOld
|
|||
|
BranchOld$ cs,cc
|
|||
|
endm
|
|||
|
|
|||
|
; beqOld
|
|||
|
|
|||
|
macro
|
|||
|
beqOld
|
|||
|
BranchOld$ eq,ne
|
|||
|
endm
|
|||
|
|
|||
|
; bgeOld
|
|||
|
|
|||
|
macro
|
|||
|
bgeOld
|
|||
|
BranchOld$ ge,lt
|
|||
|
endm
|
|||
|
|
|||
|
; bgtOld
|
|||
|
|
|||
|
macro
|
|||
|
bgtOld
|
|||
|
BranchOld$ gt,le
|
|||
|
endm
|
|||
|
|
|||
|
; bhiOld
|
|||
|
|
|||
|
macro
|
|||
|
bhiOld
|
|||
|
BranchOld$ hi,ls
|
|||
|
endm
|
|||
|
|
|||
|
; bhsOld
|
|||
|
|
|||
|
macro
|
|||
|
bhsOld
|
|||
|
BranchOld$ hs,lo
|
|||
|
endm
|
|||
|
|
|||
|
; bleOld
|
|||
|
|
|||
|
macro
|
|||
|
bleOld
|
|||
|
BranchOld$ le,gt
|
|||
|
endm
|
|||
|
|
|||
|
; bloOld
|
|||
|
|
|||
|
macro
|
|||
|
bloOld
|
|||
|
BranchOld$ lo,hs
|
|||
|
endm
|
|||
|
|
|||
|
; blsOld
|
|||
|
|
|||
|
macro
|
|||
|
blsOld
|
|||
|
BranchOld$ ls,hi
|
|||
|
endm
|
|||
|
|
|||
|
; bltOld
|
|||
|
|
|||
|
macro
|
|||
|
bltOld
|
|||
|
BranchOld$ lt,ge
|
|||
|
endm
|
|||
|
|
|||
|
; bmiOld
|
|||
|
|
|||
|
macro
|
|||
|
bmiOld
|
|||
|
BranchOld$ mi,pl
|
|||
|
endm
|
|||
|
|
|||
|
; bneOld
|
|||
|
|
|||
|
macro
|
|||
|
bneOld
|
|||
|
BranchOld$ ne,eq
|
|||
|
endm
|
|||
|
|
|||
|
; bnzOld
|
|||
|
|
|||
|
macro
|
|||
|
bnzOld
|
|||
|
BranchOld$ nz,z
|
|||
|
endm
|
|||
|
|
|||
|
; bplOld
|
|||
|
|
|||
|
macro
|
|||
|
bplOld
|
|||
|
BranchOld$ pl,mi
|
|||
|
endm
|
|||
|
|
|||
|
; braOld
|
|||
|
|
|||
|
macro
|
|||
|
braOld
|
|||
|
jmpOld
|
|||
|
endm
|
|||
|
|
|||
|
; bvcOld
|
|||
|
|
|||
|
macro
|
|||
|
bvcOld
|
|||
|
BranchOld$ vc,vs
|
|||
|
endm
|
|||
|
|
|||
|
; bvsOld
|
|||
|
|
|||
|
macro
|
|||
|
bvsOld
|
|||
|
BranchOld$ vs,vc
|
|||
|
endm
|
|||
|
|
|||
|
; bzOld
|
|||
|
|
|||
|
macro
|
|||
|
bzOld
|
|||
|
BranchOld$ z,nz
|
|||
|
endm
|
|||
|
|
|||
|
; leaROM loads the fixed ROM address of something.
|
|||
|
; There must be a corresponding ROMBind somewhere else.
|
|||
|
|
|||
|
macro
|
|||
|
leaROM &name,®ister
|
|||
|
gbla &noCodeYet
|
|||
|
&noCodeYet: seta 1
|
|||
|
|
|||
|
; try optimal case
|
|||
|
|
|||
|
Try$ LastROM$&name,32768-4,move.l,®ister
|
|||
|
|
|||
|
; if optimized cases didn’t kick in, generate an LEA for the patch linker
|
|||
|
|
|||
|
if &noCodeYet then
|
|||
|
@where: move.l #'dba',®ister
|
|||
|
org @where + 2
|
|||
|
import ROM$&name.$
|
|||
|
jmp ROM$&name.$
|
|||
|
LastROM$&name: set @where + 2
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; peaROM pushes the fixed ROM address of something.
|
|||
|
; There must be a corresponding ROMBind somewhere else.
|
|||
|
|
|||
|
macro
|
|||
|
peaROM &name
|
|||
|
gbla &noCodeYet
|
|||
|
&noCodeYet: seta 1
|
|||
|
|
|||
|
; try optimal case
|
|||
|
|
|||
|
Try$ LastROM$&name,32768-4,move.l,-(sp)
|
|||
|
|
|||
|
; if optimized cases didn’t kick in, generate a PEA for the patch linker
|
|||
|
|
|||
|
if &noCodeYet then
|
|||
|
@where: move.l #'dba',-(sp)
|
|||
|
org @where + 2
|
|||
|
import ROM$&name.$
|
|||
|
jmp ROM$&name.$
|
|||
|
LastROM$&name: set @where + 2
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; jmpROM jumps to something by fixed ROM address.
|
|||
|
; There must be a corresponding ROMBind somewhere else.
|
|||
|
|
|||
|
macro
|
|||
|
jmpROM &name
|
|||
|
gbla &noCodeYet
|
|||
|
&noCodeYet: seta 1
|
|||
|
|
|||
|
; try optimal case
|
|||
|
|
|||
|
Try$ LastRealJMPROM$&name,128-2,bra.s,,LastJMPOld$&name
|
|||
|
Try$ LastJMPROM$&name,128-2,bra.s,,LastJMPROM$&name
|
|||
|
Try$ LastRealJMPROM$&name,32768-4,bra.w,,LastJMPROM$&name
|
|||
|
Try$ LastJMPROM$&name,32768-4,bra.w,,LastJMPROM$&name
|
|||
|
|
|||
|
; if optimized cases didn’t kick in, generate a JMP for the patch linker
|
|||
|
|
|||
|
if &noCodeYet then
|
|||
|
@where: jmp 'dba'
|
|||
|
org @where + 2
|
|||
|
import ROM$&name.$
|
|||
|
jmp ROM$&name.$
|
|||
|
LastJMPROM$&name: set @where
|
|||
|
LastRealJMPROM$&name: set LastJMPROM$&name
|
|||
|
LastROM$&name: set LastJMPROM$&name + 2
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; jsrROM calls something by fixed ROM address.
|
|||
|
; There must be a corresponding ROMBind somewhere else.
|
|||
|
|
|||
|
macro
|
|||
|
jsrROM &name
|
|||
|
gbla &noCodeYet
|
|||
|
&noCodeYet: seta 1
|
|||
|
|
|||
|
; try optimal case
|
|||
|
|
|||
|
Try$ LastRealJMPROM$&name,128-2,bsr.s
|
|||
|
Try$ LastJMPROM$&name,128-2,bsr.s
|
|||
|
Try$ LastRealJMPROM$&name,32768-4,bsr.w
|
|||
|
Try$ LastJMPROM$&name,32768-4,bsr.w
|
|||
|
|
|||
|
; if optimized cases didn’t kick in, generate a JSR for the patch linker
|
|||
|
|
|||
|
if &noCodeYet then
|
|||
|
@where: jsr 'dba'
|
|||
|
org @where + 2
|
|||
|
import ROM$&name.$
|
|||
|
jmp ROM$&name.$
|
|||
|
LastROM$&name: set @where + 2
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; cmpROM compares an operand with a fixed ROM address.
|
|||
|
; There must be a corresponding ROMBind somewhere else.
|
|||
|
|
|||
|
macro
|
|||
|
cmpROM &nameWithPossiblePoundPrefix,&operand
|
|||
|
gbla &noCodeYet
|
|||
|
&noCodeYet: seta 1
|
|||
|
|
|||
|
; strip off the '#' prefix on a name, if it exists
|
|||
|
|
|||
|
lclc &name
|
|||
|
if &substr(&nameWithPossiblePoundPrefix,1,1) = '#' then
|
|||
|
&name: setc &substr(&nameWithPossiblePoundPrefix,2,&len(&nameWithPossiblePoundPrefix)-1)
|
|||
|
else
|
|||
|
&name: setc &nameWithPossiblePoundPrefix
|
|||
|
endif
|
|||
|
|
|||
|
; try optimal case
|
|||
|
|
|||
|
if &substr(&type(&operand),1,4) = 'REG ' then
|
|||
|
Try$ LastROM$&name,32768-4,cmp.l,&operand
|
|||
|
endif
|
|||
|
|
|||
|
; if optimized cases didn’t kick in, generate a PEA and CMP for the patch linker
|
|||
|
|
|||
|
if &noCodeYet then
|
|||
|
@where: cmp.l #'dba',&operand
|
|||
|
org @where + 2
|
|||
|
import ROM$&name.$
|
|||
|
jmp ROM$&name.$
|
|||
|
LastROM$&name: set @where + 2
|
|||
|
org
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; BranchROM$ branches to the ROM implementation of a trap.
|
|||
|
; It is used by the specific branch macros to build a variety of branches.
|
|||
|
|
|||
|
macro
|
|||
|
BranchROM$ &name,&condition,&oppositeCondition
|
|||
|
gbla &noCodeYet
|
|||
|
&noCodeYet: seta 1
|
|||
|
|
|||
|
; try optimal case
|
|||
|
|
|||
|
Try$ LastRealJMPROM$&name,128-2,b&condition..s
|
|||
|
Try$ LastJMPROM$&name,128-2,b&condition..s
|
|||
|
Try$ LastRealJMPROM$&name,32768-4,b&condition..w
|
|||
|
Try$ LastJMPROM$&name,32768-4,b&condition..w
|
|||
|
|
|||
|
; if optimized cases didn’t kick in, generate a JMP for the patch linker
|
|||
|
|
|||
|
if &noCodeYet then
|
|||
|
b&oppositeCondition..s @skip
|
|||
|
@where: jmp 'dba'
|
|||
|
@skip:
|
|||
|
org @where + 2
|
|||
|
import ROM$&name.$
|
|||
|
jmp ROM$&name.$
|
|||
|
LastJMPROM$&name: set @where
|
|||
|
LastRealJMPROM$&name: set LastJMPROM$&name
|
|||
|
LastROM$&name: set LastJMPROM$&name + 2
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; dcROM creates a long word containing a ROM address.
|
|||
|
; There must be a corresponding ROMBind somewhere else.
|
|||
|
|
|||
|
macro
|
|||
|
dcROM &name
|
|||
|
import ROM$&name.$
|
|||
|
LastROM$&name: jmp ROM$&name.$
|
|||
|
endm
|
|||
|
|
|||
|
; dcImport creates an absolute address from an imported symbol.
|
|||
|
|
|||
|
macro
|
|||
|
dcImport &name
|
|||
|
import &name
|
|||
|
@where: jmp &name
|
|||
|
org @where
|
|||
|
dc.w 0
|
|||
|
org
|
|||
|
endm
|
|||
|
|
|||
|
; dcImportResident creates an absolute address from an imported symbol.
|
|||
|
; The module containing the address will be copied into the system heap.
|
|||
|
|
|||
|
macro
|
|||
|
dcImportResident &name
|
|||
|
dcImport &name
|
|||
|
export RESIDENT$&name.$&sysmod.$&sysindex.$
|
|||
|
RESIDENT$&name.$&sysmod.$&sysindex.$: equ *-2
|
|||
|
endm
|
|||
|
|
|||
|
; dcOLD defines a long word magic cookie which will be filled in by the LinkPatch
|
|||
|
; loader
|
|||
|
|
|||
|
macro
|
|||
|
&lab dcOld
|
|||
|
&lab dc.l (OldTrapAddressMagicCookie)
|
|||
|
endm
|
|||
|
|
|||
|
|
|||
|
; leaResident gets the address of a routine, and also marks it resident.
|
|||
|
; It will be copied into the system heap if the install code with the leaResident is executed.
|
|||
|
|
|||
|
macro
|
|||
|
leaResident &name,®ister
|
|||
|
import &name
|
|||
|
lea &name,®ister
|
|||
|
export RESIDENT$&name.$&sysmod.$&sysindex.$
|
|||
|
RESIDENT$&name.$&sysmod.$&sysindex.$: equ *-2
|
|||
|
endm
|
|||
|
|
|||
|
; peaResident gets the address of a routine, and also marks it resident.
|
|||
|
; It will be copied into the system heap if the install code with the peaResident is executed.
|
|||
|
|
|||
|
macro
|
|||
|
peaResident &name
|
|||
|
import &name
|
|||
|
pea &name
|
|||
|
export RESIDENT$&name.$&sysmod.$&sysindex.$
|
|||
|
RESIDENT$&name.$&sysmod.$&sysindex.$: equ *-2
|
|||
|
endm
|
|||
|
|
|||
|
; MakePatch makes the specified routine installed as a patch.
|
|||
|
; It works by creating a strange symbol that is recognized by the LinkPatch tool.
|
|||
|
|
|||
|
macro
|
|||
|
MakePatch &entry,&trap,&roms
|
|||
|
gbla &loadConditions,&defaultLoadConditions
|
|||
|
gbla &trapNum
|
|||
|
gbla &comeFromAllowed
|
|||
|
gblc &LPFileName
|
|||
|
|
|||
|
if &nbr(&syslist) > 3 then
|
|||
|
aerror 'too many parameters to MakePatch'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
|
|||
|
; figure out which ROMs this patch applies for
|
|||
|
|
|||
|
if &roms = '' then
|
|||
|
&loadConditions: seta &defaultLoadConditions
|
|||
|
else
|
|||
|
ParseLoadConditions$ &roms
|
|||
|
endif
|
|||
|
|
|||
|
; at least one ROM must be mentioned
|
|||
|
|
|||
|
if (&loadConditions and ROMsMask$) = 0 then
|
|||
|
aerror 'no ROMs mentioned (each patch or install must apply to at least one ROM)'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
; evaluate the trap
|
|||
|
|
|||
|
if &trap = '' then
|
|||
|
aerror 'no trap mentioned (each patch must specify a trap)'
|
|||
|
exitm
|
|||
|
elseif &type(&upcase(&trap)) = 'OPWORD' then
|
|||
|
if &findsym(&sysglobal, &upcase(&trap)) then
|
|||
|
&trapNum: seta &sysvalue
|
|||
|
elseif &findsym(&syslocal, &upcase(&trap)) then
|
|||
|
&trapNum: seta &sysvalue
|
|||
|
else
|
|||
|
aerror 'internal error in MakePatch (an OPWORD, but not in any symbol table)'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
elseif &substr(&upcase(&trap),1,13) = 'EXPANDMEMREC.' then
|
|||
|
&trapNum: seta &eval(&trap) + $4000
|
|||
|
if (&trapNum < $4000) or (&trapNum > $7FFC) then
|
|||
|
aerror 'ExpandMem global that is not in the $0000 - $3FFC range'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
else
|
|||
|
&trapNum: seta &eval(&trap)
|
|||
|
if ((&trapNum < 0) or (&trapNum > $3FFC)) and ((&trapNum and $F000) ≠ $A000) then
|
|||
|
aerror 'not a low memory global ($0002 - $3FFC) or a trap number ($A000 - $AFFF)'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
endif
|
|||
|
|
|||
|
; if come-from, check to see that it is a real trap number and not just a vector number
|
|||
|
; changing the high nibble to C instead of A makes it a come-from patch
|
|||
|
|
|||
|
if &type('InComeFrom$') = 'EQU' then
|
|||
|
if (&trapNum and $F000) = $A000 then
|
|||
|
&trapNum: seta $C000 or (&trapNum and $0FFF)
|
|||
|
else
|
|||
|
aerror 'come-from patch on a trap that is not in the $A000 range'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
endif
|
|||
|
|
|||
|
; export a symbol for the patch linker
|
|||
|
|
|||
|
ExportSymbol$ PATCH$&entry.$&trapNum.$&loadConditions.$
|
|||
|
COMMENT 'PATCH$&LPFileName.$&entry.$&trapNum.$&loadConditions.$'
|
|||
|
endm
|
|||
|
|
|||
|
; ComeFromPatchProc makes a proc that is installed as a come-from patch.
|
|||
|
; Specify the trap, and the name of a fixed ROM address that should trigger the patch.
|
|||
|
|
|||
|
macro
|
|||
|
&module: ComeFromPatchProc &trap,&fromWhere,&roms
|
|||
|
gbla &trapNum
|
|||
|
|
|||
|
if &nbr(&syslist) > 3 then
|
|||
|
aerror 'too many parameters to ComeFromPatchProc'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
if &module = '' then
|
|||
|
aerror 'come-from patches must be named; invent one that I’ll like'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
&module: proc export
|
|||
|
bra.s @skipOld
|
|||
|
jmpOld
|
|||
|
@skipOld:
|
|||
|
InComeFrom$: equ 1
|
|||
|
MakePatch &module,&trap,&roms
|
|||
|
|
|||
|
; figure out the depth of the return address
|
|||
|
|
|||
|
if &trapNum < $A000 then ; not a trap <33>
|
|||
|
ReturnAddressDepth: equ 0
|
|||
|
elseif &trapNum and $800 then ; Toolbox trap
|
|||
|
ReturnAddressDepth: equ 0
|
|||
|
elseif &trapNum and $100 then ; OS trap (no save A0)
|
|||
|
ReturnAddressDepth: equ 6*4
|
|||
|
else ; OS trap (save A0)
|
|||
|
ReturnAddressDepth: equ 7*4
|
|||
|
endif
|
|||
|
|
|||
|
; generate a compare with the return address if that is appropriate
|
|||
|
|
|||
|
gblc &comeFromWhere ; remember address for rejoinROM
|
|||
|
&comeFromWhere: setc &fromWhere
|
|||
|
if &fromWhere ≠ '' then
|
|||
|
cmpROM &fromWhere,ReturnAddressDepth(sp)
|
|||
|
bneOld
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; ComeFromAfterPatchProc makes a proc that is installed as a come-from patch.
|
|||
|
; Specify the trap, and the name of a fixed ROM address that should trigger the patch.
|
|||
|
; It triggers *after* the original trap has been called.
|
|||
|
; You must return by jumping back into the ROM, not with an rts.
|
|||
|
|
|||
|
macro
|
|||
|
&module: ComeFromAfterPatchProc &trap,&fromWhere,&roms
|
|||
|
if &nbr(&syslist) > 3 then
|
|||
|
aerror 'too many parameters to ComeFromAfterPatchProc'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
if &fromWhere = '' then
|
|||
|
aerror 'ComeFromAfterPatchProc must have a fromWhere address'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
&module: ComeFromPatchProc &trap,&fromWhere,&roms
|
|||
|
|
|||
|
; generate the code that will call the original trap and return
|
|||
|
|
|||
|
if ReturnAddressDepth = 0 then
|
|||
|
addq.w #4,sp
|
|||
|
jsrOld
|
|||
|
else
|
|||
|
pea @returnHere ; push the return address
|
|||
|
move.l (sp)+,ReturnAddressDepth(sp) ; put it where the trap dispatcher will find it
|
|||
|
jmpOld
|
|||
|
@returnHere:
|
|||
|
endif
|
|||
|
endm
|
|||
|
|
|||
|
; rejoinROM returns to the ROM address that triggered a ComeFromPatchProc.
|
|||
|
|
|||
|
macro
|
|||
|
rejoinROM
|
|||
|
if &type('ReturnAddressDepth') = 'UNDEFINED' then
|
|||
|
aerror 'rejoinROM can only be used within a ComeFromPatchProc or ComeFromAfterPatchProc.'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
gblc &comeFromWhere
|
|||
|
|
|||
|
if &comeFromWhere = '' then
|
|||
|
aerror 'rejoinROM can only be used if you specify a come-from address in ComeFromPatchProc'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
jmpROM &comeFromWhere
|
|||
|
endm
|
|||
|
|
|||
|
; MakeDispatcherTable
|
|||
|
; Called by EndDispatcher to generate the dispatch table for _DispatchHelper
|
|||
|
; Unlike the version for ROM, we can use absolute addresses in the dispatch table.
|
|||
|
|
|||
|
macro
|
|||
|
MakeDispatcherTable
|
|||
|
gbla &firstSelector
|
|||
|
gbla &lastSelector
|
|||
|
gbla &allSelectorsEven
|
|||
|
|
|||
|
gblc &selectorName[256]
|
|||
|
gbla &selectorIndex[256]
|
|||
|
|
|||
|
; make table header
|
|||
|
|
|||
|
DispatchTable:
|
|||
|
|
|||
|
; ***DispatchHelper doesn't support even selectors and absolute entries for now.
|
|||
|
; If it did support them, &allSelectorsEven is a flag that allows us to shrink
|
|||
|
; the size of the dispatch table. For now, we'll just set it to false again and
|
|||
|
; fill the unused entries in the table with the unimplemented routine.
|
|||
|
;
|
|||
|
; If we decide to make DispatchHelper support even selectors and absolute entries,
|
|||
|
; just remove the following if statement.
|
|||
|
if &allSelectorsEven then
|
|||
|
&allSelectorsEven: seta 0
|
|||
|
endif
|
|||
|
|
|||
|
if &allSelectorsEven then
|
|||
|
dc.w (1<<dhSelectorsEven)+(1<<dhAbsoluteEntries)
|
|||
|
else
|
|||
|
dc.w (1<<dhAbsoluteEntries)
|
|||
|
endif
|
|||
|
|
|||
|
dc.b &firstSelector
|
|||
|
dc.b &lastSelector
|
|||
|
|
|||
|
; make table
|
|||
|
|
|||
|
lclc &name
|
|||
|
lcla &num
|
|||
|
lcla &index
|
|||
|
|
|||
|
&num: seta &firstSelector
|
|||
|
while &num <= &lastSelector do
|
|||
|
&index: seta &selectorIndex[&num + 129]
|
|||
|
if &index = 0 then
|
|||
|
dcImport DispatchHelperBadSelector ; unused entry, set it to unimplemented routine in DispatchHelper.a
|
|||
|
else
|
|||
|
dcImport &selectorName[&index] ; get address of entry
|
|||
|
endif
|
|||
|
if &allSelectorsEven then
|
|||
|
&num: seta &num + 2
|
|||
|
else
|
|||
|
&num: seta &num + 1
|
|||
|
endif
|
|||
|
endwhile
|
|||
|
endm
|
|||
|
|
|||
|
; ——————————————————————————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|||
|
endif
|
|||
|
|
|||
|
; ——————————————————————————————————————————————————————————————————————————————————————————————————
|
|||
|
; more macros that are the same for ROM or patches (these mostly call other macros)
|
|||
|
|
|||
|
; bccROM
|
|||
|
|
|||
|
macro
|
|||
|
bccROM &name
|
|||
|
BranchROM$ &name,cc,cs
|
|||
|
endm
|
|||
|
|
|||
|
; bcsROM
|
|||
|
|
|||
|
macro
|
|||
|
bcsROM &name
|
|||
|
BranchROM$ &name,cs,cc
|
|||
|
endm
|
|||
|
|
|||
|
; beqROM
|
|||
|
|
|||
|
macro
|
|||
|
beqROM &name
|
|||
|
BranchROM$ &name,eq,ne
|
|||
|
endm
|
|||
|
|
|||
|
; bgeROM
|
|||
|
|
|||
|
macro
|
|||
|
bgeROM &name
|
|||
|
BranchROM$ &name,ge,lt
|
|||
|
endm
|
|||
|
|
|||
|
; bgtROM
|
|||
|
|
|||
|
macro
|
|||
|
bgtROM &name
|
|||
|
BranchROM$ &name,gt,le
|
|||
|
endm
|
|||
|
|
|||
|
; bhiROM
|
|||
|
|
|||
|
macro
|
|||
|
bhiROM &name
|
|||
|
BranchROM$ &name,hi,ls
|
|||
|
endm
|
|||
|
|
|||
|
; bhsROM
|
|||
|
|
|||
|
macro
|
|||
|
bhsROM &name
|
|||
|
BranchROM$ &name,hs,lo
|
|||
|
endm
|
|||
|
|
|||
|
; bleROM
|
|||
|
|
|||
|
macro
|
|||
|
bleROM &name
|
|||
|
BranchROM$ &name,le,gt
|
|||
|
endm
|
|||
|
|
|||
|
; bloROM
|
|||
|
|
|||
|
macro
|
|||
|
bloROM &name
|
|||
|
BranchROM$ &name,lo,hs
|
|||
|
endm
|
|||
|
|
|||
|
; blsROM
|
|||
|
|
|||
|
macro
|
|||
|
blsROM &name
|
|||
|
BranchROM$ &name,ls,hi
|
|||
|
endm
|
|||
|
|
|||
|
; bltROM
|
|||
|
|
|||
|
macro
|
|||
|
bltROM &name
|
|||
|
BranchROM$ &name,lt,ge
|
|||
|
endm
|
|||
|
|
|||
|
; bmiROM
|
|||
|
|
|||
|
macro
|
|||
|
bmiROM &name
|
|||
|
BranchROM$ &name,mi,pl
|
|||
|
endm
|
|||
|
|
|||
|
; bneROM
|
|||
|
|
|||
|
macro
|
|||
|
bneROM &name
|
|||
|
BranchROM$ &name,ne,eq
|
|||
|
endm
|
|||
|
|
|||
|
; bnzROM
|
|||
|
|
|||
|
macro
|
|||
|
bnzROM &name
|
|||
|
BranchROM$ &name,nz,z
|
|||
|
endm
|
|||
|
|
|||
|
; bplROM
|
|||
|
|
|||
|
macro
|
|||
|
bplROM &name
|
|||
|
BranchROM$ &name,pl,mi
|
|||
|
endm
|
|||
|
|
|||
|
; braROM
|
|||
|
|
|||
|
macro
|
|||
|
braROM &name
|
|||
|
jmpROM &name
|
|||
|
endm
|
|||
|
|
|||
|
; bvcROM
|
|||
|
|
|||
|
macro
|
|||
|
bvcROM &name
|
|||
|
BranchROM$ &name,vc,vs
|
|||
|
endm
|
|||
|
|
|||
|
; bvsROM
|
|||
|
|
|||
|
macro
|
|||
|
bvsROM &name
|
|||
|
BranchROM$ &name,vs,vc
|
|||
|
endm
|
|||
|
|
|||
|
; bzROM
|
|||
|
|
|||
|
macro
|
|||
|
bzROM &name
|
|||
|
BranchROM$ &name,z,nz
|
|||
|
endm
|
|||
|
|
|||
|
; MakeInstall activates the routine specified (calls it while patching).
|
|||
|
|
|||
|
macro
|
|||
|
MakeInstall &entry,&roms
|
|||
|
if &nbr(&syslist) > 2 then
|
|||
|
aerror 'too many parameters to MakeInstall'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
MakePatch &entry,0,&roms
|
|||
|
endm
|
|||
|
|
|||
|
; PatchProc makes a proc that is installed as a patch.
|
|||
|
|
|||
|
macro
|
|||
|
&module: PatchProc &trap,&roms
|
|||
|
if &nbr(&syslist) > 2 then
|
|||
|
aerror 'too many parameters to PatchProc'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
if &module = '' then
|
|||
|
aerror 'patches must be named, ranked, and serial numbered'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
&module: proc export
|
|||
|
MakePatch &module,&trap,&roms
|
|||
|
endm
|
|||
|
|
|||
|
; InstallProc makes a proc that will be called while patching.
|
|||
|
|
|||
|
macro
|
|||
|
&module: InstallProc &roms
|
|||
|
if &nbr(&syslist) > 1 then
|
|||
|
aerror 'too many parameters to InstallProc'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
if &module = '' then
|
|||
|
aerror 'install routines must be named, so that they can be lined up and executed'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
&module: proc export
|
|||
|
MakePatch &module,0,&roms
|
|||
|
endm
|
|||
|
|
|||
|
; BeginDispatcher
|
|||
|
|
|||
|
macro
|
|||
|
&module: BeginDispatcher &trap,&roms
|
|||
|
gbla &inDispatcher
|
|||
|
|
|||
|
gblc &dispatcherModule
|
|||
|
gblc &dispatcherTrap
|
|||
|
gblc &dispatcherROMs
|
|||
|
|
|||
|
gbla &numSelectors
|
|||
|
gbla &firstSelector
|
|||
|
gbla &lastSelector
|
|||
|
gbla &allSelectorsEven
|
|||
|
|
|||
|
if &nbr(&syslist) > 2 then
|
|||
|
aerror 'too many parameters to BeginDispatcher'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
if &inDispatcher then
|
|||
|
aerror 'two BeginDispatchers without an intervening EndDispatcher'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
; initialize variables for registering selectors
|
|||
|
|
|||
|
&inDispatcher: seta -1 ; means an error initializing
|
|||
|
|
|||
|
if &module = '' then
|
|||
|
aerror 'dispatchers must be named, pick a cool one from your sordid past'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
&dispatcherModule: setc &module
|
|||
|
&dispatcherTrap: setc &trap
|
|||
|
&dispatcherROMs: setc &roms
|
|||
|
|
|||
|
&numSelectors: seta 0
|
|||
|
&firstSelector: seta 127
|
|||
|
&lastSelector: seta -128
|
|||
|
&allSelectorsEven: seta 1
|
|||
|
|
|||
|
&inDispatcher: seta 1 ; means success
|
|||
|
endm
|
|||
|
|
|||
|
; DispatchSelectors
|
|||
|
|
|||
|
macro
|
|||
|
DispatchSelectors &selectors
|
|||
|
gbla &inDispatcher
|
|||
|
|
|||
|
gbla &numSelectors
|
|||
|
gbla &firstSelector
|
|||
|
gbla &lastSelector
|
|||
|
gbla &allSelectorsEven
|
|||
|
|
|||
|
gblc &selectorName[256]
|
|||
|
gbla &selectorIndex[256]
|
|||
|
|
|||
|
if &inDispatcher < 0 then
|
|||
|
exitm
|
|||
|
elseif &inDispatcher = 0 then
|
|||
|
aerror 'DispatchSelector must be used within a Begin/EndDispatcher pair'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
; find first and last, also notice if all selectors are even
|
|||
|
|
|||
|
lcla &count
|
|||
|
lcla ¬List
|
|||
|
|
|||
|
lclc &element
|
|||
|
lclc &name
|
|||
|
lcla &num
|
|||
|
lcla &index
|
|||
|
lcla &equalPos
|
|||
|
|
|||
|
&count: seta &nbr(&selectors)
|
|||
|
¬List: seta &count = 0
|
|||
|
if ¬List then
|
|||
|
&count: seta &nbr(&syslst)
|
|||
|
endif
|
|||
|
|
|||
|
&index: seta 0
|
|||
|
while &index < &count do
|
|||
|
&index: seta &index + 1
|
|||
|
|
|||
|
if ¬List then
|
|||
|
&element: setc &syslst[&index]
|
|||
|
else
|
|||
|
&element: setc &selectors[&index]
|
|||
|
endif
|
|||
|
|
|||
|
; find the equal sign to split the parameter in two
|
|||
|
|
|||
|
if &element ≠ '' then
|
|||
|
&equalPos: seta &pos('=',&element)
|
|||
|
if (&equalPos = 1) or (&equalPos >= &len(&element)) then
|
|||
|
aerror &concat('selector must have the form “name=number”, not “',\
|
|||
|
&element,'”, you unfortunate slime')
|
|||
|
else
|
|||
|
if (&equalPos = 0) then
|
|||
|
&name: setc &trim(&element)
|
|||
|
&num: seta &eval(&concat('select', &element))
|
|||
|
else
|
|||
|
&name: setc &trim(&substr(&element,1,&equalPos-1))
|
|||
|
&num: seta &eval(&substr(&element,&equalPos+1,32767))
|
|||
|
endif
|
|||
|
if (&num > 127) or (&num < -128) then
|
|||
|
aerror &concat('selector must be between -128 and 127, “',\
|
|||
|
&element,'” is byteing off more than you can chew')
|
|||
|
else
|
|||
|
; file away the results in a cool array
|
|||
|
|
|||
|
&numSelectors: seta &numSelectors + 1
|
|||
|
if &numSelectors > 256 then
|
|||
|
aerror 'maximum is 256 selectors (go overload some other trap)'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
&selectorName[&numSelectors]: setc &name
|
|||
|
if &selectorIndex[&num + 129] ≠ 0 then
|
|||
|
aerror &concat('selector ',&inttostr(&num),' was used twice, ',\
|
|||
|
'for “',&selectorName[&selectorIndex[&num + 129]],'” and “',&name,\
|
|||
|
'”; make up your mind')
|
|||
|
endif
|
|||
|
&selectorIndex[&num + 129]: seta &numSelectors
|
|||
|
|
|||
|
; keep track of common properties of all the selectors
|
|||
|
|
|||
|
if &num < &firstSelector then
|
|||
|
&firstSelector: seta &num
|
|||
|
endif
|
|||
|
if &num > &lastSelector then
|
|||
|
&lastSelector: seta &num
|
|||
|
endif
|
|||
|
if &num and 1 then
|
|||
|
&allSelectorsEven: seta 0
|
|||
|
endif
|
|||
|
endif
|
|||
|
endif
|
|||
|
endif
|
|||
|
endwhile
|
|||
|
|
|||
|
endm
|
|||
|
|
|||
|
; EndDispatcher
|
|||
|
; Specify the trap for the dispatcher, the ROMs, and each selector, along with its ID number.
|
|||
|
|
|||
|
macro
|
|||
|
EndDispatcher
|
|||
|
gbla &inDispatcher
|
|||
|
|
|||
|
gblc &dispatcherModule
|
|||
|
gblc &dispatcherTrap
|
|||
|
gblc &dispatcherROMs
|
|||
|
|
|||
|
gbla &numSelectors
|
|||
|
gbla &firstSelector
|
|||
|
gbla &lastSelector
|
|||
|
gbla &allSelectorsEven
|
|||
|
|
|||
|
gblc &selectorName[256]
|
|||
|
gbla &selectorIndex[256]
|
|||
|
|
|||
|
if &inDispatcher < 0 then
|
|||
|
&inDispatcher: seta 0
|
|||
|
exitm
|
|||
|
elseif &inDispatcher = 0 then
|
|||
|
aerror 'EndDispatcher without a matching BeginDispatcher'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
&inDispatcher: seta 0
|
|||
|
|
|||
|
; check parameters
|
|||
|
|
|||
|
if &numSelectors = 0 then
|
|||
|
aerror 'you must specify at least one selector, otherwise there’s not much to dispatch'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
|
|||
|
; make proc
|
|||
|
|
|||
|
&dispatcherModule: proc export
|
|||
|
MakePatch &dispatcherModule,&dispatcherTrap,&dispatcherROMs
|
|||
|
|
|||
|
; call the dispatch helper with the address of the table
|
|||
|
|
|||
|
lea DispatchTable,a0
|
|||
|
_DispatchHelper
|
|||
|
|
|||
|
; make the dispatch table (different formats depending on whether for ROM or for patches)
|
|||
|
|
|||
|
MakeDispatcherTable
|
|||
|
|
|||
|
; end the proc, and we are outa here
|
|||
|
|
|||
|
endproc
|
|||
|
endm
|
|||
|
|
|||
|
; Dispatcher makes a patch for a dispatched trap.
|
|||
|
; Specify the trap for the dispatcher, the ROMs, and each selector, along with its ID number.
|
|||
|
|
|||
|
macro
|
|||
|
&module: Dispatcher &trap,&roms,&selectors
|
|||
|
if &nbr(&syslist) > 3 then
|
|||
|
aerror 'too many parameters to Dispatcher'
|
|||
|
exitm
|
|||
|
endif
|
|||
|
&module: BeginDispatcher &trap,&roms
|
|||
|
DispatchSelectors &selectors
|
|||
|
EndDispatcher
|
|||
|
endm
|
|||
|
|
|||
|
|
|||
|
; ——————————————————————————————————————————————————————————————————————————————————————————————————
|
|||
|
; initialization (add new ROMs and conditions here)
|
|||
|
|
|||
|
; hasEricksonOverpatchMistake is currently used for:
|
|||
|
; a patch to the Sony driver that needs different addresses than the IIci ROMs
|
|||
|
; a patch to the Sound Mgr. that needs to know if the new Sound Mgr. is present
|
|||
|
; notEricksonSoundMgr is currently used for:
|
|||
|
; a patch to the Sound Mgr.
|
|||
|
; we should probably rethink these two names, and stick to our ROM version strategy in the future
|
|||
|
|
|||
|
if not FORROM then
|
|||
|
DefineConditions$ (Plus,$0075),(SE,$0276),(II,$0178),(Portable,$037A),(IIci,$067C),(SuperMario,$077D),\
|
|||
|
noPatchProtector,\
|
|||
|
notVM,notAUX,\
|
|||
|
hasHMMU,hasPMMU,hasMemoryDispatch,\
|
|||
|
has800KDriver,hasFDHDDriver,hasIWM,\
|
|||
|
hasEricksonOverpatchMistake,\
|
|||
|
hasEricksonSoundMgr,notEricksonSoundMgr,\
|
|||
|
using24BitHeaps,using32BitHeaps,notTERROR,hasTERROR,\
|
|||
|
hasC96,hasPwrMgr
|
|||
|
endif
|
|||
|
|
|||
|
; ——————————————————————————————————————————————————————————————————————————————————————————————————
|
|||
|
|
|||
|
endif ; ...already included
|