        NAME MSC_START_UP_CODE		; startup.asm, version 7.0.
;
; Copyright (c) 1987-1992, Systems & Software, Inc. All rights reserved.
;
; This file contains sample start-up code for building a Microsoft C 
; application for an embedded environment.
;
; You may modify this file to adapt it to your embedded environment.  
;
; *****************************************************************************
; For embedded system applications, your application is burned into one
; or more eprom.  In order to boot your system at power-up or reboot at
; hardware reset, you must place an opcode equivalent to a far jump 
; instruction at absolute address FFFF0H.  The CPU will execute
; this instruction upon a hardware reset or power-up.  The instruction 
; jumps to the system initialization routine.  This piece of code is called
; bootstrap code.
; 
; There are two ways to include the bootstrap code in your application:
;
; (1) Specify the BOOTSTRAP control in the locator command line,
;
; If you look at the locator's map file (.MP2 file), a segment named
; UNNAME is generated by the locator at address 0FFFF0H which
; contains the bootstrap code.  The bootstrap code is equivalent to a
; far jump instruction to the label START_.
;
; or 
;
; (2) Locate a segment in this source file at 0FFFF:0000H, such as:
;
; BOOTSTRAP SEGMENT
;	JMP FAR PTR START_
; BOOTSTRAP ENDS
;
; NOTE: 
;	The bootstrap code is not needed when you are debugging with a 
; 	debugger, such as SoftProbe 86/TX target debugger or an in-circuit
;	emulator.  You add this code when you are ready to burn eproms.
;
; *****************************************************************************
;
;
; The primary function of the start-up code is to set up the run-time 
; environment before passing control to the function main().
; The start-up code performs the following functions:
;
; 1) Initialize hardware and check RAM (user defined).  Place your code
;    after the label _start_ and before the label _init_begin.
;
; 2) Copy initializers from ROM to RAM to set up initialized program variables 
;    to proper initial values.  The copy of NEAR DATA is from the label
;    _init_begin to the label no_init_data.  The copy of FAR DATA is from
;    the label no_uninit_data to loopend.  Initializers are placed in ROM
;    with the ROMINIT option in LL86 and EXE2OMF or with the INITDATA option
;    in PROM86.  Please see the sample command files in the demo directories.
;
; 3) Zero all uninitialized program variables.  Clearing of BSS is from the
;    label no_init_data to the label no_uninit_data.  Clearing of FAR_BSS
;    is from the label loopend to the label loopfend.  Clearing of HUGE_BSS
;    is from the label loopfend to loophend.
;
; 4) Initialize interrupt vector table, if necessary.  This is done after the
;    label _init_done.
;
; 5) Set up C and C++ initializers.  This is done after initializing the
;    interrupt vector table.
;
; 6) Set up data segment.  This is after setup of C and C++ initializers.
;
; 7) Set up stack segment.  This is after setting up the data segment.
;
; 8) Pass control to function main().  This is after setting up the stack
;    segment
;
; You can refer to inthand.c for interrupt vectors installation or setup the
; interrupt vectors in this file.
;
; This assembly file is called startup.asm.  You should use the Microsoft MASM
; assembler, version 4 and up.  For example,
;   	masm /Mx startup,startup,startup,nul
; The /Mx option is needed to preserve lower-case in public and external names.
;
	PUBLIC  __acrtused	
