|
|
;*** ;cruntime.inc - multi-model assembly macros for interfacing to HLLs ; ; Copyright (c) 1988-1995, Microsoft Corporation. All rights reserved. ; ;Purpose: ; This file defines the current memory model being used. ; ;*******************************************************************************
;============================================================================== ; ;Use the following defines to control processor/segment model ; ; -DI86 8086/8088 processor ; -DI286 80286 processor ; -DI386 80386 processor with 32-bit code/data segment ; ; -Dmem_S Small memory model (near code, near data) ; -Dmem_M Medium memory model (far code, near data) ; -Dmem_C Compact memory model (near code, fat data) ; -Dmem_L Large memory model (far code, far data) ; ; -DSS_NEQ_DGROUP SS and DS point to different segments ; ; default is -DI86 -Dmem_S ; ;============================================================================== ; ;The following variables are defined by this file: ; cpu 86, 286, or 386 ; sizeC code distance; 1 = far code, 0 = near code ; sizeD data distance; 1 = far data, 0 = near data ; mmodel english name of the memory model, i.e. "Medium" ; ISIZE, LSIZE, NSIZE size of ints, longs, shorts ; FLTSIZE, DBLSIZE, LDBLSIZE size of float, double, long double ; NPSIZE, FPSIZE size of near/far pointers ; CPSIZE, DPSIZE size of code/data pointers ; ISHIFT, LSHIFT bits to shift to convert byte to int/long ; ;The following macros allow easy writing of combined 16/32 bit code: ; ; 16/32 bit registers: ; rax, rbx, rcx, rdx, expand to native registers (rax = eax or ax) ; rsi, rdi, rsp, rbp ; 16/32 bit register instructions: ; JRCXZ jump when rcx is zero ; CBI convert byte to int (al to rax) ; CAXDX convert rax to rax:rdx ; ZXAL, ZXBL, ZXCL, ZXDL zero extend al,bl,cl,dl to rax,rbx,rcx,rdx ; Pointer instructions: ; LPDS, LPES load data pointer with ES or DS ; PDS, PES segment overrides when pointer loaded as above ; PCS, PSS segment override to get at code/stack segment ; LFPDS, LFPES load far pointer with ES or DS ; FPDS, FPES segment overrides when pointer loaded as above ; CPTR data type of code pointer ; CPDIST distance of code (near/far) ; DNPTR, DFPTR define near/far pointer ; DCPTR, DDPTR define code/data pointer ; DCPTR?, DDPTR? define uninitialized code/data pointer ; CPWORD, DPWORD data type of code or data pointer ; Numeric type instructions: ; IWORD, LWORD, SWORD data type of int, long, short ; DINT, DLONG, DSHORT define int, long, short ; DFLOAT, DDOUBLE, DLDOUBLE define float, double, long double ; Offsets: ; codeoffset, dataoffset offsets from code and data segments ; API calls: ; APIDIST distance of API calls (near/far) ; APIEXT ApiName extrn declaration for an API function ; ;The following utility macros are provided: ; codeseg define/declare code segment ; error <msg> stop assembly with message ; display <msg> display a message, unless QUIET defined ; savelist [<reg> ...] init list of regs to be save by 'proc uses' ; _if cond <instruction> assemble instruction only if cond is TRUE ; _ife cond <instruction> assemble instruction only if cond is FALSE ; _ifd symbol <instruction> assemble instruction only if symbol defined ; _ifnd symbol <instruction> assemble instruction only if symbol not defined ; ; lab LabelName assembles to "LabelName:" If DEBUG is defined ; LabelName is made public ; ; JS* (ex. JSE,JSZ,JSB ...) assemble to "je short","jz short","jb short" ; ; Cmacro look alikes ; static* Name, InitialValue, Repeat defines a static variable of type * ; global* Name, InitialValue, Repeat defines a global variable of type * ; label* Name, {PUBLIC,PASCAL,C} defines a label of type * ; ; PUSH16 SegmentReg pushes 16 bits in a use32 segment ; JMPFAR16 label will do a far 16:16 jmp from a use32 segment ; ;==============================================================================
; error <msg> - Output message and generate error
error MACRO msg if2 ;; only on pass 2 can we generate errors %out ********************************************************** %out *** E r r o r -- msg %out ********************************************************** .err endif ENDM
; display msg - Output message unless QUIET defined
display MACRO msg ifndef QUIET ;; only when quiet flag not set if1 ;; and on pass 1, then display message %out msg endif endif ENDM
; One line conditionals: ; here we create the capability of writing code lines like ; ; _if sizeD <push ds> as opposed to if sizeD ; push ds ; endif
_if MACRO cond,text if cond text endif ENDM
_ife MACRO cond,text ife cond text endif ENDM
_ifd MACRO cond,text ifdef cond text endif ENDM
_ifnd MACRO cond,text ifndef cond text endif ENDM
; set windows flag to 0
?WIN equ 0 ; disable windows-specific code
; check for _MT, requires 286 or greater processor
ifdef _MT ifndef I386 ifndef I286 ; _MT implies 286 processor display <Multi-thread specified - assuming 80286 processor> I286 equ <> endif endif endif
; Process memory-model arguments
ifdef mem_M ; Medium model sizeC equ 1 sizeD equ 0 mmodel equ <Medium> elseifdef mem_C ; Compact model sizeC equ 0 sizeD equ 1 mmodel equ <Compact> elseifdef mem_L ; Large model sizeC equ 1 sizeD equ 1 mmodel equ <Large> else ; Small model - default sizeC equ 0 sizeD equ 0 mmodel equ <Small> endif
; Process processor arguments
ifdef _WIN32 display <Processor: 486/586> cpu equ 586 .586 elseifdef I286 display <Processor: 80286> cpu equ 286 .286 elseifdef I386 display <Processor: 80386> cpu equ 386 .386 else display <Processor: 8086/8088> cpu equ 86 .8086 endif
; 386 32-bit checking. Currently we are only expecting small model ; 32 bit segments, so we make a few checks to be sure nothing is ; incorrectly being defined.
ifdef I386 if sizeC or sizeD error <Must use Small memory model for 386 version.> endif
ifdef _LOAD_DGROUP error <No loading DGROUP in 386 version.> endif
ifdef SS_NEQ_DGROUP error <SS always equals DGROUP in 386 version.> endif endif
; Set memory model
% display <Memory model: mmodel> % .model mmodel, C
; ; *** Temporary Workaround *** ; Currently, MASM will not recognize the 'FLAT' keyword unless it previously ; appears in an 'assume' statement. Presumably, when the '.model FLAT' feature ; is implemented, this will go away. [Use 'gs:' since we never use that ; segment register. ;
ifdef I386 ; ensure that MASM recognizes 'FLAT' assume gs:FLAT endif
; Define registers: ; Instead of using the "word" registers directly, we will use a set of ; text equates. This will allow you to use the native word size instead of ; hard coded to 16 bit words. We also have some instruction equates for ; instruction with the register type hard coded in.
ifdef I386
rax equ <eax> rbx equ <ebx> rcx equ <ecx> rdx equ <edx> rdi equ <edi> rsi equ <esi> rbp equ <ebp> rsp equ <esp>
JRCXZ equ <jecxz> CBI equ <movsx eax, al> ; convert byte to int (al to rax) CAXDX equ <cdq> ; convert rax to rdx:rax ZXAL equ <movzx eax, al> ; zero extend al ZXBL equ <movzx ebx, bl> ; zero extend bl ZXCL equ <movzx ecx, cl> ; zero extend cl ZXDL equ <movzx edx, dl> ; zero extend dl
else
rax equ <ax> rbx equ <bx> rcx equ <cx> rdx equ <dx> rdi equ <di> rsi equ <si> rbp equ <bp> rsp equ <sp>
JRCXZ equ <jcxz> CBI equ <cbw> ; convert byte to int (al to rax) CAXDX equ <cwd> ; convert rax to rdx:rax ZXAL equ <xor ah, ah> ; zero extend al ZXBL equ <xor bh, bh> ; zero extend bl ZXCL equ <xor ch, ch> ; zero extend cl ZXDL equ <xor dh, dh> ; zero extend dl
endif
; The following equates deal with the differences in near versus ; far data pointers, and segment overrides. ; ; Use LPES and PES when loading a default size pointer -- it loads ; a 16-bit pointer register in 286 Small/Medium model, ; a 16-bit pointer register and 16-bit segment register in 8086/286 ; Compact/Large model, and a 32-bit pointer register in 386 mode. ; ; Use LFPES and FPES when loading an always far pointer -- it loads a ; 16-bit pointer register and 16-bit segment register in 8086/286, ; all models; a 32-bit pointer register in 386 mode.
if sizeD LPES equ <les> LPDS equ <lds> PDS equ <ds:> PES equ <es:> else LPES equ <mov> LPDS equ <mov> PDS equ <> PES equ <> endif
ifdef I386 LFPES equ <mov> LFPDS equ <mov> FPES equ <> FPDS equ <> else LFPES equ <les> LFPDS equ <lds> FPES equ <es:> FPDS equ <ds:> endif
if sizeC or @WordSize eq 2 PCS equ <cs:> ; large code model or non-386 else IF 1 ;*** TEMP 16/32 TESTBED *** PCS equ <cs:> ELSE PCS equ <> ; 386 small code model ENDIF ;*** END TEMP CODE endif
ifdef SS_NEQ_DGROUP PSS equ <ss:> ; SS != DS else PSS equ <> ; SS == DS endif
; Define offset macros: ; The 32-bit segments will not have 'groups'
ifdef I386 codeoffset equ <offset FLAT:> dataoffset equ <offset FLAT:> else codeoffset equ <offset @code:> dataoffset equ <offset DGROUP:> endif
; The next set of equates deals with the size of SHORTS, INTS, LONGS, and ; pointers in the 16 and 32 bit versions.
ifdef I386 ;--- 32 bit segment ---
; parameters and locals IWORD equ <dword> LWORD equ <dword>
; static storage DINT equ <dd> DLONG equ <dd> DSHORT equ <dw>
; sizes for fixing SP, stepping through tables, etc. ISIZE equ 4 LSIZE equ 4 SSIZE equ 2 NPSIZE equ 4 FPSIZE equ 4
; bit shift count to convert byte cnt/ptr to int/long cnt/ptr ISHIFT equ 2 ; byte-to-int shift count LSHIFT equ 2 ; byte-to-long shift count
; sizes dependent upon memory model. dq -vs- df is not yet clear DNPTR equ <dd> ; near pointer DFPTR equ <dd> ; far pointer
DCPTR equ <dd offset FLAT:>; 32 bit offset only DCPTR? equ <dd> ; No seg override for uninitialized values CPSIZE equ 4 CPDIST equ <near> ; code pointers are near CPTR equ <near ptr>
DDPTR equ <dd offset FLAT:> DDPTR? equ <dd> DPSIZE equ 4
CPWORD equ <dword> ; code pointers are dwords DPWORD equ <dword> ; data pointers are dwords
APIDIST equ <near> ; all API calls are NEAR in the 32 bit model
; macro to declare API functions EXTAPI macro apiname extrn pascal apiname:near endm
else ;--- 16-bit segment ---
; parameters and locals IWORD equ <word> LWORD equ <dword>
; static storage DINT equ <dw> DLONG equ <dd> DSHORT equ <dw>
; sizes for fixing SP, stepping through tables, etc ISIZE equ 2 LSIZE equ 4 SSIZE equ 2 NPSIZE equ 2 FPSIZE equ 4
; bit shift count to convert byte cnt/ptr to int/long cnt/ptr ISHIFT equ 1 ; byte-to-int shift count LSHIFT equ 2 ; byte-to-long shift count
; sizes dependent upon memory model DNPTR equ <dw> ; near pointer DFPTR equ <dd> ; far pointer
if sizeC DCPTR equ <dd> ; 16 bit segment and 16 bit offset DCPTR? equ <dd> CPSIZE equ 4 CPDIST equ <far> ; code pointers are far CPTR equ <far ptr> CPWORD equ <dword> ; code pointers are dwords else DCPTR equ <dw> ; 16 bit offset only DCPTR? equ <dw> CPSIZE equ 2 CPDIST equ <near> ; code pointers are near CPTR equ <near ptr> CPWORD equ <word> ; code pointers are words endif
if sizeD DDPTR equ <dd> DDPTR? equ <dd> DPSIZE equ 4 DPWORD equ <dword> ; data pointers are dwords else DDPTR equ <dw> DDPTR? equ <dw> DPSIZE equ 2 DPWORD equ <word> ; data pointers are words endif
APIDIST equ <far> ; API calls are FAR in 16 bit model
; macro to declare API functions EXTAPI macro apiname extrn pascal apiname:far endm
endif ; --- 16/32 segment ---
; Float/double definitions ; (currently the same for 16- and 32-bit segments)
FLTSIZE equ 4 ; float DBLSIZE equ 8 ; double LDBLSIZE equ 10 ; long double
DFLOAT equ <dd> DDOUBLE equ <dq> DLDOUBLE equ <dt>
; ; savelist - Generate a list of regs to be saved by the proc 'uses' option. ; ; Input: ; reg1, reg2, reg3, reg4 = registers to be saved across function ; Output: ; reglist = text string of registers that can be passed to the 'uses' ; option on the 'proc' command. ;
savelist MACRO reg1, reg2, reg3, reg4 local ws, listsize ws catstr < > ; whitespace char
IFNDEF I386 rbx equ <> ; 8086/286 don't save rbx ENDIF
IFNB <reg4> reglist catstr reg1, ws, reg2, ws, reg3, ws, reg4 ELSEIFNB <reg3> reglist catstr reg1, ws, reg2, ws, reg3, ws ELSEIFNB <reg2> reglist catstr reg1, ws, reg2, ws, ws ELSEIFNB <reg1> reglist catstr reg1, ws, ws, ws ELSE reglist catstr <> ENDIF
listsize sizestr reglist ; size of register list
IF listsize LE 3 ; if list is only the 3 ws chars... reglist catstr <> ENDIF
IFNDEF I386 rbx equ <bx> ; restore rbx ENDIF
ENDM ; savelist
; ; codeseg - Define/declare the standard code segment. Maps to the proper ; form of the .code directive. ; ; Input: ; ; Output: ; .code _TEXT ; for large code models ; .code ; for small code models ; assume cs:FLAT ; for 386 ; assume ds:FLAT ; for 386 ; assume es:FLAT ; for 386 ; assume ss:FLAT ; for 386 ;
codeseg MACRO
if sizeC .code _TEXT else .code endif
ifdef I386 assume ds:FLAT assume es:FLAT assume ss:FLAT endif
ENDM
;*======== ;* ;* Debug lab macro ;* ;*========
lab macro name ifdef DEBUG public pascal name ;; define label public for Symdeb endif name: endm
;*======== ;* ;* Conditional jump short macros ;* ;*========
irp x,<Z,NZ,E,NE,S,NS,C,NC,P,NP,PE,PO,A,AE,B,BE,NB,G,GE,L,LE> JS&x equ <j&x short> endm
;*======== ;* ;* Global data definition macros ;* ;* Usage: ;* globalI Name, InitialValue, Repeat ;* ;*========
MakeGlobal macro suffix, DataType ;; makes all of the global* macros
global&suffix macro name, data, rep public name ifb <rep> _repeat = 1 else _repeat = (rep) endif
name &DataType _repeat dup( data ) endm
endm
MakeGlobal T, dt ; globalT MakeGlobal Q, dq ; globalQ MakeGlobal D, dd ; globalD MakeGlobal W, dw ; globalW MakeGlobal B, db ; globalB
% MakeGlobal I, <DINT> ; globalI
% MakeGlobal DP, <DDPTR> ; globalDP % MakeGlobal CP, <DCPTR> ; globalCP % MakeGlobal FP, <DFPTR> ; globalFP % MakeGlobal NP, <DNPTR> ; globalNP
;*======== ;* ;* Static data definition macros ;* ;* Usage: ;* staticI Name, InitialValue, Repeat ;* ;*========
MakeStatic macro suffix, DataType ;; makes all of the static* macros
static&suffix macro name, data, rep
ifdef DEBUG public pascal name ;; make statics public if DEBUG endif
ifb <rep> _repeat = 1 else _repeat = (rep) endif
name &DataType _repeat dup( data ) endm
endm
MakeStatic T, dt ; staticT MakeStatic Q, dq ; staticQ MakeStatic D, dd ; staticD MakeStatic W, dw ; staticW MakeStatic B, db ; staticB
% MakeStatic I, <DINT> ; staticI
% MakeStatic DP, <DDPTR> ; staticDP % MakeStatic CP, <DCPTR> ; staticCP % MakeStatic FP, <DFPTR> ; staticFP % MakeStatic NP, <DNPTR> ; staticNP
;*======== ;* ;* Label definition macros ;* ;*======== ;* ;* Label definition macros ;* ;* Usage: ;* labelI Name, {PUBLIC, PASCAL, C} ;* ;*========
__MakePublic macro name, option ;; decides if a label should be ifidni <option>, <PUBLIC> ;; made public public name elseifidni <option>, <PASCAL> public pascal name elseifidni <option>, <C> public C name elseifb <option> ifdef DEBUG public pascal name ;; make public if DEBUG endif endif endm
MakeLabel macro suffix, LabelType ;; makes all of the label* macros
%@CatStr(<label>,<suffix>) macro name, option __MakePublic <name>,<option> name label &LabelType endm
endm
MakeLabel T, tbyte ; make labelT MakeLabel Q, qword ; make labelQ MakeLabel D, dword ; make labelD MakeLabel W, word ; make labelW MakeLabel B, byte ; make labelB
MakeLabel P, proc ; make labelP MakeLabel FP, far ; make labelFP MakeLabel NP, near ; make labelNP
% MakeLabel I, IWORD ; make labelI
labelDP macro name, option ;; labelDP __MakePublic <name>,<option> ifdef I386 if sizeD name label fword else name label dword endif else ;not I386 if sizeD name label dword else name label word endif endif ;not I386 endm
labelCP macro name, option ;; labelCP __MakePublic <name>,<option> ifdef I386 if sizeC name label fword else name label dword endif else ;not I386 if sizeC name label dword else name label word endif endif ;not I386 endm
;* ;* PUSH16 SegReg - pushes 16 bits in a use32 segment ;*
PUSH16 macro SegReg
ifdef I386 nop db 66h ; operand size over-ride endif ; I386
push SegReg endm
;* ;* JMPFAR16 label - jmps far from a use32 to a use16 segment ;*
JMPFAR16 macro label
ifndef I386 error <JMPFAR16 can only be used in a use32 code segment> endif ;I386
nop db 66h ;; operand size over-ride db 0eah ;; jmp far immediate op code dw offset label dw seg label endm
|