;*** ;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 stop assembly with message ; display display a message, unless QUIET defined ; savelist [ ...] init list of regs to be save by 'proc uses' ; _if cond assemble instruction only if cond is TRUE ; _ife cond assemble instruction only if cond is FALSE ; _ifd symbol assemble instruction only if symbol defined ; _ifnd symbol 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 - 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 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 I286 equ <> endif endif endif ; Process memory-model arguments ifdef mem_M ; Medium model sizeC equ 1 sizeD equ 0 mmodel equ elseifdef mem_C ; Compact model sizeC equ 0 sizeD equ 1 mmodel equ elseifdef mem_L ; Large model sizeC equ 1 sizeD equ 1 mmodel equ else ; Small model - default sizeC equ 0 sizeD equ 0 mmodel equ endif ; Process processor arguments ifdef _WIN32 display cpu equ 586 .586 elseifdef I286 display cpu equ 286 .286 elseifdef I386 display cpu equ 386 .386 else display 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 endif ifdef _LOAD_DGROUP error endif ifdef SS_NEQ_DGROUP error endif endif ; Set memory model % display % .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 rbx equ rcx equ rdx equ rdi equ rsi equ rbp equ rsp equ JRCXZ equ CBI equ ; convert byte to int (al to rax) CAXDX equ ; convert rax to rdx:rax ZXAL equ ; zero extend al ZXBL equ ; zero extend bl ZXCL equ ; zero extend cl ZXDL equ ; zero extend dl else rax equ rbx equ rcx equ rdx equ rdi equ rsi equ rbp equ rsp equ JRCXZ equ CBI equ ; convert byte to int (al to rax) CAXDX equ ; convert rax to rdx:rax ZXAL equ ; zero extend al ZXBL equ ; zero extend bl ZXCL equ ; zero extend cl ZXDL equ ; 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 LPDS equ PDS equ PES equ else LPES equ LPDS equ PDS equ <> PES equ <> endif ifdef I386 LFPES equ LFPDS equ FPES equ <> FPDS equ <> else LFPES equ LFPDS equ FPES equ FPDS equ endif if sizeC or @WordSize eq 2 PCS equ ; large code model or non-386 else IF 1 ;*** TEMP 16/32 TESTBED *** PCS equ ELSE PCS equ <> ; 386 small code model ENDIF ;*** END TEMP CODE endif ifdef SS_NEQ_DGROUP PSS equ ; SS != DS else PSS equ <> ; SS == DS endif ; Define offset macros: ; The 32-bit segments will not have 'groups' ifdef I386 codeoffset equ dataoffset equ else codeoffset equ dataoffset equ 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 LWORD equ ; static storage DINT equ
DLONG equ
DSHORT equ ; 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
; near pointer DFPTR equ
; far pointer DCPTR equ
; 32 bit offset only DCPTR? equ
; No seg override for uninitialized values CPSIZE equ 4 CPDIST equ ; code pointers are near CPTR equ DDPTR equ
DDPTR? equ
DPSIZE equ 4 CPWORD equ ; code pointers are dwords DPWORD equ ; data pointers are dwords APIDIST equ ; 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 LWORD equ ; static storage DINT equ DLONG equ
DSHORT equ ; 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 ; near pointer DFPTR equ
; far pointer if sizeC DCPTR equ
; 16 bit segment and 16 bit offset DCPTR? equ
CPSIZE equ 4 CPDIST equ ; code pointers are far CPTR equ CPWORD equ ; code pointers are dwords else DCPTR equ ; 16 bit offset only DCPTR? equ CPSIZE equ 2 CPDIST equ ; code pointers are near CPTR equ CPWORD equ ; code pointers are words endif if sizeD DDPTR equ
DDPTR? equ
DPSIZE equ 4 DPWORD equ ; data pointers are dwords else DDPTR equ DDPTR? equ DPSIZE equ 2 DPWORD equ ; data pointers are words endif APIDIST equ ; 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
DDOUBLE equ DLDOUBLE equ
; ; 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 reglist catstr reg1, ws, reg2, ws, reg3, ws, reg4 ELSEIFNB reglist catstr reg1, ws, reg2, ws, reg3, ws ELSEIFNB reglist catstr reg1, ws, reg2, ws, ws ELSEIFNB 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 ; 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, JS&x equ 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 _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, ; globalI % MakeGlobal DP, ; globalDP % MakeGlobal CP, ; globalCP % MakeGlobal FP, ; globalFP % MakeGlobal NP, ; 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 _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, ; staticI % MakeStatic DP, ; staticDP % MakeStatic CP, ; staticCP % MakeStatic FP, ; staticFP % MakeStatic NP, ; staticNP ;*======== ;* ;* Label definition macros ;* ;*======== ;* ;* Label definition macros ;* ;* Usage: ;* labelI Name, {PUBLIC, PASCAL, C} ;* ;*======== __MakePublic macro name, option ;; decides if a label should be ifidni