__acrtused	EQU	1	
; The symbol __acrtused has to be in lower-case.  Starting from version 4,
; when the Microsoft C optimizing compiler compiles a C file, it places an
; external reference to this symbol in the object file.  The public definition
; of __acrtused is contained in an object module called crt0.  This module is
; placed in the Microsoft C run-time library file.  This module contains the
; start-up code for the DOS environment.  So when you link your C object files
; with the run-time library file, the linker will extract the start-up object
; module from the run-time library file to satisfy the external references.
; As a result, the start-up code for DOS environment will be included in the 
; linker output.
; If you do not make use of any function supplied in the run-time library
; file, you do not link with the library file at all.  Then you have to
; include a public definition of __acrtused in this file to resolve all the
; external references in the C object files.
; Even though you are building an application for an embedded environment,
; sometimes you may want to link with the run-time library file.  The reason
; is that the run-time library file contains both DOS-dependent functions, 
; such as printf(), and DOS-independent functions, such as strcpy().  If you
; want to make use of certain DOS-independent functions that are contained in
; the run-time library file, you would link with the library file.  If the
; link map shows that the linked module contains the crt0 module, you know 
; that you have linked in some DOS-dependent functions from the run-time 
; library file.
; Make sure you specify this start-up file as the first object file
; in the linker command line, then the other object files and place the
; modified combined run-time library file as the last file.  
;
; The following memory map shows a typical run-time environment of an embedded
; application developed using the Microsoft C optimizing compiler.  
; It will help you understand the start-up code presented in this file.
; The naming convention of class names presented here conforms with the 
; Microsoft C optimizing compiler, version 4 and up.  The names enclosed in
; single quotes are class names of segments.
;
;  High address
;  -	    ----------------
;  |	    |              |
;  | FFFF:0 ---------------- <-- Bootstrap code (JMP FAR PTR START_)
;  |	    :              :
;  |	    ---------------- <-- 
;  |	    | [FAR_DATA]   |     This area of ROM contains initializers that 
;  |	    ----------------     are used by start-up routine to initialize 
;  |	    | [CONST]      |     segments with these class names in RAM at power-up.
;  R	    ----------------  ^  (Assume ROMINIT control in locater place the 
;  O	    | [DATA]       |  |  class DATA first then CONST then FAR_DATA)
;  M _brdata---------------- <-- Initializers are located starting at _brdata.
;  |	    | 'SSI_ROMINIT'| <-- This class contains only one segment with a 
;  |        ----------------     16-byte message to mark the beginning of rom data.
;  | START_ | 'CODE'       | <-- Text segments with class name CODE.
;  | _start_----------------    
;  -        :              :
;     	    :              :
;  - 	    :              :
;  |	    ---------------- <---- End of DGROUP (size of DGROUP <= 64K bytes)
;  |	    | 'STACK'      | <-- This class contains the stack.
;  |	    ----------------
;  |	    | 'BSS_END'    | 
;  | _end   ----------------
;  |	    | 'BSS'        | <-- This class contains uninitialized data.
;  |	    ---------------- 
;  |	    | 'DATA_END'   | 
;  | _edata ---------------- <----
;  |	    | 'CONST'      |  ^ These classes of segments are to be 
;  R	    ----------------  |  initialized with initializers in ROM 
;  A	    | 'DATA'       |  v  by start-up routine at power-up.
;  M	    ---------------- <----
;  |	    | 'DATA_BEG'   | 
;  | _bdata ---------------- <---- Start of DGROUP
;  |	    |'HUGE_BSS_END'| 
;  | _ehbss ----------------
;  |	    | 'HUGE_BSS'   | <-- This class contains uninitialized data.
;  | 	    ----------------
;  |	    |'HUGE_BSS_BEG'| 
;  | _bhbss ----------------
;  |	    | 'FAR_BSS_END'| 
;  | _efbss ----------------
;  |	    | 'FAR_BSS'    | <-- This class contains uninitialized data.
;  |	    ----------------
;  |	    | 'FAR_BSS_BEG'| 
;  | _bfbss ----------------
;  |	    |'FAR_DATA_END'| 
;  | _efdata----------------
;  |	    | 'FAR_DATA'   | <-- This class contains initialized data.
;  |	    ----------------
;  |	    |'FAR_DATA_BEG'| 
;  | _bfdata----------------
;  | 	    :              :
;  |	    ----------------
;  |	    |              | <-- The interrupt vector table should be 
;  -	0:0 ----------------     initialized by start-up routine at power-up.
;  Low address
;
; NOTE: 
; 	It is important to maintain the order of SEGMENTS/ENDS pairs as shown
;	below.
;
;	Text segments all have class name CODE.  They contain program code
;	which is machine instructions generated by the compiler.
;
;	Data segments with class names DATA_BEG, DATA, CONST, BSS and STACK
;	belong to a group named DGROUP.  Since these segments belong to
;	a group, it follows that the total memory space occupied by them
;	cannot exceed 64K bytes.
;
;	The object files may contain data segments with class names
;	FAR_DATA, FAR_BSS and HUGE_BSS.  
;	These classes of segments are generated by the Microsoft C 
;	optimizing compiler to support 'far' and 'huge' data objects.
;	Check your C manual for details.
;
;	Data segments with class names FAR_BSS and HUGE_BSS contain 
;	'far' and 'huge' uninitialized data, respectively. These segments 
;	do not belong to any group.  They should be located before
;	the group DGROUP in the RAM space of your target system.  The
;	advantage of locating these segments before DGROUP is that you may
;	use the memory space from the end of STACK segment to the end of 
;	RAM as heap to implement your own memory allocation scheme.
;
;	For 'huge' data objects, multiple segments may be generated by the 
;	C compiler to hold a single data object that is greater than 64K 
;	bytes in size.  These segments must be located together in proper 
;	order.  
;
;	Data segments with class name FAR_DATA contain 'far' and 'huge'
;	initialized data.  They should also be located before the group 
;	DGROUP in the RAM space of your target system.  
;
;	The LL86 and EXE2OMF (v7.0 and up) will move the segments specified
;       in ROMINIT control to the same segment name with class SSI_ROMINIT.
;	This start-up routine assumes all classes(segments) between _bfdata 
;	to _efdata and  _bdata to _edata are placed in ROM by ROMINIT control.
;	At power-up, the start-up routine will copy these initializers 
;       from ROM to initialize the appropriate variables in RAM.
;
;	The labels list below are served as markers for calculation of 
;	start-up routine to copy the initializers from ROM to RAM. 
;	The segments containing these labels should be of zero length.
;
;	_bfdata - beginning of initializers in FAR_DATA class
;	_efdata - end of initializers in FAR_DATA class
;	_bdata	- beginning of initializers in DGROUP group
;	_edata  - end of initializers in DGROUP group
;
;	The label below is served as marker of the initialized ROM data.
;
;	_brdata  - beginning of initialized ROM data
;
;	If you want PROM86 to determine the extraction address range,
;	i.e. the ADDRESSES option is not specified in PROM86 v6.0, you must
;	preserve the public label _start_ in this start-up file.
;
;	In addition to the above labels, the routine in this start-up file
;	uses the following public labels:
;	_end	- end of uninitialized data in BSS class
;	_bfbss	- beginning of uninitialized data in FAR_BSS class
;	_efbss	- end of uninitialized data in FAR_BSS class
;	_bhbss	- beginning of uninitialized data in HUGE_BSS class
;	_ehbss	- end of uninitialized data in HUGE_BSS class
;
; These constants are defined in makefile for condition assemblier
;
;	__S__	=> small model	
;	__C__	=> compact model
;	__M__	=> medium model
;	__L__	=> large model
;	__H__	=> huge model
; *****************************************************************************
; 	CPU86	=> Choose the target CPU 
;	   EQU 1 IF target CPU is 8086 or 8088.
; 	   EQU 0 IF target CPU is 80186 or 80188.
; *****************************************************************************
;	STACK_SIZE => stack size in byte
; *****************************************************************************	
;	FLOAT	=> floating point control
;	   0 : no floating point   1 : alternate , 2 : emulator , 3 : coprocessor		
;

INCLUDE STARTUP.INC

BEGFDATA SEGMENT PARA PUBLIC 'FAR_DATA_BEG'
	PUBLIC _bfdata
_bfdata LABEL BYTE ; This label marks the beginning of 'far' data.
; This segment must be of zero length and placed before 'FAR_DATA' class.
BEGFDATA ENDS
;
FAR_DATA_START SEGMENT PARA PUBLIC 'FAR_DATA'
FAR_DATA_START ENDS
; By default, the locator places segments with the same class name together.
; The purpose of the FAR_DATA_START segment is to cause the locator
; to locate all segments with class name FAR_DATA that contain
; initialized variables between the BEGFDATA and ENDFDATA segments.

EMULATOR_DATA  segment para public 'FAR_DATA'
; Segment contains data for floating point.
EMULATOR_DATA  ends

ENDFDATA SEGMENT PARA PUBLIC 'FAR_DATA_END'
	PUBLIC _efdata
_efdata LABEL BYTE ; This label marks the end of 'far' data.
ENDFDATA ENDS

BEGFBSS SEGMENT PARA PUBLIC 'FAR_BSS_BEG'
	PUBLIC _bfbss
_bfbss LABEL BYTE	; This label marks the beginning of uninitialized 
			; data in FAR_BSS class.
BEGFBSS ENDS
;
FAR_BSS_START SEGMENT PARA PUBLIC 'FAR_BSS'
FAR_BSS_START ENDS
; By default, the locator places segments with the same class name 
; together.
; The purpose of the FAR_BSS_START segment is to cause the locator to locate
; all segments with class name FAR_BSS between the BEGFBSS and ENDFBSS 
; segments.
; Segments with class name FAR_BSS contain uninitialized variables.
ENDFBSS SEGMENT PARA PUBLIC 'FAR_BSS_END'
	PUBLIC _efbss
_efbss LABEL BYTE	; This label marks the end of uninitialized data
			; in FAR_BSS class.
ENDFBSS ENDS

BEGHBSS SEGMENT PARA PUBLIC 'HUGE_BSS_BEG'
	PUBLIC _bhbss
_bhbss LABEL BYTE	; This label marks the beginning of uninitialized 
			; data in HUGE_BSS class.
BEGHBSS ENDS
HUGE_BSS_START SEGMENT PARA PUBLIC 'HUGE_BSS'
HUGE_BSS_START ENDS
; By default, the locator places segments with the same class name 
; together.
; The purpose of the HUGE_BSS_START segment is to cause the locator to locate 
; all segments with class name HUGE_BSS between the BEGHBSS and ENDHBSS 
; segments.
; Segments with class name HUGE_BSS contain uninitialized variables.
ENDHBSS SEGMENT PARA PUBLIC 'HUGE_BSS_END'
	PUBLIC _ehbss
_ehbss LABEL BYTE	; This label marks the end of uninitialized data
			; in HUGE_BSS class.
ENDHBSS ENDS

DGROUP GROUP BDATA,_DATA,PSP,CDATA,XIFCB,XIFU,XIFL,XIFM,XIFCE,XIFB,XIF,XIFE
DGROUP GROUP XIB,XI,XIE,CONST,HDR,MSG,PAD,EPAD,ENDDATA,_BSS,ENDBSS,STACK

