Figure 2

Sample Microsoft C Start-Up Routine for Embedded Applications

	NAME STARTUP_CODE
; THIS IS A SAMPLE START-UP PROGRAM FOR AN EMBEDDED SYSTEM.
; THE MEMORY LAYOUT CONFORMS TO THE NAMING CONVENTION USED 
; IN MICROSOFT C, VERSION 4.X AND 5.X.
; THIS ASSEMBLY FILE SHOULD BE ASSEMBLED USING MICROSOFT 
; MASM ASSEMBLER USING THE FOLLOWING COMMAND, ASSUMING THIS
; FILE IS CALLED STARTUP.ASM:
; >MASM STARTUP/MX,STARTUP,STARTUP,NUL
; THE /MX OPTION IS USED TO PRESERVE LOWER-CASE IN PUBLIC
; AND EXTERNAL NAMES.
;
;  SETUP OF SEGMENT CLASSES IN MICROSOFT C 5.X PROGRAMS.
;
;  HIGH ADDRESS
;    -		-------------
;    |		|'BOOTSTRAP'|
;    |		-------------
;    |		:           :
;    |		:           :
;    R		-------------  ---THESE TWO CLASSES ARE TO BE
;    O		| 'CONST'   |  ^    COPIED TO THEIR RAM
;    M		-------------  |    LOCATIONS AT POWER-UP
;    |		| 'DATA'    |  v
;    |		------------- <---ROMCODE_END SEGMENT
;    |		| 'CODE'    |
;    -		------------- <---ROMCODE_BEG SEGMENT
;     		:           :
;     		:           :
;    -		------------- <---UDATA_END SEGMENT
;    |		| 'STACK'   |
;    |		-------------
;    |		| 'BSS'     |   
;    |		------------- <---IDATA_END & UDATA_BEG
;    |		| 'CONST'   |  ^    SEGMENTS
;    R		-------------  |--THESE TWO CLASSES ARE TO BE ;    A		| 'DATA'    |  v    INITIALIZED BY START-UP 
;    M		------------- <--   ROUTINE AT POWER-UP
;    |		:           :   |
;    |		:           :   |-IDATA_BEG SEGMENT
;    |		-------------
;    |		| 'INT_PTR' |
;    -		-------------
;  LOW ADDRESS
;
; CHOOSE THE MEMORY MODEL BY SETTING THE APPROPRIATE LABEL 
; TO 1.
;
SMALL		EQU	0
COMPACT	EQU	0
MEDIUM	EQU	0
LARGE		EQU	1
HUGE		EQU	0
STACK_SIZE	EQU	400H	; RESERVE 1K WORD OF STACK OR ANY SIZE YOU WANT
__acrtused	EQU	1	; IT IS USED TO SATISFY THE EXTERNAL REFERENCE
				; FOUND IN EVERY OBJECT FILE GENERATED
				; BY THE MICROSOFT C COMPILER, VER 5.X
  PUBLIC  __acrtused	; THE SYMBOL HAS TO BE IN LOWER-CASE

DGROUP GROUP IDATA_BEG,_DATA,CONST,IDATA_END,UDATA_BEG,_BSS,STACK,UDATA_END

;THIS SEGMENT MARKS THE BEGINNING OF ROM CODE
ROMCODE_BEG SEGMENT PARA 'ROMCODE_BEG'
ROMCODE_BEG ENDS

IF SMALL OR COMPACT
_TEXT SEGMENT BYTE PUBLIC 'CODE'
	EXTRN	_main:NEAR	;C main()
ASSUME  CS:_TEXT
ENDIF
IF MEDIUM OR LARGE OR HUGE
	EXTRN	_main:FAR	;C main()
STARTUP_TEXT SEGMENT BYTE PUBLIC 'CODE'
ASSUME  CS:STARTUP_TEXT
ENDIF
	ASSUME DS:DGROUP, SS:DGROUP
	PUBLIC START
START:
START_I2ICE LABEL BYTE    ; ADDRESS LABEL FOR INTEL I2ICE
	CLI
	CLD
; ************************************************************
; *** YOUR CODE HERE TO DO HARDWARE INITIALIZATION
;     AND RAM CHECK ***
************************************************************
        PUBLIC INIT_RAM_DATA
INIT_RAM_DATA:
INIT_RAM_DATA_I2ICE LABEL BYTE     ; ADDRESS LABEL FOR INTEL
							; I2ICE
; *** TRANSFER INITIALIZATION DATA FROM ROM TO RAM ***
; COMPUTE THE SIZE OF 'DATA' AND 'CONST' CLASS IN NO. OF PARAGRAPHS:

	MOV AX,SEG IDATA_END ; FRAME NO. OF IDATA_END SEGMENT
 			     ;   = END OF 'CONST' CLASS IN RAM
	MOV BX,SEG IDATA_BEG ; FRAME NO. OF IDATA_BEG SEGMENT
			     ;   = START OF 'DATA' CLASS IN RAM
	SUB AX,BX	     ; AX = SIZE OF 'DATA' & 'CONST' CLASSES
	MOV CL,3	     ; SET UP TO MULTIPLE BY 8
	SHL AX,CL	     ; COMPUTE NO. OF WORDS TO BE TRANSFERRED
	MOV CX,AX	     ; TRANSFER COUNTER
	JCXZ NO_IDATA_DATA

; OBTAIN THE FRAME NO. OF 'DATA' CLASS PLACED IN ROM

	MOV AX,SEG ROMCODE_END ; FRAME NO. OF ROMCODE_END SEGMENT
			     ; = BEGINNING OF 'DATA' CLASS IN ROM
	MOV DS,AX	     ; SOURCE STRING
	MOV SI,0

; OBTAIN THE FRAME NO. OF 'DATA' CLASS LOCATED IN RUN-TIME RAM SPACE

	MOV AX,SEG IDATA_BEG ; FRAME NO. OF IDATA_BEG SEGMENT
			     ; = BEGINNING OF 'DATA' CLASS IN RAM
	MOV ES,AX	     ; DESTINATION STRING
	MOV DI,0

; INITIALIZE THE 'DATA' AND 'CONST' CLASSES IN 
; RUN-TIME RAM SPACE

REP	MOVSW			; BEGIN WORD TRANSFER
        PUBLIC NO_IDATA_DATA
NO_IDATA_DATA:
NO_IDATA_DATA_I2ICE LABEL BYTE	; ADDRESS LABEL FOR 
							; INTEL I2ICE

; *** CLEAR UNINITIALIZED DATA ***
; COMPUTE THE SIZE OF 'BSS' & 'STACK' CLASSES IN NO. OF 
; PARAGRAPHS:

	MOV AX,SEG UDATA_END ; FRAME NO. OF UDATA_END SEGMENT
			     ;   = END OF 'STACK' CLASS IN RAM
	MOV BX,SEG UDATA_BEG ; FRAME NO. OF UDATA_BEG SEGMENT
			     ;   = START OF 'BSS' CLASS IN RAM
	SUB AX,BX	     ; AX = SIZE IN PARAGRAPHS
	MOV CL,3	     ; SET UP TO MULTIPLE BY 8
	SHL AX,CL	     ; COMPUTE NO. OF WORDS TO BE INITIALIZED
	MOV CX,AX	     ; SETUP COUNTER
	JCXZ NO_UDATA
	MOV ES,BX	     ; SETUP DESTINATION POINTER
	MOV DI,0
	MOV AX,0	     ; INITIALIZE TO 0
REP	STOSW
        PUBLIC NO_UDATA
NO_UDATA:
NO_UDATA_I2ICE LABEL BYTE          ; ADDRESS LABEL FOR INTEL I2ICE

; *** SETUP DATA AND STACK SEGMENT ***

	MOV AX,DGROUP	     
	MOV DS,AX	     ; SETUP DATA SEGMENT
	MOV SS,AX	     ; SETUP STACK POINTER
	MOV SP,OFFSET DGROUP:STACK_TOP
	STI		     ; ENABLE INTERRUPT NOW
	JMP _main	     ; ENTER C main() FUNCTION
	HLT
IF SMALL OR COMPACT
_TEXT	ENDS
ENDIF
IF MEDIUM OR LARGE OR HUGE
STARTUP_TEXT	ENDS
ENDIF

;THIS SEGMENT MARKS THE END OF ROM CODE
ROMCODE_END SEGMENT PARA 'ROMCODE_END'
ROMCODE_END ENDS

; *** THE FOLLOWING SEGMENTS ARE ALL LOCATED IN RAM ***

INT_PTR SEGMENT AT 0H		;'INT_PTR'
;INTERRUPT POINTER TABLE, LOCATE AT 0H IN RAM.
	PUBLIC TYPE_0,TYPE_1,TYPE_2,TYPE_3,TYPE_4,TYPE_32
TYPE_0	DD  ?	;DIVIDE-ERROR
TYPE_1	DD  ?	;SINGLE-STEP
TYPE_2	DD  ?	;NON-MASKABLE INTERRUPT
TYPE_3	DD  ?	;BREAKPOINT
TYPE_4	DD  ?	;OVERFLOW
;SKIP INTEL RESERVED VECTORS
	ORG	32 * 4
TYPE_32	DD  ?	;MAY PLACE YOUR VECTORS HERE
;MORE INTERRUPT VECTORS 
INT_PTR	ENDS

; THIS SEGMENT MARKS THE BEGINNING OF DGROUP AND INITIALIZED DATA IN RAM
IDATA_BEG SEGMENT PARA PUBLIC 'IDATA_BEG'
IDATA_BEG ENDS

_DATA SEGMENT WORD PUBLIC 'DATA'
_DATA ENDS

CONST SEGMENT WORD PUBLIC 'CONST'
CONST ENDS

; THIS SEGMENT MARKS THE END OF INITIALIZED DATA IN RAM
IDATA_END SEGMENT PARA PUBLIC 'IDATA_END'
IDATA_END ENDS

; THIS SEGMENT MARKS BEGINNING OF UNINITIALIZED DATA IN RAM
UDATA_BEG SEGMENT PARA PUBLIC 'UDATA_BEG'
UDATA_BEG ENDS

_BSS	SEGMENT WORD PUBLIC 'BSS'
_BSS	ENDS

STACK	SEGMENT PARA STACK 'STACK'
	DW STACK_SIZE DUP (?)
STACK_TOP LABEL WORD
STACK	ENDS

; THIS SEGMENT MARKS THE END OF UNINITIALIZED DATA IN RAM
UDATA_END SEGMENT PARA PUBLIC 'UDATA_END'
UDATA_END ENDS

; THIS SEGMENT CONTAINS BOOTSTRAP CODE AT HARDWARE RESET OR ; POWER-UP
; FAR JUMP TO PROGRAM START, LOCATE AT FFFF0H IN ROM.
BOOTSTRAP SEGMENT AT 0FFFFH 	;'BOOTSTRAP'
	JMP FAR PTR START
BOOTSTRAP ENDS
	END START








Extra Figure (not used in article)

Example of a Locator Map File


REX 8086/8087/8088/80186 OBJECT	CODE LOCATER, V5.0
TIME:  14:55:23	08-10-1988

INPUT FILES: SAMPLE.LNK
OUTPUT FILE: SAMPLE.ABS
CONTROLS SPECIFIED IN INVOCATION COMMAND:
  ORDER(CLASSES(IDATA_BEG,DATA,CONST,IDATA_END,	
		UDATA_BEG,BSS,STACK,FAR_BSS,UDATA_END, 
		DEBSYM,DEBTYP, 
		ROMCODE_BEG,CODE,ROMCODE_END)) 
  ADDRESSES(CLASSES(IDATA_BEG(200H), 
		    DEBSYM(20000H), 
		    ROMCODE_BEG(0E0000H))) 
  NOINITCODE

SYMBOL TABLE OF	MODULE	startup
BASE	OFFSET TYPE SYMBOL		BASE	OFFSET TYPE SYMBOL
E000H	0002H  PUB  INIT_RAM_DATA	E000H	0024H  PUB  NO_IDATA_DATA
E000H	003EH  PUB  NO_UDATA		E000H	0000H  PUB  START
0000H	0000H  PUB  TYPE_0		0000H	0004H  PUB  TYPE_1
0000H	0008H  PUB  TYPE_2		0000H	000CH  PUB  TYPE_3
0000H	0080H  PUB  TYPE_32		0000H	0010H  PUB  TYPE_4
0000H	0001H  PUB  __acrtused		0020H	0008H  PUB  _count
0020H	0000H  PUB  _in_ptr		E005H	0000H  PUB  _main
0020H	0004H  PUB  _out_ptr		00A1H	0080H  PUB  _picmask
E005H	0086H  PUB  _process_data	00A1H	0000H  PUB  _ring_buf
E005H	0092H  PUB  _sio_handler

MODULE	= startup
BASE	OFFSET TYPE SYMBOL		BASE	OFFSET TYPE SYMBOL
E000H	0000H  LIN  77			E000H	0001H  LIN  78
E000H	0002H  LIN  88			E000H	0005H  LIN  90
E000H	0008H  LIN  92			E000H	000AH  LIN  93
E000H	000CH  LIN  94			E000H	000EH  LIN  95
E000H	0010H  LIN  96			E000H	0012H  LIN  100
E000H	0015H  LIN  102			E000H	0017H  LIN  103
E000H	001AH  LIN  107			E000H	001DH  LIN  109
E000H	001FH  LIN  110			E000H	0022H  LIN  114
E000H	0024H  LIN  122			E000H	0027H  LIN  124
E000H	002AH  LIN  126			E000H	002CH  LIN  127
E000H	002EH  LIN  128			E000H	0030H  LIN  129
E000H	0032H  LIN  130			E000H	0034H  LIN  131
E000H	0036H  LIN  132			E000H	0039H  LIN  133
E000H	003CH  LIN  134			E000H	003EH  LIN  141
E000H	0041H  LIN  142			E000H	0043H  LIN  143
E000H	0045H  LIN  144			E000H	0048H  LIN  145
E000H	0049H  LIN  146			E000H	004EH  LIN  147
FFFFH	0000H  LIN  208

MODULE	= main
BASE	OFFSET TYPE SYMBOL		BASE	OFFSET TYPE SYMBOL
E005H	0000H  LIN  27			E005H	0018H  LIN  28
E005H	001FH  LIN  30			E005H	002FH  LIN  31
E005H	0047H  LIN  32			E005H	004BH  LIN  33
E005H	0065H  LIN  34			E005H	006FH  LIN  35
E005H	0083H  LIN  37			E005H	0086H  LIN  41
E005H	0089H  LIN  43			E005H	0090H  LIN  44
E005H	0092H  LIN  47			E005H	00A4H  LIN  48
E005H	00A5H  LIN  49			E005H	00AEH  LIN  50
E005H	00C8H  LIN  51			E005H	00D2H  LIN  52
E005H	00DAH  LIN  53			E005H	00DEH  LIN  54
E005H	00E3H  LIN  55

MEMORY MAP OF MODULE startup
MODULE START ADDRESS PARAGRAPH = E000H	OFFSET = 0000H

