📄 cmacros.inc
字号:
ife ?t_&n
push word ptr (n)
exitm
endif
endif
push n
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 conventing 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 arguments to be pushed (optional, may be
;; specified with the "arg" macro.
;; c is the convention, C for C, PLM or PSACAL for PL/M.
;; The default (?PLM flag) will be used if not specified.
cCall macro n,a,c
ifnb <a>
arg <a>
endif
mpush %?rsl
ifdef ?CC&n
?cCall1=?CC&n
else
?cCall1=?PLM
endif
ifnb <c>
?gcc ?cCall1,%?cCall1,<c>
endif
?argl=0
ife ?cCall1
?acb=?argc
else
?acb=1
endif
rept ?argc
uconcat <?ali>,%?acb
uconcat <purge>,,<?ali>,%?acb
ife ?cCall1
?acb=?acb-1
else
?acb=?acb+1
endif
endm
call n
if ((?cCall1 eq 0) and (?argl ne 0))
add sp,?argl
endif
mpop %?rsl
?rsl=0
?argc= 0
?argl= 0
endm
;; cProc - define a 'c' procedure
;;
;; cProc is the procedure definition for procedures.
;;
;; format:
;; cProc n,cf,a
;; where:
;; n is the name of the procedure
;;
;; cf controls certain definitions, and may be:
;; NEAR proc is to be a near label
;; FAR proc is to be a far label
;; PUBLIC proc is to be defined as public
;; SMALL call makeframe procedure
;; NODATA dont create prolog code to setup DS
;; ATOMIC don't link stack if not needed
;; NODATA must be specified for ATOMIC
;; FORCEFRAME Force generation of a frame
;; C proc is to be a C procedure
;; PLM proc is to be a PL/M procedure
;; PASCAL proc is to be a PL/M procedure
;; WIN proc is to be a windows procedure
;; NONWIN proc isn't to be a windows procedure
;;
;; a is a list of registers that are to be saved whenever
;; the procedure is invoked.
;;
;; makeframe procedure: If small is specified, then
;; the "makeframe procedure" is invoked instead of
;; generating normal prologues/epilogues
;;
;; A call is performed to the makeframe procedure. The
;; call is followed by two bytes. the first byte is the
;; number of locals to allocate for the frame, the second
;; is the number of bytes of parameters. The makeframe
;; procedure will in turn call the cProc routine at the
;; address following the data bytes. When the cProc is
;; finished, it will do a near return to the makeframe
;; procedure to clean up the frame and exit.
;;
;; Note that register parameters and makeframe are
;; incompatible and cannot be used together.
;;
;; The makeframe procedure will save SI, DI, and also
;; DS if a far procedure. These registers will be
;; removed from the autosave list if specified.
cProc macro n,cf,a
if ?cpd
?utpe
endif
?cpd=1
???=0
?argc=0
?ba=0
?po=0
?pu=0
?ia=0
?adj=4
?rp=0
?uf=0
?wfp=?WIN
?ff=0
?pas=0
?pcc=?PLM
ifnb <a>
?ri ?pas,<a>
endif
?pc=sizec
?nd=?nodata1
?nx=0
irp x,<cf>
ifidn <x>,<FAR>
?pc=1
endif
ifidn <x>,<NEAR>
?pc=0
endif
ifidn <x>,<PUBLIC>
?pu=1
endif
ifidn <x>,<SMALL>
?uf=1
endif
ifidn <x>,<DATA>
?nd=0
endif
ifidn <x>,<NODATA>
?nd=1
endif
ifidn <x>,<ATOMIC>
?nx=1
endif
ifidn <x>,<FORCEFRAME>
?ff=1
endif
ifidn <x>,<C>
?pcc=0
endif
ifidn <x>,<PLM>
?pcc=1
endif
ifidn <x>,<PASCAL>
?pcc=1
endif
ifidn <x>,<WIN>
?wfp=1
endif
ifidn <x>,<NONWIN>
?wfp=0
endif
endm
if ?pcc
?PLMPrevParm=0
.xcref
.xcref ?PLMParm0
.cref
?PLMParm0 macro arg
purge ?PLMParm0
endm
endif
.xcref
.xcref ?CC&n
.cref
?CC&n=?pcc
if (?nx eq 1) and (?nd eq 0)
?nx = 0
??error <ATOMIC specified without NODATA - ATOMIC ignored>
endif
if ?pc
if ?wfp
ife ?nx
?ia=2
?pas = ?pas and (not ?ds)
endif
endif
?adj=?adj+2
else
?wfp=0
endif
?pas = ?pas and (not (?sp+?cs+?ss))
if ?uf
?pas = ?pas and (not (?bp+?si+?di))
endif
ife ?pcc
?pg <_&n>,%?pu,%?pc,%?pas,%?wfp,<n>,%?pcc
else
?pg <n>,%?pu,%?pc,%?pas,%?wfp,<n>,%?pcc
endif
endm
;; ?pg - generate begin and nested macros for current procedure
;;
;; format:
;; ?pg n,p,c,a,w,nnu,cc
;; where:
;; n is the name of the procedure
;; p is the public flag
;; c is the class definition for the procedure
;; a is an enumerated list of registers to save
;; at entry and restore at exit
;; w true if a far windows procedure
;; nnu procedure name without any underscore
;; cc calling convention (C or PL/M)
;;
;;
;; local stack allocation will be forced to an even byte count to
;; maintain stack word alignment.
?pg macro n,p,c,a,w,nnu,cc
.xcref
if ?uf
if ?nd
??error <NODATA encountered in &n - user frame ignored>
?uf=0
endif
endif
.xcref cBegin
cBegin macro g
.xcref
if cc
uconcat <?PLMParm>,%?PLMPrevParm,%?po
endif
if ?uf
if ?rp
??error <parmR encountered in &n - user frame ignored>
?uf=0
endif
endif
?pg1 <n>,c,a,%?po,w,%?uf,%?nd,%?rp,cc
?cpd=0
?argc=0
?ba=1
???=(???+1) and 0fffeh
if p
public n
endif
ife c
n proc near
else
n proc far
endif
ife cc
nnu equ n
endif
ifidn <g>,<nogen>
if ???+?po+a+?rp
??_out <cBegin - possible invalid use of nogen>
endif
else
if ?uf
?mf c,%???,%?po
mpush a
else
if w
ife ?nd
mov ax,ds
nop
endif
ife ?nx
ife ?DOS5
inc bp
endif
push bp
mov bp,sp
push ds
else
if ?ff+???+?po+?rp
push bp
mov bp,sp
endif
endif
ife ?nd
mov ds,ax
endif
else
if ?ff+???+?po+?rp
push bp
mov bp,sp
endif
endif
if ?rp
?uf=0
rept ?rp
uconcat mpush,,?rp,%?uf
?uf=?uf+1
endm
endif
if ???
if ?chkstk1
ifdef ?CHKSTKPROC
?CHKSTKPROC %???
else
mov ax,???
ife cc
call _chkstk
else
call chkstk
endif
endif
else
sub sp,???
endif
endif
mpush a
endif
ifdef ?PROFILE
if c
call StartNMeas
endif
endif
endif
.cref
purge cBegin
endm
.xcref ?utpe
?utpe macro
??error <unterminated procedure definition: "&n">
endm
.cref
endm
;; ?pg1 - generate end macro for current procedure
;;
;; format:
;; ?pg1 n,c,a,o,w,f,d,r,cc
;; where:
;; n is the name of the procedure
;; c is the class definition for the procedure
;; a is an enumerated list of registers to save
;; at entry and restore at exit
;; o is the number of bytes of paramteres to remove at exit
;; w true if a far windows procedure
;; f is 1 if to use the user's makeframe procedure
;; d is 1 if NODATA procedure
;; r number of register parameters
;; cc calling convention (C or PL/M)
?pg1 macro n,c,a,o,w,f,d,r,cc
.xcref
.xcref cEnd
cEnd macro g
.xcref
?ba=0
ifidn <g>,<nogen>
if o+a+r
??_out <cEnd - possible invalid use of nogen>
endif
else
ifdef ?PROFILE
if c
call StopNMeas
endif
endif
mpop a
if f
db 0c3h
else
if w
ife ?nx
if (?TF eq 0) or (???+?rp)
lea sp,(-2)[bp]
endif
pop ds
pop bp
ife ?DOS5
dec bp
endif
else
if (?TF eq 0) or (???+?rp)
mov sp,bp
endif
if ???+?po+?rp
pop bp
endif
endif
else
if ?ff+???+?po+?rp
if (?TF eq 0) or (???+?rp)
mov sp,bp
endif
pop bp
endif
endif
ife cc
ret
else
ret o
endif
endif
endif
n endp
.cref
purge cEnd
endm
.cref
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
ifdef MS_STARTUP
ifidn <code>,<ln>
assume s&:_TEXT
exitm
elseifidn <CODE>,<ln>
assume s&:_TEXT
exitm
elseifidn <data>,<ln>
assume s&:dgroup
exitm
elseifidn <DATA>,<ln>
assume s&:dgroup
exitm
endif
endif
ifndef ln&_assumes
assume s:ln
else
ln&_assumes s
endif
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 enter the segment, but it cannot be used for anything
; 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 this segment
createSeg macro n,ln,a,co,cl,grp
ifnb <cl>
n segment a co '&cl'
else
n segment a co
endif
n ends
?cs1 <ln>,<n>
ifnb <grp>
grp group n
?cs3 <ln>,<grp>
ln&OFFSET equ <offset grp:>
ln&BASE equ <grp>
else
?cs3 <ln>,<n>
ln&OFFSET equ <offset>
ln&BASE equ <n>
endif
endm
addseg macro grp,seg
.xcref
.xcref grp&_add
.cref
grp&_add macro s
grp&_in <seg>,s
endm
.xcref
.xcref grp&_in
.cref
grp&_in macro sl,s
ifb <s>
grp group sl
else
grp&_add macro ns
grp&_in <sl,s>,ns
endm
endif
endm
endm
defgrp macro grp,ln
endm
?cs1 macro ln,n
.xcref
.xcref ln&_sbegin
.cref
ln&_sbegin macro
?cs2 <ln>,<n>
n segment
.xcref
.xcref ?mf
.cref
?mf macro c,l,p
if c
extrn n&_FARFRAME:near
call n&_FARFRAME
else
extrn n&_NEARFRAME:near
call n&_NEARFRAME
endif
db l shr 1
db p shr 1
endm
endm
endm
?cs2 macro ln,n
.xcref
.xcref sEnd
.cref
sEnd macro arg
n ends
purge ?mf
purge sEnd
endm
endm
?cs3 macro ln,n
.xcref
.xcref ln&_assumes
.cref
ln&_assumes macro s
assume s:&n
endm
endm
.xcref
.xcref sBegin
.cref
; sBegin is the macro that opens up the definition of a segment.
; The segment must have already been defined with the createSeg
; macro.
;
; usage:
; sBegin ln
;
; where:
; ln is the logical name given to the segment when
; it was declared.
sBegin macro ln
ln&_sbegin
endm
; 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 name,logname,align,combine,class,group
ife ?DF
createSeg _TEXT,Code,word,public,CODE
ife ?nodata1
createSeg _DATA,Data,word,public,DATA,DGROUP
defgrp DGROUP,Data
endif
if ?chkstk1
ifndef ?CHKSTKPROC
externp <chkstk>
endif
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
ifnb <x>
.errnz (x),<x>
endif
endm
errnz1 macro x1,x2
= *errnz* x1 = x2
.err
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
errnz <offset $ - offset l x>
endm
;; If profile has been specified, declare the profile routines
;; to be external and far. It would be best if this could be done
;; when the call is actually made, but then the fix-up would be
;; generated as segment-relative.
ifdef ?PROFILE
externFP <StartNMeas,StopNMeas>
endif
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 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.
callcrt MACRO funcname
ifdef _QC2
call funcname
else
if sizeC
push cs
call near ptr (funcname)
else
call funcname
endif
endif
ENDM
.cref
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -