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

📄 pcrom.htm

📁 这是一个TC2.0下的对X86平台进行ROM运行的开发工具,包括源代码和文档说明。包括重写了TC的启动代码和一个代码定位工具。
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<!doctype html public "-//IETF//DTD HTML//EN">
<HTML>
<HEAD>
<TITLE>EMBEDDED SYSTEMS</TITLE>
<META NAME="GENERATOR" CONTENT="Internet Assistant for Word 1.00">
<META NAME="AUTHOR" CONTENT="Brian Brown">
</HEAD>

<BODY>
<CENTER><H2>EMBEDDED CODE GENERATION FOR IBM-PCS</H2></CENTER>
<CENTER><B>Copyright Brian Brown, 1989-1995</B></CENTER>
<A HREF="default.htm"><IMG SRC="images/menu.gif" ALT="menu"></A>
<HR>
The introduction of low cost PC clones has popularized their use 
for tasks other than personal computing. These PC's offer 
advantages such as 
<UL>
<LI>speed 
<LI>memory
<LI>low cost 
<LI>quick development time over traditional strategies for embedded<br> 
    control systems.
</UL>
Using PC's in embedded systems does pose significant problems however. 
The software generated for the target system adheres to two basic principles.
<P>
First, it is normally standalone, in that the operating system is 
not present.
<P>
Secondly, the target software is position dependent, residing within 
physical memory at specific address locations. This second requirement 
also means that any static data required by the program must also be 
stored in non-volatile memory (Eprom) and copied to RAM before the 
main program starts.
<P>
The first requirement of not relying upon an operating system severely 
limits the choice of development software. The advent of utilities to 
convert standard generated .EXE files, converting them to position 
dependent code has certainly helped.
<P>
How-ever, the downfall occurs in that the library routines used by 
the mainstream compilers are not rommable. The routines use DOS to 
perform most functions, and as DOS is not present, any call to these 
functions will result in a system crash.
<P>
The second requirement for position dependent code has been alleviated 
by special utilities. These covert a .EXE file, and assign physical 
addresses to the various segments of the program. The resultant file 
is then copied to an Eprom programmer where the code is transferred 
into a non-volatile memory chip. The chip is then mounted on the target 
system.
<P>
ROMLIB.ASM is the source code for a large or small memory model rom 
code interface for C Compilers. It has been tested with the following 
C Compilers,
<UL>
<LI>    TurboC         V1.00, 1.5
<LI>    Microsoft C    V4.00
<LI>    Intel C86      V1.3
</UL>

The source code does not use DOS to perform any function, thus is 
completely rommable. The rom code interface comprises the following files.
<UL>
<LI><A HREF="sw/romlib/romlib.asm">ROMLIB.ASM</A>,  assembler source for rom 
	code routines
<LI><A HREF="sw/romlib/romlib.mac">ROMLIB.MAC</A>,  assembler macro file 
	used to determine offsets for parameters accepted by routines
<LI><A HREF="sw/romlib/romlib.h">ROMLIB.H</A>,    prototype header file for 
	C compilers
<LI><A HREF="sw/romlib/romdemo.c">ROMDEMO.C</A>,   turboc demonstration 
	program
<LI><A HREF="sw/romlib/romdemo.cfg">ROMDEMO.CFG</A>, configuration file 
	specifying addresses for each program segment
<LI><A HREF="sw/romlib/romdemo.prj">ROMDEMO.PRJ</A>, project file
</UL>
Many clones have empty ROM sockets on the motherboard. These empty 
sockets house the BASIC chips on true PC machines. On a PC clone, 
these sockets are usually mapped as follows.
<UL>
<LI>    FE00    ROM BIOS
<LI>    FC00
<LI>    FA00
<LI>    F800
<LI>    F600
<LI>    F400
</UL>
The empty sockets on the motherboard provide an ideal solution for 
producing embedded code. The solution is to dump the program into 
Eprom, place it into the appropriate slot, and when the PC is turned 
on, the program in Eprom will take over.
<P>