BDATA SEGMENT PARA PUBLIC 'DATA_BEG'
; This segment must be of zero length and placed at the beginning of DGROUP.
	PUBLIC _bdata  	; This label marks the beginning of initialized data.
_bdata	LABEL BYTE
BDATA ENDS

_DATA SEGMENT WORD PUBLIC 'DATA'
; Segment with class name DATA contains initialized variables.
; If you have implemented a routine to check for null pointer assignment,
; then you should include the following DB statement in this segment.
; If a DS:0 null pointer assignment ever occurs, the first few bytes of
; this segment will be overwritten.
;
;	DB 8 DUP (0)
;
_DATA ENDS

PSP SEGMENT PARA PUBLIC 'DATA' ; MUST BE PARAGRAPH ALIGNED
; Segment contains data for initializing floating point emulator.
PSP ENDS

CDATA SEGMENT WORD COMMON 'DATA'
; DO NOT DEFINE ANY VARIABLE IN THIS SEGMENT
CDATA ENDS

XIFCB SEGMENT word public 'DATA'
    xifcbegin label   byte	; far C++ constructors begin
XIFCB ENDS
XIFU SEGMENT word public 'DATA' ; far C++ User constructors.
XIFU ENDS
XIFL SEGMENT word public 'DATA' ; far C++ Lib constructors.
XIFL ENDS
XIFM SEGMENT word public 'DATA' ; far C++ MS constructors.
XIFM ENDS
XIFCE SEGMENT word public 'DATA'
    xifcend   label   byte	; far C++ constructors begin
XIFCE ENDS

XIFB SEGMENT word public 'DATA'
xifbegin label	byte		; Far initializers begin
XIFB ENDS
XIF SEGMENT word public 'DATA' ; far init's
XIF ENDS
XIFE SEGMENT word public 'DATA'
xifend	label	byte		; Far initializers end
XIFE ENDS

XIB SEGMENT word public 'DATA'
xibegin label	byte		; Initializers begin/end
XIB ENDS
XI SEGMENT word public 'DATA' ; init's
XI ENDS
XIE SEGMENT word public 'DATA'
xiend	label	byte		; Initializers begin/end
XIE ENDS

CONST SEGMENT WORD PUBLIC 'CONST'
; Segment with class name CONST contains constants.
CONST ENDS

HDR SEGMENT BYTE PUBLIC 'MSG'   ; HEADER SEGMENT OF ERROR MESSAGE STRINGS
; Segment contains data for the floating point messages.
HDR ENDS

MSG SEGMENT BYTE PUBLIC 'MSG'   ; ERROR MESSAGE STRINGS
; Segment contains data for the floating point messages.
MSG ENDS

PAD SEGMENT BYTE COMMON 'MSG'   ; ERROR MESSAGE PADDING MARKER
; Segment contains data for the floating point messages.
PAD ENDS

EPAD SEGMENT BYTE COMMON 'MSG'  ; END OF PADDING MARKER
; Segment contains data for the floating point messages.
EPAD ENDS

ENDDATA SEGMENT PARA PUBLIC 'DATA_END'
	PUBLIC _edata	; C6
_edata	LABEL BYTE	; This label marks the end of initialized data.
	PUBLIC __edata	; C7
__edata	LABEL BYTE	; This label marks the end of initialized data.
ENDDATA ENDS

_BSS	SEGMENT WORD PUBLIC 'BSS'
; Segment with class name BSS contains uninitialized variables.
_BSS	ENDS

ENDBSS	SEGMENT WORD PUBLIC 'BSS_END'
	PUBLIC _end	; C6
_end	LABEL BYTE	; This label marks the end of uninitialized data.
	PUBLIC __end	; C7
__end	LABEL BYTE	
ENDBSS	ENDS

STACK	SEGMENT PARA STACK 'STACK'
	DB STACK_SIZE DUP (?)
stack_top LABEL WORD
STACK	ENDS

IF CPU86 EQ 0
        EXTRN START_:FAR        ; INIT186.ASM for 80186 CPU hardware init
ENDIF

IF FLOAT NE	0
	EXTRN   __fpinit:DWORD	; define this external symbol to link in FPINIT
ENDIF

IF LPROG EQ 1 	;MEDIUM OR LARGE OR HUGE MODEL
	EXTRN	_main:FAR	;C main()
ENDIF

_TEXT SEGMENT PARA PUBLIC 'CODE'
	ASSUME  CS:_TEXT
	ASSUME DS:DGROUP, SS:DGROUP
IF CPU86
	PUBLIC START_
START_:
ENDIF

IF LPROG EQ 0 	;SMALL OR COMPACT MODEL
	EXTRN	_main:NEAR	;C main()
ENDIF

	PUBLIC _start_  ;Must be paragraph aligned (i.e. offset is 0)
_start_ proc far		;and the address where program code starts.
	CLI
