mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-01-16 03:29:58 +00:00
5b0f0cc134
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.
1843 lines
43 KiB
Plaintext
1843 lines
43 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
|