⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cstart.htm

📁 这是一个TC2.0下的对X86平台进行ROM运行的开发工具,包括源代码和文档说明。包括重写了TC的启动代码和一个代码定位工具。
💻 HTM
📖 第 1 页 / 共 3 页
字号:
</PRE>
The purpose of the BSSEND segment is to provide a means of 
determining how long _BSS is. As BSSEND occurs after _BSS, 
then zeroing everything from _BSS to _BSSEND will ensure that 
all of _BSS is zeroed out!
<P>
<HR>
<B>INITIALIZATION OF THE _DATA SEGMENT</B><BR>
The _DATA segment must be copied to RAM before execution of _main() 
begins.
<PRE>
_DATA           segment para public 'DATA'
_DATA           ends

_DATAEND                segment para public 'DATAEND'
		public enddata
enddata         label   byte
_DATAEND                ends

DGROUP  group   _DATA, _DATAEND, _BSS, _BSSEND

_TEXT           segment byte public 'CODE'
_TEXT           ends

_TEXTEND                segment para public 'CODEEND'
		public  codeend
		db  16  dup (?)
codeend         label   byte
_TEXTEND                ends

CGROUP  group   _TEXT, _TEXTEND

_TEXT           segment
		assume CS:_TEXT, DS:DGROUP, ES:DGROUP, SS:_STACK
start:          cli                                     ; disable interrupts
		...                                     ; initialize _STACK
		...                                     ; initialise _BSS
		mov     ax, seg DGROUP
		mov     es, ax                          ; point ES to _DATA
		mov     cx, offset DGROUP:enddata
		mov     si, 0
		mov     di, 0
		assume ds:CGROUP:_TEXTEND
		mov     ax, seg _TEXTEND:codeend
		inc     ax
		mov     ds, ax                          ; point DS to _CONST
		rep     movsb                           ; copy _CONST to _DATA
		push    es                              ; point DS to _DATA
		pop     ds
		sti                                     ; enable interrupts
		call    _main
		jmp     start
_TEXT           ends


</PRE>
The option chosen by the <A HREF="sw/turboc/locate.exe">LOCATE</A> utility 
is to duplicate the _DATA segment into a segment called _CONST. 
This is then attached to the end of the _CODE segment and stored in EPROM. 
<P>
The startup code then copies this _CONST segment to the address reserved in 
RAM for _DATA. It figures out the start address of the _CONST segment using 
the dummy _TEXTEND segment, and the length of the _DATA segment using the 
dummy segment _DATAEND.
<P>
<HR>
<B>ROMCODE AND THE TURBO C COMPILER</B><BR>
A sample startup code, written in assembler is
<PRE>
<A HREF="sw/turboc/tcf600.asm">; tcstart.asm,  for f600:0000</A>
extrn           _main:far

_text           segment byte    public 'CODE'
_text           ends
_textend                segment para    public 'CODEEND'
_textend                ends
_data           segment para    public 'DATA'
_data           ends
_dataend                segment para public 'DATAEND'
_dataend                ends
_bss            segment para    public 'BSS'
_bss            ends
_bssend                 segment byte    public 'BSSEND'
_bssend         ends
_stack          segment para    stack  'STACK'
_stack          ends
DGROUP          group   _DATA, _DATAEND, _BSS, _BSSEND
CGROUP          group   _TEXT, _TEXTEND

_TEXT           segment
		assume CS:CGROUP, DS:DGROUP, ES:DGROUP, SS:_STACK
start:          cli                ; disable interrupts
		mov     ax, _STACK ; initialize stack
		mov     ss, ax
		mov     ax, offset stackend
		mov     sp, ax  
		mov     ax, _BSS
		mov     es, ax
		mov     cx, offset DGROUP:enddata       ; calculate length of _BSS      
		mov     ax, offset DGROUP:endbss
		sub     ax, cx
		mov     cx, ax
		mov     di, 0
		mov     ax, 0
		rep     stosb   ; write to ES:DI
		mov     ax, seg DGROUP
		mov     es, ax  ; point ES to _DATA
		mov     cx, offset DGROUP:enddata
		mov     si, 0
		mov     di, 0
		assume ds:CGROUP:_TEXTEND
		mov     ax, seg _TEXTEND:codeend
		inc     ax
		mov     ds, ax  ; point DS to _CONST
		rep     movsb   ; copy _CONST to _DATA
		push    es      ; point DS to _DATA
		pop     ds
		sti             ; enable interrupts
		call    _main
		jmp     start
