mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1197 lines
19 KiB
1197 lines
19 KiB
;
|
|
; Microsoft Confidential
|
|
; Copyright (C) Microsoft Corporation 1991
|
|
; All Rights Reserved.
|
|
;
|
|
|
|
;** Macro definitions for MSDOS.
|
|
;
|
|
; Revision history:
|
|
; M019 DB 10/26/90 - Added Cmp32 macro.
|
|
|
|
TRUE EQU 0FFFFh
|
|
FALSE EQU 0
|
|
|
|
SUBTTL BREAK a listing into pages and give new subtitles
|
|
PAGE
|
|
BREAK MACRO subtitle
|
|
SUBTTL subtitle
|
|
PAGE
|
|
ENDM
|
|
.xcref break
|
|
|
|
BREAK <ASMVAR - handle assembly variables once and for all>
|
|
|
|
AsmVars Macro varlist
|
|
IRP var,<varlist>
|
|
AsmVar var
|
|
ENDM
|
|
ENDM
|
|
|
|
AsmVar Macro var
|
|
IFNDEF var
|
|
var = FALSE
|
|
ENDIF
|
|
ENDM
|
|
|
|
BREAK <I_NEED: declare a variable external, if necessary, and allocate a size>
|
|
|
|
;
|
|
; declare a variable external and allocate a size
|
|
;
|
|
AsmVar InstalledData
|
|
I_NEED MACRO sym,len
|
|
IF NOT InstalledData
|
|
DOSDATA SEGMENT WORD PUBLIC 'DATA'
|
|
IFIDN <len>,<WORD>
|
|
EXTRN &sym:WORD
|
|
ELSE
|
|
IFIDN <len>,<DWORD>
|
|
EXTRN &sym:DWORD
|
|
ELSE
|
|
EXTRN &sym:BYTE
|
|
ENDIF
|
|
ENDIF
|
|
DOSDATA ENDS
|
|
ENDIF
|
|
ENDM
|
|
.xcref I_need
|
|
|
|
|
|
; call a procedure that may be external. The call will be short.
|
|
|
|
invoke MACRO name
|
|
.xcref
|
|
IF2
|
|
IFNDEF name
|
|
EXTRN name:NEAR
|
|
ENDIF
|
|
ENDIF
|
|
.cref
|
|
CALL name
|
|
ENDM
|
|
.xcref invoke
|
|
|
|
PAGE
|
|
;
|
|
; jump to a label that may be external. The jump will be near.
|
|
;
|
|
transfer MACRO name
|
|
.xcref
|
|
IF2
|
|
IFNDEF name
|
|
EXTRN name:NEAR
|
|
ENDIF
|
|
ENDIF
|
|
.cref
|
|
JUMP name
|
|
ENDM
|
|
.xcref transfer
|
|
|
|
;
|
|
; get a short address in a word
|
|
;
|
|
short_addr MACRO name
|
|
IFDIF <name>,<?>
|
|
.xcref
|
|
IF2
|
|
IFNDEF name
|
|
EXTRN name:NEAR
|
|
ENDIF
|
|
ENDIF
|
|
.cref
|
|
DW OFFSET DOSCODE:name
|
|
ELSE
|
|
DW ?
|
|
ENDIF
|
|
ENDM
|
|
.xcref short_addr
|
|
|
|
;
|
|
; get a long address in a dword
|
|
;
|
|
long_addr MACRO name
|
|
.xcref
|
|
IF2
|
|
IFNDEF name
|
|
EXTRN name:NEAR
|
|
ENDIF
|
|
ENDIF
|
|
.cref
|
|
DD name
|
|
ENDM
|
|
.xcref long_addr
|
|
|
|
;
|
|
; declare a PROC near or far but PUBLIC nonetheless
|
|
;
|
|
.xcref ?frame
|
|
.xcref ?aframe
|
|
.xcref ?stackdepth
|
|
.xcref ?initstack
|
|
?frame = 0 ; initial
|
|
?aframe = 0 ; initial
|
|
?stackdepth = 0 ; initial stack size
|
|
?initstack = 0 ; initial stack size
|
|
|
|
procedure MACRO name,distance
|
|
?frame = 0
|
|
?aframe = 2 ;; remember the pushed BP
|
|
PUBLIC name
|
|
name PROC distance
|
|
ASSUME DS:nothing,ES:nothing
|
|
?initstack = ?stackdepth ;; beginning of procedure
|
|
ENDM
|
|
.xcref procedure
|
|
|
|
|
|
; end a procedure and check that stack depth is preserved
|
|
|
|
EndProc MACRO name, chk
|
|
IFDIF <chk>,<NoCheck> ;; check the stack size
|
|
IF2
|
|
IF ?initstack NE ?stackdepth ;; is it different?
|
|
%OUT ***** Possible stack size error in name *****
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
name ENDP
|
|
ENDM
|
|
.xcref endproc
|
|
PAGE
|
|
;
|
|
; define a data item to be public and of an appropriate size/type
|
|
;
|
|
|
|
I_AM MACRO name,size,init
|
|
;; declare the object public
|
|
PUBLIC name
|
|
;; declare the type of the object
|
|
IFIDN <size>,<WORD>
|
|
name LABEL WORD
|
|
I_AM_SIZE = 1
|
|
I_AM_LEN = 2
|
|
ELSE
|
|
IFIDN <size>,<DWORD>
|
|
name LABEL DWORD
|
|
I_AM_SIZE = 2
|
|
I_AM_LEN = 2
|
|
ELSE
|
|
IFIDN <size>,<BYTE>
|
|
name LABEL BYTE
|
|
I_AM_SIZE = 1
|
|
I_AM_LEN = 1
|
|
ELSE
|
|
name LABEL BYTE
|
|
I_AM_SIZE = size
|
|
I_AM_LEN = 1
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
;; if no initialize then allocate blank storage
|
|
IFB <init>
|
|
DB I_AM_SIZE*I_AM_LEN DUP (?)
|
|
ELSE
|
|
IF NOT InstalledData
|
|
IRP itm,<init>
|
|
IF I_AM_LEN EQ 1
|
|
DB itm
|
|
ELSE
|
|
DW itm
|
|
ENDIF
|
|
I_AM_SIZE = I_AM_SIZE - 1
|
|
ENDM
|
|
IF I_AM_SIZE NE 0
|
|
%out ***** initialization of name not complete *****
|
|
ENDIF
|
|
ELSE
|
|
DB I_AM_SIZE*I_AM_LEN DUP (?)
|
|
ENDIF
|
|
ENDIF
|
|
ENDM
|
|
.xcref I_AM
|
|
.xcref I_AM_SIZE
|
|
.xcref I_AM_LEN
|
|
I_AM_SIZE = 0
|
|
I_AM_LEN = 0
|
|
|
|
PAGE
|
|
|
|
;
|
|
; define an entry in a procedure
|
|
;
|
|
entry macro name
|
|
PUBLIC name
|
|
name:
|
|
endm
|
|
.xcref entry
|
|
|
|
BREAK <ERROR - store an error code then jump to a label>
|
|
|
|
error macro code
|
|
.xcref
|
|
MOV AL,code
|
|
transfer SYS_RET_ERR
|
|
.cref
|
|
ENDM
|
|
.xcref error
|
|
|
|
BREAK <JUMP - real jump that links up shortwise>
|
|
;
|
|
; given a label <lbl> either 2 byte jump to another label <lbl>_J
|
|
; if it is near enough or 3 byte jump to <lbl>
|
|
;
|
|
|
|
jump macro lbl
|
|
local a
|
|
.xcref
|
|
|
|
ifndef lbl&_J ;; is this the first invocation
|
|
a: JMP lbl
|
|
ELSE
|
|
IF (lbl&_J GE $) OR ($-lbl&_J GT 126)
|
|
a: JMP lbl ;; is the jump too far away?
|
|
ELSE
|
|
a: JMP lbl&_J ;; do the short one...
|
|
ENDIF
|
|
ENDIF
|
|
lbl&_j = a
|
|
.cref
|
|
endm
|
|
.xcref jump
|
|
|
|
BREAK <RETURN - return from a function>
|
|
|
|
return macro x
|
|
local a
|
|
.xcref
|
|
a:
|
|
RET
|
|
ret_l = a
|
|
.cref
|
|
endm
|
|
.xcref return
|
|
|
|
BREAK <CONDRET - conditional return>
|
|
|
|
condret macro cc,ncc
|
|
local a
|
|
.xcref
|
|
.xcref a
|
|
.cref
|
|
ifdef ret_l ;; if ret_l is defined
|
|
if (($ - ret_l) le 126) and ($ gt ret_l)
|
|
;; if ret_l is near enough then
|
|
a: j&cc ret_l ;; a: j<CC> to ret_l
|
|
ret_&cc = a ;; define ret_<CC> to be a:
|
|
exitm
|
|
endif
|
|
endif
|
|
ifdef ret_&cc ;; if ret_<CC> defined
|
|
if (($ - ret_&cc) le 126) and ($ gt ret_&cc)
|
|
;; if ret_<CC> is near enough
|
|
a: j&cc ret_&cc ;; a: j<CC> to ret_<CC>
|
|
ret_&cc = a ;; define ret_<CC> to be a:
|
|
exitm
|
|
endif
|
|
endif
|
|
j&ncc a ;; j<NCC> a:
|
|
return ;; return
|
|
a: ;; a:
|
|
ret_&cc = ret_l ;; define ret_<CC> to be ret_l
|
|
endm
|
|
.xcref condret
|
|
|
|
BREAK <RETZ - return if zero, links up shortwise if necessary>
|
|
|
|
retz macro
|
|
condret z,nz
|
|
endm
|
|
.xcref retz
|
|
|
|
BREAK <RETNZ - return if not zero, links up shortwise if necessary>
|
|
|
|
retnz macro
|
|
condret nz,z
|
|
endm
|
|
.xcref retnz
|
|
|
|
BREAK <RETC - return if carry set, links up shortwise if necessary>
|
|
|
|
retc macro
|
|
condret c,nc
|
|
endm
|
|
.xcref retc
|
|
|
|
BREAK <RETNC - return if not carry, links up shortwise if necessary>
|
|
|
|
retnc macro
|
|
condret nc,c
|
|
endm
|
|
.xcref retnc
|
|
|
|
BREAK <CONTEXT - set the DOS context to a particular register>
|
|
|
|
context macro r
|
|
PUSH SS
|
|
POP r
|
|
ASSUME r:DOSDATA
|
|
endm
|
|
.xcref context
|
|
|
|
BREAK <SaveReg - save a set of registers>
|
|
|
|
SaveReg MACRO reglist ;; push those registers
|
|
IRP reg,<reglist>
|
|
?stackdepth = ?stackdepth + 1
|
|
PUSH reg
|
|
ENDM
|
|
ENDM
|
|
.xcref SaveReg
|
|
|
|
Save MACRO arglist ;; push those arguments
|
|
IRP arg,<arglist>
|
|
?stackdepth = ?stackdepth + 1
|
|
PUSH arg
|
|
ENDM
|
|
ENDM
|
|
.xcref Save
|
|
|
|
BREAK <RestoreReg - unsave some registers>
|
|
|
|
RestoreReg MACRO reglist ;; pop those registers
|
|
IRP reg,<reglist>
|
|
?stackdepth = ?stackdepth - 1
|
|
POP reg
|
|
ENDM
|
|
ENDM
|
|
.xcref RestoreReg
|
|
|
|
Restore MACRO arglist ;; pop those arguments
|
|
IRP arg,<arglist>
|
|
?stackdepth = ?stackdepth - 1
|
|
POP arg
|
|
ENDM
|
|
ENDM
|
|
.xcref Restore
|
|
|
|
BREAK <Critical section macros>
|
|
|
|
EnterCrit MACRO section
|
|
; Invoke E§ion
|
|
ENDM
|
|
|
|
LeaveCrit MACRO section
|
|
; Invoke L§ion
|
|
ENDM
|
|
|
|
Break <message - display a message>
|
|
|
|
AsmVars <ShareF,Cargs,Redirector>
|
|
|
|
if debug
|
|
fmt MACRO typ,lev,fmts,args
|
|
local a,b,c
|
|
PUSHF
|
|
IFNB <typ>
|
|
TEST BugTyp,typ
|
|
JZ c
|
|
CMP BugLev,lev
|
|
JB c
|
|
ENDIF
|
|
PUSH AX
|
|
PUSH BP
|
|
MOV BP,SP
|
|
If (not sharef) and (not redirector)
|
|
DOSDATA segment
|
|
a db fmts,0
|
|
DOSDATA ends
|
|
MOV AX,OFFSET DOSDATA:a
|
|
else
|
|
jmp short b
|
|
a db fmts,0
|
|
if sharef
|
|
b: mov ax,offset share:a
|
|
else
|
|
b: mov ax,offset netwrk:a
|
|
endif
|
|
endif
|
|
PUSH AX
|
|
cargs = 2
|
|
IRP item,<args>
|
|
IFIDN <AX>,<item>
|
|
push [bp+2]
|
|
; MOV AX,[BP+2]
|
|
ELSE
|
|
; MOV AX,item
|
|
push item
|
|
ENDIF
|
|
; PUSH AX
|
|
cargs = cargs + 2
|
|
ENDM
|
|
invoke PFMT
|
|
ADD SP,Cargs
|
|
POP BP
|
|
POP AX
|
|
c:
|
|
POPF
|
|
ENDM
|
|
else
|
|
fmt macro
|
|
endm
|
|
endif
|
|
|
|
Break <DOSAssume - validate assumes>
|
|
|
|
AsmVar Debug,$temp
|
|
|
|
;** DOSAssume - Check that a register addresses DOSSEG
|
|
;
|
|
; DOSAssume reglist, message
|
|
|
|
|
|
IF debug
|
|
DOSAssume Macro reglist,message
|
|
local a,b
|
|
$temp = 0
|
|
IRP r,<reglist>
|
|
IFIDN <r>,<DS>
|
|
$temp = $temp OR 2
|
|
ELSE
|
|
IFIDN <r>,<ES>
|
|
$temp = $temp OR 4
|
|
ELSE
|
|
IFIDN <r>,<SS>
|
|
$temp = $temp OR 1
|
|
ELSE
|
|
%out ***** Invalid register reg in DOSAssume *****
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDM
|
|
Invoke SegCheck
|
|
jmp short a
|
|
db $temp
|
|
db message,0
|
|
a:
|
|
|
|
IRP r,<reglist>
|
|
ASSUME r:DOSDATA
|
|
ENDM
|
|
ENDM
|
|
|
|
ELSE
|
|
|
|
DOSAssume Macro reglist,message
|
|
IRP r,<reglist>
|
|
ASSUME r:DOSDATA
|
|
ENDM
|
|
ENDM
|
|
ENDIF
|
|
|
|
BREAK <ASSERT - make assertions about registers>
|
|
|
|
IF DEBUG
|
|
Assert MACRO kind, objs, message
|
|
LOCAL a,b
|
|
IFIDN <kind>,<Z>
|
|
CMP objs,0
|
|
JZ a
|
|
fmt <>,<>,<message>
|
|
a:
|
|
ELSE
|
|
IFIDN <kind>,<NZ>
|
|
CMP objs,0
|
|
JNZ a
|
|
fmt <>,<>,<message>
|
|
a:
|
|
ELSE
|
|
PUSH AX
|
|
IRP obj,<objs>
|
|
PUSH obj
|
|
ENDM
|
|
IF SHAREF
|
|
MOV AX,OFFSET b
|
|
ELSE
|
|
MOV AX,OFFSET DOSDATA:b
|
|
ENDIF
|
|
PUSH AX
|
|
IFIDN <kind>,<ISBUF>
|
|
Invoke BUFCheck
|
|
ENDIF
|
|
IFIDN <kind>,<ISSFT>
|
|
Invoke SFTCheck
|
|
ENDIF
|
|
IFIDN <kind>,<ISDPB>
|
|
Invoke DPBCheck
|
|
ENDIF
|
|
POP AX
|
|
IF SHAREF
|
|
JMP SHORT a
|
|
b DB Message,0
|
|
a:
|
|
ELSE
|
|
DOSDATA segment
|
|
b db Message,0
|
|
DOSDATA ends
|
|
ENDIF
|
|
ENDIF
|
|
ENDIF
|
|
ENDM
|
|
ELSE
|
|
Assert Macro
|
|
ENDM
|
|
ENDIF
|
|
|
|
Break <CallInstall - hook to installable pieces>
|
|
|
|
CallInstall MACRO name,mpx,fn,save,restore
|
|
IF Installed
|
|
IFNB <save>
|
|
SaveReg <save>
|
|
ENDIF
|
|
MOV AX,(mpx SHL 8) + fn
|
|
INT 2Fh
|
|
IFNB <restore>
|
|
RestoreReg <restore>
|
|
ENDIF
|
|
ELSE
|
|
Invoke name
|
|
ENDIF
|
|
ENDM
|
|
|
|
Break <Stack frame manipulators>
|
|
|
|
localvar macro name,length
|
|
local a
|
|
ifidn <length>,<BYTE>
|
|
?frame = ?frame + 1
|
|
a = ?frame
|
|
name EQU BYTE PTR [BP-a]
|
|
else
|
|
ifidn <length>,<WORD>
|
|
?frame = ?frame + 2
|
|
a = ?frame
|
|
name EQU WORD PTR [BP-a]
|
|
else
|
|
ifidn <length>,<DWORD>
|
|
?frame = ?frame + 4
|
|
a = ?frame
|
|
name EQU DWORD PTR [BP-a]
|
|
name&l EQU WORD PTR [BP-a]
|
|
name&h EQU WORD PTR [BP-a+2]
|
|
else
|
|
?frame = ?frame + length
|
|
a = ?frame
|
|
name EQU BYTE PTR [BP-a]
|
|
endif
|
|
endif
|
|
endif
|
|
endm
|
|
|
|
enter macro
|
|
push bp
|
|
mov bp,sp
|
|
sub sp,?frame
|
|
endm
|
|
|
|
leave macro
|
|
mov sp,bp
|
|
pop bp
|
|
endm
|
|
|
|
Argvar macro name,length
|
|
local a
|
|
ifidn <length>,<BYTE>
|
|
a = ?aframe
|
|
?aframe = ?aframe + 1
|
|
name EQU BYTE PTR [BP+a]
|
|
else
|
|
ifidn <length>,<WORD>
|
|
a = ?aframe
|
|
?aframe = ?aframe + 2
|
|
name EQU WORD PTR [BP+a]
|
|
else
|
|
ifidn <length>,<DWORD>
|
|
a = ?aframe
|
|
?aframe = ?aframe + 4
|
|
name EQU DWORD PTR [BP+a]
|
|
name&l EQU WORD PTR [BP+a]
|
|
name&h EQU WORD PTR [BP+a+2]
|
|
else
|
|
a = ?aframe
|
|
?aframe = ?aframe + length
|
|
name EQU BYTE PTR [BP+a]
|
|
endif
|
|
endif
|
|
endif
|
|
endm
|
|
|
|
|
|
save_world macro
|
|
|
|
push es
|
|
invoke save_user_world
|
|
|
|
endm
|
|
|
|
restore_world macro
|
|
|
|
invoke restore_user_world
|
|
pop es
|
|
|
|
endm
|
|
|
|
;
|
|
; This macro gets the DOS data segment value and puts it in the specified
|
|
; segment register. This can only be used in the DOSCODE segment.
|
|
;
|
|
|
|
getdseg macro r
|
|
|
|
mov r, cs:[DosDseg]
|
|
assume r:dosdata
|
|
endm
|
|
|
|
;
|
|
; This macro does the necessary extrns to allow use of the getdseg macro.
|
|
;
|
|
allow_getdseg macro
|
|
|
|
ifdef ROMDOS
|
|
extrn BioDataSeg:word
|
|
bdata segment at 70H
|
|
extrn DosDataSg:word
|
|
bdata ends
|
|
else
|
|
extrn DosDseg:word
|
|
endif
|
|
|
|
endm
|
|
|
|
|
|
|
|
BREAK <LJcc - Long Conditional Jumps>
|
|
|
|
LJE macro l
|
|
LJ JE JNE l
|
|
endm
|
|
|
|
LJNE macro l
|
|
LJ jne JE l
|
|
endm
|
|
|
|
LJZ macro l
|
|
LJE l
|
|
endm
|
|
|
|
LJNZ macro l
|
|
LJNE l
|
|
endm
|
|
|
|
LJC macro l
|
|
LJ jc JNC l
|
|
endm
|
|
|
|
LJNC macro l
|
|
LJ jnc JC l
|
|
endm
|
|
|
|
LJA macro l
|
|
LJ ja JNA l
|
|
endm
|
|
|
|
LJNA macro l
|
|
LJ jna JA l
|
|
endm
|
|
|
|
LJB macro l
|
|
LJ jb JNB l
|
|
endm
|
|
|
|
LJNB macro l
|
|
LJ jnb JB l
|
|
endm
|
|
|
|
LJS macro l
|
|
LJ js JNS l
|
|
endm
|
|
|
|
LJNS macro l
|
|
LJ jns JS l
|
|
endm
|
|
|
|
LJAE macro l
|
|
LJ jae JNAE l
|
|
endm
|
|
|
|
LJBE macro l
|
|
LJ jbe JNBE l
|
|
endm
|
|
|
|
LJL macro l
|
|
LJ jl JNL l
|
|
endm
|
|
|
|
LJG macro l
|
|
LJ jg JNG l
|
|
endm
|
|
|
|
LJLE macro l
|
|
LJ jle JNLE l
|
|
endm
|
|
|
|
DLJE macro l
|
|
DLJ JE JNE l
|
|
endm
|
|
|
|
DLJNE macro l
|
|
DLJ jne JE l
|
|
endm
|
|
|
|
DLJZ macro l
|
|
DLJE l
|
|
endm
|
|
|
|
DLJNZ macro l
|
|
DLJNE l
|
|
endm
|
|
|
|
DLJC macro l
|
|
DLJ jc JNC l
|
|
endm
|
|
|
|
DLJNC macro l
|
|
DLJ jnc JC l
|
|
endm
|
|
|
|
DLJA macro l
|
|
DLJ ja JNA l
|
|
endm
|
|
|
|
DLJNA macro l
|
|
DLJ jna JA l
|
|
endm
|
|
|
|
DLJB macro l
|
|
DLJ jb JNB l
|
|
endm
|
|
|
|
DLJNB macro l
|
|
DLJ jnb JB l
|
|
endm
|
|
|
|
DLJS macro l
|
|
DLJ js JNS l
|
|
endm
|
|
|
|
DLJNS macro l
|
|
DLJ jns JS l
|
|
endm
|
|
|
|
DLJAE macro l
|
|
DLJ jae JNAE l
|
|
endm
|
|
|
|
DLJBE macro l
|
|
DLJ jbe JNBE l
|
|
endm
|
|
|
|
DLJG macro l
|
|
DLJ jg JNG l
|
|
endm
|
|
|
|
DLJL macro l
|
|
DLJ jl JNL l
|
|
endm
|
|
|
|
DLJLE macro l
|
|
DLJ jle JNLE l
|
|
endm
|
|
|
|
|
|
;* LJ - generate long conditional jump
|
|
;
|
|
; if target preceeds us and is in range just use a short jump
|
|
; else use a long jump
|
|
;
|
|
; LJ <direct jmp>,<skip jmp>,<label>
|
|
|
|
LJ MACRO dirop,idirop,l
|
|
local a
|
|
IF ((.TYPE l) XOR 20h) AND 0A0h
|
|
idirop a ;; not defined or is external
|
|
jmp l
|
|
a:
|
|
ELSE ;; is local definied
|
|
IF (($-l) LT 124) AND ($ GT l)
|
|
dirop l ;; is before and within range
|
|
ELSE
|
|
idirop a ;; is out of range or forward (pass 2)
|
|
jmp l
|
|
a:
|
|
ENDIF
|
|
ENDIF
|
|
ENDM
|
|
|
|
|
|
;* DLJ - generate debug long conditional jump
|
|
;
|
|
; If DEBUG is defined then we generate a long jump, else a short
|
|
; one.
|
|
;
|
|
; DLJ <direct jmp>,<skip jmp>,<label>
|
|
|
|
DLJ MACRO dirop,idirop,l
|
|
local a
|
|
IF DEBUG
|
|
idirop a
|
|
jmp l
|
|
a:
|
|
ELSE
|
|
dirop l
|
|
ENDIF
|
|
ENDM
|
|
|
|
.xcref LJE, LJNE, LJZ, LJNZ, LJC, LJNC, LJA, LJNA
|
|
.xcref LJB, LJNB, LJS, LJNS, LJAE, LJBE, LJG, LJL, LJLE
|
|
.xcref DLJE, DLJNE, DLJZ, DLJNZ, DLJC, DLJNC, DLJA, DLJNA
|
|
.xcref DLJB, DLJNB, DLJS, DLJNS, DLJAE, DLJBE, DLJG, DLJL, DLJLE
|
|
.xcref LJ,DLJ
|
|
|
|
|
|
|
|
;** SHORT offset macro
|
|
;
|
|
; expands to SHORT if non debug, to nul if debug.
|
|
;
|
|
; this allows us to code
|
|
;
|
|
; jmp SHRT foobar
|
|
;
|
|
; and get a long form if debugging is turned on (because the extra
|
|
; debug code puts the target out of range)
|
|
|
|
if DEBUG
|
|
SHRT EQU <>
|
|
else
|
|
SHRT EQU SHORT
|
|
endif
|
|
|
|
|
|
;** FALLTHRU - Verifies Fallthrough Validity
|
|
|
|
FALLTHRU MACRO labl
|
|
; BUGBUG - restore align when we make code segment word aligned
|
|
; align 2 ; don't have errnz fail due to alignment
|
|
IF2 ; of following label
|
|
.errnz labl-$
|
|
ENDIF
|
|
ENDM
|
|
|
|
|
|
;** INTTEST - Generate an INT 3 for testing
|
|
|
|
INTTEST MACRO
|
|
if DEBUG
|
|
int 3
|
|
endif
|
|
ENDM
|
|
|
|
|
|
;** DPUBLIC - Make a public symbol for debugging
|
|
|
|
DPUBLIC MACRO arg
|
|
if DEBUG
|
|
public arg
|
|
endif
|
|
ENDM
|
|
|
|
;* Debug Traps
|
|
;
|
|
; These are removed as the code is exercised
|
|
|
|
TRAP macro ; Like INTTEST but is normally left in during
|
|
int 3 ; debugging; indicates "should not occur"
|
|
ENDM
|
|
|
|
TRAPC macro
|
|
local l
|
|
jnc short l
|
|
int 3
|
|
l:
|
|
ENDM
|
|
|
|
TRAPNC macro
|
|
local l
|
|
jc short l
|
|
int 3
|
|
l:
|
|
ENDM
|
|
|
|
TRAPA macro
|
|
local l
|
|
jna short l
|
|
int 3
|
|
l:
|
|
ENDM
|
|
|
|
TRAPNA macro
|
|
local l
|
|
ja short l
|
|
int 3
|
|
l:
|
|
ENDM
|
|
|
|
TRAPZ macro
|
|
local l
|
|
jnz short l
|
|
int 3
|
|
l:
|
|
ENDM
|
|
|
|
TRAPNZ macro
|
|
local l
|
|
jz short l
|
|
int 3
|
|
l:
|
|
ENDM
|
|
|
|
|
|
|
|
BREAK <Structure Field Macros>
|
|
|
|
|
|
;** Follows - Verify that a field follows another
|
|
;
|
|
; FOLLOWS field1, field2 [, size]
|
|
;
|
|
; This macro generates an error if "field1" doesn't immeidately
|
|
; follow "field2". If "size" is specified then an error is generated
|
|
; if Field1 is not of the proper size.
|
|
|
|
FOLLOWS macro field1, field2, fldsiz
|
|
.errnz field1 - size field2 - field2
|
|
IFNB <fldsiz>
|
|
.errnz size field1 - fldsiz
|
|
ENDIF
|
|
ENDM
|
|
|
|
|
|
|
|
;** LAST - Verify that a field is the last field in a structure
|
|
;
|
|
; LAST fieldname, structname
|
|
;
|
|
; Generates an error if fieldname is not last in structname.
|
|
|
|
LAST macro fldnam, strunam
|
|
.errnz size strunam - fldnam - size fldnam
|
|
endm
|
|
|
|
|
|
|
|
;** TESTB - Use Byte form for Word TESTS, when possible
|
|
;
|
|
; TESTB is used in place of 16-bit TEST instructions. It substitutes
|
|
; a smaller 8-bit test when possible.
|
|
|
|
TESTB macro targ,mask,thirdarg
|
|
local mask2,delta
|
|
|
|
ifnb <thirdarg>
|
|
.err mask must be enclosed in brackets
|
|
endif
|
|
|
|
ifidn <targ>,<[bx]>
|
|
test targ,mask
|
|
exitm
|
|
endif
|
|
ifidn <targ>,<[si]>
|
|
test targ,mask
|
|
exitm
|
|
endif
|
|
ifidn <targ>,<[di]> ; don't process these operands specially
|
|
test targ,mask
|
|
exitm
|
|
endif
|
|
ifidn <targ>,<[BX]>
|
|
test targ,mask
|
|
exitm
|
|
endif
|
|
ifidn <targ>,<[SI]>
|
|
test targ,mask
|
|
exitm
|
|
endif
|
|
ifidn <targ>,<[DI]>
|
|
test targ,mask
|
|
exitm
|
|
endif
|
|
ifidn <targ>,<SI>
|
|
test targ,mask
|
|
exitm
|
|
endif
|
|
ifidn <targ>,<DI>
|
|
test targ,mask
|
|
exitm
|
|
endif
|
|
ifidn <targ>,<BP>
|
|
test targ,mask
|
|
exitm
|
|
endif
|
|
delta = 0
|
|
mask2 = mask
|
|
|
|
if mask2 AND 0ff00h
|
|
; have a mask bit in the high half
|
|
if mask2 AND 0ffh
|
|
test targ,mask
|
|
exitm
|
|
endif
|
|
mask2 = mask2 SHR 8
|
|
delta = 1
|
|
endif
|
|
|
|
ifidn <targ>,<AX>
|
|
if delta
|
|
test targ,mask
|
|
else
|
|
test AL,mask2
|
|
endif
|
|
exitm
|
|
endif
|
|
ifidn <targ>,<BX>
|
|
if delta
|
|
test BH,mask2
|
|
else
|
|
test BL,mask2
|
|
endif
|
|
exitm
|
|
endif
|
|
ifidn <targ>,<CX>
|
|
if delta
|
|
test CH,mask2
|
|
else
|
|
test CL,mask2
|
|
endif
|
|
exitm
|
|
endif
|
|
ifidn <targ>,<DX>
|
|
if delta
|
|
test DH,mask2
|
|
else
|
|
test DL,mask2
|
|
endif
|
|
exitm
|
|
endif
|
|
ifidn <targ>,<ax>
|
|
if delta
|
|
test targ,mask
|
|
else
|
|
test AL,mask2
|
|
endif
|
|
exitm
|
|
endif
|
|
ifidn <targ>,<bx>
|
|
if delta
|
|
test BH,mask2
|
|
else
|
|
test BL,mask2
|
|
endif
|
|
exitm
|
|
endif
|
|
ifidn <targ>,<cx>
|
|
if delta
|
|
test CH,mask2
|
|
else
|
|
test CL,mask2
|
|
endif
|
|
exitm
|
|
endif
|
|
ifidn <targ>,<dx>
|
|
if delta
|
|
test DH,mask2
|
|
else
|
|
test DL,mask2
|
|
endif
|
|
exitm
|
|
endif
|
|
|
|
test byte ptr targ+delta,mask2
|
|
endm
|
|
|
|
|
|
;
|
|
; Some old versions of the 80286 have a bug in the chip. The popf
|
|
; instruction will enable interrupts. Therefore in a section of code with
|
|
; interrupts disabled and you need a popf instruction use the 'popff'
|
|
; macro instead.
|
|
;
|
|
|
|
POPFF macro
|
|
jmp $+3
|
|
iret
|
|
push cs
|
|
call $-2
|
|
endm
|
|
|
|
Break <Cmp32 - 32-bit compare>
|
|
;----------------------------------------------------------------------------
|
|
;
|
|
; Macro Name : Cmp32
|
|
;
|
|
; Inputs:
|
|
; msw1 -- 1st operand, most significant word; MUST BE REGISTER.
|
|
; lsw1 -- 1st operand, least significant word; MUST BE REGISTER.
|
|
; msw2 -- 2nd operand, most significant word.
|
|
; lsw2 -- 2nd operand, least significant word.
|
|
; Function:
|
|
; Compare 2 32-bit operands. Implemented as a macro.
|
|
; Outputs:
|
|
; CF = 1 if 1st operand < 2nd operand
|
|
; = 0 if 1st operand >= 2nd operand
|
|
; ZF = 1 if 1st operand == 2nd operand
|
|
; = 0 if 1st operand <> 2nd operand
|
|
;-----------------------------------------------------------------------------
|
|
;M019: Created.
|
|
|
|
Cmp32 MACRO msw1,lsw1,msw2,lsw2
|
|
LOCAL cmp32x
|
|
|
|
cmp msw1,msw2
|
|
jne cmp32x
|
|
cmp lsw1,lsw2
|
|
cmp32x:
|
|
ENDM
|
|
|
|
Break <HRDSVC - SVC call where hard error is possible>
|
|
;----------------------------------------------------------------------------
|
|
;
|
|
; Macro Name : HRDSVC
|
|
;
|
|
; Inputs:
|
|
; iSVC -- SVC index
|
|
; Function:
|
|
; Make a DEM SVC. If hard error happens handle it.
|
|
; Outputs:
|
|
; CF = 1 if operation failed
|
|
; = 0 if operation successful
|
|
;-----------------------------------------------------------------------------
|
|
|
|
HRDSVC MACRO iSVC
|
|
LOCAL hs_nerr,hs_fail,hs_retry
|
|
|
|
SVC iSVC
|
|
jnc hs_nerr
|
|
|
|
; Check if hard err to be handled . If no harderr then it
|
|
; will come back without effecting any reg or carry flags.
|
|
; Else it will do an int24. If user chooses retry it
|
|
; will retry the SVC call. On fail or abort it will
|
|
; come back with usual dos style setup.
|
|
; If user chose "Abort" it wont come back
|
|
|
|
invoke TestHrdErr
|
|
hs_nerr:
|
|
ENDM
|
|
|