Well, life is not that simple. Whether the code stored in these Eproms 
ever gets to execute depends upon a lot of things. Most clones will 
generate an int18h instruction if the boot from the floppy drive was 
unsuccessful (when the enter key is pressed, some may require more 
than one enter key press!). This is due because most clones generate 
an int19h instruction to boot from floppy, and when this is unsuccessful, 
the type int18h instruction is executed, forcing a jump to F600:0000
<P>
If the Eproms are placed into the correct sockets, the code should now 
be executing. Lifting the lid off the clone should reveal the ROM BIOS 
chip, and about four or five empty sockets (latest clones only have one 
empty socket, which takes up the memory space of the four or five empty 
ones on earlier machines). The socket which is the FOURTH empty one 
furthest away from the BIOS chip is that which will be executed first 
(it maps to F600:0000).
<P>
Having identified where to place the first Eprom on the motherboard, 
the next task is to generate some code to try everything out. Problems 
again arise, as a utility is needed to locate the program to the correct 
physical addresses in memory. Another problem is that in using library 
routines supplied with common compilers invariably call DOS routines. 
As DOS will not be loaded when the program starts up, the use of functions 
like printf() and puts() are forbidden (they will cause a system crash).
<P>
This means that you need to write your own routines to perform I/O, 
which are not reliant upon DOS being present. As a short cut, because the 
ROM BIOS chip is still present, some of the routines in that chip can be 
used. A runtime interface which adheres to the above rules is called 
ROMLIB and will be used in the examples which follow.
<P>
A good article on romcode generation using turboc, written by R Naro, 
was published in Dr Dobbs, Dec 1987. The article develops a locate utility 
which converts .EXE files to position dependent code. The following 
examples use the locate utility to demonstrate an example rommable 
program written in turboc.
<P>
<HR>
<B>PREPARING THE ROMLIB OBJECT CODE INTERFACE ROUTINES</B><BR>
The file <A HREF="sw/romlib/romlib.asm">ROMLIB.ASM</A> supports both small 
and large memory models, as well as an option for saving the DI and SI 
registers on entry to procedures (if you intend to use register variables in 
your C programs).
<P>
The following command line assembles the romcode interface for a 
large memory model and register variables.
<PRE>
  MASM  romlib;
</PRE>
Note that the defaults are a large memory model with the DI and SI 
registers saved. If you do not intend to use register based variables in 
your C program, then the NREGISTER option should be specified as follows,
<PRE>
  MASM  /DNREGISTER romlib;
</PRE>
This will create an object file which will be linked together with the 
C program, providing the runtime support needed.
<P>
<HR>
<B>COMPILING THE PROGRAM ROMDEMO.C</B><BR>
Using the turboc compiler, compile the file 
<A HREF="sw/romlib/romdemo.c">ROMDEMO.C</A> to object format, using a large 
memory model, unsigned chars and register variables on.
<P>
<HR>
<B>COMBINING THE OBJECT FILES USING TLINK</B><BR>
The tlink utility will combine the object files into a single executable 
program. DO NOT try to run this program on your machine under DOS. It is 
designed to fit in specific memory locations.
<PRE>
  TLINK  /m  tc romdemo romlib, romdemo, romdemo
</PRE>
This combines the startup code from R Naros article (tc) with the 
object files <i>romdemo</i> and <i>romlib</i>, creating <i>romdemo.exe</i> 
and a map file name <i>romdemo.map</i>.
<P>
<HR>
<B>DECIDING WHERE TO PLACE THE CODE</B><BR>
When the locate utility (Dr Dobbs Dec 1987, R Naro) is executed, it 
searches for a configuration file which specifies where the various 
program segments are to reside. As DOS is not present, and assuming 
that the PC we have has 640k of RAM, then it is an easy task of 
assigning addresses to the various segments.
<P>
Obviously, the code segment must start at F600 so as to intercept with 
the int18h instruction upon an unsuccessful cold boot. The data segment 
and stack segment can go anywhere except low memory (ie, 0000 which is 
used to store all the interrupt vectors).
<P>
The supplied file <A HREF="sw/romlib/romdemo.cfg"<i>ROMDEMO.CFG</i></A> 
details the addresses assigned to the program segments, which are,
<PRE>
    CODE   F600
    DATA   6000
    STACK  7000

</PRE>
This instructs the locate utility to copy the initialized data variables 
into a CONSTant segment, which is part of the Eprom. The startup code 
copies these variables into RAM when the program begins.
<P>
To locate the program, generating a file suitable for transfer into Eprom, 
type the command
<PRE>
  LOCATE ROMDEMO