_TEXT           ends

_TEXTEND                segment
		public  codeend
		db  16  dup  (?)
codeend         label   byte
_TEXTEND                ends
_STACK          segment
		db      1024 dup ('STACK');
stackend                label   word
_STACK          ends
_DATAEND                segment
		public enddata
enddata         label   byte
_DATAEND                ends
_BSSEND         segment
		public  endbss
endbss          label   byte
_BSSEND         ends
end

</PRE>
The C source is compiled using the command line version of the 
compiler (tcc), then linked (using tlink) with the startup code 
and any user supplied libraries or object files 
(<A HREF="sw/turboc/doit.bat">doit.bat</A>).
<PRE>
	tasm /mx tcstart
	tasm /mx <A HREF="sw/turboc/tclib.asm">tclib</A>
	tcc -a- -c -f- -G- -K -B -ml -M -N- -O- -r- -v- -y- -Z- -S -O- %1.c
	tlink /m tcstart %1 tclib, %1, %1
	locate %1
	<A HREF="sw/turboc/hexbin2.exe">hexbin2</A>  %1.hex  %1.bin  i  f600

</PRE>
The LOCATE utility (developed by R Naro, Dr Dobbs, Dec 1987) is 
then used to process the .EXE file and assign physical addresses 
to each of the segments. This creates a .HEX file which is then 
used to burn an EPROM. The locate utility uses a special configuration 
file which specifies where the segments are to be located.
<P>
<HR>
<B>ROMCODE AND THE IC86 INTEL C COMPILER</B><BR>
The ic86 compiler generates the following segments using a LARGE 
memory model,
<PRE>        
	filename_CODE
	filename_DATA
	filename_CONST          ; if using the RAM directive
	STACK

</PRE>
It does not prefix variable names, segments or function names with 
an underscore. If the compiler option ROM is specified, all constants 
and string literals are placed into the filename_CODE segment.
<P>
The startup code declares the segments which are used to arrange 
them in the correct order in physical memory. Initialized constants 
are placed in the FILENAME_CONST segment (when using RAM, else they 
are placed in the filename_CODE if using the ROM directive).
<P>
All other data is placed into FILENAME_DATA. This creates a small 
problem in referencing data, so it is best to local variables and 
pass them as parameters to functions which access them (ie, do 
not use GLOBAL variables!). 
<P>
Initialized global variables should be avoided if designing 
programs for ROM. The compiler generates an error if it encounters 
initialized data, eg,
<PRE>        
	static int y = 7;
	static int z;
</PRE>
compiled with the command line
<PRE>        
	ic86 file.c LARGE ROM
</PRE>
will generate an error for the initialization of the variable y. 
As the DATA segment will be placed in RAM, any initial values will 
be lost.
<P>
The compiler also inserts code to initialize the DS register to 
the FILENAME_DATA segment. The following code will be used with 
the IC86 compiler.
<PRE>
<A HREF="sw/intel/c86start.asm">; c86start.asm</A>
name    c86start

extrn           main : far

STACK           segment para stack 'STACK'
		public top
		db      1024 dup ('STACK')
top             label   word
STACK           ends

CODE            segment byte public 'CODE'
		assume  cs:CODE, SS:STACK
start           proc    far
entry:          cli
		mov     ax, STACK
		mov     ss, ax
		mov     ax, offset top
		mov     sp, ax
		sti
		call    main
		jmp     entry
start           endp
CODE            ends
end

</PRE>
The command line sequence to generate the file is,
<PRE>
	asm86           c86start.asm
	ic86            <A HREF="sw/intel/test.c">test.c</A> LARGE
	link86          c86start.obj,test.obj,c86clib.obj to test.lnk nobind
	loc86           test.lnk order(classes(stack,data,code)) &amp;
	&gt;&gt; order(segments(STACK,TEST_DATA,CODE,TEST_CODE)) &amp;
	&gt;&gt; ad(sm(stack(10000h),test_data(20000h))),(code(0f6000h)))
	oh86    test to test.hex

</PRE>
The segment maps look like,
<PRE> 
C Program                       c86start
+---------+                     +---------+
|         |FILENAME_CODE        |+++++++++|STACK
|         |                     |+++++++++|
|         |                     |+++++++++|
+---------+                     +---------+
|         |FILENAME_DATA        |/////////|CODE
|         |                     |/////////|
+---------+                     +---------+
|+++++++++|STACK
+---------+