SEGMENT	MAP
START	  STOP	   LENGTH ALIGN	NAME		 CLASS		  OVERLAY
00000H	 00083H	    0084H   A	INT_PTR				  
00200H	 00200H	    0000H   G	IDATA_BEG	 IDATA_BEG	  
00200H	 00209H	    000AH   W	_DATA		 DATA		  
0020AH	 0020BH	    0002H   W	CONST		 CONST		  
00210H	 00210H	    0000H   G	IDATA_END	 IDATA_END	  
00210H	 00210H	    0000H   G	UDATA_BEG	 UDATA_BEG	  
00210H	 00210H	    0000H   W	_BSS		 BSS		  
00210H	 00A0FH	    0800H   G	STACK		 STACK		  
00A10H	 00A90H	    0081H   G	FAR_BSS_1	 FAR_BSS	  
00AA0H	 00AA0H	    0000H   G	UDATA_END	 UDATA_END	  
20000H	 20074H	    0075H   G	$$SYMBOLS	 DEBSYM		  
20075H	 200F6H	    0082H   B	$$SYMBOLS	 DEBSYM		  
20100H	 2010BH	    000CH   G	$$TYPES		 DEBTYP		  
2010CH	 20197H	    008CH   B	$$TYPES		 DEBTYP		  
E0000H	 E0000H	    0000H   G	ROMCODE_BEG	 ROMCODE_BEG	  
E0000H	 E004EH	    004FH   B	STARTUP_TEXT	 CODE		  
E0050H	 E013DH	    00EEH   W	MAIN_TEXT	 CODE		  
E0140H	 E0140H	    0000H   G	ROMCODE_END	 ROMCODE_END	  
FFFF0H	 FFFF4H	    0005H   A	BOOTSTRAP			  

GROUP MAP
ADDRESS	 GROUP OR SEGMENT NAME
00200H	 DGROUP
	  IDATA_BEG\\IDATA_BEG\\
	  _DATA\\DATA\\
	  CONST\\CONST\\
	  IDATA_END\\IDATA_END\\
	  UDATA_BEG\\UDATA_BEG\\
	  _BSS\\BSS\\
	  STACK\\STACK\\
	  UDATA_END\\UDATA_END\\





Figure 6

C Source for functions that implement a Ring Buffer


/* To generate in-line 8086 opcodes for intrinsic functions,
   such as inp, outp, and _enable, specify /Oi in C compiler */
#define RING_BUF_SIZ 128
#define PICIER 0xC2
#define PICEOI 0xC0
#define IRQDIS 0x20
#define EOI 0x20
#define SIOPORT 0x10
#define OUTPORT 0x12
#define enable_sio() picmask = inp(PICIER); \\
                     picmask &= (~IRQDIS); \\
                     outp(PICIER, picmask);
#define disable_sio() picmask = inp(PICIER); \\
                      picmask |= IRQDIS; \\
                      outp(PICIER, picmask);
char ring_buf[RING_BUF_SIZ];
char *in_ptr = ring_buf;
char *out_ptr = ring_buf;
int count = 0;
char picmask;
void process_data(char);

main()
{
    while(1)
    {
        enable_sio();	/* enable serial i/o */
    	if (count > 0)
    	{
    	    process_data(*out_ptr);
    	    disable_sio();	/* disable serial i/o */
    	    count--;
    	    if (out_ptr++ == ring_buf + RING_BUF_SIZ)
    		out_ptr = ring_buf;	/* ring buffer */
    	    enable_sio();	/* enable serial i/o */
    	}
    }
}

void process_data(c)
char c;
{
    outp(OUTPORT, c);
}

void interrupt far sio_handler()
{
    _enable();	/* enable higher order interrupt */
    *in_ptr = inp(SIOPORT);
    if (in_ptr++ == ring_buf + RING_BUF_SIZ)
    	in_ptr = ring_buf;
    if (count != RING_BUF_SIZ)
    	count++;
    outp(PICEOI, EOI);	/* reset interrupt */
}

