home *** CD-ROM | disk | FTP | other *** search
- ;****************************************************************************
- ;*
- ;* Copyright (C) 1994 SciTech Software.
- ;* All rights reserved.
- ;*
- ;* Filename: $RCSfile: model.mac $
- ;* Version: $Revision: 1.5 $
- ;*
- ;* Language: Turbo Assembler 3.0
- ;* Environment: IBM PC (MS DOS)
- ;*
- ;* Description: Macros to provide memory model independant assembly language
- ;* module for C programming. Supports the large memory model
- ;* and 386 extended DOS memory models.
- ;*
- ;* The defines that you should use when assembling modules that
- ;* use this macro package are:
- ;*
- ;* __LARGE__ Assemble for real mode large memory model
- ;* __X386__ Assemble for 386 extended memory model
- ;* __FLAT__ Assemble for 386 FLAT memory model
- ;* __8086__ Assemble for 8086 real mode code
- ;* __80286__ Assemble for 80286 real mode code
- ;* __COMM__ Declare global variables as COMMunal
- ;*
- ;* By default the real mode large memory model targeted for the
- ;* 80386 processor is selected.
- ;*
- ;* Note that we use the TASM simplified segment directives so
- ;* that 32 bit code will assemble correctly, and we also use
- ;* TASM's IDEAL mode syntax, so this is not compatible with
- ;* MASM. The __FLAT__ mode should be used whenever possible to
- ;* assemble code that needs to be converted to Unix style .o
- ;* files for DJGPP and EMX, and for most new compilers. Symantec
- ;* C++ however requires the __X386__ memory model, or it will not
- ;* link correctly). You should specify either of __X386__ or
- ;* __FLAT__ to assemble code correctly.
- ;*
- ;* The main intent of the macro file is to enable programmers
- ;* to write _one_ set of source that can be assembled to run
- ;* in either 16 bit real and protected modes or 32 bit
- ;* protected mode without the need to riddle the code with
- ;* 'if flatmodel' style conditional assembly (it is still there
- ;* but nicely hidden by a macro layer that enhances the
- ;* readability and understandability of the resulting code).
- ;*
- ;* NOTES: When you declare the data and code segments, you should specify
- ;* a name to be used. This name should be the name of the file
- ;* being assembled, but you may use the same name for mutiple
- ;* modules if you wish so that the data and code for these modules
- ;* are all contained in the same segments. Of course the maximum
- ;* size of data and code must be less than 64k respectively.
- ;*
- ;* $Id: model.mac 1.5 1994/08/22 07:58:32 kjb release $
- ;*
- ;****************************************************************************
-
- IDEAL
-
- ; Define symbols codesize and datasize depending on the requested memory
- ; model. Note that because of the differences in addressing used in the
- ; 16 and 32 bit memory models, we need a couple of macros to define things
- ; such as what register is used for looping (CX or ECX) etc. Note that we
- ; can use simple 16 bit code in 32 bit mode and vice-versa, but unless this
- ; is absolutely necessary it poses the performance hit of requiring an
- ; operand size prefex for the instruction. Hence if we simply need to use
- ; a set of registers for an operation, use the macros to use the best
- ; register for the current mode of operation. Of course the real registers
- ; may be specified for operations that specifically require 16 or 32 bits.
- ;
- ; The following things are defined:
- ;
- ; UCHAR - Typedef for a character type
- ; USHORT - Typedef for a short type
- ; UINT - Typedef for an integer type
- ; BOOL - Typedef for a boolean type
- ; DPTR - Operand size of data pointers
- ; DDIST - Distance to data variables (NEAR or FAR)
- ; CPTR - Operand size of code pointers
- ; FCPTR - Operand size of far code pointers
- ; NCPTR - Operand size of near code pointers
- ; FPTR - Function pointer modifier, either NEAR or FAR
- ; _AX - General accumulator register, either AX or EAX
- ; _BX - General base register, either BX or EBX
- ; _CX - Loop counter register, either CX or ECX
- ; CXPTR - Operand size of loop counter, either WORD or DWORD
- ; _DX - General data register, either DX or EDX
- ; _SI - Source index register, either SI or ESI
- ; _DI - Destination index register, either DI or EDI
- ; _BP - Base pointer register, either BP or EBP
- ; _SP - Stack pointer register, either SP or ESP
- ; _ES - ES segment override - evaluates to nothing in 32 bit PM
-
- ifdef __FLAT__
- __X386__ = 1
- endif
-
- ifdef __X386__
- flatmodel EQU 1 ; This is a flat memory model
- datasize EQU 0 ; Near data memory model
- dptrsize EQU 4 ; Size of a data pointer (32 bit near)
- stackalign EQU 4 ; Align stack to 4 byte boundary
- typedef UCHAR BYTE ; Size of a character
- typedef USHORT WORD ; Size of a short
- typedef UINT DWORD ; Size of an integer
- typedef ULONG DWORD ; Size of a long
- typedef BOOL WORD ; Size of a boolean
- typedef DPTR DWORD ; Size of a data pointer
- typedef FDPTR FWORD ; Size of a far data pointer
- typedef NDPTR DWORD ; Size of a near data pointer
- DDIST EQU NEAR
- codesize EQU 0 ; Near code memory model
- cptrsize EQU 4
- typedef CPTR DWORD ; Size of a code pointer
- typedef FCPTR FWORD ; Size of a far code pointer
- typedef NCPTR DWORD ; Size of a near code pointer
- FPTR EQU NEAR
- _AX EQU EAX ; EAX is used for accumulator
- _BX EQU EBX ; EBX is used for accumulator
- _CX EQU ECX ; ECX is used for looping
- CXPTR EQU DWORD ; loop variables are 32 bits
- _DX EQU EDX ; EDX is used for data register
- _SI EQU ESI ; ESI is the source index register
- _DI EQU EDI ; EDI is the destination index register
- _BP EQU EBP ; EBP is used for base pointer register
- _SP EQU ESP ; ESP is used for stack pointer register
- _ES EQU ; ES and DS are the same in 32 bit PM
- P386 ; Turn on 386 code generation
- ifdef __FLAT__
- MODEL FLAT ; Set up for 32 bit simplified FLAT model
- else
- LARGESTACK ; Set up for a 32 bit stack model
- endif
- else
- flatmodel EQU 0 ; This is a segmented memory model
- datasize EQU 1 ; Far data memory model
- dptrsize EQU 4 ; Size of a data pointer
- stackalign EQU 2 ; Align stack to 2 byte boundary
- typedef UCHAR BYTE ; Size of a character
- typedef USHORT WORD ; Size of a short
- typedef UINT WORD ; Size of an integer
- typedef ULONG DWORD ; Size of a long
- typedef BOOL WORD ; Size of a boolean
- typedef DPTR DWORD ; Size of a data pointer
- typedef FDPTR DWORD ; Size of a far data pointer
- typedef NDPTR WORD ; Size of a near data pointer
- DDIST EQU FAR
- codesize EQU 1 ; Far code memory model
- cptrsize EQU 4 ; Size of a code pointer
- typedef CPTR DWORD ; Size of a code pointer
- typedef FCPTR DWORD ; Size of a far code pointer
- typedef NCPTR WORD ; Size of a near code pointer
- FPTR EQU FAR
- _AX EQU AX ; AX is used for accumulator
- _BX EQU BX ; BX is used for accumulator
- _CX EQU CX ; CX is used for looping
- CXPTR EQU WORD ; loop variables are 16 bits
- _DX EQU DX ; DX is used for data register
- _SI EQU SI ; SI is the source index register
- _DI EQU DI ; DI is the destination index register
- _BP EQU BP ; BP is used for base pointer register
- _SP EQU SP ; SP is used for stack pointer register
- _ES EQU es: ; ES is used for segment override
- ifndef __8086__
- ifdef __80286__
- P286 ; Turn on 286 code generation
- else
- P386 ; Turn on 386 code generation
- endif
- endif
- endif
-
- ; Macros for declaring external global variables
-
- ifdef __COMM__
- MACRO $EXTRN name,type
- COMM DDIST name:type
- ENDM
- else
- MACRO $EXTRN name,type
- EXTRN name:type
- ENDM
- endif
-
- ; Macros for entering and exiting C callable functions. Note that we must
- ; always save and restore the SI and DI registers for C functions, and for
- ; 32 bit C functions we also need to save and restore EBX and clear the
- ; direction flag.
-
- MACRO enter_c LocalSize
- ifdef __8086__
- push bp
- mov bp,sp
- sub sp,LocalSize
- else
- enter LocalSize,0
- ifdef __X386__
- push ebx
- endif
- endif
- push _si
- push _di
- ENDM
-
- MACRO leave_c
- pop _di
- pop _si
- ifdef __X386__
- pop ebx
- endif
- cld
- ifdef __8086__
- mov sp,bp
- pop bp
- else
- leave
- endif
- ENDM
-
- MACRO use_ebx
- if flatmodel
- push ebx
- endif
- ENDM
-
- MACRO unuse_ebx
- if flatmodel
- pop ebx
- endif
- ENDM
-
- ; Macros for saving and restoring the value of DS,ES,FS,GS when it is to
- ; be used in assembly routines. This evaluates to nothing in the flat memory
- ; model, but is saves and restores DS in the normal memory model.
-
- MACRO use_ds
- ife flatmodel
- push ds
- endif
- ENDM
-
- MACRO unuse_ds
- ife flatmodel
- pop ds
- endif
- ENDM
-
- MACRO use_es
- ife flatmodel
- push es
- endif
- ENDM
-
- MACRO unuse_es
- ife flatmodel
- pop es
- endif
- ENDM
-
- ; Macros for loading the address of a data pointer into a segment and
- ; index register pair. The macro explicitly loads DS or ES in the 16 bit
- ; memory model, or it simply loads the offset into the register in the flat
- ; memory model since DS and ES always point to all addressable memory. You
- ; must use the correct _REG (ie: _BX) macros for documentation purposes.
-
- MACRO _lds reg, addr
- if flatmodel
- mov reg,addr
- else
- lds reg,addr
- endif
- ENDM
-
- MACRO _les reg, addr
- if flatmodel
- mov reg,addr
- else
- les reg,addr
- endif
- ENDM
-
- ; Macros for setting the value of the DS,ES,FS,GS registers to the same
- ; value. This is does nothing in 32 bit protected mode.
-
- MACRO es_eq_ds
- ife flatmodel
- push ds
- pop es
- endif
- ENDM
-
- MACRO ds_eq_es
- ife flatmodel
- push es
- pop ds
- endif
- ENDM
-
- MACRO fs_eq_ds
- ife flatmodel
- push ds
- pop fs
- endif
- ENDM
-
- ; Macro for loading a value into a register given a pointer and an
- ; offset from the pointer. Will work in either 16 and 32 bit mode.
- ;
- ; NOTE: The value of BX or EBX will be trashed over this macro!!
-
- MACRO get_val reg, pointer, offset
- if flatmodel
- mov ebx,[pointer]
- mov reg,[ebx + offset]
- else
- les bx,[pointer]
- mov reg,[es:bx + offset]
- endif
- ENDM
-
- ; Macros for adding and subtracting a value from registers. Two value are
- ; provided, one for 16 bit modes and another for 32 bit modes (the extended
- ; register is used in 32 bit modes).
-
- MACRO _add reg, val16, val32
- if flatmodel
- add e®&, val32
- else
- add reg, val16
- endif
- ENDM
-
- MACRO _sub reg, val16, val32
- if flatmodel
- sub e®&, val32
- else
- sub reg, val16
- endif
- ENDM
-
- ; Macro to clear the high order word for the 32 bit extended registers.
- ; This is used to convert an unsigned 16 bit value to an unsigned 32 bit
- ; value, and will evaluate to nothing in 16 bit modes.
-
- MACRO clrhi reg
- if flatmodel
- and reg, 0FFFFh ; Mask out top 16 bit
- endif
- ENDM
-
- ; Macro to load an extended register with an integer value in either mode
-
- MACRO loadint reg,val
- if flatmodel
- mov e®&,val
- else
- xor e®&,e®&
- mov reg,val
- endif
- ENDM
-
- ; Macros for procedure definitions given a name. Note that they also export
- ; the symbol with the PUBLIC directive, so that it need not be explicitly
- ; exported.
-
- MACRO procstart name ; Set up model independant proc
- if codesize ; and export name
- PROC name FAR
- else
- PROC name NEAR
- endif
- PUBLIC name
- ENDM
-
- MACRO procstatic name ; Set up model independant private proc
- if codesize
- PROC name FAR
- else
- PROC name NEAR
- endif
- ENDM
-
- MACRO procnear name ; Set up near proc
- PROC name NEAR ; and export name
- PUBLIC name
- ENDM
-
- MACRO procfar name ; Set up far proc
- PROC name FAR ; and export name
- PUBLIC name
- ENDM
-
- MACRO procend name ; End procedure macro
- ENDP name
- ENDM
-
- ; Macros for the _DATA data segment. This segment contains initialised data.
-
- MACRO begdataseg name
- ifdef __FLAT__
- DATASEG
- else
- if flatmodel
- SEGMENT _DATA DWORD PUBLIC USE32 'DATA'
- else
- SEGMENT _DATA WORD PUBLIC 'DATA'
- endif
- endif
- ENDM
-
- MACRO enddataseg name
- ifndef __FLAT__
- ENDS _DATA
- endif
- ENDM
-
- ; Macros for the _BSS data segment. This segment contains initialised data.
-
- MACRO begbssseg name
- ifdef __FLAT__
- DATASEG
- else
- if flatmodel
- SEGMENT _BSS DWORD PUBLIC USE32 'BSS'
- else
- SEGMENT _BSS WORD PUBLIC 'BSS'
- endif
- endif
- ENDM
-
- MACRO endbssseg name
- ifndef __FLAT__
- ENDS _BSS
- endif
- ENDM
-
- ; Macro to be invoked at the start of all modules to set up segments for
- ; later use.
-
- MACRO header name
- begdataseg name
- enddataseg name
- begbssseg name
- endbssseg name
- ENDM
-
- ; Macro for the main code segment.
-
- MACRO begcodeseg name
- ifdef __FLAT__
- CODESEG
- ASSUME CS:FLAT,DS:FLAT
- else
- if flatmodel
- SEGMENT _TEXT DWORD PUBLIC USE32 'CODE'
- GROUP DGROUP _DATA,_BSS
- ASSUME CS:_TEXT,DS:DGROUP
- else
- SEGMENT &name&_TEXT BYTE PUBLIC 'CODE'
- GROUP DGROUP _DATA,_BSS
- ASSUME CS:&name&_TEXT,DS:DGROUP
- endif
- endif
- ENDM
-
- MACRO endcodeseg name
- ifndef __FLAT__
- if flatmodel
- ENDS _TEXT
- else
- ENDS &name&_TEXT
- endif
- endif
- ENDM
-
- ; Boolean truth values (same as those in debug.h)
-
- False = 0
- True = 1
- No = 0
- Yes = 1
-
-