;
; *****************************************************************************
; Place code here to do hardware initialization and RAM check 
; *****************************************************************************
;
; Perform variable initialization.  Initializers are copied from ROM to RAM.
;
; Your program will contain segments with class names DATA, CONST and MSG
; which contain initialized variables.  Since these variables may be modified
; at run-time, the segments containing them have to be located in RAM space.
; When the main function of your C program takes control, it expects
; all variables in these classes of segments to be initialized.
; For embedded systems, the initializers for these variables have to be placed
; in ROM space which are copied to the segments in RAM space by the start-up
; routine at power-up.
; The start-up routine assumes these initializers are placed behind _brdata 
; in ROM and copy them to RAM at power-up.
;
_init_begin:
	CLD
; 	Destination
	MOV AX,SEG _bdata
	MOV ES,AX	     ; Destination ES:[DI]
	MOV DI,0	     ; Start of initialized variable area in RAM
; 	Source
	MOV AX,SEG _brdata    ; Source DS:[SI]
	INC AX		     ; Skip the 16-byte string 'Rom Data Begin  '
	MOV DS,AX	     ; Start of initializer storage in ROM
	MOV SI,0
;	Transfer Count
	MOV AX,OFFSET DGROUP:_edata     ; Transfer counter
	CMP AX,0
	JZ no_init_data
	MOV CX,AX
;	Begin BYTE transfer
REP	MOVSB		     ; Begin byte transfer from ROM to RAM
no_init_data:
;   Clear uninitialized data area in DGROUP group 

	MOV CX,OFFSET DGROUP:_end ; End of 'BSS' class in RAM
	MOV DI,OFFSET DGROUP:_edata ; Start of 'BSS' class in RAM
	SUB CX,DI	     ; Size of 'BSS' class in bytes
	JCXZ no_uninit_data
	MOV AX,0	     ; Initialize to 0
REP	STOSB
no_uninit_data:
;   Initialize FAR_DATA data in RAM with initializers stored in ROM   
; 	Transfer Count
	MOV AX,SEG _bfdata
	MOV CX,SEG _efdata
	SUB CX,AX	     ; Compute size of FAR_DATA segments in paragraphs
	JCXZ loopend	     ; No FAR_DATA class
	MOV DX,CX	     ; Saves transfer count in paragraphs
; 	Destination
	MOV ES,AX	     ; Destination ES:[DI]
	MOV DI,0	     ; Start of FAR_DATA class in RAM
; 	Source
	MOV AX,SEG _brdata    ; Source DS:[SI]
	INC AX		     ; Skip the 16-byte string 'Rom Data Begin  '
	MOV DS,AX	     ; Start of FAR_DATA initializer storage in ROM
	MOV SI,OFFSET DGROUP:_edata     ; _edata is paragraph aligned
;	Normalize Source Pointer
	MOV AX,SI	     ; Process base of source pointer
	MOV CL,4
	SHR AX,CL	     ; Divide by 16
	MOV BX,AX
	MOV AX,DS
	ADD AX,BX
	MOV DS,AX	     ; Adjust base of source pointer
	MOV SI,0	     ; Offset of source pointer is zero
	MOV AX,DX	     ; Restore transfer count in paragraphs
loopbegin:
	CMP AX,1000H	     ; More than 64K bytes to transfer?
	JBE lastxfer	     ; No
	MOV CX,8000H	     ; Prepare to transfer 8000H words
	SUB AX,1000H	     ; 
	JMP SHORT xferbegin
lastxfer:
	MOV CL,3
	SHL AX,CL	     ; Number of WORDs = paragraph * 8
	MOV CX,AX	     ; Set up transfer count in terms of WORDs
	MOV AX,0	     ; No more to transfer
xferbegin:
REP	MOVSW		     ; Transfer WORDs from ROM to RAM
	CMP AX,0  	     ; Any more data to transfer?
	JE loopend	     ; No
	; Adjust Source and Destination pointers
	MOV BX,AX	     ; Saves transfer count
	MOV AX,DS
	ADD AX,1000H
	MOV DS,AX
	MOV AX,ES
	ADD AX,1000H
	MOV ES,AX
	MOV SI,0
	MOV DI,0
	MOV AX,BX	     ; Restores transfer count
	JMP loopbegin
loopend:

;   Clear uninitialized data area in FAR_BSS class  
; 	Transfer Count
	MOV AX,SEG _bfbss
	MOV CX,SEG _efbss
	SUB CX,AX	     ; Compute size of FAR_BSS segments in paragraphs
	JCXZ loopfend	     ; No FAR_BSS class
; 	Destination
	MOV ES,AX	     ; Destination ES:[DI]
	MOV DI,0	     ; Start of FAR_BSS class in RAM
;	Transfer Count
	MOV AX,CX
loopfbegin:
	CMP AX,1000H	     ; More than 64K bytes to initialize?
	JBE lastfxfer	     ; No
	MOV CX,8000H	     ; Prepare to transfer 8000H words
	SUB AX,1000H	     ; 
	MOV BX,AX	     ; Saves transfer count
	JMP SHORT xferfbegin
lastfxfer:
	MOV CL,3
	SHL AX,CL	     ; Number of WORDs = paragraph * 8
	MOV CX,AX	     ; Set up transfer count in terms of WORDs
	MOV AX,0	     ; No more to transfer
	MOV BX,AX	     ; Saves transfer count
xferfbegin:
	MOV AX,0
REP	STOSW		     ; Initialize WORDs to zero
	MOV AX,BX	     ; Restore transfer count
	CMP AX,0  	     ; Any more data to transfer?
	JE loopfend	     ; No
	; Adjust Destination pointers
	MOV AX,ES
	ADD AX,1000H
	MOV ES,AX
	MOV DI,0
	MOV AX,BX	     ; Restore transfer count
	JMP loopfbegin
loopfend:

;   Clear uninitialized data area in HUGE_BSS class  
; 	Transfer Count
	MOV AX,SEG _bhbss
	MOV CX,SEG _ehbss
	SUB CX,AX	     ; Compute size of HUGE_BSS segments in paragraphs
	JCXZ loophend	     ; No HUGE_BSS class
; 	Destination
	MOV ES,AX	     ; Destination ES:[DI]
	MOV DI,0	     ; Start of HUGE_BSS class in RAM
;	Transfer Count
	MOV AX,CX
loophbegin:
	CMP AX,1000H	     ; More than 64K bytes to initialize?
	JBE lasthxfer	     ; No
	MOV CX,8000H	     ; Prepare to transfer 8000H words
	SUB AX,1000H	     ; 
	MOV BX,AX	     ; Saves transfer count
	JMP SHORT xferhbegin
lasthxfer:
	MOV CL,3
	SHL AX,CL	     ; Number of WORDs = paragraph * 8
	MOV CX,AX	     ; Set up transfer count in terms of WORDs
	MOV AX,0	     ; No more to transfer
	MOV BX,AX	     ; Saves transfer count
xferhbegin:
	MOV AX,0
REP	STOSW		     ; Initialize WORDs to zero
	MOV AX,BX	     ; Restore transfer count
	CMP AX,0  	     ; Any more data to transfer?
	JE loophend	     ; No
	; Adjust Destination pointers
	MOV AX,ES
	ADD AX,1000H
	MOV ES,AX
	MOV DI,0
	MOV AX,BX	     ; Restore transfer count
	JMP loophbegin
loophend:
_init_done:
; *****************************************************************************
; You may initialize the interrupt vector table here or refer to inthand.c
; for setting up interrupt vectors in C language.                 
; *****************************************************************************
; Interrupt types 0 to 4 are dedicated internal interrupts.
; Type 0 - Divide-error
; Type 1 - Single-step
; Type 2 - Non-maskable interrupt
; Type 3 - 1-byte INT instruction or Breakpoint
; Type 4 - Overflow
; Interrupt types 5 to 31 are reserved internal interrupts.
; Interrupt types 32 to 255 are available for use.
;
; For example:
;   The interrupt handling routine for vector 32 decimal is assumed to
;   be the C function: void interrupt far int_hdlr().
;   The statement declaring code label _int_hdlr as an external far procedure
;   has to be placed outside of all SEGMENT/ENDS pairs.  
;   See the sample EXTRN statement above.  It is behind the GROUP statement.
;   Below is the sample code to initialize an entry in the vector table:
;
;   	INT_TYPE32 EQU 32*4
;	MOV AX,0
;	MOV ES,AX	;Reference base of interrupt vector table
;	MOV AX,OFFSET _int_hdlr
;	MOV ES:WORD PTR INT_TYPE32,AX   ;Offset portion of vector 32
;	MOV AX,SEG _int_hdlr
;	MOV ES:WORD PTR INT_TYPE32+2,AX ;Base portion of vector 32
;
;;; C and C++ initializer ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	MOV AX,DGROUP	     
	MOV DS,AX	     ; Setup data segment
	ASSUME DS:DGROUP
	MOV SS,AX	     ; Setup stack pointer
	MOV SP,OFFSET DGROUP:stack_top
	ASSUME SS:DGROUP
	
	mov	si,offset DGROUP:xifbegin
	mov	di,offset DGROUP:xifend
	call	farinitterm	; call the far initializers

	mov	si,offset DGROUP:xibegin
	mov	di,offset DGROUP:xiend
	call	initterm	; call the initializers

	mov	si,offset DGROUP:xifcbegin
	mov	di,offset DGROUP:xifcend
	call	farinitterm	; call far C++ constructors.	
;;; end C and C++ initializer  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Setup data and stack segment here
	MOV AX,DGROUP	     
	MOV DS,AX	     ; Setup data segment
	ASSUME DS:DGROUP
	MOV SS,AX	     ; Setup stack pointer
	MOV SP,OFFSET DGROUP:stack_top
	ASSUME SS:DGROUP
	STI		     ; Enable interrupt now
	CALL _main	     ; Pass control to C main() function
_sys_halt:
	HLT
	JMP _sys_halt
_start_	endp 
;
;***
;initterm - do a set of initializers or terminators
;
;Purpose:
;	The initializors and terminators may be written in C
;	so we are assuming C conventions (DS=SS, CLD, SI and DI preserved)
;	We go through them in reverse order 
;
;Entry:
;	SI	= start of procedure list
;	DI	= end of procedure list
;
;*******************************************************************************

IF LPROG EQ 1
farinitterm:			; large code farinitterm = initterm
ENDIF

initterm:
	cmp	si,di		; are we done?
	jae	itdone		;   yes - no more

IF LPROG EQ 1
	sub	di,4
	mov	ax,[di]
	or	ax,[di+2]
	jz	initterm	; skip null procedures
	call	dword ptr [di]
ELSE
	dec	di
	dec	di
	mov	cx,[di]
	jcxz	initterm	; skip null procedures
	call	word ptr [di]
ENDIF
	jmp	initterm	; keep looping

itdone:
	ret

IF LPROG EQ 0	; SMALL or COMPACK models only
;***
;farinitterm - do a set of far initializers or terminators
;
;Purpose:
;	The initializors and terminators may be written in C
;	so we are assuming C conventions (DS=SS, CLD, SI and DI preserved)
;	We go through them in reverse order
;
;Entry:
;	SI	= start of procedure list
;	DI	= end of procedure list
;
;Exit:
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************

farinitterm:
	cmp	si,di		; are we done?
	jae	faritdone	;   yes - no more

	sub	di,4
	mov	ax,[di]
	or	ax,[di+2]
	jz	farinitterm	; skip null procedures
	call	dword ptr [di]
	jmp	farinitterm	; keep looping

faritdone:
	ret
ENDIF

; C program exit
; Default action is to halt the processor.
	PUBLIC _exit, __exit
_exit	LABEL FAR
	MOV AX,1	; Identify label _exit.
	HLT
	JMP _exit
__exit	LABEL FAR
	MOV AX,2	; Identify label __exit.
	HLT
	JMP __exit

; amsg_exit is for other run time errors.
;
; AX	= error message number (amsg_exit only).
	PUBLIC _amsg_exit	; C6
_amsg_exit LABEL FAR
	PUBLIC __amsg_exit	; C7
__amsg_exit LABEL FAR
	nop
	HLT
	JMP _amsg_exit

	PUBLIC __flsbuf
__flsbuf LABEL FAR
	ret
; Trap for missing floating-point software.
; The floating point initialization routine (__fpmath) will call this routine 
; when one of the following conditions occurs:
; (1) 8087 floating point library (87.lib) is linked in but no 8087 coprocessor
;     is present, that is, floating point emulator library is not linked.
; (2) Floating point i/o conversions are done, but no floating-point variables
;     or expressions are used in the program.
; Default action is to halt the processor.
	PUBLIC __fptrap
__fptrap LABEL FAR
	MOV AX,3	; Identify label __fptrap.
	HLT
	JMP __fptrap

IF FLOAT NE 0
;
; VARIABLE _errno:
;
; For certain C run-time functions, when an error condition occurs within the
; function, an error code will be placed in the _errno global variable. 
; If a function sets the _errno variable upon error, its reference page will
; explicitly mention the _errno variable.
; All of the error codes are described in the Microsoft C run-time library 
; reference manual.  
; The values of these error codes are listed in the errno.h include file.
;
;
; FUNCTION matherr:
;
; You may supply your own version of matherr function in your C program.
; If you do, you can obtain a value from the type field of the exception 
; data structure which corresponds to the math error code listed in the
; math.h include file.  the Microsoft C run-time library reference 
; manual contains a detail description of the matherr fucntion and the
; math error codes.
;
; If you do not link in your own matherr function, the matherr function 
; included in the Microsoft C run-time library will be linked in.
; The function simply returns a zero value.
;
; If you link in your own version of the matherr function, it may perform
; special error handling.  if corrective action is taken and the 
; the return value should be nonzero.
;
; PROCEDURE __FF_MSGBANNER:
;
; The __FF_MSGBANNER procedure will be called when an error condition occurs
; within in a math function and certain C run-time functions.
; It writes the first part of run-time error messages to standard
; error as follows:
; '\r\nrun-time error '. 
; It is implemented as a null procedure here.
;
	PUBLIC __FF_MSGBANNER
IF LPROG EQ 0 	;SMALL OR COMPACT MODEL
__FF_MSGBANNER PROC NEAR
ELSE		;MEDIUM OR LARGE OR HUGE MODEL
__FF_MSGBANNER PROC FAR
ENDIF
	RET
