windows-nt/Source/XPSP1/NT/multimedia/directx/inc/cmacros.new

1613 lines
35 KiB
Plaintext
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
COMMENT $
CMACROS - assembly macros for interfacing to HLL
(C)Copyright Microsoft Cor. 1990
$
; Revision History
; 6.0 Initial Release of cmacros for MASM 6.0
;
COMMENT $
; Note: There are some differences between this version of CMACROS
; and previous releases. The most signification is the fact
; that locals and parameter names are now scoped to the body
; of a procedure. To help ease this problem we have introduced
; a new directive cRet. This means that the following transformation
; can occur on your source to deal with parameters no referenced
; in the body of a procedure
;
; cProc cProc
; locals,parms locals,parms
; cBegin cBegin
; .... ...
; cEnd cRet
; error code referencing error code referencing
; locals and parms locals and params
; cEnd <nogen>
;
; The major reason for making locals and parameters scoped was
; the percieved benifit of error checking for defined labels in
; the procedure and the addition of codeView information on locals
; and parameters for functions.
$
.xcref ; Get rid of alot of symbols
; ??_out - output the given message to the console unless ?QUIET
; has been specified
;
; usage:
; ??_out <t>
; where:
; <t> is the message to output
??_out macro t
ifndef ?QUIET
echo t
endif
endm
; outif - output msg if name is non-zero. If name is undefined,
; set name =0, else set name to the default value.
;
; usage:
; outif name, defval, onmsg, offmsg
; where:
; name name of symbol
; defval default value to give symobl if not defined.
; if blank, then 0 will be used
; onmsg text to display if symbol is non-zero
; offmsg text to display if symbol is zero
;
outif macro name:req, defval:=<0>, onmsg, offmsg
ifndef name
name = defval
endif
if name
name = 1
ifnb <onmsg>
??_out <! onmsg>
endif
else
ifnb <offmsg>
??_out <! offmsg>
endif
endif
endm
; ??error - output message and generate an assembly time error
;
; usage:
; ??error <t>
; where:
; t is the text to output
;
??error macro msg
echo e r r o r ------ msg ;; to console
.err e r r o r ------ msg ;; forced error by assembler
endm
??_out <cMacros Version 6.00 - 1/1/91>
??_out <Copyright (C) Microsoft Corp. 1990-1991. All rights reserved.>
;
; Determine the memory model for cmacros. Default to small if
; no other model has been specified.
;
ifdef ?SMALL
memS=1
endif
ifdef ?MEDIUM
memM=1
endif
ifdef ?COMPACT
memC=1
endif
ifdef ?LARGE
memL=1
endif
ifdef ?HUGE
memH=1
endif
outif memS,0,<Small Model>
outif memM,0,<Medium Model>
outif memC,0,<Compact Model>
outif memL,0,<Large Model>
outif memH,0,<Huge Model>
memMOD = memS + memM + memL + memC + memH
if memMOD ne 1
if memMOD eq 0
memS=1 ; Assume small model
outif memS,0,<Small Model>
else
??error <must have only 1 memory model selected>
endif
endif
sizec = memM + memL + memH ; Large Code models
sizeC = sizec
sized = memC + memL + memH ; Large Data models
sizeD = sized
;
; Inform user of any other options selected
;
outif ?DF,0,<No segments or groups will be defined>
outif ?DFDATA,0,<No data segments will be defined>
outif ?DFCODE,0,<No code segments will be defined>
outif ?TF,0,<Epilogue sequences will assume valid SP>
outif ?WIN,1,<Windows support>
outif ?COW,0,<Character Windows support>
outif ?PLM,1,<PL/M calling convention>
outif ?NOATOMIC,0,<ATOMIC calling convention>
outif ?NODATA,0,<NODATA module>
ifdef ?CHKSTK
ifdef ?CHKSTKPROC
??_out <! Private stack checking enabled>
else
??_out <! Stack checking enabled>
endif
else
?CHKSTK = 0
endif
ifndef ?DOS5
?DOS5 = 0
endif
;
; Setup some local variables to the Cmacros package
;
??CM_state = 0 ; 0 - inactive, 1-cProc, 2-cBegin,
??CM_RegSaveList textequ <> ; List of saved registers
??CM_ArgList textequ <>
;
; This function is used to paste together two text items to
; get a third text item.
;
??CM_Paste macro arg1:req, arg2:req
exitm <arg1&arg2>
endm
;
; This function is used to create a text macro containning the
; n-th local to a fuction definition.
;
??CM_addLocal macro arg1:req
??CM_Paste(??CM_local, %??CM_localCount) textequ <LOCAL arg1>
??CM_localCount = ??CM_localCount + 1
endm
;
; This function is used to create a text macro containning the
; n-th parameter to a function definition
;
??CM_addParm macro arg1:req
if ??CM_argCount EQ 20
.err <CMACROS.INC: Cannot have more than 20 arguements to a procedure>
endif
??CM_Paste(??CM_arg, %??CM_argCount) textequ <, arg1>
??CM_argCount = ??CM_argCount + 1
endm
;
; This macro creates the prologue code for a cmacro defined function.
;
; Prologue sequences
;
cPrologue macro procname, flags, cbParms, cbLocals, reglist, userparms
?ba=0 ;;not in a procedure
?pu=0 ;;initial public setting
?ia=0 ;;no special prolog/epilog
?rp=0 ;;no register parameters
??CM_UserDoesFrame=0 ;;don't use makeframe
?ff=0 ;;don't force frame setup
?pas=0 ;;process register save list
?pcc=?PLM ;;calling convention (C or PL/M)
;;
;; Look at all of the user parameters and make appropriate decisions
;;
for x,<userparms>
ifdef ??CM_Paste(??_cproc_, x)
??CM_Paste(??_cproc_, x)
else
??error <e r r o r - unknown keyword x>
.err
endif
endm
;;
;; Now start some error checking
;;
if (??CM_Atomic eq 1) and (??CM_NoData eq 0) ;;ATOMIC requires NODATA
??error <ATOMIC specified without NODATA - ATOMIC ignored>
??CM_Atomic = 0 ;;clear the ATOMIC keyword
endif
if flags AND 020h ;;if a far procedure
if ??CM_WinFarProc ;;if windows
ife ??CM_Atomic ;;if not ATOMIC
ife ?COW ;; COW dos not save DS
?ia=2 ;; adjust locals for saved ds
; ?pas = ?pas and (not ?ds) ;;no need for extra save
endif
endif
endif
else
??CM_WinFarProc=0 ;;not a far windows procedure
endif
; ?pas = ?pas and (not (?sp+?cs+?ss)) ;;make no sense to save these
if ??CM_UserDoesFrame ;;don't save these if user frame
; ?pas = ?pas and (not (?bp+?si+?di))
endif
if ??CM_UserDoesFrame ;;if user frame
if ??CM_NoData
??error <NODATA encountered in &n - user frame ignored>
??CM_UserDoesFrame=0
endif
endif
if ??CM_UserDoesFrame ;;if user frame
if ?rp ;;If register parameters
??error <parmR encountered in &n - user frame ignored>
??CM_UserDoesFrame=0
endif
endif
?cpd=0 ;;terminate current proc def
ifidn <g>,<nogen> ;;if nogen, then cannot have locals
if cbLocals + cbParms + ?rp ;; saved regs, or parmRs
??_out <cBegin - possibly invalid use of nogen>
endif
else ;;else must generate a frame
;;
;; Allow the user to specify his own routine which is going to
;; do the frame set-up for this procedure
;;
if ??CM_UserDoesFrame ;;if user frame code specified
?mf c,cbLocals,%?po ;; call user's makeframe
for reg,reglist ;; save specified registers
push reg
endm
else
if ??CM_WinFarProc ;;if a far windows procedure
ife ??CM_NoData ;;if not NODATA,
mov ax,ds ;; then set AX = current ds, and ;@
nop ;; leave room for MOV AX,1234h ;@
endif
ife ??CM_Atomic ;;if not ATOMIC, far frame must be set
ife ?DOS5 ;;if not DOS5, then set far frame flag
inc bp ;; by incrementing the old bp ;@
endif
push bp ;@
mov bp,sp ;@
ife ?COW ;; save DS not needed for CW
push ds ;@
endif
else ;;ATOMIC procedure
if ?ff+cbLocals+cbParms+?rp ;;if any locals or parameters
push bp ;; then must set frame pointer ;@
mov bp,sp ;; to be able to access them ;@
endif
endif
ife ??CM_NoData ;;if not NODATA, then AX should
mov ds,ax ;; have the ds to use ;@
endif
else ;;not windows. use standard prolog
if ?ff+cbLocals+cbParms+?rp ;;if any locals or parameters
push bp ;; then must set frame pointer ;@
mov bp,sp ;; to be able to access them ;@
endif
endif
if ?rp ;;if parmR's, push them before
??CM_UserDoesFrame=0 ;; allocating locals and saving
rept ?rp ;; the autosave registers
uconcat mpush,,?rp,%??CM_UserDoesFrame
??CM_UserDoesFrame=??CM_UserDoesFrame+1
endm
endif
if cbLocals ;;if locals to allocate
if ?CHKSTK ;;if stack checking enabled
ifdef ?CHKSTKPROC ;;if user supplied stack checking
?CHKSTKPROC %cbLocals ;; invoke it with bytes requested
else
mov ax,cbLocals ;;invoke default stack checking ;@
ife cc
call _chkstk ;@
else
call chkstk ;@
endif
endif
else ;;no stack checking
sub sp,cbLocals ;; allocate any local storage ;@
endif
endif
endif
for reg,reglist ;;save autosave registers
push reg
endm
endif ;; No Gen
ifdef ?PROFILE ;;if profiling enabled
if c ;; and a far procedure
call StartNMeas ;; invoke profile start procedure ;@
endif
endif
exitm %(cbLocals+?ia)
endm
;
; This macro will define the epilogue sequences for CMACROS
; functions.
;
; Epilog sequences
cEpilog macro procname, flags, cbParms, cbLocals, reglist, userparms
if ??CM_nogen ;; Nogen the cEnd --
exitm
endif
?ba=0 ;;no longer in a procedure
ifidn <g>,<nogen> ;;if nogen, then cannot have parmRs
if a+r+lc ;; locals, or saved registers
??_out <cEnd - possibly invalid use of nogen>
endif
else ;;else must remove the frame
ifdef ?PROFILE ;;if profiling enabled
if flags AND 020H ;; and a far procedure
call StopNMeas ;; invoke profile stop procedure
endif ;; (doesn't trash DX:AX)
endif ;; ?PROFILE
for reg,reglist ;;restore autosaved registers
pop reg
endm
if ??CM_UserDoesFrame ;;if to use the "makeframe" procedure
db 0c3h ;; near return to user's makeframe @
else
if ??CM_WinFarProc ;;if far win proc, use special epilog
ife ??CM_Atomic ;;if not ATOMIC, bp was pushed
ife ?COW ;; restore DS not needed for CW
if (?TF eq 0) or (cbLocals+?rp) ;;if cannot assume valid sp
lea sp,-2+[bp] ;; or locals or parmR's, get valid SP @
endif
pop ds ;;restore saved ds and bp @
else
if (?TF eq 0) or (cbLocals+?rp) ;;if cannot assume valid sp
mov sp,bp
endif
endif
pop BP ;; @
ife ?DOS5 ;;if not DOS5, bp was
dec BP ;; incremented to mark far frame @
endif
else ;;ATOMIC frame was set up
if memS32
leave
else
if (?TF eq 0) or (cbLocals+?rp) ;;if cannot assume valid sp
mov SP,BP ;; or locals or parmR's, get valid SP @
endif
if cbLocals+cbParms+?rp
pop BP ;@
endif
endif
endif
else ;;non-windows standard epilog
if ?ff+cbLocals+cbParms+?rp ;;if any parameters
if (?TF eq 0) or (cbLocals+?rp) ;;if cannot assume valid SP
mov SP,BP ;; or locals or parmR's, get valid SP;@
endif
pop BP ;@
endif
endif ;; Far Win Proc
ife flags AND 010H ;;if Pascal calling convention
ret cbParms ;; return and remove paramteres ;@
else ;;else
ret ;; return ;@
endif
endif ;; User makes frame
endif ;; noGen
endm
;
; cProc - This macro is used to define the start of a procedure in CMACROS.
;
; PARAMETERS:
; pname - The name of the procedure to be defined. This field is
; required to be present.
; attribs - This is a list of attributes which may be placed on the
; function being defined.
; autoSave - This is an optional list of registers which are to be
; saved and restored during the prologue/epilogue processing
;
cProc macro pname:REQ, attribs, autoSave
IF ??CM_state NE 0 ;; No nesting of functions allowed
.err <CMACROS.INC: Cannot nest procedure definitions>
endif
;
; Setup some state variables to start the procedure definition
;
??CM_state = 1 ;; Set state variable to seen cProc
??CM_ProcName EQU <pname>
??CM_ProcAutoSave EQU <autoSave>
??CM_localCount = 0
??CM_argCount = 0
??CM_langType EQU <>
??CM_WinFarProc=?WIN ;;default far procedure (win or not)
??CM_NoData=?NODATA ;;default NODATA flag
??CM_Atomic=?NOATOMIC ;;default is not ATOMIC
repeat 20 ;; Clear all parameter textmacros
??CM_Paste(??CM_arg, %??CM_argCount) textequ <>
??CM_argCount = ??CM_argCount + 1
endm
??CM_argCount = 0
ife sizec ;; Set the default distance
dist equ <NEAR>
else
dist equ <FAR>
endif
vis equ <> ;; Set the default visibility
for arg,<attribs> ;; Look at the attribute list
ifidn <arg>, <FAR>
dist equ <FAR>
elseifidn <arg>,<NEAR>
dist equ <NEAR>
elseifidn <arg>,<PUBLIC>
vis equ <PUBLIC>
elseifidn <arg>,<PRIVATE>
vis equ <PRIVATE>
elseifidn <arg>,<LOCAL> ;; Ignore -- only for CRT
elseifidn <arg>,<PASCAL>
??CM_langType equ <PASCAL>
elseifidn <arg>,<C>
??CM_langType equ <C>
elseifidn <arg>,<WIN>
??CM_WinFarProc=1
elseifidn <arg>,<NOWIN>
??CM_WinFarProc=0
elseifidn <arg>,<NODATA>
??CM_NoData=1
elseifidn <arg>,<ATOMIC>
??CM_Atomic=1
else
% .err <CMACROS.INC: cProc -- Unknown arguement '&arg'>
endif
endm
option prologue:cPrologue ;; Change to our prologue sequence
option epilogue:none ;; rets from here on are just rets
endm
;
cBegin macro pname
local t2
IF ??CM_state NE 1 ;; Must follow cProc
.err <CMACROS.INC: cBegin must follow a cProc>
endif
??CM_nogen = 0
ifnb <pname>
ifidn <pname>,<nogen>
??CM_nogen = 1
elseifdif ??CM_ProcName, <pname>
% echo <cBegin name (&pname) must match name on preceding cProc (&??CM_ProcName>
endif
endif
??CM_state = 2 ;; Seen a cBegin
% setDefLangType ??CM_langType
macroarg EQU <>
ifnb ??CM_ProcAutoSave
??uses CATSTR <uses >, ??CM_ProcAutoSave
t2 = @InStr(, %??uses, <,>)
while t2 NE 0
??uses CATSTR @SubStr(<%??uses>, 1, %t2-1), < >, @SubStr(<%??uses>, %t2+1)
t2 = @InStr(, %??uses, <,>)
endm
else
??uses textequ <>
endif
ifidn defLangType,<C>
% ??CM_Paste(_, %??CM_ProcName) textequ <??CM_ProcName>
endif
??CM_ProcName proc dist defLangType vis macroarg ??uses ??CM_arg0 ??CM_arg1 ??CM_arg2 ??CM_arg3 ??CM_arg4 ??CM_arg5 ??CM_arg6 ??CM_arg7 ??CM_arg8 ??CM_arg9 ??CM_arg10 ??CM_arg11 ??CM_arg12 ??CM_arg13 ??CM_arg14 ??CM_arg15 ??CM_arg16 ??CM_arg17 ??CM_arg18 ??CM_arg19
??CM_ProcAutoSave EQU <>
t2 = 0
repeat ??CM_localCount
??CM_Paste(??CM_local, %t2)
t2 = t2 + 1
endm
endm
;
cEnd macro pname
IF ??CM_state NE 2 ;; Must follow a cEnd
.err <cEnd must follow a cProc>
endif
??CM_nogen = 0
ifnb <pname>
ifidn <pname>,<nogen>
??CM_nogen = 1
elseifdif ??CM_ProcName, <pname>
% echo <cEnd name (&pname) must match preceeding cProc name (&??CM_ProcName)>
endif
endif
option epilogue:cEpilog
ret
option prologue:prologuedef
option epilogue:epiloguedef
??CM_ProcName endp
??CM_state = 0 ;; not in a function
endm
;
;
cRet macro
IF ??CM_state NE 2 ;; Must follow a cBegin
.err <cRet must follow a cProc>
endif
option epilogue:cEpilog
ret
option epilogue:none
endm
;
; createSeg is a macro that sets up a segment definition and
; a logical name for that segment. The logical name can
; be used to egner the segment, but it cannot be used for anyting
; else.
;
; usage:
; createSeg n, ln, a, co, cl, grp
; where:
; n is the physical name of the segment
; ln is the name it is to be invoked by
; a is the alignment, and is optional
; co is the combine type, and is optional
; cl is the class, and is optional
; grp is the name of the group that contains the segment
;
createSeg macro segName, logName, aalign, combine, class, grp
ifnb <class>
segName segment aalign combine '&class'
else
segName segment aalign combine
endif
segName ends
ifnb <grp>
grp GROUP segName
logName&OFFSET equ offset grp:
logName&BASE equ grp
else
logName&OFFSET equ offset segName:
logName&BASE equ segName
endif
logName&_sbegin macro
segName segment
sEnd macro name
ifnb <name>
ifdifi <name>,<logName>
% echo <sEnd name does not match sBegin logName>
endif
endif
segName ends
purge sEnd
endm
endm
ifnb <grp>
logName&_assumes macro s
assume s:grp
endm
else
logName&_assumes macro s
assume s:segName
endm
endif
endm
sBegin macro name:req
name&_sbegin
endm
; assumes is a macro that will set up the assumes for a segment
; or group created with the createSeg macro. If the assumed
; value passed in isn't known, then a normal assume is made.
;
; usage:
; assumes s,g
;
; where:
; s is the register to make the assumption about
; g is the value to assume is in it
assumes macro s,ln
ifndef ln&_assumes
assume s:ln
else
ln&_assumes s
endif
endm
;
; defGrp
;
defGrp macro foo:vararg
endm
; setDefLangType
setDefLangType macro overLangType
ifnb <overLangType>
ifidn <overLangType>,<C>
defLangType textequ <C>
elseifidn <overLangType>,<PASCAL>
defLangType textequ <PASCAL>
elseifidn <overLangType>,<PLM>
defLangType textequ <PASCAL>
else
% .err <Illegal Language Type specified 'overLangType'>
endif
else ; !nb <overLangType>
if ?PLM EQ 1
defLangType textequ <PASCAL>
elseif ?PLM EQ 0
defLangType textequ <C>
else
.err <Illegal value for ?PLM>
endif
endif ; nb <overLangType>
endm
ifndef ?NOSTATIC
.xcref
.xcref staticB, staticW, staticD, staticQ, staticT, staticCP, staticDP, staticI
.cref
; staticX - define static data of type X
;
; usage:
; staticX n, i, s
;
; where:
; X is the type of the variable: b=byte, w=word, d=dword
; q=quad word, t=ten bytes, cp=code pointer,
; dp=data pointer, i=int
; n is the name of the given variable
; i is the initial value of the variable
; s is the duplication factor
;
; statics are always pascal symbols and non-public. If they are required
; to be public then globalX should be used.
staticB macro name:req, initVal:=<?>, repCount
ifnb <repCount>
name db repCount dup (initVal)
else
name db initVal
endif
endm
staticW macro name:req, initVal:=<?>, repCount
ifnb <repCount>
name dw repCount dup (initVal)
else
name dw initVal
endif
endm
staticD macro name:req, initVal:=<?>, repCount
ifnb <repCount>
name dd repCount dup (initVal)
else
name dd initVal
endif
endm
staticI macro name:req, initVal:=<?>, repCount
ifnb <repCount>
name asmI repCount dup (initVal)
else
name asmI initVal
endif
endm
staticQ macro name:req, initVal:=<?>, repCount
ifnb <repCount>
name dq repCount dup (initVal)
else
name dq initVal
endif
endm
staticT macro name:req, initVal:=<?>, repCount
ifnb <repCount>
name dt repCount dup (initVal)
else
name dt initVal
endif
endm
if sizec
staticCP macro name:req, i, s
staticD name,<i>,<s>
endm
else
staticCP macro name:req, i, s
staticW name,<i>,<s>
endm
endif
if sized
staticDP macro name:req, i, s
staticD name,<i>,<s>
endm
else
staticDP macro name:req, i, s
staticW name,<i>,<s>
endm
endif
endif ; ?NOSTATIC
globalB macro name:req, initVal:=<?>, repCount, langType
??CM_gbl1 name, langType, initVal, repCount, DB
endm
globalW macro name:req, initVal:=<?>, repCount, langType
??CM_gbl1 name, langType, <initVal>, repCount, DW
endm
globalD macro name:req, initVal:=<?>, repCount, langType
??CM_gbl1 name, langType, <initVal>, repCount, DD
endm
globalQ macro name:req, initVal:=<?>, repCount, langType
??CM_gbl1 name, langType, initVal, repCount, DQ
endm
globalT macro name:req, initVal:=<?>, repCount, langType
??CM_gbl1 name, langType, initVal, repCount, DT
endm
if sizec
globalCP macro n,i,s,c
globalD <n>,<i>,<s>,<c>
endm
else
globalCP macro n,i,s,c
globalW <n>,<i>,<s>,<c>
endm
endif
if sized
globalDP macro n,i,s,c
globalD <n>,<i>,<s>,<c>
endm
else
globalDP macro n,i,s,c
globalW <n>,<i>,<s>,<c>
endm
endif
??CM_gbl1 macro name, langType, initVal, repCount:=<1>, kind
setDefLangType langType
ifidn defLangType,<C>
public _&name
name textequ <_&name>
_&name kind repCount dup (initVal)
else
public name
name kind repCount dup (initVal)
endif
endm
ifndef ?NOEXTERN
.xcref
.xcref externB, externW, externD, externQ, externT
.xcref externNP, externFP, externP, externCP, externDP, externA
.cref
; externX - define external data of type X
;
; usage:
; externX n,c
;
; where:
; X is the type of the variable: b=byte, w=word, d=dword
; q=qword, t=tbyte, cp=code pointer, dp=data pointer
; a=absolute, i=int
; n is a list of names to be defined
; c is the lanague convention. C for C or PASCAL or PLM for
; pascal. The default (?PLM flag) will be used if not specified
externA macro names:req, langtype
??CM_ex1 <names>, langtype, ABS
endm
externB macro names:req, langtype
??CM_ex1 <names>, langtype, BYTE
endm
externW macro names:req, langtype
??CM_ex1 <names>, langtype, WORD
endm
externD macro names:req, langtype
??CM_ex1 <names>, langtype, DWORD
endm
externQ macro names:req, langtype
??CM_ex1 <names>, langtype, QWORD
endm
externT macro names:req, langtype
??CM_ex1 <names>, langtype, TBYTE
endm
externNP macro names:req, langtype
??CM_ex1 <names>, langtype, NEAR
endm
externFP macro names:req, langtype
??CM_ex1 <names>, langtype, FAR
endm
if sizec
externP macro n,c
externFP <n>,c
endm
externCP macro n,c
externD <n>,c
endm
else
externP macro n,c
externNP <n>,c
endm
externCP macro n,c
externW <n>,c
endm
endif
if sized
externDP macro n,c
externD <n>,c
endm
else
externDP macro n,c
externW <n>,c
endm
endif
??CM_ex1 macro names, langType, kind
setDefLangType langType
for name,<names>
ifidn defLangType,<C>
name textequ ??CM_Paste(_, name)
extern ??CM_Paste(_, name):kind
else
extern defLangType name:kind
endif
endm
endm
endif ; ?NOEXTERN
ifndef ?NOLABEL
; labelX - define label of data type X
;
labelB macro names:req,langType
??CM_lb1 <names>, langType, BYTE
endm
labelW macro names:req,langType
??CM_lb1 <names>, langType, WORD
endm
labelD macro names:req,langType
??CM_lb1 <names>, langType, DWORD
endm
labelQ macro names:req,langType
??CM_lb1 <names>, langType, QWORD
endm
labelT macro names:req,langType
??CM_lb1 <names>, langType, TBYTE
endm
labelNP macro names:req,langType
??CM_lb1 <names>, langType, NEAR
endm
labelFP macro names:req,langType
??CM_lb1 <names>, langType, FAR
endm
if sizec
labelP macro n,c
labelFP <n>,c
endm
labelCP macro n,c
labelD <n>,c
endm
else
labelP macro n,c
labelNP <n>,c
endm
labelCP macro n,c
labelW <n>,c
endm
endif
if sized
labelDP macro n,c
labelD <n>,c
endm
else
labelDP macro n,c
labelW <n>,c
endm
endif
??CM_lb1 macro names:req, langType, kind
setDefLangType langType
?pu = 0
for name,<names>
ifidn <name>,<PUBLIC>
?pu =1
else
ifidn defLangType,<C>
if ?pu
public ??CM_Paste(_, name)
endif
name textequ ??CM_Paste(_, name)
??CM_Paste(_, name) label kind
else
if ?pu
public name
endif
name label kind
endif
endif
endm
endm
endif ; ?NOLABEL
ifndef ?NODEF
; defX - inform the macros that name is of type X
;
; The given name(s) is flagged to be of the given type.
;
; This macro is no longer needed.
;
for lbl,<defB, defW, defD, defQ, defT, defCP, defDP>
lbl macro names:req
endm
endm
endif ; ?NODEF
ifndef ?NOPTR
;; regPtr generates information allowing a 32-bit pointer currently
;; in a register to be pushed as a parameter to a subroutine using
;; the cCall macro.
;;
;; usage:
;; regptr n,s,o
;; where:
;; n is the name the argument will be known as
;; s is the register containing the segment portion
;; of the pointer
;; o is the register containing the offset portion
;; of the pointer
;;
;; 2/14/85 - made obsolete with farptr
regPtr macro n,s,o
farPtr n,s,o
endm
;; farPtr generates information allowing a 32-bit pointer to be
;; pushed as a parameter to a subroutine using the cCall macro.
;;
;; usage:
;; farptr n,s,o
;; where:
;; n is the name the argument will be known as
;; s is the segment portion of the pointer
;; o is the offset portion of the pointer
;;
;; Note that any cast must have been made in the argument itself
;; (i.e. regptr ptr1,ds,<word ptr 3[si]>)
farPtr macro n,s,o
n macro
push s
push o
endm
endm
endif ; ?NOPTR
;; arg - declare arguements
;;
;; The given arguments(s) is added to the argument list structure
;;
;; format:
;; arg a
;;
;; where:
;; a is any valid arugment(s) to push
;;
;; If any element in arglist has not been defined or isn't 16-bit
;; register, then a compilete specification must have been given in
;; a text equate and a defx also given (if not, you'll pay the penalty!)
;;
arg macro args
ifnb <args>
ifnb ??CM_ArgList
??CM_ArgList textequ ??CM_ArgList, <,>, <args>
else
??CM_ArgList textequ <args>
endif
endif
endm
;; ?CM_IsIdent - is the arguement a legal identifier?
;;
;;
;; Need to enforce the following additional rules:
;; Digit may not be first character
;; Assorted other characters may be used
;; Dot may be the first character
?CM_IsIdent macro name:REQ
LOCAL result
result = 1
forc char,<name>
if ('A' LE '&char') AND ('&char' LE 'Z')
goto next
endif
if ('a' LE '&char') AND ('&char' LE 'z')
goto next
endif
if ('0' LE '&char') AND ('&char' LE '9')
goto next
endif
result = 0
exitm
:next
endm
exitm %result
endm
;; @reverse
;;
@reverse macro list
LOCAL newlist
newlist textequ <>
for x,<list>
newlist catstr <x>, <,>, newlist
endm
ifnb newlist
newlist substr newlist, 1, @sizestr(%newlist)-1
endif
exitm newlist
endm
;; ?ap - process arguments and place onto stack
;;
;; The given argument is processed (type checking) and placed
;; on the stack for a pending call. There must be a type
;; definition for all arguments (except words). This can be
;; done using text equates and the defx macro.
;;
?ap macro n
?argl=?argl+2 ;; assume one word is pushed
if 0 EQ (OPATTR n)
if ?CM_IsIdent(n)
ifdef n
n
exitm
endif
endif
% .err <'&n' is not valid to push>
exitm
else
i = (TYPE n)
if i EQ 1 ;; byte type
push word ptr(n)
exitm
endif
if i EQ 2 ;; word type
push n
exitm
endif
if i EQ 4 ;; dword type
push word ptr (n)[2]
push word ptr (n)
?argl=?argl+2
exitm
endif
if i EQ 8 ;; qword type
push word ptr (n)[6]
push word ptr (n)[4]
push word ptr (n)[2]
push word ptr (n)
?argl=?argl+6
exitm
endif
push word ptr (n) ;; variable storage
exitm
endif
endm
;; cCall - call a 'c' language procedure
;;
;; The given procedure is called with the given parameters. If the
;; calling convention is C, the arguments are pushed in reverse order,
;; and removed after the called procedure returns. If the calling
;; convention is PL/M, the arguments are pushed as they were encountered,
;; and the called procedure is assumed to have removed them
;; from the stack.
;;
;; The calling convention priority will be:
;; 1) that specified on the cCall if present,
;; 2) that defined by the target,
;; 3) the default (?PLM flag).
;;
;; format:
;; cCall n,<a>,c
;;
;; where:
;; n is the name of the procedure to call
;; a are the arguments to be pushed (optional, may be specified
;; with the "arg" macro.
;; c is the calling convention, C for C, PLM or PASCAL for
;; PL/M. The default (?PLM flag) will be used if
;; not specified).
;;
cCall macro name:req,args,langType
ifnb <args> ;; add any passed in arguments
arg <args> ;; to the list of arguments
endif ;; for this procedure
ifnb ??CM_RegSaveList ;; If there are any resgisters
% for reg,<??CM_RegSaveList> ;; to be saved across the call
push reg ;; save then on the stack
endm ;;
endif ;;
ifnb <langType> ;; If a lang type was specified then
setDefLangType langType ;; it overrides all common sense
else
i = ((OPATTR name) SHR 8) AND 7 ;; Get the lang type from the symbol
if i EQ 0 ;; No lang type ---
setDefLangType ;; Use the default lang type
elseif i EQ 1 ;; C lang type
defLangType textequ <C> ;;
elseif i EQ 4 ;; Pascal Lang Type
defLangType textequ <PASCAL> ;;
else ;; Unknown lang type
.err <Unknown lang type specfied for '&name'> ;;
endif
endif
ifidn defLangType,<C> ;; If using C calling convention
??CM_ArgList textequ @reverse(%??CM_ArgList) ;; then reverse the arguements
endif ;;
?argl=0 ;; Clear arguement byte count
% for arg,<??CM_ArgList> ;; Push the procedures arguements
?ap <arg> ;; onto the stack. ?ap takes
endm ;; care of sizing arguements
call name ;; Do the actual call
ifidn defLangType,<C> ;; If this is a C proc and there
if ?argl NE 0 ;;
add sp,?argl ;; are parameters then pop them
endif ;; off the stack
endif ;;
ifnb ??CM_RegSaveList ;; If there were any saved registers
??CM_RegSaveList textequ @reverse(%??CM_RegSaveList) ;; then pop them off the stack
% for reg,<??CM_RegSaveList> ;; at this point.
pop reg ;;
endm ;;
endif ;;
??CM_RegSaveList textequ <> ;; Clear out the global state
??CM_ArgList textequ <> ;; variable used by the cCall macro
endm
;; save - flag that the indicated registers are to be saved/restored
;; on the next cCall invocation
;;
;; usage:
;; save <r>
;;
;; where:
;; r is the list of registers to be saved.
;;
;; the macro generates a value for the variable ??CM_RegSaveList
;;
save macro r
??CM_RegSaveList textequ <r>
endm
;; parmX - generate reference to parameter(s) on the stack
;;
;; usage:
;; parmX n
;; where:
;; x is the type of the argument(s) b=byte, w=word, d=dword
;; n is the name(s) to be given the parmeter(s).
;;
;; Byte are considered to be two bytes long for alignment.
;;
;; The parmd form of the macro generates two equates:
;;
;; off_name - for accessing the offset (lsw) of the parameter
;; seg_name - for accessing the segment (msw) of the parameter
;;
parmB macro names:req
for name,<names>
??CM_addParm <&name:BYTE>
endm
endm
parmW macro names:req
for name,<names>
??CM_addParm <&name:WORD>
endm
endm
parmD macro names:req
for name,<names>
??CM_addParm <&name:DWORD>
??CM_Paste(off_, name) textequ <word ptr name[0]>
??CM_Paste(seg_, name) textequ <word ptr name[2]>
endm
endm
parmQ macro names:req
for name,<names>
??CM_addParm <&name:QWORD>
endm
endm
parmT macro names:req
for name,<names>
??CM_addParm <&name:TBYTE>
endm
endm
if sizec
parmCP macro n
parmD <n>
endm
else
parmCP macro n
parmW <n>
endm
endif
if sized
parmDP macro n
parmD <n>
endm
else
parmDP macro n
parmW <n>
endm
endif
if 0
;; parmR - register parameter
;;
;; parmR is the macro used for generating register parameters.
;; The space allocated for the register parameters will be
;; the ?ia (interface adjust) area which is between the old
;; BP and the first parameter. Normally this is empty (?ia=0),
;; or has the saved ds for a windows far procedure.
;;
;; Byte and dword register parameters will be allowed.
;;
;; usage:
;; parmR n,r,r2
;; where:
;; n is the name of the parameter
;; r is the register it is in
;; r2 is the offset register if a dword
ifndef ?NOPARMR
.xcref
.xcref ?pr,parmR
.cref
parmR macro n,r,r2
?pr n,r,r2,%?rp,%(?ia+2)
endm
;; ?pr - register parameter
;;
;; ?pr is the actual macro for generating the equates for
;; register parameters.
;;
;; usage:
;; parmR n,r,r2,i,o
;; where:
;; n is the name of the parameter
;; r is the register it is in
;; r2 is the offset register if a dword
;; i is the index of the ?rp to generate
;; o is the offset from bp where the parm will be
?pr macro n,r,r2,i,o
.xcref
ifnb <r2> ;;if a dword parameter
parmR seg_&n,r ;;define segment equate
parmR off_&n,r2 ;;define offset equate
n equ (dword ptr [bp-o-2]) ;;define dword equate
.xcref ?t&n
?t&n=4 ;;show a dword to cmacros
else
.xcref ?rp&i
?rp&i=0 ;;show no register(s)
ifdef ?&r ;;define register if valid
?rp&i=?&r
endif
if ??? or (?cpd eq 0) or (?rp&i eq 0)
??error <invalid parmR encountered: &n,&r>
exitm
endif
n equ (word ptr [bp-o]) ;;assume a word register
?t&n=2 ;;show a word to cmacros
irp x,<bh,ch,dh,bl,cl,dl,ah,al>
if ?&&x eq ?&r ;;if really a byte register
n equ (byte ptr [bp-o]) ;; then make it a byte
?t&n=1 ;;show a byte to cmacros
exitm
endif
endm
?ia=?ia+2 ;;show this guy is out there
?rp=?rp+1 ;;show one more register parameter
endif
.cref
endm
endif
endif
localB macro name
??CM_addLocal ??CM_Paste(name, <:BYTE>)
endm
localW macro name
??CM_addLocal ??CM_Paste(name, <:WORD>)
endm
localD macro name
??CM_addLocal ??CM_Paste(name, <:DWORD>)
off_&name textequ <word ptr name[0]>
seg_&name textequ <word ptr name[2]>
endm
localQ macro name
??CM_addLocal ??CM_Paste(name, <:QWORD>)
endm
localT macro name
??CM_addLocal ??CM_Paste(name, <:TBYTE>)
endm
if sizec
localCP macro n
localD <n>
endm
else
localCP macro n
localW <n>
endm
endif
if sized
localDP macro n
localD <n>
endm
else
localDP macro n
localW <n>
endm
endif
localV macro name,a
local t1
t1 catstr <name>, < [>, %a, <]:BYTE>
% ??CM_addLocal <t1>
endm
ife ?DF
;;
;; Define all segments that will be used. This will allow the
;; assume and groups to be set up at one given place, and also
;; allow quick changes to be made
;;
createSeg _TEXT,Code,word,public,CODE
ife ?NODATA
createSeg _DATA,Data,word,public,DATA,DGROUP
endif
endif
; errnz exp - generate error message if expression isn't zero
;
; The errnz will generate an error message if the expression "exp"
; does not evaluate to zero. This macro is very useful for testing
; relationships between items, labels, and data that was coded into
; an application.
;
; errnz <offset $ - offset label> ;error if not at "label"
; errnz <eofflag and 00000001b> ;eofflag must be bit 0
;
; For expressions involving more than one token, the angle brackets
; must be used.
;
; The macro is only evaluated on pass 2, so forward references may be
; used in the expression.
errnz macro x ;;display error if expression is <>0
.errnz x
endm
; errn$ label,exp - generate error message if label (exp) <> $
;
; The errnz will generate an error message if the label and "exp"
; does not evaluate to the current value of the location counter.
; This macro is very useful for testing relationships between
; labels and the location counter that was coded into an application.
;
; examples: errn$ label ;error if not at "label"
; errn$ label,+3 ;error if not three bytes from "label"
; errn$ label,-3 ;error if not three bytes past "label"
;
; If no "exp" is given, it is the same as specifying 0
;
; The macro is only evaluated on pass 2, so forward references may be
; used in the expression.
errn$ macro l,x ;;error if <$-label1 (exp2)> <>0
errnz <offset $ - offset l x>
endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Extra macros for the c-runtime package
;
; Macro for calling another run-time-library function.
; Does a PUSH CS/CALL NEAR in compact/large models, except
; for QuickC. --PHG, 5-24-89
callcrt MACRO funcname
ifdef _QC2
call funcname
else
if sizeC
push cs
call near ptr (funcname)
else
call funcname
endif
endif
ENDM
.cref ; Permit symbols to be listed again