</PRE>
Combined segments after linking and locating are,
<PRE>
+---------+
|+++++++++|STACK (10000h)
|+++++++++|
|+++++++++|
+---------+
|         |FILENAME_DATA (20000h)
|         |
+---------+
|         |
|         |
+---------+
|/////////|CODE (0F6000h)
|/////////|
+---------+
|         |FILENAME_CODE
|         |
|         |
+---------+
+---------+


</PRE>
<P>
<HR>
<B>GENERATING ROMCODE FOR PC/XT AT F600:0000 USING TURBO-C</B><BR>
There is an empty ROM slot on some PC/XT compatibles. This slot is 
normally used for BASIC on IBM machines. It is memory mapped to 
segment 0F600h. Using this ROM space has the following advantages,
<UL>
<LI>no memory board required
<LI>can use BIOS routines for keyboard, video, disk etc
<LI>simple to use
</UL>
<P>
When the PC is powered up, it first attempts to boot from floppy 
disk. If this is unsuccessful, it reads the keyboard then generates 
an int18h instruction. This normally performs the following instruction,
<PRE>
	JMP     F600:0000

</PRE>
However, generating code to fit into this empty space requires 
special libraries or run time routines. Compilers like TC and 
MSC have libraries which use DOS in order to perform many functions. 
Since our turnkey system does not have DOS loaded, any systems we 
design using these libraries will certainly result in a system crash.
<P>
To overcome this, we shall design our own library of routines which 
emulate functions found in TC. These routines will look like 
functions in C, but will be written in assembler. First, lets look 
at creating a header file for these calls.
<P>
<PRE>
<A HREF="sw/turboc/crom.h">
/* CROM.H, designed by SE2, 1990 for EMBEDDED CODE */</A>

struct eightbit
{
   unsigned char al, ah, bl, bh, cl, ch, dl, dh;
};

struct sixteenbit
{
   unsigned int ax, bx, cx, dx, si, di, cflag;
};

union REGS
{
   struct sixteenbit x;
   struct eightbit   h;
};

/* function prototypes follow */
extern void outportb( unsigned int, char);
extern char inportb( unsigned int );
extern void int86( int, union REGS *, union REGS * );
extern void enable( void );
extern void disable( void );
extern void setvect( int, void (*ptr)( void ) );

</PRE>
The _int86 call provides a method of interfacing to the existing 
ROM BIOS routines, which are accessed via software interrupt calls.
<P>
The library code, stored in TCLIB.ASM, looks like,
<PRE>
<A HREF="sw/turboc/tclib.asm">
; TCLIB.ASM, library routine for int86() calls from EMBEDDED CODE</A>
; designed by SE2, 1990
; works with CROM.H
; turboc code must be compiled using 
; tcc -a- -c -f- -G- -K -B -ml -M -N- -O- -r- -v- -y- -Z- -S -O- %1.c


public  _enable
public  _disable
public  _setvect
public  _int86
public  _inportb
public  _outportb

CODE    segment para PUBLIC 'CODE'
	assume  cs:CODE
	name    tclib

; void enable( void ) ;
; enable interrupts
_enable proc    far
	cli
	ret
_enable endp

; void disable( void );
; disable interrupts
_disable        proc    far
	sti
	ret
_disable        endp

; void setvect( int vetcnumber, void (*ptr)( void ) );
; set interrupt vector to function code
_setvect   proc far
	   push bp              ;acess local vars inside functions
	   mov  bp,sp           ;use bp to acess passed parameters
	   push ax
	   push bx
	   push dx
	   push es
	   mov  al, byte ptr [bp+6]  ; int number
	   mov  ah, 0
	   rol  ax, 1
	   rol  ax, 1
	   mov  bx, ax
	   xor  ax, ax
	   mov  es, ax
	   mov  dx, [bp+10]           ; segment
	   mov  es:[bx+2], dx
	   mov  dx, [bp+8]           ; offset
	   mov  es:[bx], dx
	   pop  es
	   pop  dx
	   pop  bx
	   pop  ax
	   pop  bp
	   ret
_setvect   endp

; void int86( int intnumber, union REGS *, union REGS *);
_int86  proc    far
	push    bp              ;acess local vars inside functions

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -