www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1996/07/30/08:24:14

Message-ID: <31FDFE92.53AE@pobox.oleane.com>
Date: Tue, 30 Jul 1996 14:22:42 +0200
From: Francois Charton <deef AT pobox DOT oleane DOT com>
Organization: CCMSA
MIME-Version: 1.0
To: Eli Zaretskii <eliz AT is DOT elta DOT co DOT il>
CC: djgpp AT delorie DOT com
Subject: Re: Re : compiling povray 3.0 with djgpp
References: <Pine DOT SUN DOT 3 DOT 91 DOT 960730132128 DOT 29599E-100000 AT is>

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	<LocalSize>,<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&reg&, val32
else
		add		reg, val16
endif
ENDM

MACRO	_sub	reg, val16, val32
if flatmodel
		sub		e&reg&, 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&,reg
endif
ENDM

MACRO	sgnhi	reg
if pmode
		movsx	e&reg&,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&,reg
endif
ENDM

MACRO	sgnhi16	reg
ife	flatmodel
		movsx	e&reg&,reg
endif
ENDM

; Macro to load an extended register with an integer value in either mode

MACRO	loadint	reg,val
if flatmodel
		mov		e&reg&,val
else
		xor		e&reg&,e&reg&
		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--

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019