</PRE>
This creates <i>ROMDEMO.HEX</i>, an Intel hex format file which can be 
downloaded into an Eprom programmer for burning into Eprom. Many companies 
will be able to do this for you, at relatively low cost. The Eprom we used 
in the demonstration was a type 2764 (8k x 8 bits), and the code started at 
offset 0 in the Eprom.
<P>
Once the code is in the Eprom, insert it into the empty slot associated 
with the location F600 (ensure the computer is turned off, preferably use 
anti-static precautions, and ensure its the right way round).
<P>
Turn the computer on, ensuring there is no system diskette in the disk 
drive (this assumes there is also no hard disk). Once the 'no system disk, 
press any key to re-boot' message is displayed, press the enter key. The 
computer then executes the int18h instruction, and execution branches to 
the code stored in the Eprom.
<P>
<HR>
<B>ROMLIB - A DESCRIPTION OF THE VARIOUS RUNTIME ROMMABLE ROUTINES</B><BR>
<PRE>
<B>BOOT from disk</B>                          ipl_load()
This function generates an int19h instruction, which will cause a cold 
boot from diskette. Its prototype is

   void ipl_load( void );
   
example usage,
   
   ipl_load();                /* boot from disk drive */


<B>JUMP to Basic ROM</B>                       basic_rom()
This function generates an int18h instruction, causing a jump to 
location F600:0000. Its prototype is
    
   void basic_rom( void );

example usage,
   
   basic_rom();             /* execute program stored in Eprom */


<B>INITIALIZE Serial Card</B>                  ser_init()
This function initializes the serial card. Its prototype is

   void ser_init( unsigned char parameters, int comport );

where comport         specifies COM1 (0) or COM2 (1)
      parameters      specifies
		      bit 7,6,5  baud rate (111=9600 baud)
		      bit 4,3    parity    (00=N,01=Odd,11=Even)
		      bit 2      stops     (0=1,1=2stops)
		      bit 1,0    word size (10=7,11=8bits)

example usage,

   ser_init( (unsigned char) 0xe3, 0);
   /* initialize com1 to 9600,n,8,1 */


<B>READ CHARACTER FROM SERIAL PORT</B>        serial_in()
This function returns an integer which represents the character read from 
the specified serial port. It uses the rom bios function int16h. The 
prototype is

   int serial_in( int comport );

example usage,

   int comport = 0;
   unsigned char ch;

   ch = serial_in( comport );


<B>WRITING A CHARACTER TO A SERIAL PORT</B>   serial_out()
This function writes the character out to the specified com port. It 
uses the rom bios function int16h. The function prototype is,

   void serial_out( char ch, int comport );

example usage,

   int comport = 0;
   char ch = 'A';

   serial_out( ch, comport );


<B>READ SERIAL PORT STATUS</B>                 serial_status()
This function returns the status of the Modem Control and Line Control 
registers. The MCR status is returned in AL, and the LCR status in AH. 
The rom bios function int16h is used. The prototype is,

   int serial_status( int comport );

example usage,

   int temp, comport = 0, mcrstatus, lcrstatus;

   temp = serial_status( comport );
   mcrstatus = temp & 0xff;
   lcrstatus = (temp & 0xff00) >> 8;


<B>OUTPUTTING A CHARACTER TO THE PRINTER</B>   prn_out()
This function outputs a character to the specified printer. It uses the 
rom bios function int17h. Its prototype is

   void prn_out( char byte, int printer );

where printer is a value between 0 and 3 (LPT1 = 0).

example usage,

   int printer = 0;
   char *message = "Hello there.";

   while( *message++ )
      prn_out( *message, printer );


<B>READ PRINTER STATUS</B>                     prn_status()
This function returns the status of the specified printer. It uses the 
rom bios function int17h. Its prototype is

   int prn_status( int printer );

The return status is returned in the AH register
   0x80 = busy       0x40 = acknowledge      0x20 = out of paper
   0x10 = on-line    0x08 = I/O error        0x01 = time out

example usage,

   #define out_of_paper 0x20
   int status_lpt1, printer = 0;

   status_lpt1 = (prn_status( printer ) &gt;&gt; 8);
   if( status_lpt1 == out_of_paper ) {
       printstr("Sorry, printer is out of paper.");
       beep();
    }
    else
       .....


<B>INITIALIZE PRINTER PORT</B>                 prn_init()
This function initializes the specified printer port. It uses the rom 
bios function int17h. The prototype is,

   int prn_init( int printer );

