Message-ID: <31FDFE92.53AE@pobox.oleane.com> Date: Tue, 30 Jul 1996 14:22:42 +0200 From: Francois Charton Organization: CCMSA MIME-Version: 1.0 To: Eli Zaretskii CC: djgpp AT delorie DOT com Subject: Re: Re : compiling povray 3.0 with djgpp References: Content-Type: multipart/mixed; boundary="------------71C5437550AB" This is a multi-part message in MIME format. --------------71C5437550AB Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Eli Zaretskii wrote: > Can you post the source of _pmlite.o? Here it is, it is a part of a copyrighted freeware program, pmode, developped by SciTech software, and included in povray 3.0 with their permission. You have two files here : _pmlite.asm, which is the actual source (due to be compiled with tasm), and model.mac, which contains macro definitions. After assembly, it compiles to _pmlite.o, which I also attached. Regards, Francois --------------71C5437550AB Content-Type: application/octet-stream Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="_PMLITE.O" BwEAAKMFAAACAAAAAAAAAJwAAAAAAAAAGAAAAAAAAABVi+xTVldmjMCLdQhmiQaMTgKMVgSM XgaMZgiMbgpfXlv8XcPNAMOQzQHDkM0Cw5DNA8OQzQTDkM0Fw5DNBsOQzQfDkM0Iw5DNCcOQ zQrDkM0Lw5DNDMOQzQ3DkM0Ow5DND8OQzRDDkM0Rw5DNEsOQzRPDkM0Uw5DNFcOQzRbDkM0X w5DNGMOQzRnDkM0aw5DNG8OQzRzDkM0dw5DNHsOQzR/DkM0gw5DNIcOQzSLDkM0jw5DNJMOQ zSXDkM0mw5DNJ8OQzSjDkM0pw5DNKsOQzSvDkM0sw5DNLcOQzS7DkM0vw5DNMMOQzTHDkM0y w5DNM8OQzTTDkM01w5DNNsOQzTfDkM04w5DNOcOQzTrDkM07w5DNPMOQzT3DkM0+w5DNP8OQ zUDDkM1Bw5DNQsOQzUPDkM1Ew5DNRcOQzUbDkM1Hw5DNSMOQzUnDkM1Kw5DNS8OQzUzDkM1N w5DNTsOQzU/DkM1Qw5DNUcOQzVLDkM1Tw5DNVMOQzVXDkM1Ww5DNV8OQzVjDkM1Zw5DNWsOQ zVvDkM1cw5DNXcOQzV7DkM1fw5DNYMOQzWHDkM1iw5DNY8OQzWTDkM1lw5DNZsOQzWfDkM1o w5DNacOQzWrDkM1rw5DNbMOQzW3DkM1uw5DNb8OQzXDDkM1xw5DNcsOQzXPDkM10w5DNdcOQ zXbDkM13w5DNeMOQzXnDkM16w5DNe8OQzXzDkM19w5DNfsOQzX/DkM2Aw5DNgcOQzYLDkM2D w5DNhMOQzYXDkM2Gw5DNh8OQzYjDkM2Jw5DNisOQzYvDkM2Mw5DNjcOQzY7DkM2Pw5DNkMOQ zZHDkM2Sw5DNk8OQzZTDkM2Vw5DNlsOQzZfDkM2Yw5DNmcOQzZrDkM2bw5DNnMOQzZ3DkM2e w5DNn8OQzaDDkM2hw5DNosOQzaPDkM2kw5DNpcOQzabDkM2nw5DNqMOQzanDkM2qw5DNq8OQ zazDkM2tw5DNrsOQza/DkM2ww5DNscOQzbLDkM2zw5DNtMOQzbXDkM22w5DNt8OQzbjDkM25 w5DNusOQzbvDkM28w5DNvcOQzb7DkM2/w5DNwMOQzcHDkM3Cw5DNw8OQzcTDkM3Fw5DNxsOQ zcfDkM3Iw5DNycOQzcrDkM3Lw5DNzMOQzc3DkM3Ow5DNz8OQzdDDkM3Rw5DN0sOQzdPDkM3U w5DN1cOQzdbDkM3Xw5DN2MOQzdnDkM3aw5DN28OQzdzDkM3dw5DN3sOQzd/DkM3gw5DN4cOQ zeLDkM3jw5DN5MOQzeXDkM3mw5DN58OQzejDkM3pw5DN6sOQzevDkM3sw5DN7cOQze7DkM3v w5DN8MOQzfHDkM3yw5DN88OQzfTDkM31w5DN9sOQzffDkM34w5DN+cOQzfrDkM37w5DN/MOQ zf3DkM3+w5DN/8OQUFOLXCQMuCQAAADB4wIDw4dEJARbw1WL7IPsDFNWVx4GD6APqIt1FI4G ZoteBold+I5mCI5uCot1DIsGi14Ei04Ii1YMi34Ui3YQHlX4/3UIjl346Kf///9dXR+cj0X8 Vo9F9B6PRfiLdRCJBoleBIlOCIlWDP919I9GEIl+FItd/IPjAYleGIt1FIwGi134ZoleBoxm CIxuCg+pD6EHH19eW/yL5V3DVYvsUx6OXQiLXQyKAx9bXcNVi+xTHo5dCItdDGaLAx9bXcNV i+xTHo5dCItdDIsDH1tdw1WL7FMejl0Ii10MikUQiAMfW13DVYvsUx6OXQiLXQxmi0UQZokD H1tdw1WL7FMejl0Ii10Mi0UQiQMfW13DVYvsU1ZXHot9CGaLRQyO2It1EItNFIvBwekC86WL yIPhA/OkH19eW/xdw1WL7FNWVwaLdRBmi0UIjsCLfQyLTRSLwcHpAvOli8iD4QPzpAdfXlv8 XcOMHQAAAADDLo4dAAAAAMMAACsEAAAEAAAElgUAAAYAAASeBQAABgAABAQAAAAHAAAAAAAA ABAAAAAFAAAAAAAAABwAAAAFAAAAOgQAACgAAAAFAAAAzAQAADQAAAAFAAAA3QQAAEAAAAAF AAAA7wQAAEwAAAAFAAAAAAUAAFgAAAAFAAAAFAUAAGQAAAAFAAAAKgUAAHAAAAAFAAAAPgUA AH0AAAAFAAAAaQUAAIoAAAAFAAAAlAUAAJUAAAAFAAAAmwUAAKAAAABfUE1fc2F2ZWREUwBf UE1fc2VncmVhZABfUE1faW50Mzg2eABfUE1fZ2V0Qnl0ZQBfUE1fZ2V0V29yZABfUE1fZ2V0 TG9uZwBfUE1fc2V0Qnl0ZQBfUE1fc2V0V29yZABfUE1fc2V0TG9uZwBfUE1fbWVtY3B5bmYA X1BNX21lbWNweWZuAF9QTV9zYXZlRFMAX1BNX2xvYWREAAA= --------------71C5437550AB Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="_PMLITE.ASM" ;**************************************************************************** ;* ;* PM/Lite Library ;* ;* Copyright (C) 1996 SciTech Software ;* All rights reserved. ;* ;* Filename: $Workfile: _pmlite.asm $ ;* Version: $Revision: 1.0 $ ;* ;* Language: 80386 Assembler, TASM 4.0 or later ;* Environment: IBM PC Real mode and 16/32 bit protected mode ;* ;* Description: Low level assembly support. ;* ;* $Date: 05 Feb 1996 21:42:18 $ $Author: KendallB $ ;* ;**************************************************************************** IDEAL INCLUDE "model.mac" ; Memory model macros header _pmlite ; Set up memory model begdataseg _pmlite if flatmodel _PM_savedDS dw 0 ; Saved value of DS PUBLIC _PM_savedDS endif ifdef X32VM DOSX EQU 1 endif ifdef DOSX ; Special external declarations for the DOSX extender that we may need $EXTRN __x386_data_16_alias,WORD $EXTRN __x386_zero_base_selector,WORD $EXTRN __x386_zero_base_ptr,DWORD endif enddataseg _pmlite ifdef DOSX SEGMENT __X386_DATASEG_16 PARA PUBLIC USE16 'DATA16' $EXTRN __x386_fm,DWORD ENDS __X386_DATASEG_16 endif begcodeseg _pmlite ; Start of code segment ifndef DPMI16 ifndef __WINDOWS16__ ife flatmodel struc rmregs_s ax dw ? bx dw ? cx dw ? dx dw ? si dw ? di dw ? cflag dw ? ends rmregs_s RMREGS = (rmregs_s PTR es:bx) struc rmsregs_s es dw ? cs dw ? ss dw ? ds dw ? ends rmsregs_s RMSREGS = (rmsregs_s PTR es:bx) ;---------------------------------------------------------------------------- ; void PM_callRealMode(unsigned s,unsigned o, RMREGS *regs, ; RMSREGS *sregs) ;---------------------------------------------------------------------------- ; Calls a real mode procedure, loading the appropriate registers values ; from the passed in structures. Only the DS and ES register are loaded ; from the SREGS structure. ;---------------------------------------------------------------------------- procstart _PM_callRealMode ARG s:WORD, o:WORD, regs:DWORD, sregs:DWORD LOCAL addr:DWORD, bxVal:WORD, esVal:WORD, flags:WORD = LocalSize enter_c LocalSize push ds push es mov ax,[o] ; Build the address to call in 'addr' mov [WORD addr],ax mov ax,[s] mov [WORD addr+2],ax les bx,[sregs] mov ax,[RMSREGS.ds] mov ds,ax ; DS := passed in value mov ax,[RMSREGS.es] mov [esVal],ax les bx,[regs] mov ax,[RMREGS.bx] mov [bxVal],ax mov ax,[RMREGS.ax] ; AX := passed in value mov cx,[RMREGS.cx] ; CX := passed in value mov dx,[RMREGS.dx] ; DX := passed in value mov si,[RMREGS.si] ; SI := passed in value mov di,[RMREGS.di] ; DI := passed in value push bp push [esVal] pop es ; ES := passed in value mov bx,[bxVal] ; BX := passed in value call [addr] ; Call the specified routine pushf ; Save flags for later pop [flags] pop bp push es pop [esVal] push bx pop [bxVal] les bx,[sregs] push ds pop [RMSREGS.ds] ; Save value of DS push [esVal] pop [RMSREGS.es] ; Save value of ES les bx,[regs] mov [RMREGS.ax],ax ; Save value of AX mov [RMREGS.cx],cx ; Save value of CX mov [RMREGS.dx],dx ; Save value of DX mov [RMREGS.si],si ; Save value of SI mov [RMREGS.di],di ; Save value of DI mov ax,[flags] ; Return flags and ax,1h ; Isolate carry flag mov [RMREGS.cflag],ax ; Save carry flag status mov ax,[bxVal] mov [RMREGS.bx],ax ; Save value of BX pop es pop ds leave_c ret procend _PM_callRealMode endif endif endif ;---------------------------------------------------------------------------- ; void PM_segread(PMSREGS *sregs) ;---------------------------------------------------------------------------- ; Read the current value of all segment registers ;---------------------------------------------------------------------------- procstartdll16 _PM_segread ARG sregs:DPTR enter_c 0 mov ax,es _les _si,[sregs] mov [_ES _si],ax mov [_ES _si+2],cs mov [_ES _si+4],ss mov [_ES _si+6],ds mov [_ES _si+8],fs mov [_ES _si+10],gs leave_c_nolocal ret procenddll16 _PM_segread ; Create a table of the 256 different interrupt calls that we can jump ; into intno = 0 intTable: REPT 256 db 0CDh db intno intno = intno + 1 ret nop ENDM PROC genInt near push _ax ; Save _ax push _bx ; Save _bx if flatmodel mov ebx,[UINT esp+12] ; EBX := interrupt number else mov bx,sp ; Make sure ESP is zeroed mov bx,[UINT ss:bx+6] ; BX := interrupt number endif mov _ax,offset intTable ; Point to interrupt generation table shl _bx,2 ; _BX := index into table add _ax,_bx ; _AX := pointer to interrupt code if flatmodel xchg eax,[esp+4] ; Restore eax, and set for int else mov bx,sp xchg ax,[ss:bx+2] ; Restore ax, and set for int endif pop _bx ; restore _bx ret ENDP genInt ;---------------------------------------------------------------------------- ; int PM_int386x(int intno, PMREGS *in, PMREGS *out,PMSREGS *sregs) ;---------------------------------------------------------------------------- ; Issues a software interrupt in protected mode. This routine has been ; written to allow user programs to load CS and DS with different values ; other than the default. ;---------------------------------------------------------------------------- procstartdll16 _PM_int386x ARG intno:UINT, inptr:DPTR, outptr:DPTR, sregs:DPTR LOCAL flags:UINT, sv_ds:UINT, sv_esi:ULONG = LocalSize enter_c LocalSize push ds push es ; Save segment registers push fs push gs _lds _si,[sregs] ; DS:_SI -> Load segment registers mov es,[_si] mov bx,[_si+6] mov [sv_ds],_bx ; Save value of user DS on stack mov fs,[_si+8] mov gs,[_si+10] _lds _si,[inptr] ; Load CPU registers mov eax,[_si] mov ebx,[_si+4] mov ecx,[_si+8] mov edx,[_si+12] mov edi,[_si+20] mov esi,[_si+16] push ds ; Save value of DS push _bp ; Some interrupts trash this! clc ; Generate the interrupt push [intno] mov ds,[WORD sv_ds] ; Set value of user's DS selector call genInt pop _bp ; Pop intno from stack (flags unchanged) pop _bp ; Restore value of stack frame pointer pop ds ; Restore value of DS pushf ; Save flags for later pop [flags] push esi ; Save ESI for later pop [sv_esi] push ds ; Save DS for later pop [sv_ds] _lds _si,[outptr] ; Save CPU registers mov [_si],eax mov [_si+4],ebx mov [_si+8],ecx mov [_si+12],edx push [sv_esi] pop [DWORD _si+16] mov [_si+20],edi mov _bx,[flags] ; Return flags and ebx,1h ; Isolate carry flag mov [_si+24],ebx ; Save carry flag status _lds _si,[sregs] ; Save segment registers mov [_si],es mov _bx,[sv_ds] mov [_si+6],bx ; Get returned DS from stack mov [_si+8],fs mov [_si+10],gs pop gs ; Restore segment registers pop fs pop es pop ds leave_c ret procenddll16 _PM_int386x if flatmodel ;---------------------------------------------------------------------------- ; unsigned char PM_getByte(unsigned s, unsigned o) ;---------------------------------------------------------------------------- procstartdll16 _PM_getByte ARG s:UINT, o:UINT push ebp mov ebp,esp push ds mov ax,[WORD s] mov ds,ax mov eax,[o] mov al,[eax] pop ds pop ebp ret procenddll16 _PM_getByte ;---------------------------------------------------------------------------- ; unsigned short PM_getWord(unsigned s, unsigned o) ;---------------------------------------------------------------------------- procstartdll16 _PM_getWord ARG s:UINT, o:UINT push ebp mov ebp,esp push ds mov ax,[WORD s] mov ds,ax mov eax,[o] mov ax,[eax] pop ds pop ebp ret procenddll16 _PM_getWord ;---------------------------------------------------------------------------- ; unsigned long PM_getLong(unsigned s, unsigned o) ;---------------------------------------------------------------------------- procstartdll16 _PM_getLong ARG s:UINT, o:UINT push ebp mov ebp,esp push ds mov ax,[WORD s] mov ds,ax mov eax,[o] mov eax,[eax] pop ds pop ebp ret procenddll16 _PM_getLong ;---------------------------------------------------------------------------- ; void PM_setByte(unsigned s, unsigned o,unsigned char v) ;---------------------------------------------------------------------------- procstartdll16 _PM_setByte ARG s:UINT, o:UINT, v:UCHAR push ebp mov ebp,esp push ds mov ax,[WORD s] mov ds,ax mov edx,[o] mov al,[v] mov [edx],al pop ds pop ebp ret procenddll16 _PM_setByte ;---------------------------------------------------------------------------- ; void PM_setWord(unsigned s, unsigned o,unsigned short v) ;---------------------------------------------------------------------------- procstartdll16 _PM_setWord ARG s:UINT, o:UINT, v:USHORT push ebp mov ebp,esp push ds mov ax,[WORD s] mov ds,ax mov edx,[o] mov ax,[v] mov [edx],ax pop ds pop ebp ret procenddll16 _PM_setWord ;---------------------------------------------------------------------------- ; void PM_setLong(unsigned s, unsigned o,unsigned long v) ;---------------------------------------------------------------------------- procstartdll16 _PM_setLong ARG s:UINT, o:UINT, v:ULONG push ebp mov ebp,esp push ds mov ax,[WORD s] mov ds,ax mov edx,[o] mov eax,[v] mov [edx],eax pop ds pop ebp ret procenddll16 _PM_setLong ;---------------------------------------------------------------------------- ; void PM_memcpynf(void *dst,unsigned src_s,unsigned src_o,unsigned n) ;---------------------------------------------------------------------------- ; Copies a block of memory from a far memory block to a near memory block. ;---------------------------------------------------------------------------- procstartdll16 _PM_memcpynf ARG dst:DPTR, src_s:UINT, src_o:UINT, n:UINT enter_c 0 push ds force_es_eq_ds ; Force ES == DS mov edi,[dst] ; ES:EDI -> destination memory block mov ax,[WORD src_s] mov ds,ax mov esi,[src_o] ; DS:ESI -> source memory block mov ecx,[n] mov eax,ecx shr ecx,2 rep movsd mov ecx,eax and ecx,3 rep movsb pop ds leave_c_nolocal ret procenddll16 _PM_memcpynf ;---------------------------------------------------------------------------- ; void PM_memcpyfn(unsigned dst_s,unsigned dst_o,void *src,unsigned n) ;---------------------------------------------------------------------------- ; Copies a block of memory from a near memory block to a far memory block. ;---------------------------------------------------------------------------- procstartdll16 _PM_memcpyfn ARG dst_s:UINT, dst_o:UINT, src:DPTR, n:UINT enter_c 0 push es mov esi,[src] ; DS:ESI -> source memory block mov ax,[WORD dst_s] mov es,ax mov edi,[dst_o] ; ES:EDI -> source memory block mov ecx,[n] mov eax,ecx shr ecx,2 rep movsd mov ecx,eax and ecx,3 rep movsb pop es leave_c_nolocal ret procenddll16 _PM_memcpyfn ifdef TNT ;---------------------------------------------------------------------------- ; unsigned _PL_allocsel(void) ;---------------------------------------------------------------------------- ; Allocate am empty segment selector with Phar Lap (there is no C based ; API for doing this in a compiler portable manner). ;---------------------------------------------------------------------------- procstart __PL_allocsel mov ah,48h ; Allocate memory service xor ebx,ebx ; EBX := 0 pages to allocate int 21h jc @@Fail and eax,0FFFFh ; EAX := segment selector ret @@Fail: xor eax,eax ret procend __PL_allocsel endif ifdef DOSX ;---------------------------------------------------------------------------- ; ulong _X32_getPhysMem(void) ;---------------------------------------------------------------------------- ; Determines the amount of physical memory available under the X32 DOS ; extender. There is no proper way to do this, so what we have to do is ; look in the X32 extender stub and sniff around for the info we need. This ; is what was suggested by Joe Huffman and provided to us by Kevin Aguilar. ;---------------------------------------------------------------------------- procstart __X32_getPhysMem push es mov es,[__x386_data_16_alias] mov eax,[es:__x386_fm+12] sub eax,[es:__x386_fm+4] sub eax,100 * 1024 pop es ret procend __X32_getPhysMem endif endif ife flatmodel _PM_savedDS dw DGROUP ; Saved value of DS endif ;---------------------------------------------------------------------------- ; void PM_saveDS(void) ;---------------------------------------------------------------------------- ; Save the value of DS into a section of the code segment, so that we can ; quickly load this value at a later date in the PM_loadDS() routine from ; inside interrupt handlers etc. The method to do this is different ; depending on the DOS extender being used. ;---------------------------------------------------------------------------- procstartdll16 _PM_saveDS if flatmodel mov [_PM_savedDS],ds ; Store away in data segment endif ret procenddll16 _PM_saveDS ;---------------------------------------------------------------------------- ; void PM_loadDS(void) ;---------------------------------------------------------------------------- ; Routine to load the DS register with the default value for the current ; DOS extender. Only the DS register is loaded, not the ES register, so ; if you wish to call C code, you will need to also load the ES register ; in 32 bit protected mode. ;---------------------------------------------------------------------------- procstartdll16 _PM_loadDS mov ds,[cs:_PM_savedDS] ; We can access the proper DS through CS ret procenddll16 _PM_loadDS endcodeseg _pmlite END ; End of module --------------71C5437550AB Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="MODEL.MAC" ;**************************************************************************** ;* ;* Copyright (C) 1996 SciTech Software. ;* All rights reserved. ;* ;* Filename: $Workfile: model.mac $ ;* Version: $Revision: 1.0 $ ;* ;* 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 memory models. ;* ;* The defines that you should use when assembling modules that ;* use this macro package are: ;* ;* __LARGE__ Assemble for 16 bit large model ;* __COMPACT__ Assemble for 16 bit model ;* __WINDOWS16__ Assemble for Hybrid 16/32 bit PM large 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 ;* ES_NOT_DS Assemble assuming ES != DS for 32 bit code ;* BUILD_DLL Assembler for use in a DLL ;* ;* 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. ;* ;* $Date: 05 Feb 1996 18:53:52 $ $Author: KendallB $ ;* ;**************************************************************************** IDEAL ; Define the __WINDOWS__ symbol if we are compiling for any Windows ; environment ifdef __WINDOWS16__ __WINDOWS__ = 1 endif ifdef __WINDOWS32__ __WINDOWS__ = 1 endif ; 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 pmode EQU 1 ; This is a protected mode memory model intsize EQU 4 ; Size of an integer 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 DWORD ; 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 S_UCHAR EQU UCHAR S_USHORT EQU USHORT S_BOOL EQU BOOL else ; The following is for Symantec C++ which wont link with code assembled in ; the FLAT model (stuffed if I know why), but TASM does not correctly set ; the size of WORD arguments on the stack to 4 bytes, so we create a set ; of macros to do this for us. LARGESTACK ; Set up for a 32 bit stack model S_UCHAR EQU BYTE:4 S_USHORT EQU WORD:2 S_BOOL EQU BOOL endif else flatmodel EQU 0 ; This is a segmented memory model ifdef __WINDOWS16__ pmode EQU 1 ; This is a protected mode memory model else pmode EQU 0 ; This is a real mode memory model endif intsize EQU 2 ; Size of an integer 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 ifdef __COMPACT__ codesize EQU 0 ; Near code memory model cptrsize EQU 2 ; Size of a code pointer typedef CPTR WORD ; 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 NEAR else 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 endif _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 S_UCHAR EQU UCHAR S_USHORT EQU USHORT S_BOOL EQU BOOL ifndef __8086__ ifdef __80286__ P286 ; Turn on 286 code generation else P386 ; Turn on 386 code generation endif endif endif ; Provide a typedef for real floating point numbers ifdef DOUBLE typedef REAL QWORD else typedef REAL DWORD 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 save_c_regs ifdef __X386__ push ebx endif push _si push _di ENDM MACRO enter_c LocalSize push _bp mov _bp,_sp IFDIFI ,<0> sub _sp,LocalSize ENDIF save_c_regs ENDM MACRO restore_c_regs pop _di pop _si ifdef __X386__ pop ebx endif ENDM MACRO leave_c restore_c_regs cld mov _sp,_bp pop _bp ENDM MACRO leave_c_nolocal restore_c_regs cld pop _bp 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 large 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 MACRO use_fs ife flatmodel push fs endif ENDM MACRO unuse_fs ife flatmodel pop fs 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 to use the FS register as a scratch segment register for 16 bit ; code. For 32 bit code we assume DS addresses the same area. MACRO _lfs reg, addr if flatmodel mov reg,addr else lfs reg,addr endif ENDM if flatmodel _FS EQU else _FS EQU fs: endif ; Macro to force the value of ES to be the same as DS for 32 bit assembler ; code. For most compilers this evaluates to nothing, but for Symantec C++ ; we cant assume that DS == ES at all times (since Symantec uses a different ; selector for SS). MACRO force_es_eq_ds ifdef ES_NOT_DS push ds ; Force ES == DS for following code pop es endif ENDM ; Macros for setting the value of the DS,ES,FS,GS registers to the same ; value. This does nothing in 32 bit protected mode, except for compilers ; that assume that DS != ES (Symantec C++ is one) and hence ES is always ; available to be loaded with any value you desire. 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 ds_eq_ss ife flatmodel push ss pop ds else ifdef ES_NOT_DS push ss pop ds endif endif ENDM MACRO fs_eq_ds ife flatmodel push ds pop fs 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 pmode movzx e®&,reg endif ENDM MACRO sgnhi reg if pmode movsx e®&,reg 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 in 16 bit real mode and PM USE32 code. For 32 bit FLAT model ; code it will evaluate to nothing. MACRO clrhi16 reg ife flatmodel movzx e®&,reg endif ENDM MACRO sgnhi16 reg ife flatmodel movsx e®&,reg 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 to load and store integer values with string instructions MACRO LODSINT if flatmodel lodsd else lodsw endif ENDM MACRO STOSINT if flatmodel stosd else stosw 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 PROC name FAR else PROC name NEAR endif PUBLIC name ENDM MACRO procstartdll name ; Set up DLL _export'ed proc if codesize PROC name FAR else PROC name NEAR endif ifdef BUILD_DLL PUBLICDLL name else PUBLIC name endif ENDM ; This macro sets up a procedure to be exported from a 16 bit DLL. Since the ; calling conventions are always _far _pascal for 16 bit DLL's, we actually ; rename this routine with an extra underscore with 'C' calling conventions ; and a small DLL stub will be provided by the high level code to call the ; assembler routine. MACRO procstartdll16 name ; Set up DLL _export'ed proc ifdef __WINDOWS16__ procstartdll _&name& else procstartdll name endif ENDM MACRO procenddll16 name ifdef __WINDOWS16__ procend _&name& else procend name endif 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 MACRO procstart32 name ; Set up hybrid 16/32 proc ifdef __WINDOWS16__ ; and export name ; For the hybrid 16/32 bit memory model, the function is actually FAR, ; but because the segment is marked as USE32, TASM assumes a 32 bit ; calling convention, which causes the ARG directives to be off by 2 ; bytes. To fix this we make the far functions 32 bit NEAR, so that the ; return stack frame is 4 bytes not 6 bytes for a 32 bit FAR function. ; To return from a hybrid 16/32 function you must use the ret32 macro ; rather than issuing a normal ret instruction. PROC name NEAR else if codesize PROC name FAR else PROC name NEAR endif endif PUBLIC name 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,SS: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 USE16 '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 ; Macro to begin a 32 bit code segment. For 32 bit protected mode this is ; no different to a normal FLAT mode code segment. For 16 bit protected mode, ; this is a USE32 code segment, with 16 bit calling conventions. The code ; itself is assembled as full 32 bit code, but the stack is 16 bit and ; the functions are 16 bit far functions. This allows the code full access ; to 4Gb from the start of a data segment, so we can get full access to ; large memory blocks from 16 bit PM without needing to resort to horrid ; selector/offset manipulation. This does of course require a 386 or higher ; processor! Note also that you _CANNOT_ link this USE32 code with other ; USE16 code segments. You should put all your 32 bit code in one hybrid ; segment if possible - maximum of 64k in each of course. If you have ; more than one segment, you will need to declare and call multiple ; ??_enable32() functions to convert the segments to 32 bit hyrbid code ; under Windows DPMI. MACRO begcodeseg32 name ifdef __WINDOWS16__ SEGMENT &name&_TEXT32 DWORD PUBLIC USE32 'CODE' GROUP DGROUP _DATA,_BSS ASSUME CS:&name&_TEXT32,DS:DGROUP else begcodeseg name endif ENDM MACRO endcodeseg32 name ifdef __WINDOWS16__ ENDS &name&_TEXT32 else endcodeseg name endif ENDM ; Macro to return from a 32 bit routine to the native protected mode ; environment. In 16 bit PM this does a 16:16 far return to the original ; 16 bit code. Under 32 bit PM this will be a 32 bit near return. MACRO ret32 ifdef __WINDOWS16__ db 066h,0CBh else ret endif ENDM ; Macro to create a routine to convert the CS selector for the segment from ; a 16 bit selector to a 32 bit selector. We do this by checking if we ; are running 16 or 32 bit code, if we are running 16 bit code we convert ; the selector to 32 bit (the code currently requires DPMI for this, but ; we only support Borland's DPMI16 and Windows DPMI for 16 bit PM code ; anyway). This code comes courtesy of the 32 bit hacked CMACROS.INC ; in the Microsoft WinG Software Development Kit. ; ; Note that you will need to explicitly call this function before accessing ; any 32 bit code in each separate 32 bit segment that you have created. MACRO define_enable32 name ifdef __WINDOWS16__ &name&_fix_cs: db 057h ; push di db 083h,0ECh,008h ; sub sp,8 db 08Ch,0CBh ; mov bx,cs db 08Ch,0D0h ; mov ax,ss db 08Eh,0C0h ; mov es,ax db 08Bh,0FCh ; mov di,sp db 0B8h,00Bh,000h ; mov ax,000Bh db 0CDh,031h ; int 31h db 026h,080h,04Dh,006h,040h ; or byte ptr es:[di+6],40h db 0B8h,00Ch,000h ; mov ax,000Ch db 0CDh,031h ; int 31h add sp,8 ; db 083h,0C4h,008h pop di ; db 05Fh procfar &name&_enable32 xor eax,eax mov ah,80h add eax,eax jc short &name&_fix_cs db 066h,0CBh ; 16:16 retf procend &name&_enable32 endif ENDM ; Boolean truth values (same as those in debug.h) False = 0 True = 1 No = 0 Yes = 1 --------------71C5437550AB--