__FF_MSGBANNER ENDP
;
; PROCEDURE __wrt2err:
;
; The __wrt2err procedure will be called when an error condition occurs
; within in a math function and certain C run-time functions.
; It takes a near pointer in BX (DS:BX) which points to a LSTRING which is
; to be written to standard error.  A LSTRING is a one-byte length followed
; by that many bytes for the character string (as opposed to a null-
; terminated string).
; These LSTRINGs has the form of the first character being a capital letter
; followed by four digits.  For examples, 'R6001', 'M6101', etc.  The
; meaning of these error numbers are explained in detail in the Microsoft C 
; reference manual.
; The __wrt2err procedure is implemented as a null procedure here.
;
	PUBLIC __wrt2err
IF LPROG EQ 0	;SMALL OR COMPACT MODEL
__wrt2err PROC NEAR
ELSE		;MEDIUM OR LARGE OR HUGE MODEL
__wrt2err PROC FAR
ENDIF
;	DS:BX points to the LSTRING.
	RET
__wrt2err ENDP
;
; PROCEDURE __NMSG_WRITE:
;
; The  __NMSG_WRITE procedure will be called when an error condition occurs
; within in a math function and certain C run-time functions.
; It searches the MSG segment for the address of a message string corresponding
; to the error condition.
; If a message string is found, DS:DX = string address, CX = string length.
; You may process or ignore the error message string.
; 
; The follow table lists some of the error message numbers and the message strings:
; 253  ': MATH',13,10,'- floating-point error: ',0
; 101  'invalid',13,10,0
; 102  'denormal',13,10,0
; 103  'divide by 0',13,10,0
; 104  'overflow',13,10,0
; 105  'underflow',13,10,0
; 106  'inexact',13,10,0
; 107  'unemulated',13,10,0
; 108  'square root',13,10,0
; 109  13,10,0
; 110  'stack overflow',13,10,0
; 111  'stack underflow',13,10,0
; 112  'explicitly generated',13,10,0
;
	PUBLIC __NMSG_WRITE
IF LPROG EQ 0	;SMALL OR COMPACT MODEL
__NMSG_WRITE PROC NEAR
ELSE		;MEDIUM OR LARGE OR HUGE MODEL
__NMSG_WRITE PROC FAR
ENDIF
	PUSH BP
	MOV BP,SP
	PUSH	DS
	POP	ES
IF LPROG EQ 0	;SMALL OR COMPACT MODEL
	MOV DX,WORD PTR [BP+4]	; DX = error message number
ELSE		;MEDIUM OR LARGE OR HUGE MODEL
	MOV DX,WORD PTR [BP+6]	; DX = error message number
ENDIF
	CMP	DX,253
	JE	NOTFOUND	; Skip error message no. 253,
				; But process other error message numbers
	ASSUME DS:DGROUP
	MOV	SI,OFFSET DGROUP:MSG  ; start of near messages
TLOOP:
	LODSW			; AX = current message number
	CMP	AX,DX
	JE	FOUND		; Found error message string
	INC	AX
	XCHG	AX,SI
	JZ	NOTFOUND	; At end and error message string not found 
	XCHG	DI,AX
	XOR	AX,AX
	MOV	CX,-1
	REPNE	SCASB		; Skip until 0H
	MOV	SI,DI
	JMP	TLOOP		; Try next entry
FOUND:
	XCHG	AX,SI		; SI = offset to string address
	XCHG	DX,AX		; DS:DX = string address
	MOV	DI,DX		; Determine length of message string 
	XOR	AX,AX		; String is terminated with byte 0h
	MOV	CX,-1
	REPNE	SCASB		; ES = DS already
	NOT	CX
	DEC	CX		; CX = string length
; May include user-defined code here to output error message
; DS:DX = string address, CX = string length
NOTFOUND:
	MOV SP,BP
	POP BP
	RET
__NMSG_WRITE ENDP

ENDIF	; FLOAT

;
_TEXT	ENDS

EMULATOR_TEXT SEGMENT PARA PUBLIC 'CODE'
EMULATOR_TEXT ENDS

SSI_ROMDATA SEGMENT PARA PUBLIC 'SSI_ROMINIT'
	db 'Rom Data Begin  ' ; Do not delete this string, for correct fixupp
	PUBLIC _etext
_etext 	LABEL BYTE	      ; for startup.asm backward compatibility
	PUBLIC _brdata
_brdata LABEL BYTE	; This label marks the start of initialized ROM DATA
; If you specify the ROMINIT control in the LL86 and EXE2OMF, v7.0 and up, it
; will cause LL86 and EXE2OMF to place all segments that are specified in
; ROMINIT control at this location.  The start-up routine in this file
; assumes all classes between _bfdata to _efdata and  _bdata to _edata are
; placed in ROM by the ROMINIT control and copies them to RAM at power-up.
; This segment must be PARA aligned, unless you modify the start-up code.
; We suggest the SSI_ROMINIT class be located right after the CODE class.
SSI_ROMDATA ENDS
;
	END START_	; Make sure you include the START_ symbol here.
