📄 st.asm
字号:
COMMENT ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C_thru_ROM Startup Code
Version 2.00
Copyright (C) 1988-1992 Datalight, Inc.
All Rights Reserved
This file is the Startup Code for the C_thru_ROM package.
While it is provided in source form, this file should NOT
be changed. All startup code options should be set in
the file ST.INC.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
.186
; ALPHA TEST FEATURE - NOT FOR GENERAL USE!!
; Copy all of program CODE and DATA to RAM. Typically RAMs are
; faster than ROMs so the program will run faster.
COPYCODE = 0
; define COMPILER types, this MUST be before ST.INC is included
USEASM = 0
MSC5 = 1
MSC6 = 2
MSC7 = 3
TC2 = 10
TCPP = 11
BC2 = 12
BC3 = 13
; define FLOATing point types, this MUST be before ST.INC is included
NONE = 0
INLINE = 1
EMULATED = 2
ALTERNATE = 3
; define CPU types, this MUST be before ST.INC is included
I8086 = 0
I186 = 1
I286 = 2
I386 = 3
I486 = 4
V25 = 5
V40 = 6
V53 = 7
; define BOOT METHODs, this MUST be before ST.INC is included
POWERUP = 1
BIOSEXT = 2
include .\inc\st.inc
; handle the USEASM compiler switch
IF COMPILER EQ USEASM
IFDEF ??version
IF ??version LT 0200H
COMPILER = TC2
ENDIF
IF ??version EQ 0200H
COMPILER = TCPP
ENDIF
IF ??version EQ 0205H
COMPILER = BC2
ENDIF
IF ??version EQ 0300H
COMPILER = BC3
ENDIF
ELSE
; NOTE: we should figure out MASM versions
COMPILER = MSC6
ENDIF
ENDIF
; this cannot be included until AFTER st.inc
include .\inc\macros.inc
include .\inc\am186msr.inc
; []--------------------------------------[]
; | |
; | DEFINE THE exit() CODES |
; | |
; []--------------------------------------[]
;
; 80H Return from main
; 81H NULL ptr assignment
; 82H Stack overflow
; 83H MS-DOS call
; 90H Floating Point not loaded
; 91H Divide by zero
; 92H Divide overflow
; 93H Floating Point Exception
ERR_MAINRET equ 80H ; main() has returned
ERR_NULLPTR equ 81H ; the data at DS:0 has been modified
ERR_OVERFLOW equ 82H ; the stack has overflowed
ERR_NO21 equ 83H ; INT 21H has occurred when it shouldn't
ERR_NOFLOAT equ 90H ; floating point not loaded
ERR_DIVZERO equ 91H ; divide by zero
ERR_DIVOVER equ 92H ; overflow (INTO)
ERR_FP equ 93H ; floating point exception
; []----------------------------------------------[]
; | |
; | DEFINE THE SEGMENT ORDERING |
; | |
; []----------------------------------------------[]
;
;
; CODE All program code (runs in ROM)
; PLHOLDER Placeholder in ROM to find FAR_DATA
; FAR_DATA Floating point and large arrays
; +-- DATA Initialized data
; | INITDATA (BC++ only) Global Constructors
; | EXITDATA (BC++ only) Global Destructors
;DGROUP ----| CONST (MSC only) Constant data
; | MSG (MSC only) Message data
; | BSS Unintialized data
; +-- STACK The stack
; FAR_BSS Large uninitialized arrays
; HEAP Beginning of the heap
; segment defined when booting via BIOS extension
IF BOOTMETHOD EQ BIOSEXT ; {
; ALPHA TEST CONCEPT - TRIAL BASIS
IF COPYCODE ; {
; a BIOS extension must be 1st. If copying CODE, then
; the segment BIOS_EXT must be in its own class.
BIOS_EXT SEGMENT PARA PUBLIC 'BIOS_EXT'
BIOS_EXT ENDS
RELOC_CODE SEGMENT PARA PUBLIC 'PLHOLDER'
DB "RELOC_CODE XXXX",0
RELOC_CODE ENDS
; to simplify location, the BIOS extension is in class CODE
ELSE
BIOS_EXT SEGMENT PARA PUBLIC 'CODE'
BIOS_EXT ENDS
ENDIF ; }
; segment defined when cold booting the processor
; note: program CANNOT contain BOTH a BIOS extension and
; a cold boot segment
ELSE
IF BOOTMETHOD EQ POWERUP ; {
; This segment will contain cold boot code
POWER_UP SEGMENT PARA PUBLIC 'POWER_UP'
POWER_UP ENDS
; ALPHA TEST IDEA - NOT NORMALLY USED
IF COPYCODE ; {
RELOC_CODE SEGMENT PARA PUBLIC 'PLHOLDER'
DB "RELOC_CODE DATA",0
RELOC_CODE ENDS
ENDIF ; }
; paragraph align the CODE so segment is different than POWER_UP
BEG_CODE SEGMENT PARA PUBLIC 'CODE'
BEG_CODE ENDS
ENDIF ; } powerup
ENDIF ; } biosext
; this segment is the startup code
cBegCode
; Borland C needs DGROUP to be the first fixup
IF COMPILER GE TC2
dw DGROUP
ENDIF
cEndCode
; if Microsoft C and Floating Point
IF COMPILER LT TC2
IF FLOAT
EMULATOR_TEXT SEGMENT PARA PUBLIC 'CODE'
IF COMPILER GE MSC6
public __EmDataSeg
IF FLOAT EQ ALTERNATE
__EmDataSeg dw 0
ELSE
__EmDataSeg dw EMULATOR_DATA
ENDIF
ENDIF ; MSC6
EMULATOR_TEXT ENDS
ENDIF ; Floating Point
ENDIF ; MSC
; placeholder to find initialized data in ROM
IFE COPYCODE
RELOC_DATA SEGMENT PARA PUBLIC 'PLHOLDER'
PUBLIC __alicia
__alicia DB "Alicia Gislason",0 ; to my lovely wife...
RELOC_DATA ENDS
ENDIF
; far data
_FARDATA SEGMENT PARA PUBLIC 'FAR_DATA'
db ? ; just so far_data always has something in it
_FARDATA ENDS
; Microsoft C and Floating Point (not alternate)
IF (COMPILER LT TC2) AND FLOAT AND (FLOAT NE ALTERNATE)
EMULATOR_DATA SEGMENT PARA PUBLIC 'FAR_DATA'
EMULATOR_DATA ENDS
ENDIF ; MSC FLOAT, NOT ALTERNATE
; DATA begins 1 para (16 bytes) after RDATA
cBegData
cEndData
IF FLOAT
; define a "fake" PSP so FP init can look at "environment"
DGROUP GROUP PSP
PSP SEGMENT PARA PUBLIC 'DATA'
db 2CH DUP (?)
public envseg
envseg dw seg PSP ; point to a NULL environment
PSP ENDS
ENDIF
;
; Borland Turbo C and C++
;
IF COMPILER GE TC2 ; {
IF FLOAT ; {
; add all these segments to the DATA GROUP
DGROUP GROUP _EMUSEG
; the emulator data
_EMUSEG SEGMENT WORD COMMON 'DATA'
_EMUSEG ENDS
ENDIF ; } // Floating Point
DGROUP GROUP _CVTSEG, _SCNSEG
_CVTSEG SEGMENT WORD PUBLIC 'DATA'
_CVTSEG ENDS
_SCNSEG SEGMENT WORD PUBLIC 'DATA'
_SCNSEG ENDS
ENDIF ; } // Borland/Turbo C/C++
; Used ONLY by Borland C++, these segments are defined so a
; common LOCation file can be used for both MSC and BC programs.
DGROUP GROUP _INIT_,_INITEND_,_EXIT_,_EXITEND_
_INIT_ SEGMENT WORD PUBLIC 'INITDATA'
InitStart label byte
_INIT_ ENDS
_INITEND_ SEGMENT BYTE PUBLIC 'INITDATA'
InitEnd label byte
_INITEND_ ENDS
_EXIT_ SEGMENT WORD PUBLIC 'EXITDATA'
ExitStart label byte
_EXIT_ ENDS
_EXITEND_ SEGMENT BYTE PUBLIC 'EXITDATA'
ExitEnd label byte
_EXITEND_ ENDS
; Used ONLY by Microsoft C, these segments are defined so a
; common LOCation file can be used by both MSC and BC programs.
DGROUP GROUP _CONST,MSG
_CONST SEGMENT WORD PUBLIC 'CONST'
_CONST ENDS
MSG SEGMENT WORD PUBLIC 'MSG'
MSG ENDS
DGROUP GROUP BEG_BSS
BEG_BSS SEGMENT PARA PUBLIC 'BSS'
BEG_BSS ENDS
DGROUP GROUP _STACK
_STACK SEGMENT STACK PARA 'STACK'
c_label _bss_end,word
DB STACKSIZE dup (?) ; default stack size
c_label _stack_end,word
_STACK ENDS
; FAR_BSS allows for large amounts of uninitialized data
_FARBSS SEGMENT PARA PUBLIC 'FAR_BSS'
c_label _beg_farbss,word
_FARBSS ENDS
; start of heap for malloc()
_HEAP SEGMENT PARA PUBLIC 'HEAP'
DB 16 DUP (?)
_HEAP ENDS
;[]---------------------------------------------[]
; | |
; | INTITIALIZED DATA |
; | |
;[]---------------------------------------------[]
; used only for miniature INT 21H handler
DOS_VERSION equ 0B02H
cBegData
; copyright must be at DS:0 for NULL PTR CHECK to work.
DB "Copyright (C) Datalight, 1988, 1989, 1990",0
; Display the startup code version
out1 <>
out1 <Startup Version 2.00>
; Display the chosen compiler
IF COMPILER EQ MSC5
out1 <For Microsoft C 5.0, 5.1>
ENDIF
IF COMPILER EQ MSC6
out1 <For Microsoft C 6.0>
ENDIF
IF COMPILER EQ MSC7
out1 <For Microsoft C/C++ 7.0>
ENDIF
IF COMPILER EQ TC2
out1 <For Turbo C 2.0>
ENDIF
IF COMPILER EQ TCPP
out1 <For Turbo C++ 1.0>
ENDIF
IF COMPILER EQ BC2
out1 <For Borland C/C++ 2.0>
ENDIF
IF COMPILER EQ BC3
out1 <For Borland C/C++ 3.0>
ENDIF
; Display the memory model to screen
outif memS,<Small Model>
outif memM,<Medium Model>
outif memC,<Compact Model>
outif memL,<Large Model>
outif memH,<Huge Model>
;
; C_thru_ROM Specific Data
;
;
c_public st_ver
c_public exit_status,exit_21func,exit_21addr
_st_ver DW 200H ; version 2.00 of C_thru_ROM startup code
_exit_status DW ? ; exit status error code
_exit_21func DW ? ; the INT 21H function that caused abort
_exit_21addr DD ? ; the address of the offending INT 21H
;
; Turbo C/Borland C++ Specific Data
;
;
IF COMPILER GE TC2
PUBLIC __version,_errno
IF FLOAT
IF FLOAT EQ INLINE
PUBLIC __8087
__8087 DW 0FFFFH
ELSE
PUBLIC __8087
__8087 DW 0H
ENDIF
ENDIF
__version DW DOS_VERSION ; this label is used even though
_errno DW 0 ; no DOS is present
; used by memory management
c_public _asizds, _atopsp, __brklvl
__asizds DW 8000H ; DS size (in bytes)
__atopsp DW 0 ; top of stack (heap bottom)
___brklvl DW GOFFSET _bss_end+6,DGROUP ; bottom of stack
;
; Microsoft C Specific Data
;
;
ELSE
segrec struc ; note: from MSC 5.0
sz dw ?
sg dw ?
segrec ends
; this "variable" is defined in every MSC module to force
; the linker to pull in MSC startup code. We must define
; it here so CTR startup is used instead.
PUBLIC __acrtused
__acrtused = 9876h ; can be anything
PUBLIC STKHQQ
PUBLIC __aintdiv,__fac,_errno,__doserrno,__umaskval
PUBLIC __osmajor,__osminor
PUBLIC _pspadr,_psp
c_public _atopsp
c_public _abrktb
c_public _abrktbe,_abrkp
; memory management variables
STKHQQ DW GOFFSET _bss_end+6 ; bottom of stack
__atopsp DW 0 ; top of stack (heap bottom)
__abrktb DW ? ; segment table for brkctl
DW DGROUP
DB (20-1) * (size segrec) dup (?) ; MAX segments for
__abrktbe LABEL WORD
__abrkp DW OFFSET _abrktb
__aintdiv DD 0 ; divide error interrupt vector save
__fac DQ 0 ; floating accumulator
_errno DW 0 ; initial error code
__doserrno DW 0 ; dos error #, not used (needed for ext defs)
__umaskval DW 0 ; initial umask value
; do not change the order of the following
c_label _osversion,WORD
c_label _dosvermajor,BYTE
__osmajor DB 0
c_label _dosverminor,BYTE
__osminor DB 0
_pspadr DW 0 ; psp:0 (far * to PSP segment)
IF FLOAT
_psp DW seg PSP ; psp:0 (paragraph #)
ELSE
_psp DW 0 ; psp:0 (paragraph #)
ENDIF
ENDIF ; MSC
cEndData
cBegUdata
public _heap_seg, _heap_eseg
_heap_seg dw ? ; segment of start of heap
_heap_eseg dw ? ; segment of end of heap
; places to save the INT 21H and 11H vectors (for FP init)
IF FLOAT
old21 dd ? ; for saving the old interrupt vectors
old11 dd ?
ENDIF ; FLOAT
cEndUdata
; []---------------------------------------------[]
; | |
; | THE STARTUP CODE |
; | |
; []---------------------------------------------[]
c_extrnP main ; C main function
IF USEREXIT
c_extrnP my_exit ; C or assembly exit() function
ENDIF
cBegCode
COMMENT ~
/*
Here is the real start of code. This program makes
a stack, copies data from ROM to RAM and calls main().
*/
void _astart()
~
PUBLIC __astart
__astart:
; Set up a stack
MOV AX,DGROUP
CLI
MOV SS,AX
MOV SP,GOFFSET _stack_end ; top of the stack
MOV DS,AX
; Initialize hardware
IF HARDINIT
include .\inc\HARDINIT.INC
; Set up the stack again in case user changed it
MOV AX,DGROUP
CLI
MOV SS,AX
MOV SP,GOFFSET _stack_end
ENDIF
; This section relocates initialized data (and CODE if requested)
; from ROM into RAM. The mechanism requires cooperation between
; the startup code (here) and the location (.LOC) file for this
; program. See the Startup Code and Locator chapters.
;
IF COPYCODE
; Relocate CODE and DATA from ROM to RAM
CLD
; get start of move into DS and ES
MOV AX, SEG RELOC_CODE ; The RELOC_CODE segment begins
INC AX ; one paragraph before CODE in
MOV DS, AX ; ROM. Any references directly
MOV AX, SEG _TEXT ; to CODE would yield a RAM address.
MOV ES, AX
; determine length to move in paras
MOV DX, SEG BEG_BSS ; move everything from CODE to
SUB DX, SEG _TEXT ; the end of initialized data
move_again:
CMP DX, 0 ; DX contains paragraphs to move...
JZ done_move
CMP DX, 0F00H ; we can only move 64K at a time
JA big_move
MOV CX, DX
JMP SHORT small_move
big_move:
MOV CX, 0F00H ; F00H paragraphs = F000H bytes = 60K
small_move:
MOV BX, CX ; save paragraphs in BX
SHL CX, 1 ; paragraphs * 16 = bytes
SHL CX, 1
SHL CX, 1
SHL CX, 1 ; move CX bytes
XOR SI, SI ; the move always starts on a paragraph boundary
XOR DI, DI ; zero both SI and DI
REP MOVSB ; move DS:SI to ES:DI
; update counters and segments
SUB DX, BX ; BX contains paragraphs that were moved
MOV AX, ES
ADD AX, BX ; increment ES by the same amount
MOV ES, AX
MOV AX, DS
ADD AX, BX ; increment DS by the same amount
MOV DS, AX
JMP SHORT move_again
done_move:
; jump to the RAM address
MOV AX, SEG _TEXT
PUSH AX
MOV AX, OFFSET _TEXT:done_copy
PUSH AX
RETF
done_copy:
ELSE
; Relocate initialized far data from ROM to RAM
CLD
MOV AX, SEG RELOC_DATA ; The RELOC_DATA segment begins
INC AX ; one paragraph before FAR_DATA
MOV DS, AX ; in ROM. Any references directly
MOV AX, SEG _FARDATA ; to FAR_DATA would yield RAM address.
MOV ES, AX ; DS:0 now points to FAR_DATA
; ES:0 now points to RAM address
; for FAR_DATA
; determine length of move in paras
MOV DX, SEG BEG_BSS
SUB DX, SEG _FARDATA
move_again:
CMP DX, 0 ; DX contains paragraphs to move...
JZ done_move
CMP DX, 0F00H ; we can only move 64K at a time
JA big_move
MOV CX, DX
JMP SHORT small_move
big_move:
MOV CX, 0F00H ; F00H paragraphs = F000H bytes = 60K
small_move:
MOV BX, CX ; save paragraphs in BX
SHL CX, 1 ; paragraphs * 16 = bytes
SHL CX, 1
SHL CX, 1
SHL CX, 1 ; move CX bytes
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -