mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 01:29:20 +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.
754 lines
13 KiB
Plaintext
754 lines
13 KiB
Plaintext
;
|
||
; File: InternalMacros.a
|
||
;
|
||
; Contains: generally useful macros
|
||
;
|
||
; Written by: Darin Adler
|
||
;
|
||
; Copyright: © 1989-1990, 1992 by Apple Computer, Inc., all rights reserved.
|
||
;
|
||
; Change History (most recent first):
|
||
;
|
||
; <2> 3/24/92 PN <kc> Fix bug in endPreviousWith (changed WithModule to
|
||
; endWithModule).
|
||
; <6> 1/30/91 gbm sab, #38: Change the Ôalready including this fileÕ variable to
|
||
; all uppercase (for security reasons)
|
||
; <5> 9/25/90 KIP (really dba) DT.W now works on lists of items
|
||
; <4> 6/8/90 dba change so that debug switch defaults to 0
|
||
; <2> 4/17/90 dba change nil and false and true to defaults
|
||
; <1.1> 11/14/89 dba fixed Symbol and added scottÕs cool ideas from Finder to it
|
||
; <1.0> 6/2/89 prp Initial release. Folder Manager now part of Alias Manager.
|
||
; 6/2/89 dba rolled into system; fixed bug in linkFrame macro
|
||
; 5/6/89 dba new today
|
||
;
|
||
; To Do:
|
||
; optimize for non-68000 assemblies
|
||
; keep a stack of saved register sets
|
||
;
|
||
|
||
IF &TYPE('__INCLUDINGINTERNALMACROS__') = 'UNDEFINED' THEN
|
||
__INCLUDINGINTERNALMACROS__ SET 1
|
||
|
||
; do an equ if the symbol is not already defined
|
||
|
||
macro
|
||
&symbol default &value
|
||
|
||
if &type(&symbol) = 'UNDEFINED' then
|
||
&symbol: equ &value
|
||
endif
|
||
|
||
endm
|
||
|
||
; a few symbols
|
||
|
||
nil: default 0
|
||
false: default 0
|
||
true: default 1
|
||
DEBUG: default false
|
||
|
||
; assert that a condition is true
|
||
|
||
macro
|
||
assert &condition
|
||
|
||
if &eval(&condition) = false then
|
||
aerror 'assert: failed'
|
||
endif
|
||
|
||
endm
|
||
|
||
; end a record and declare a size field
|
||
|
||
macro
|
||
endrsize
|
||
|
||
org
|
||
size: equ *
|
||
endr
|
||
|
||
endm
|
||
|
||
; push something onto the stack
|
||
|
||
macro
|
||
push.&size &operand
|
||
|
||
move.&size &operand,-(sp)
|
||
|
||
endm
|
||
|
||
; pop something off of the stack
|
||
|
||
macro
|
||
pop.&size &operand
|
||
|
||
move.&size (sp)+,&operand
|
||
|
||
endm
|
||
|
||
; reserve space on the stack
|
||
|
||
macro
|
||
rsrv.&size &number
|
||
lcla &bytes
|
||
lclc &sizeLetter
|
||
|
||
; calculate the default size is 1
|
||
|
||
if &number = '' then
|
||
&bytes: seta 1
|
||
else
|
||
&bytes: seta &eval(&number)
|
||
endif
|
||
|
||
; the size letter is required
|
||
|
||
&sizeLetter: setc &upCase(&size)
|
||
if &sizeLetter = 'L' then
|
||
&bytes: seta 4 * &bytes
|
||
elseif &sizeLetter = 'W' then
|
||
&bytes: seta 2 * &bytes
|
||
elseif &sizeLetter = 'B' then
|
||
&bytes: seta (&bytes + 1) and (~1) ; round up to a word, since this is the stack
|
||
else
|
||
aerror &concat('rsrv: bad size letter: ',&size)
|
||
endif
|
||
|
||
; assembler optimization does the rest
|
||
|
||
if &bytes < 0 then
|
||
aerror &concat('rsrv: negative byte count: ', &bytes)
|
||
elseif &bytes and 1 then
|
||
aerror &concat('rsrv: odd byte count: ', &bytes)
|
||
else
|
||
sub.l #&bytes,sp
|
||
endif
|
||
|
||
endm
|
||
|
||
; free space from the stack
|
||
|
||
macro
|
||
free.&size &number
|
||
lcla &bytes
|
||
lclc &sizeLetter
|
||
|
||
; calculate the default size is 1
|
||
|
||
if &number = '' then
|
||
&bytes: seta 1
|
||
else
|
||
&bytes: seta &eval(&number)
|
||
endif
|
||
|
||
; the size letter is required
|
||
|
||
&sizeLetter: setc &upCase(&size)
|
||
if &sizeLetter = 'L' then
|
||
&bytes: seta 4 * &bytes
|
||
elseif &sizeLetter = 'W' then
|
||
&bytes: seta 2 * &bytes
|
||
elseif &sizeLetter = 'B' then
|
||
&bytes: seta (&bytes + 1) and (~1) ; round up to a word, since this is the stack
|
||
else
|
||
aerror &concat('free: bad size letter: ',&size)
|
||
endif
|
||
|
||
; assembler optimization does the rest
|
||
|
||
if &bytes < 0 then
|
||
aerror &concat('free: negative byte count: ', &bytes)
|
||
elseif &bytes and 1 then
|
||
aerror &concat('free: odd byte count: ', &bytes)
|
||
else
|
||
add.l #&bytes,sp
|
||
endif
|
||
|
||
endm
|
||
|
||
; move condition codes
|
||
|
||
macro
|
||
moveccr &destination
|
||
|
||
move.w sr,&destination
|
||
|
||
endm
|
||
|
||
; save some registers on the stack, possibly changing the condition codes
|
||
|
||
macro
|
||
save ®isters,&preserve==0
|
||
gblc &savedRegisters
|
||
gbla &port
|
||
|
||
if &savedRegisters <> '' then
|
||
aerror 'save: two without an intervening restore'
|
||
endif
|
||
|
||
&port: seta false
|
||
if ®isters = '' then
|
||
&savedRegisters: setc 'none'
|
||
elseif &upCase(®isters) = 'THEPORT' then
|
||
&savedRegisters: setc 'none'
|
||
&port: seta true
|
||
else
|
||
if &upCase(&subStr(®isters, &len(®isters) - 7, 8)) = '/THEPORT' then
|
||
&savedRegisters: setc &subStr(®isters, 1, &len(®isters) - 8)
|
||
&port: seta 1
|
||
else
|
||
&savedRegisters: setc ®isters
|
||
endif
|
||
|
||
if &subStr(&type(&savedRegisters), 1, 5) = 'REG A' then
|
||
move.l &savedRegisters,-(sp)
|
||
elseif &subStr(&type(&savedRegisters), 1, 4) = 'REG ' then
|
||
if &preserve then
|
||
movem.l &savedRegisters,-(sp)
|
||
else
|
||
move.l &savedRegisters,-(sp)
|
||
endif
|
||
else
|
||
movem.l &savedRegisters,-(sp)
|
||
endif
|
||
endif
|
||
|
||
if &port then
|
||
rsrv.l
|
||
movem.l d0-d2/a0-a1,-(sp)
|
||
|
||
if &preserve then
|
||
moveccr -(sp)
|
||
pea 2+5*4(sp)
|
||
else
|
||
pea 5*4(sp)
|
||
endif
|
||
|
||
_GetPort
|
||
|
||
if &preserve then
|
||
move.w (sp)+,ccr
|
||
endif
|
||
|
||
movem.l (sp)+,d0-d2/a0-a1
|
||
endif
|
||
|
||
if DEBUG then
|
||
pea ('save')
|
||
endif
|
||
|
||
endm
|
||
|
||
; restore some registers saved by a save macro
|
||
|
||
macro
|
||
restore &preserve==0
|
||
gblc &savedRegisters
|
||
gbla &port
|
||
|
||
if &savedRegisters = '' then
|
||
aerror 'restore: without save'
|
||
else
|
||
if DEBUG then
|
||
if &preserve then
|
||
moveccr -(sp)
|
||
cmp.l #('save'),2(sp)
|
||
else
|
||
cmp.l #('save'),(sp)+
|
||
endif
|
||
|
||
beq.s @goodSave
|
||
_Debugger
|
||
@goodSave:
|
||
|
||
if &preserve then
|
||
move.w (sp)+,ccr
|
||
free.l
|
||
endif
|
||
endif
|
||
|
||
; *** handle case where register is already saved
|
||
|
||
if &port then
|
||
movem.l d0-d2/a0-a1,-(sp)
|
||
|
||
if &preserve then
|
||
moveccr -(sp)
|
||
move.l 2+5*4(sp),-(sp)
|
||
else
|
||
move.l 5*4(sp),-(sp)
|
||
endif
|
||
|
||
_SetPort
|
||
|
||
if &preserve then
|
||
move.w (sp)+,ccr
|
||
endif
|
||
|
||
movem.l (sp)+,d0-d2/a0-a1
|
||
free.l
|
||
endif
|
||
|
||
if &savedRegisters <> 'none' then
|
||
if &subStr(&type(&savedRegisters), 1, 5) = 'REG A' then
|
||
move.l (sp)+,&savedRegisters
|
||
elseif &subStr(&type(&savedRegisters), 1, 4) = 'REG ' then
|
||
if &preserve then
|
||
movem.l (sp)+,&savedRegisters
|
||
else
|
||
move.l (sp)+,&savedRegisters
|
||
endif
|
||
else
|
||
movem.l (sp)+,&savedRegisters
|
||
endif
|
||
endif
|
||
&savedRegisters: setc ''
|
||
endif
|
||
|
||
endm
|
||
|
||
; pad a piece of memory to blockSize items (item is either bytes, words, or longs)
|
||
|
||
macro
|
||
pad.&size &blockSize,&startLabel,&itemValue==0
|
||
lcla &padItems
|
||
lclc &sizeLetter
|
||
|
||
&padItems: seta &eval(&blockSize) - (* - &eval(&startLabel))
|
||
|
||
&sizeLetter setc &upCase(&sizeLetter)
|
||
if &sizeLetter = '' then
|
||
&sizeLetter: setc 'B'
|
||
elseif &sizeLetter = 'B' then
|
||
elseif &sizeLetter = 'W' then
|
||
&padItems: seta &padItems div 2
|
||
elseif &sizeLetter = 'L' then
|
||
&padItems: seta &padItems div 4
|
||
else
|
||
aerror &concat('pad: cannot handle unknown item length: ',&size)
|
||
endif
|
||
|
||
if &padItems < 0 then
|
||
aerror 'pad: cannot pad a block bigger than the block size'
|
||
elseif &padItems > 0 then
|
||
dcb.&itemtype &padItems,&itemValue
|
||
endif
|
||
|
||
endm
|
||
|
||
; create a jump table starting with the label and having a given prefix
|
||
|
||
macro
|
||
&name Table &prefix,&base
|
||
lclc &tableName
|
||
gblc &tablePrefix,&tableBase
|
||
|
||
if &name = '' then
|
||
&tableName: setc '@table'
|
||
else
|
||
&tableName: setc &name
|
||
endif
|
||
|
||
&tablePrefix: setc &prefix
|
||
|
||
if &base = '' then
|
||
&tableBase: setc &tableName
|
||
elseif &upCase(&base) = 'ABSOLUTE' then
|
||
&tableBase: setc ''
|
||
else
|
||
&tableBase: setc &base
|
||
endif
|
||
|
||
&tableName:
|
||
|
||
endm
|
||
|
||
; create a jump table entry
|
||
|
||
macro
|
||
dt.&size
|
||
gblc &tablePrefix,&tableBase
|
||
lcla &index
|
||
|
||
&index: seta 0
|
||
while &index < &nbr(&syslist) do
|
||
&index: seta &index + 1
|
||
if &tableBase = '' then
|
||
dc.&size &concat(&tablePrefix, &syslist[&index])
|
||
else
|
||
dc.&size &concat(&tablePrefix, &syslist[&index], '-', &tableBase)
|
||
endif
|
||
endwhile
|
||
|
||
endm
|
||
|
||
; end the with from a previous stack frame (never called directly)
|
||
|
||
macro
|
||
endPreviousWith
|
||
gblc &frameState,&endWithModule
|
||
|
||
if &sysMod = &endWithModule then
|
||
endwith
|
||
endif
|
||
&frameState: setc ''
|
||
|
||
endm
|
||
|
||
; declare some results in a stack frame
|
||
|
||
macro
|
||
resultsStackFrame &frame
|
||
gblc &frameName,&frameState,&endWithModule
|
||
|
||
if &frameState = 'needEndWith' then
|
||
endPreviousWith
|
||
endif
|
||
|
||
if &frameState = '' then
|
||
if &frame = '' then
|
||
&frameName: setc 'StackFrame'
|
||
else
|
||
&frameName: setc &frame
|
||
endif
|
||
&frameName: record {savedA6},decr
|
||
&frameState: setc 'results'
|
||
elseif &frameState = 'results'
|
||
aerror 'resultsStackFrame: two without intervening endStackFrame'
|
||
else
|
||
aerror 'resultsStackFrame: must come before parameters and locals'
|
||
endif
|
||
|
||
endm
|
||
|
||
; declare some parameters in a stack frame
|
||
|
||
macro
|
||
parametersStackFrame &frame
|
||
gblc &frameName,&frameState,&endWithModule
|
||
|
||
if &frameState = 'needEndWith' then
|
||
endPreviousWith
|
||
endif
|
||
|
||
if &frameState = '' then
|
||
resultsStackFrame &frame
|
||
endif
|
||
|
||
if &frameState = 'results' then
|
||
belowParameters: equ *
|
||
&frameState: setc 'parameters'
|
||
elseif &frameState = 'parameters' then
|
||
aerror 'parametersStackFrame: two without intervening endStackFrame'
|
||
else
|
||
aerror 'parametersStackFrame: must come before locals'
|
||
endif
|
||
|
||
endm
|
||
|
||
; declare some locals in a stack frame
|
||
|
||
macro
|
||
localsStackFrame &frame
|
||
gblc &frameState
|
||
|
||
if &frameState = 'needEndWith' then
|
||
endPreviousWith
|
||
endif
|
||
|
||
if &frameState = '' then
|
||
resultsStackFrame &frame
|
||
endif
|
||
|
||
if &frameState = 'results' then
|
||
parametersStackFrame
|
||
endif
|
||
|
||
if &frameState = 'parameters' then
|
||
org
|
||
parametersSize: equ belowParameters - *
|
||
returnAddress: ds.l 1
|
||
savedA6: ds.l 1
|
||
&frameState: setc 'locals'
|
||
else
|
||
aerror 'localsStackFrame: two without intervening endStackFrame'
|
||
endif
|
||
|
||
endm
|
||
|
||
; end a stack frame
|
||
|
||
macro
|
||
endStackFrame
|
||
gblc &frameName,&frameState
|
||
|
||
if &frameState = 'results' then
|
||
parametersStackFrame
|
||
endif
|
||
|
||
if &frameState = 'parameters' then
|
||
localsStackFrame
|
||
endif
|
||
|
||
if &frameState = 'locals' then
|
||
org
|
||
align
|
||
localsSize: equ *
|
||
endr
|
||
&frameState: setc 'needWith'
|
||
else
|
||
aerror 'endStackFrame: without results or parameters or locals'
|
||
endif
|
||
|
||
endm
|
||
|
||
; use instead of a link or for debugging
|
||
|
||
macro
|
||
linkFrame &size
|
||
gblc &linkState,&frameName,&frameState,&endWithModule
|
||
|
||
if &linkState = '' then
|
||
if &frameState = 'needWith' then
|
||
with &frameName
|
||
&frameState: setc 'needEndWith'
|
||
&endWithModule: setc &sysMod
|
||
link a6,#localsSize
|
||
if &size '' then
|
||
aerror 'linkFrame: specified frame and a specific size'
|
||
endif
|
||
&linkState: setc 'needUnlink'
|
||
elseif &size = '' then
|
||
if DEBUG then
|
||
link a6,#0
|
||
unlk a6
|
||
endif
|
||
&linkState: setc 'needFakeUnlink'
|
||
else
|
||
link a6,#&size
|
||
&linkState: setc 'needUnlink'
|
||
endif
|
||
|
||
if DEBUG then
|
||
pea ('link')
|
||
endif
|
||
else
|
||
aerror 'linkFrame: missing unlinkFrame'
|
||
endif
|
||
|
||
endm
|
||
|
||
; use for any kind of unlink
|
||
|
||
macro
|
||
unlinkFrame &preserve==0
|
||
gblc &linkState
|
||
|
||
if DEBUG then
|
||
if &preserve then
|
||
moveccr -(sp)
|
||
cmp.l #('link'),2(sp)
|
||
else
|
||
cmp.l #('link'),(sp)+
|
||
endif
|
||
|
||
beq.s @goodUnlink
|
||
_Debugger
|
||
@goodUnlink:
|
||
|
||
if &preserve then
|
||
move.w (sp)+,ccr
|
||
free.l
|
||
endif
|
||
endif
|
||
|
||
if &linkState = 'needUnlink' then
|
||
unlk a6
|
||
&linkState: setc ''
|
||
elseif &linkState = 'needFakeUnlink' then
|
||
if DEBUG then
|
||
bra.s @skipUnlink
|
||
unlk a6
|
||
@skipUnlink:
|
||
endif
|
||
&linkState: setc ''
|
||
else
|
||
aerror 'unlinkFrame: missing linkFrame'
|
||
endif
|
||
|
||
endm
|
||
|
||
; fake rts for debugging only
|
||
|
||
macro
|
||
noReturn
|
||
gblc &linkState
|
||
|
||
if &linkState '' then
|
||
unlinkFrame
|
||
endif
|
||
|
||
if DEBUG then
|
||
bra.s @skipReturn
|
||
rts
|
||
@skipReturn:
|
||
endif
|
||
|
||
endm
|
||
|
||
; rts
|
||
|
||
macro
|
||
return &size
|
||
gblc &linkState,&frameState
|
||
lcla &bytes
|
||
|
||
if &linkState '' then
|
||
unlinkFrame
|
||
endif
|
||
|
||
if &size = '' then
|
||
if &frameState = '' then
|
||
&bytes: seta 0
|
||
else
|
||
&bytes: seta parametersSize
|
||
endif
|
||
elseif &subStr(&size, 1, 1) = '#' then
|
||
&bytes: seta &strToInt(&subStr(&size, 2, &len(&size) - 1))
|
||
else
|
||
aerror 'return: bad size'
|
||
endif
|
||
|
||
if &bytes = 0 then
|
||
rts
|
||
elseif &bytes = 4 then
|
||
move.l (sp)+,(sp)
|
||
rts
|
||
else
|
||
move.l (sp)+,a0
|
||
free.b &bytes
|
||
jmp (a0)
|
||
endif
|
||
|
||
endm
|
||
|
||
; debugging symbol
|
||
|
||
macro
|
||
symbol &routineName=&SysMod,&size=0
|
||
lclc &name, &oldString
|
||
|
||
if DEBUG then
|
||
if &routineName[1:1] = '''' then
|
||
&name: setc &eval(&routineName)
|
||
else
|
||
&name: setc &routineName
|
||
endif
|
||
|
||
&oldString: setc &setting('string')
|
||
string asis
|
||
if &len(&name) < 32 then
|
||
dc.b &len(&name)+$80,'&name'
|
||
else
|
||
dc.b $80,&len(&name),'&name'
|
||
endif
|
||
string &oldString
|
||
align
|
||
dc.w &size
|
||
endif
|
||
|
||
endm
|
||
|
||
; composite macros for even shorter use
|
||
|
||
macro
|
||
linkSave ®isters
|
||
|
||
linkFrame
|
||
save ®isters
|
||
|
||
endm
|
||
|
||
macro
|
||
restoreUnlinkReturn
|
||
|
||
restore
|
||
unlinkFrame
|
||
return
|
||
symbol
|
||
|
||
endm
|
||
|
||
|
||
macro
|
||
getCaseState
|
||
|
||
gblc &savedCaseState
|
||
&savedCaseState: SETC &SETTING('CASE')
|
||
|
||
endm
|
||
|
||
macro
|
||
restoreCaseState
|
||
|
||
gblc &savedCaseState
|
||
CASE &savedCaseState
|
||
|
||
endm
|
||
|
||
asmNeedsDSWorkaround default true
|
||
|
||
if asmNeedsDSWorkaround then
|
||
|
||
macro
|
||
&label: dsWorkaround &recordName
|
||
|
||
lclc &savedCaseState
|
||
lclc &upperCaseLabel
|
||
|
||
&savedCaseState: setc &setting('CASE')
|
||
if &savedCaseState = 'ON' then
|
||
&label: ds.b &recordName
|
||
else
|
||
case on
|
||
&upperCaseLabel: setc &upcase(&label)
|
||
&upperCaseLabel: ds.b &recordName
|
||
case &savedCaseState
|
||
endif
|
||
|
||
endm
|
||
|
||
macro
|
||
&label: equWorkaround &someName
|
||
|
||
lclc &savedCaseState
|
||
lclc &upperCaseLabel
|
||
|
||
&savedCaseState: setc &setting('CASE')
|
||
if &savedCaseState = 'ON' then
|
||
&label: ds.b &someName
|
||
else
|
||
case on
|
||
&upperCaseLabel: setc &upcase(&label)
|
||
&upperCaseLabel: ds.b &someName
|
||
case &savedCaseState
|
||
endif
|
||
|
||
endm
|
||
|
||
else
|
||
|
||
macro
|
||
&label: dsWorkaround &recordName
|
||
&label: ds.b &recordName
|
||
endm
|
||
|
||
macro
|
||
&label: equWorkaround &someName
|
||
&label: ds.b &someName
|
||
endm
|
||
|
||
endif
|
||
|
||
ENDIF ; ...already included |