;****************************************************************************
;*
;*                  Copyright (C) 1993 Kendall Bennett.
;*                          All rights reserved.
;*
;* Filename:    $RCSfile: model.mac $
;* Version:     $Revision: 1.5 $
;*
;* Language:    Turbo Assembler 2.5
;* Environment: IBM PC (MS DOS)
;*
;* Description: Macros to provide memory model independant assembly language
;*              module for Borland C++.
;*
;* 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 1992/06/10 01:11:16 kjb release $
;*
;* Revision History:
;* -----------------
;*
;* $Log: model.mac $
;* Revision 1.5  1992/06/10  01:11:16  kjb
;* Optimised for faster polygon/line scan conversion.
;*
;* Revision 1.4  92/04/24  16:32:38  kjb
;* Fixed bug in declaration of data segment in HUGE model (again!)
;* 
;* Revision 1.3  92/01/01  21:35:42  kjb
;* Fixed bug in declaration of data segment for the HUGE data model.
;* 
;* Revision 1.2  91/11/12  11:36:14  kjb
;* Added macro for static model independant procedures.
;* 
;* Revision 1.1  91/09/20  16:26:07  kjb
;* Initial revision
;* 
;****************************************************************************

; Define symbols codesize and datasize depending on the requested memory
; model.

ifdef   __TINY__
        codesize    EQU 0
        datasize    EQU 0
        hugedata    EQU 0
else
ifdef   __MEDIUM__
        codesize    EQU 1
        datasize    EQU 0
        hugedata    EQU 0
else
ifdef   __COMPACT__
        codesize    EQU 0
        datasize    EQU 1
        hugedata    EQU 0
else
ifdef   __LARGE__
        codesize    EQU 1
        datasize    EQU 1
        hugedata    EQU 0
else
ifdef   __HUGE__
        codesize    EQU 1
        datasize    EQU 1
        hugedata    EQU 1
else
        codesize    EQU 0       ; Default to small model if none specified
        datasize    EQU 0
        hugedata    EQU 0
endif
endif
endif
endif
endif

; Macros for obtaining size of pointer for model requested.

if datasize
        DPTR        EQU DWORD
        dptrsize    EQU 4       ; Size of a data pointer
else
        DPTR        EQU WORD
        dptrsize    EQU 2
endif

if codesize
        CPTR        EQU DWORD
        FPTR        EQU FAR
        cptrsize    EQU 4       ; Size of a code pointer
else
        CPTR        EQU WORD
        FPTR        EQU NEAR
        cptrsize    EQU 2
endif

; Macros for procedure definitions given a name. Note that they also exports
; 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 _BSS data segment. This segment contains uninitialised data.

MACRO   begbssseg
SEGMENT _BSS WORD PUBLIC 'BSS'
ENDM

MACRO   endbssseg
ENDS    _BSS
ENDM

; Macros for the _DATA data segment. This segment contains initialised data.

MACRO   begdataseg name
ifdef   __HUGE__
SEGMENT &name&_DATA WORD PUBLIC 'DATA'
else
SEGMENT _DATA WORD PUBLIC 'DATA'
endif
ENDM

MACRO   enddataseg name
ifdef   __HUGE__
ENDS    &name&_DATA
else
ENDS    _DATA
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
endbssseg
ENDM

; Macro for the main code segment.

MACRO   begcodeseg name
if codesize
SEGMENT &name&_TEXT BYTE PUBLIC 'CODE'
ifdef   __HUGE__
GROUP   DGROUP &name&_DATA
        ASSUME CS:&name&_TEXT,DS:DGROUP
else
GROUP   DGROUP _DATA,_BSS
        ASSUME CS:&name&_TEXT,DS:DGROUP
endif
else
SEGMENT _TEXT BYTE PUBLIC 'CODE'
GROUP   DGROUP _DATA,_BSS
        ASSUME CS:_TEXT,DS:DGROUP
endif
ENDM

MACRO   endcodeseg name
if codesize
ENDS    &name&_TEXT
else
ENDS    _TEXT
endif
ENDM

; Macros for entering and leaving procedures. Here we automatically save
; the SI and DI registers that are used as register variables by Borland C++.
; We also save the DS register in the HUGE model and make it point to our
; data segment. Upon leaving all registers are restored.

MACRO   setupDS
        push    si                      ; Save register variables
        push    di                      ; For Borland C++

    IF  hugedata
        push    ds                      ; Save DS
        mov     ax,DGROUP               ; Address our data segment
        mov     ds,ax
    ENDIF
ENDM

MACRO   restoreDS
    IF  hugedata
        pop     ds
    ENDIF
        pop     di
        pop     si
ENDM