and returns a printer status byte in AH. See the prn_status() function 
call for a description of the status bits.

example usage,

   #define on_line 0x10
   int printer = 0, status;

   status = (prn_init(printer) &gt;&gt; 8);
   if( status != on_line )  {
       printstr("Sorry, printer is off_line.");
       beep();
   }


<B>TEST FOR KEYBOARD CHARACTER READY</B>       kbhit()
This function returns non-zero if a character is available from the 
keyboard, otherwise it returns zero. If a character is available, the 
function kbgetch() is used to retrieve the character. The function uses 
int6h and its prototype is

   int kbhit( void );

example usage,

   int key;

   while( kbhit() == 0)
	;
   key = kbgetch() &amp; 0xff;


<B>READ A CHARACTER FROM THE KEYBOARD</B>      kbgetch()
This function returns an integer which contains the ASCII code in AL, 
and the keyscan code in AH. It uses int16h and the prototype is

   int kbgetch( void );

example usage;

   int key;

   key = kbgetch();
   if( (key &amp; 0xff ) == 0)    /* is it a function or special key */
      key = key &gt;&gt; 8;
   else
      key = key &amp; 0xff;       /* no, its ascii */


<B>GET KEYBOARD SHIFT STATUS</B>               kbstatus()
This function returns the status of the caps, shift, alt, ctrl, numlock 
and scroll-lock keys. It uses the rom bios function int16h, and the 
prototype is

   int kbstatus( void );

The return integer has the following values.
     0x80 = insert on         0x40 = caps toggled
     0x20 = num lock togled   0x10 = scroll lock toggled
     0x08 = alt key pressed   0x04 = ctrl key pressed
     0x02 = left shift down   0x01 = right shift down

example usage,

   #define INS 0x80
   int keystatus;

   keystatus = kbstatus();
   if( (keystatus &amp; INS) == INS)
      beep();


<B>READ SEGMENT REGISTER VALUES</B>            segread()
This function copies the values of the DS, ES, SS and CS registers 
into the structure pointed to by sregs. The structure definition is 
included in the file ronlib.h. The prototype is

   void segread( struct SREGS *sregs );

example usage,

   struct SREGS sregs;

   segread( &amp;sregs );


<B>READ A BYTE FROM A PORT</B>                 inportb()
This function reads a byte from an input port. Its prototype is,

   int inport( int port_number );

example usage,

   int value, port = 0x3ff;

   value = inportb( port );


<B>WRITE A BYTE TO A PORT</B>                  outportb()
This function writes a character out to an output port. The prototype is

   void outportb( int port, char byte );

example usage,

   int port = 0x3d9;
   
   outportb( port, '9' );


<B>SOFTWARE GENERATED INTERRUPTS</B>           int86()
This function generates a software interrupt of the type specified. 
It accepts a structure (defined in romlib.h) which represents the 
programming model of the CPU. Before executing the interrupt, the 
function copies the value of each pseudo register into the cpu's 
registers. On exit, the function copies the cpu registers back into 
the pseudo registers. The prototype is

void int86(int intnum,struct REGS *inregs,struct REGS *outregs );

example usage,

   struct REGS regs;
   int video_page, video_columns, video_mode;

   regs.h.ah = 15;            /* get video status */
   int86( 0x10, &amp;regs, &amp;regs );
   video_page = regs.h.bh;
   video_columns = regs.h.ah;
   video_mode = regs.h.al;


<B>WRITE A BYTE TO MEMORY</B>                  pokeb()
This function writes a byte to the specified absolute address. The 
prototype is,

void pokeb(unsigned segment,unsigned offset,unsigned char byte );

example usage,

   unsigned int segment = 0xb000, offset = 0;
   unsigned char value = 'A';

   pokeb( segment, offset, byte );


<B>READ A BYTE FROM MEMORY</B>                 peekb()
This function returns a character from memory. The prototype is

   char peekb( unsigned segment, offset );

example usage;

   unsigned int segment = 0xb000, offset = 0;
   unsigned char value;

   value = peekb( segment, offset );


<B>EQUIPMENT DETERMINATION</B>                 biosequip()
This function returns the equipment settings for the attatched hardware. 
It uses int11h and the prototype is

⌨️ 快捷键说明

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