windows-nt/Source/XPSP1/NT/base/mvdm/dos/v86/inc/dosmac.inc
2020-09-26 16:20:57 +08:00

1198 lines
19 KiB
PHP
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; 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&section
ENDM
LeaveCrit MACRO section
; Invoke L&section
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